<!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>[224973] 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/224973">224973</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2017-11-17 10:40:09 -0800 (Fri, 17 Nov 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>SVG scrolling anchor should be reset if the fragmentIdentifier does not exist or is not provided
https://bugs.webkit.org/show_bug.cgi?id=176577

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-11-17
Reviewed by Simon Fraser.

Source/WebCore:

Because the SVGImage can be cached only once but used multiple times with
different fragmentIdentifiers, SVGImage has to call FrameView::scrollToFragment()
before the image is displayed. If the fragmentIdentifier is not provided
in the URL or it does not exist in the SVGImage, FrameView::scrollToFragment()
has to reset the scrolling anchor of the SVG as if it was not displayed before.
We do not want the previous scrolling anchor to be used when the FrameView
of SVGImage can't scroll to the current fragmentIdentifier for any reason.

Test: http/tests/svg/svg-fragment-url-special-cases.html

* page/FrameView.cpp:
(WebCore::FrameView::scrollToFragment):
(WebCore::FrameView::scrollToAnchor):
(WebCore::FrameView::resetScrollAnchor):
* page/FrameView.h:
* platform/URL.cpp:
(WebCore::URL::fragmentIdentifier const): Call hasFragmentIdentifier()
instead of repeating the same condition.
(WebCore::decodeURLEscapeSequences):
* svg/SVGSVGElement.cpp:
(WebCore::SVGSVGElement::findViewAnchor const):
(WebCore::SVGSVGElement::findRootAnchor const):
(WebCore::SVGSVGElement::scrollToAnchor): We want to know whether the SVG
root element could scroll to the fragmentIdentifier or not. If it could not,
FrameView::scrollToAnchor() can still try one last time to do the scrolling
only if anchorElement is not nullptr.
(WebCore::SVGSVGElement::resetScrollAnchor): Reset the FrameView scrolling
state to its initial value.
* svg/SVGSVGElement.h:

LayoutTests:

* http/tests/svg/svg-fragment-url-special-cases-expected.html: Added.
* http/tests/svg/svg-fragment-url-special-cases.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="#trunkSourceWebCorepageFrameViewcpp">trunk/Source/WebCore/page/FrameView.cpp</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewh">trunk/Source/WebCore/page/FrameView.h</a></li>
<li><a href="#trunkSourceWebCoreplatformURLcpp">trunk/Source/WebCore/platform/URL.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGSVGElementcpp">trunk/Source/WebCore/svg/SVGSVGElement.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGSVGElementh">trunk/Source/WebCore/svg/SVGSVGElement.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestssvgsvgfragmenturlspecialcasesexpectedhtml">trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases-expected.html</a></li>
<li><a href="#trunkLayoutTestshttptestssvgsvgfragmenturlspecialcaseshtml">trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/LayoutTests/ChangeLog 2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2017-11-17  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        SVG scrolling anchor should be reset if the fragmentIdentifier does not exist or is not provided
+        https://bugs.webkit.org/show_bug.cgi?id=176577
+
+        Reviewed by Simon Fraser.
+
+        * http/tests/svg/svg-fragment-url-special-cases-expected.html: Added.
+        * http/tests/svg/svg-fragment-url-special-cases.html: Added.
+
</ins><span class="cx"> 2017-11-16  Antoine Quint  <graouts@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Web Animations] Force a stacking context during animations that animate properties that will force a stacking context
</span></span></pre></div>
<a id="trunkLayoutTestshttptestssvgsvgfragmenturlspecialcasesexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases-expected.html (0 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases-expected.html                            (rev 0)
+++ trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases-expected.html       2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+     <style>
+        img {
+            width: 100px;
+            height: 100px;
+        }
+        span {
+            display: inline-block;
+            width: 100px;
+            height: 100px;
+            background-color: green;
+        }
+    </style>
+</head>
+<body>
+    <div id="group-1">
+        <p>Image URL with no fragmentIdentifier:</p>
+        <img src="resources/rgb-icons-1.svg">
+        <img src="resources/rgb-icons-1.svg">
+    </div>
+    <div id="group-2">
+        <p>Image URL with trailing spaces after the fragmentIdentifier:</p>
+        <span></span>
+        <span></span>
+        <span></span>
+    </div>
+    <div id="group-3">
+        <p>Image URL with non-existent fragmentIdentifier:</p>
+        <img src="resources/rgb-icons-1.svg">
+        <img src="resources/rgb-icons-1.svg">
+    </div>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestssvgsvgfragmenturlspecialcaseshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases.html (0 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases.html                             (rev 0)
+++ trunk/LayoutTests/http/tests/svg/svg-fragment-url-special-cases.html        2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+     <style>
+        img {
+            width: 100px;
+            height: 100px;
+         }
+    </style>
+</head>
+<body>
+    <div id="group-1">
+        <p>Image URL with no fragmentIdentifier:</p>
+        <img src="resources/rgb-icons-1.svg#">
+        <img src="http://localhost:8000/svg/resources/rgb-icons-2.svg#">
+        <img src="http://127.0.0.1:8000/svg/resources/rgb-icons-3.svg#">
+    </div>
+    <div id="group-2">
+        <p>Image URL with trailing spaces after the fragmentIdentifier:</p>
+        <img src="resources/rgb-icons-1.svg#green-icon-view    ">
+        <img src="http://localhost:8000/svg/resources/rgb-icons-2.svg#svgView(viewBox(0,32,32,32))    ">
+        <img src="http://127.0.0.1:8000/svg/resources/rgb-icons-3.svg#green-icon    ">
+    </div>
+    <div id="group-3">
+        <p>Image URL with non-existent fragmentIdentifier:</p>
+        <img src="resources/rgb-icons-1.svg#non-existent-icon-view">
+        <img src="http://localhost:8000/svg/resources/rgb-icons-2.svg#">
+        <img src="http://127.0.0.1:8000/svg/resources/rgb-icons-3.svg#non-existent-icon">
+    </div>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/Source/WebCore/ChangeLog      2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -1,3 +1,40 @@
</span><ins>+2017-11-17  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        SVG scrolling anchor should be reset if the fragmentIdentifier does not exist or is not provided
+        https://bugs.webkit.org/show_bug.cgi?id=176577
+
+        Reviewed by Simon Fraser.
+
+        Because the SVGImage can be cached only once but used multiple times with
+        different fragmentIdentifiers, SVGImage has to call FrameView::scrollToFragment()
+        before the image is displayed. If the fragmentIdentifier is not provided
+        in the URL or it does not exist in the SVGImage, FrameView::scrollToFragment()
+        has to reset the scrolling anchor of the SVG as if it was not displayed before.
+        We do not want the previous scrolling anchor to be used when the FrameView
+        of SVGImage can't scroll to the current fragmentIdentifier for any reason.
+
+        Test: http/tests/svg/svg-fragment-url-special-cases.html
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::scrollToFragment):
+        (WebCore::FrameView::scrollToAnchor):
+        (WebCore::FrameView::resetScrollAnchor):
+        * page/FrameView.h:
+        * platform/URL.cpp:
+        (WebCore::URL::fragmentIdentifier const): Call hasFragmentIdentifier() 
+        instead of repeating the same condition.
+        (WebCore::decodeURLEscapeSequences):
+        * svg/SVGSVGElement.cpp:
+        (WebCore::SVGSVGElement::findViewAnchor const):
+        (WebCore::SVGSVGElement::findRootAnchor const):
+        (WebCore::SVGSVGElement::scrollToAnchor): We want to know whether the SVG 
+        root element could scroll to the fragmentIdentifier or not. If it could not,
+        FrameView::scrollToAnchor() can still try one last time to do the scrolling
+        only if anchorElement is not nullptr.
+        (WebCore::SVGSVGElement::resetScrollAnchor): Reset the FrameView scrolling
+        state to its initial value.
+        * svg/SVGSVGElement.h:
+
</ins><span class="cx"> 2017-11-17  Youenn Fablet  <youenn@apple.com>
</span><span class="cx"> 
</span><span class="cx">         ServiceWorker intercepted FetchRequest should have their referrer set appropriately.
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.cpp (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.cpp  2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/Source/WebCore/page/FrameView.cpp     2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -2086,28 +2086,26 @@
</span><span class="cx"> 
</span><span class="cx"> bool FrameView::scrollToFragment(const URL& url)
</span><span class="cx"> {
</span><del>-    // If our URL has no ref, then we have no place we need to jump to.
-    // OTOH If CSS target was set previously, we want to set it to 0, recalc
-    // and possibly repaint because :target pseudo class may have been
-    // set (see bug 11321).
-    if (!url.hasFragmentIdentifier()) {
-        frame().document()->setCSSTarget(nullptr);
-        return false;
-    }
-
</del><span class="cx">     String fragmentIdentifier = url.fragmentIdentifier();
</span><span class="cx">     if (scrollToAnchor(fragmentIdentifier))
</span><span class="cx">         return true;
</span><span class="cx"> 
</span><span class="cx">     // Try again after decoding the ref, based on the document's encoding.
</span><del>-    if (TextResourceDecoder* decoder = frame().document()->decoder())
-        return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
</del><ins>+    if (TextResourceDecoder* decoder = frame().document()->decoder()) {
+        if (scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding())))
+            return true;
+    }
</ins><span class="cx"> 
</span><ins>+    resetScrollAnchor();
</ins><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool FrameView::scrollToAnchor(const String& name)
</del><ins>+bool FrameView::scrollToAnchor(const String& fragmentIdentifier)
</ins><span class="cx"> {
</span><ins>+    // If our URL has no ref, then we have no place we need to jump to.
+    if (fragmentIdentifier.isNull())
+        return false;
+
</ins><span class="cx">     ASSERT(frame().document());
</span><span class="cx">     auto& document = *frame().document();
</span><span class="cx"> 
</span><span class="lines">@@ -2118,23 +2116,26 @@
</span><span class="cx"> 
</span><span class="cx">     document.setGotoAnchorNeededAfterStylesheetsLoad(false);
</span><span class="cx"> 
</span><del>-    Element* anchorElement = document.findAnchor(name);
</del><ins>+    Element* anchorElement = document.findAnchor(fragmentIdentifier);
</ins><span class="cx"> 
</span><span class="cx">     // Setting to null will clear the current target.
</span><span class="cx">     document.setCSSTarget(anchorElement);
</span><span class="cx"> 
</span><span class="cx">     if (is<SVGDocument>(document)) {
</span><ins>+        if (fragmentIdentifier.isEmpty())
+            return false;
</ins><span class="cx">         if (auto rootElement = SVGDocument::rootElement(document)) {
</span><del>-            rootElement->scrollToAnchor(name, anchorElement);
</del><ins>+            if (rootElement->scrollToFragment(fragmentIdentifier))
+                return true;
+            // If SVG failed to scrollToAnchor() and anchorElement is null, no other scrolling will be possible.
</ins><span class="cx">             if (!anchorElement)
</span><del>-                return true;
</del><ins>+                return false;
</ins><span class="cx">         }
</span><ins>+    } else if (!anchorElement && !(fragmentIdentifier.isEmpty() || equalLettersIgnoringASCIICase(fragmentIdentifier, "top"))) {
+        // Implement the rule that "" and "top" both mean top of page as in other browsers.
+        return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Implement the rule that "" and "top" both mean top of page as in other browsers.
-    if (!anchorElement && !(name.isEmpty() || equalLettersIgnoringASCIICase(name, "top")))
-        return false;
-
</del><span class="cx">     ContainerNode* scrollPositionAnchor = anchorElement;
</span><span class="cx">     if (!scrollPositionAnchor)
</span><span class="cx">         scrollPositionAnchor = frame().document();
</span><span class="lines">@@ -2192,6 +2193,26 @@
</span><span class="cx">     ScrollView::setScrollPosition(scrollPosition);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void FrameView::resetScrollAnchor()
+{
+    ASSERT(frame().document());
+    auto& document = *frame().document();
+
+    // If CSS target was set previously, we want to set it to 0, recalc
+    // and possibly repaint because :target pseudo class may have been
+    // set (see bug 11321).
+    document.setCSSTarget(nullptr);
+
+    if (is<SVGDocument>(document)) {
+        if (auto rootElement = SVGDocument::rootElement(document)) {
+            // We need to update the layout before resetScrollAnchor(), otherwise we
+            // could really mess things up if resetting the anchor comes at a bad moment.
+            document.updateStyleIfNeeded();
+            rootElement->resetScrollAnchor();
+        }
+    }
+}
+
</ins><span class="cx"> void FrameView::contentsResized()
</span><span class="cx"> {
</span><span class="cx">     // For non-delegated scrolling, updateTiledBackingAdaptiveSizing() is called via addedOrRemovedScrollbar() which occurs less often.
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.h (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.h    2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/Source/WebCore/page/FrameView.h       2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -742,6 +742,7 @@
</span><span class="cx">     void scrollPositionChanged(const ScrollPosition& oldPosition, const ScrollPosition& newPosition);
</span><span class="cx">     void scrollableAreaSetChanged();
</span><span class="cx">     void sendScrollEvent();
</span><ins>+    void resetScrollAnchor();
</ins><span class="cx"> 
</span><span class="cx">     bool hasCustomScrollbars() const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URL.cpp (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URL.cpp    2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/Source/WebCore/platform/URL.cpp       2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -224,7 +224,7 @@
</span><span class="cx"> 
</span><span class="cx"> String URL::fragmentIdentifier() const
</span><span class="cx"> {
</span><del>-    if (!m_isValid || m_queryEnd == m_string.length())
</del><ins>+    if (!hasFragmentIdentifier())
</ins><span class="cx">         return String();
</span><span class="cx"> 
</span><span class="cx">     return m_string.substring(m_queryEnd + 1);
</span><span class="lines">@@ -674,11 +674,15 @@
</span><span class="cx"> 
</span><span class="cx"> String decodeURLEscapeSequences(const String& string)
</span><span class="cx"> {
</span><ins>+    if (string.isEmpty())
+        return string;
</ins><span class="cx">     return decodeEscapeSequences<URLEscapeSequence>(string, UTF8Encoding());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> String decodeURLEscapeSequences(const String& string, const TextEncoding& encoding)
</span><span class="cx"> {
</span><ins>+    if (string.isEmpty())
+        return string;
</ins><span class="cx">     return decodeEscapeSequences<URLEscapeSequence>(string, encoding);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGSVGElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGSVGElement.cpp (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGSVGElement.cpp       2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/Source/WebCore/svg/SVGSVGElement.cpp  2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -635,8 +635,27 @@
</span><span class="cx">     return transform;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SVGSVGElement::scrollToAnchor(const String& fragmentIdentifier, Element* anchorNode)
</del><ins>+SVGViewElement* SVGSVGElement::findViewAnchor(const String& fragmentIdentifier) const
</ins><span class="cx"> {
</span><ins>+    auto* anchorElement = document().findAnchor(fragmentIdentifier);
+    return is<SVGViewElement>(anchorElement) ? downcast<SVGViewElement>(anchorElement): nullptr;
+}
+
+SVGSVGElement* SVGSVGElement::findRootAnchor(const SVGViewElement* viewElement) const
+{
+    auto* viewportElement = SVGLocatable::nearestViewportElement(viewElement);
+    return is<SVGSVGElement>(viewportElement) ? downcast<SVGSVGElement>(viewportElement) : nullptr;
+}
+
+SVGSVGElement* SVGSVGElement::findRootAnchor(const String& fragmentIdentifier) const
+{
+    if (auto* viewElement = findViewAnchor(fragmentIdentifier))
+        return findRootAnchor(viewElement);
+    return nullptr;
+}
+
+bool SVGSVGElement::scrollToFragment(const String& fragmentIdentifier)
+{
</ins><span class="cx">     auto renderer = this->renderer();
</span><span class="cx">     auto view = m_viewSpec;
</span><span class="cx">     if (view)
</span><span class="lines">@@ -649,7 +668,7 @@
</span><span class="cx">         // FIXME: XPointer references are ignored (https://bugs.webkit.org/show_bug.cgi?id=17491)
</span><span class="cx">         if (renderer && hadUseCurrentView)
</span><span class="cx">             RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
</span><del>-        return;
</del><ins>+        return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (fragmentIdentifier.startsWith("svgView(")) {
</span><span class="lines">@@ -661,7 +680,7 @@
</span><span class="cx">             view->reset();
</span><span class="cx">         if (renderer && (hadUseCurrentView || m_useCurrentView))
</span><span class="cx">             RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
</span><del>-        return;
</del><ins>+        return m_useCurrentView;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Spec: If the SVG fragment identifier addresses a "view" element within an SVG document (e.g., MyDrawing.svg#MyView
</span><span class="lines">@@ -668,22 +687,44 @@
</span><span class="cx">     // or MyDrawing.svg#xpointer(id('MyView'))) then the closest ancestor "svg" element is displayed in the viewport.
</span><span class="cx">     // Any view specification attributes included on the given "view" element override the corresponding view specification
</span><span class="cx">     // attributes on the closest ancestor "svg" element.
</span><del>-    if (is<SVGViewElement>(anchorNode)) {
-        auto& viewElement = downcast<SVGViewElement>(*anchorNode);
-        auto viewportElement = makeRefPtr(SVGLocatable::nearestViewportElement(&viewElement));
-        if (is<SVGSVGElement>(viewportElement)) {
-            auto& element = downcast<SVGSVGElement>(*viewportElement);
-            element.inheritViewAttributes(viewElement);
-            if (auto* renderer = element.renderer())
</del><ins>+    if (auto* viewElement = findViewAnchor(fragmentIdentifier)) {
+        if (auto* rootElement = findRootAnchor(viewElement)) {
+            rootElement->inheritViewAttributes(*viewElement);
+            if (auto* renderer = rootElement->renderer())
</ins><span class="cx">                 RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
</span><ins>+            m_currentViewFragmentIdentifier = fragmentIdentifier;
+            return true;
</ins><span class="cx">         }
</span><del>-        return;
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // FIXME: We need to decide which <svg> to focus on, and zoom to it.
</span><span class="cx">     // FIXME: We need to actually "highlight" the viewTarget(s).
</span><ins>+    return false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SVGSVGElement::resetScrollAnchor()
+{
+    if (!m_useCurrentView && m_currentViewFragmentIdentifier.isEmpty())
+        return;
+
+    if (m_viewSpec)
+        m_viewSpec->reset();
+
+    if (!m_currentViewFragmentIdentifier.isEmpty()) {
+        if (auto* rootElement = findRootAnchor(m_currentViewFragmentIdentifier)) {
+            SVGViewSpec& view = rootElement->currentView();
+            view.setViewBoxBaseValue(viewBox());
+            view.setPreserveAspectRatioBaseValue(preserveAspectRatioBaseValue());
+            view.setZoomAndPanBaseValue(zoomAndPan());
+            m_currentViewFragmentIdentifier = { };
+        }
+    }
+
+    m_useCurrentView = false;
+    if (renderer())
+        RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer());
+}
+
</ins><span class="cx"> void SVGSVGElement::inheritViewAttributes(const SVGViewElement& viewElement)
</span><span class="cx"> {
</span><span class="cx">     SVGViewSpec& view = currentView();
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGSVGElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGSVGElement.h (224972 => 224973)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGSVGElement.h 2017-11-17 18:38:32 UTC (rev 224972)
+++ trunk/Source/WebCore/svg/SVGSVGElement.h    2017-11-17 18:40:09 UTC (rev 224973)
</span><span class="lines">@@ -113,7 +113,8 @@
</span><span class="cx"> public:
</span><span class="cx">     static Ref<SVGSVGElement> create(const QualifiedName&, Document&);
</span><span class="cx">     static Ref<SVGSVGElement> create(Document&);
</span><del>-    void scrollToAnchor(const String& fragmentIdentifier, Element* anchor);
</del><ins>+    bool scrollToFragment(const String& fragmentIdentifier);
+    void resetScrollAnchor();
</ins><span class="cx"> 
</span><span class="cx">     using SVGGraphicsElement::ref;
</span><span class="cx">     using SVGGraphicsElement::deref;
</span><span class="lines">@@ -155,11 +156,16 @@
</span><span class="cx">     void inheritViewAttributes(const SVGViewElement&);
</span><span class="cx">     Ref<NodeList> collectIntersectionOrEnclosureList(SVGRect&, SVGElement*, bool (*checkFunction)(SVGElement&, SVGRect&));
</span><span class="cx"> 
</span><ins>+    SVGViewElement* findViewAnchor(const String& fragmentIdentifier) const;
+    SVGSVGElement* findRootAnchor(const SVGViewElement*) const;
+    SVGSVGElement* findRootAnchor(const String&) const;
+
</ins><span class="cx">     bool m_useCurrentView { false };
</span><span class="cx">     SVGZoomAndPanType m_zoomAndPan { SVGZoomAndPanMagnify };
</span><span class="cx">     Ref<SMILTimeContainer> m_timeContainer;
</span><span class="cx">     FloatPoint m_currentTranslate;
</span><span class="cx">     RefPtr<SVGViewSpec> m_viewSpec;
</span><ins>+    String m_currentViewFragmentIdentifier;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline bool SVGSVGElement::useCurrentView() const
</span></span></pre>
</div>
</div>

</body>
</html>