Load event must be fired only for the SVG structurally external elements and the outermost SVG element
https://bugs.webkit.org/show_bug.cgi?id=203044

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2019-10-18
Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

* web-platform-tests/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-expected.txt:
The timeout issues are now fixed. webkit.org/b/202013 will fix the other
failures.

* web-platform-tests/svg/images/20x20.png: Added.
Add an image which is referenced by these tests:
    web-platform-tests/svg/import/styling-pres-02-f-manual.svg
    web-platform-tests/svg/import/struct-use-01-t-manual.svg
    web-platform-tests/svg/import/interact-events-02-b-manual.svg

* web-platform-tests/svg/linking/scripted/href-script-element-expected.txt:

Source/WebCore:

The SVG1.1 spec for SVGLoad event is:
    https://www.w3.org/TR/SVG11/interact.html

The SVG2 spec for the load event is:
    https://www.w3.org/TR/SVG/changes.html#interact
    https://www.w3.org/TR/SVG/interact.html

SVG2 removes the SVGExternalResourcesRequired interface. It also simplifies
the rules for firing the load event and made them consistent with the HTML
specs. The plan is to remove SVGExternalResourcesRequired in a following
patch. This patch makes SVGExternalResourcesRequired have no effect on the
load event firing rules. It moves all the functionalities to SVGURIReference
as a step towards removing the SVGExternalResourcesRequired interface.

Test: svg/custom/image-load-event.html

* dom/Document.cpp:
(WebCore::Document::implicitClose):
Do not use the SVGLoad term. It has been removed from the specs.

* dom/ScriptElement.cpp:
(WebCore::ScriptElement::ScriptElement):
* dom/ScriptElement.h:
(WebCore::ScriptElement::errorOccurred const):
(WebCore::ScriptElement::setErrorOccurred):
Add a method to track the occurrence  of loading error. errorOccurred()
|| haveFiredLoadEvent() means no pending loading activity.

* svg/SVGDocumentExtensions.cpp:
(WebCore::SVGDocumentExtensions::dispatchLoadEventToOutermostSVGElements):
(WebCore::SVGDocumentExtensions::dispatchSVGLoadEventToOutermostSVGElements): Deleted.
* svg/SVGDocumentExtensions.h:
Do not use the SVGLoad term.

* svg/SVGElement.cpp:
(WebCore::SVGElement::sendLoadEventIfPossible):
(WebCore::SVGElement::loadEventTimerFired):
(WebCore::SVGElement::loadEventTimer):
(WebCore::SVGElement::finishParsingChildren):
(WebCore::SVGElement::sendSVGLoadEventIfPossible): Deleted.
(WebCore::SVGElement::sendSVGLoadEventIfPossibleAsynchronously): Deleted.
(WebCore::SVGElement::svgLoadEventTimerFired): Deleted.
(WebCore::SVGElement::svgLoadEventTimer): Deleted.
* svg/SVGElement.h:
finishParsingChildren() won't fire 'load' event anymore. The 'load' event
will be fired explicitly for the outermost SVG element from Document::implicitClose().

* svg/SVGExternalResourcesRequired.cpp:
(WebCore::SVGExternalResourcesRequired::svgAttributeChanged):
(WebCore::SVGExternalResourcesRequired::dispatchLoadEvent): Deleted.
(WebCore::SVGExternalResourcesRequired::insertedIntoDocument): Deleted.
(WebCore::SVGExternalResourcesRequired::finishParsingChildren): Deleted.
(WebCore::SVGExternalResourcesRequired::haveLoadedRequiredResources const): Deleted.
* svg/SVGExternalResourcesRequired.h:
(WebCore::SVGExternalResourcesRequired::setHaveFiredLoadEvent): Deleted.
(WebCore::SVGExternalResourcesRequired::isParserInserted const): Deleted.
(WebCore::SVGExternalResourcesRequired::haveFiredLoadEvent const): Deleted.
* svg/SVGImageElement.cpp:
(WebCore::SVGImageElement::haveLoadedRequiredResources):
* svg/SVGImageLoader.cpp:
(WebCore::SVGImageLoader::dispatchLoadEvent):
The value of externalResourcesRequired() no longer controls firing the
'load' event.

* svg/SVGScriptElement.cpp:
(WebCore::SVGScriptElement::SVGScriptElement):
(WebCore::SVGScriptElement::insertedIntoAncestor):
(WebCore::SVGScriptElement::dispatchErrorEvent):
(WebCore::SVGScriptElement::finishParsingChildren): Deleted.
* svg/SVGScriptElement.h:
dispatchErrorEvent() is now a virtual function. Let SVGScriptElement
overrides it so it can track when the loader finishes its activity.

* svg/SVGStyleElement.cpp:
(WebCore::SVGStyleElement::SVGStyleElement):
* svg/SVGStyleElement.h:

* svg/SVGURIReference.cpp:
(WebCore::SVGURIReference::contextElement const):
(WebCore::SVGURIReference::parseAttribute):
(WebCore::SVGURIReference::haveLoadedRequiredResources const):
(WebCore::SVGURIReference::dispatchLoadEvent):
* svg/SVGURIReference.h:
(WebCore::SVGURIReference::haveFiredLoadEvent const):
(WebCore::SVGURIReference::setHaveFiredLoadEvent):
(WebCore::SVGURIReference::errorOccurred const):
(WebCore::SVGURIReference::setErrorOccurred):
SVGURIReference will decide whether the 'load' event can be fired or not.

* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::SVGUseElement):
(WebCore::SVGUseElement::insertedIntoAncestor):
(WebCore::SVGUseElement::notifyFinished):
(WebCore::SVGUseElement::finishParsingChildren): Deleted.
(WebCore::SVGUseElement::isValid const): Deleted.
(WebCore::SVGUseElement::haveLoadedRequiredResources): Deleted.
(WebCore::SVGUseElement::setHaveFiredLoadEvent): Deleted.
(WebCore::SVGUseElement::haveFiredLoadEvent const): Deleted.
(WebCore::SVGUseElement::svgLoadEventTimer): Deleted.
* svg/SVGUseElement.h:
SVGUseElement needs to track firing the load event or error occurrence
the same way SVGImageElement and SVGScriptElement do.

LayoutTests:

* fast/dom/crash-moving-subtree-between-documents.html:
* fast/dom/focus-style-resolution.html:
* fast/html/marquee-reparent-check.html:
The SVGElement element should not fire "load" event. Set the HTML <body>
element's "onload" event handler to be the function which was set to the
SVGElement's "onload" event handler.

* svg/custom/image-load-event-expected.html: Added.
* svg/custom/image-load-event.html: Added.
Images with external resources or data URIs must fire load events once
the data is loaded or decoded.

* svg/custom/loadevents-async-expected.txt: Removed.
* svg/custom/loadevents-async.html: Removed.
* svg/custom/loadevents-capturing-expected.txt: Removed.
* svg/custom/loadevents-capturing.svg: Removed.
* svg/custom/loadevents-externalresourcesrequired-displaynone-expected.txt: Removed.
* svg/custom/loadevents-externalresourcesrequired-displaynone.svg: Removed.
* svg/custom/loadevents-externalresourcesrequired-expected.txt: Removed.
* svg/custom/loadevents-externalresourcesrequired.svg: Removed.
* svg/custom/loadevents-normal-displaynone-expected.txt: Removed.
* svg/custom/loadevents-normal-displaynone.svg: Removed.
* svg/custom/loadevents-normal-expected.txt: Removed.
* svg/custom/loadevents-normal.svg: Removed.
These tests were implementing the SVG1.1 SVGLoad event interactivity:
https://www.w3.org/TR/SVG11/interact.html where every SVG element had to
fire the SVGLoad event once it parsed its closing tag. SVG structurally
external elements were firing load events when the corresponding external
resources had finished loading but only if externalResourcesRequired = true.

* svg/dom/SVGScriptElement/script-load-and-error-events.svg:
This test had two wrong assumptions:
1) The SVG structurally external element fires a load event when parsing
the children finishes. Then they may fire another load or error event if
externalResourcesRequired = true.
2) The outermost SVG element will not fire its load event unless all the
children fires their load events correctly.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251290 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index a60deca..c6a0e13 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,48 @@
+2019-10-18  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Load event must be fired only for the SVG structurally external elements and the outermost SVG element
+        https://bugs.webkit.org/show_bug.cgi?id=203044
+
+        Reviewed by Simon Fraser.
+
+        * fast/dom/crash-moving-subtree-between-documents.html:
+        * fast/dom/focus-style-resolution.html:
+        * fast/html/marquee-reparent-check.html:
+        The SVGElement element should not fire "load" event. Set the HTML <body>
+        element's "onload" event handler to be the function which was set to the
+        SVGElement's "onload" event handler.
+
+        * svg/custom/image-load-event-expected.html: Added.
+        * svg/custom/image-load-event.html: Added.
+        Images with external resources or data URIs must fire load events once
+        the data is loaded or decoded.
+
+        * svg/custom/loadevents-async-expected.txt: Removed.
+        * svg/custom/loadevents-async.html: Removed.
+        * svg/custom/loadevents-capturing-expected.txt: Removed.
+        * svg/custom/loadevents-capturing.svg: Removed.
+        * svg/custom/loadevents-externalresourcesrequired-displaynone-expected.txt: Removed.
+        * svg/custom/loadevents-externalresourcesrequired-displaynone.svg: Removed.
+        * svg/custom/loadevents-externalresourcesrequired-expected.txt: Removed.
+        * svg/custom/loadevents-externalresourcesrequired.svg: Removed.
+        * svg/custom/loadevents-normal-displaynone-expected.txt: Removed.
+        * svg/custom/loadevents-normal-displaynone.svg: Removed.
+        * svg/custom/loadevents-normal-expected.txt: Removed.
+        * svg/custom/loadevents-normal.svg: Removed.
+        These tests were implementing the SVG1.1 SVGLoad event interactivity:
+        https://www.w3.org/TR/SVG11/interact.html where every SVG element had to
+        fire the SVGLoad event once it parsed its closing tag. SVG structurally
+        external elements were firing load events when the corresponding external
+        resources had finished loading but only if externalResourcesRequired = true.
+
+        * svg/dom/SVGScriptElement/script-load-and-error-events.svg:
+        This test had two wrong assumptions:
+        1) The SVG structurally external element fires a load event when parsing
+        the children finishes. Then they may fire another load or error event if
+        externalResourcesRequired = true.        
+        2) The outermost SVG element will not fire its load event unless all the
+        children fires their load events correctly.
+
 2019-10-18  Russell Epstein  <repstein@apple.com>
 
         REGRESSION (r251262): Layout Test scrollingcoordinator/ios/non-stable-viewport-scroll.html is a Flaky Failure
diff --git a/LayoutTests/fast/dom/crash-moving-subtree-between-documents.html b/LayoutTests/fast/dom/crash-moving-subtree-between-documents.html
index 0f47009..583d410 100644
--- a/LayoutTests/fast/dom/crash-moving-subtree-between-documents.html
+++ b/LayoutTests/fast/dom/crash-moving-subtree-between-documents.html
@@ -1,8 +1,10 @@
 <!DOCTYPE html>
 <html>
 <script>
-if (window.testRunner)
+if (window.testRunner) {
     testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
 function go()
 {
     var v = document.getElementById("v");
@@ -14,19 +16,23 @@
     var d = document.implementation.createHTMLDocument("doc");
     var s = d.createElement("script");
     s.prepend(v);
+    testRunner.notifyDone();
 }
 function eventhandler1()
 {
     v.appendChild(o);
     o.addEventListener("DOMNodeRemoved", eventhandler2);
+    setTimeout(() => {
+        go();
+    }, 0);
 }
 </script>
-<body onload=go()>
+<body onload=eventhandler1()>
 This test passes if it does not assert or crash.
 <a id="a"></a>
 <output id="o">foo</output>
 <video id="v"></video>
 <svg>
-<text onload="eventhandler1()" />
+<text/>
 </body>
 </html>
diff --git a/LayoutTests/fast/dom/focus-style-resolution.html b/LayoutTests/fast/dom/focus-style-resolution.html
index 6a13918..c15459d 100644
--- a/LayoutTests/fast/dom/focus-style-resolution.html
+++ b/LayoutTests/fast/dom/focus-style-resolution.html
@@ -17,6 +17,7 @@
 }
 
 </script>
+<body onload="eventhandler3()">
 This test passes if it doesn't assert or crash.
 <table id="table"></table>
 <form>
@@ -24,7 +25,7 @@
 </form>
 <svg>
 <animate id="anim" attributeName="text-anchor" from="middle" to="inherit" onbegin="eventhandler1()" />
-<text id="txt" onload="eventhandler3()">
+<text id="txt">
 <font color="white"></font>
 <select onfocus="eventhandler2()" autofocus="autofocus">
 <textarea>a</textarea>
diff --git a/LayoutTests/fast/html/marquee-reparent-check.html b/LayoutTests/fast/html/marquee-reparent-check.html
index 6d4b85a..69a7f2fc 100644
--- a/LayoutTests/fast/html/marquee-reparent-check.html
+++ b/LayoutTests/fast/html/marquee-reparent-check.html
@@ -2,32 +2,6 @@
 <html>
 <head>
 <script src="../../resources/js-test-pre.js"></script>
-<script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-description("The test passes if it does not ASSERT in debug builds.");
-
-var innerMarquee;
-var outerMarquee;
-
-function runTest() {
-    innerMarquee = document.getElementById("innerMarquee");
-    outerMarquee = document.getElementById("outerMarquee");
-
-    document.execCommand("createLink", false, "#foo");
-    document.getElementById("htmlTableHeader").innerHTML = "TEST";
-}
-
-function blurHandler() {
-    document.getElementById("htmlTextArea").setSelectionRange(0, 0, "foo");
-}
-
-function focusHandler() {
-    document.getElementById("htmlTextArea").click();
-    innerMarquee.appendChild(outerMarquee);
-}
-</script>
 </head>
 <body>
     <div id="divElement">
@@ -46,8 +20,7 @@
                 <th id="htmlTableHeader">
                     <marquee id="innerMarquee">
                         <svg>
-                            <mesh onload="runTest()">
-                            </mesh>
+                            <mesh/>
                         </svg>
                     </marquee>
                 </th>
@@ -56,6 +29,27 @@
     </table>
     <keygen autofocus="autofocus">
     <iframe>Test Frame</iframe>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        description("The test passes if it does not ASSERT in debug builds.");
+
+        var innerMarquee = document.getElementById("innerMarquee");
+        var outerMarquee = document.getElementById("outerMarquee");
+
+        document.execCommand("createLink", false, "#foo");
+        document.getElementById("htmlTableHeader").innerHTML = "TEST";
+
+        function blurHandler() {
+            document.getElementById("htmlTextArea").setSelectionRange(0, 0, "foo");
+        }
+
+        function focusHandler() {
+            document.getElementById("htmlTextArea").click();
+            innerMarquee.appendChild(outerMarquee);
+        }
+    </script>
     <script src="../../resources/js-test-post.js"></script>
 </body>
 </html>
diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog
index 45825f0..2ad4078 100644
--- a/LayoutTests/imported/w3c/ChangeLog
+++ b/LayoutTests/imported/w3c/ChangeLog
@@ -1,3 +1,22 @@
+2019-10-18  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Load event must be fired only for the SVG structurally external elements and the outermost SVG element
+        https://bugs.webkit.org/show_bug.cgi?id=203044
+
+        Reviewed by Simon Fraser.
+
+        * web-platform-tests/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-expected.txt:
+        The timeout issues are now fixed. webkit.org/b/202013 will fix the other
+        failures.
+
+        * web-platform-tests/svg/images/20x20.png: Added.
+        Add an image which is referenced by these tests:
+            web-platform-tests/svg/import/styling-pres-02-f-manual.svg
+            web-platform-tests/svg/import/struct-use-01-t-manual.svg
+            web-platform-tests/svg/import/interact-events-02-b-manual.svg
+
+        * web-platform-tests/svg/linking/scripted/href-script-element-expected.txt:
+
 2019-10-18  Antti Koivisto  <antti@apple.com>
 
         [CSS Shadow Parts] :part rules should be able to override style attribute
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-expected.txt
index 61873c4..a45ffbe 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/geometry/svg-image-intrinsic-size-with-cssstyle-auto-expected.txt
@@ -1,34 +1,32 @@
 
-Harness Error (TIMEOUT), message = null
-
-TIMEOUT <svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='64' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 256x256 png image, attributes width='128' height='64' and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='128' and CSS 'height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='64' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image, attributes width='50' height='50' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' height='50' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' height='50' and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image, without attributes width and height and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image, attributes height='50' and 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' and CSS height:auto Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image, attributes width='200' height='200' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image, attributes height='200' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image, attributes width='200' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image, without attributes width and height, no css width/height specified Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' Test timed out
-TIMEOUT <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' Test timed out
+PASS <svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='64' 
+FAIL <svg:image> 'auto' sizing with 256x256 png image, attributes width='128' height='64' and CSS 'width:auto' assert_equals: expected 64 but got 128
+FAIL <svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='128' and CSS 'height:auto' assert_equals: expected 64 but got 128
+FAIL <svg:image> 'auto' sizing with 256x256 png image, attributes width='64' height='64' and CSS 'width:auto; height:auto' assert_equals: expected 256 but got 128
+PASS <svg:image> 'auto' sizing with default sized svg image, attributes width='50' height='50' 
+FAIL <svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' height='50' and CSS 'width:auto; height:auto' assert_equals: expected 200 but got 50
+FAIL <svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' height='50' and CSS 'width:auto' assert_equals: expected 100 but got 50
+FAIL <svg:image> 'auto' sizing with 200x100 svg image, without attributes width and height and CSS 'width:auto' assert_equals: expected 200 but got 0
+FAIL <svg:image> 'auto' sizing with 200x100 svg image, attributes height='50' and 'width:auto' assert_equals: expected 100 but got 0
+FAIL <svg:image> 'auto' sizing with 200x100 svg image, attributes width='50' and CSS height:auto assert_equals: expected 25 but got 0
+FAIL <svg:image> 'auto' sizing with default sized svg image, attributes width='200' height='200' and CSS 'width:auto; height:auto' assert_equals: expected 300 but got 200
+FAIL <svg:image> 'auto' sizing with default sized svg image, attributes height='200' and CSS 'width:auto; height:auto' assert_equals: expected 300 but got 0
+FAIL <svg:image> 'auto' sizing with default sized svg image, attributes width='200' and CSS 'width:auto; height:auto' assert_equals: expected 300 but got 200
+FAIL <svg:image> 'auto' sizing with default sized svg image, without attributes width and height, no css width/height specified assert_equals: expected 300 but got 0
+PASS <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified 
+FAIL <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' assert_equals: expected 240 but got 60
+FAIL <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' assert_equals: expected 15 but got 60
+FAIL <svg:image> 'auto' sizing with default sized svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' assert_equals: expected 300 but got 60
+PASS <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified 
+FAIL <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' assert_equals: expected 240 but got 60
+FAIL <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' assert_equals: expected 15 but got 60
+FAIL <svg:image> 'auto' sizing with svg image width='200' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' assert_equals: expected 200 but got 60
+PASS <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified 
+FAIL <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' assert_equals: expected 240 but got 60
+FAIL <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' assert_equals: expected 15 but got 60
+FAIL <svg:image> 'auto' sizing with svg image height='100' viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' assert_equals: expected 400 but got 60
+PASS <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and no css width/height specified 
+FAIL <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto' assert_equals: expected 120 but got 60
+FAIL <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'height:auto' assert_equals: expected 30 but got 60
+FAIL <svg:image> 'auto' sizing with 200x100 svg image viewBox='0 0 400 100', attributes width='60' height='60' and CSS 'width:auto; height:auto' assert_equals: expected 200 but got 60
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/images/20x20.png b/LayoutTests/imported/w3c/web-platform-tests/svg/images/20x20.png
new file mode 100644
index 0000000..32399c6
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/images/20x20.png
Binary files differ
diff --git a/LayoutTests/imported/w3c/web-platform-tests/svg/linking/scripted/href-script-element-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/svg/linking/scripted/href-script-element-expected.txt
index 9a2f472f..8aa3529 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/svg/linking/scripted/href-script-element-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/svg/linking/scripted/href-script-element-expected.txt
@@ -1,5 +1,5 @@
 
-FAIL Test for loading external script from href when setting href and then xlink:href promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: loadedScript"
-FAIL Test for loading external script from xlnk:href by adding xlink:href and then href promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: loadedScript"
-FAIL Test for loading external script from href by adding href and then xlink:href, and then removing href promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: loadedScript"
+PASS Test for loading external script from href when setting href and then xlink:href 
+PASS Test for loading external script from xlnk:href by adding xlink:href and then href 
+PASS Test for loading external script from href by adding href and then xlink:href, and then removing href 
 
diff --git a/LayoutTests/svg/custom/image-load-event-expected.html b/LayoutTests/svg/custom/image-load-event-expected.html
new file mode 100644
index 0000000..68b635e
--- /dev/null
+++ b/LayoutTests/svg/custom/image-load-event-expected.html
@@ -0,0 +1,5 @@
+<body>
+    <svg width="100" height="100">
+        <rect width="100%" height="100%" fill="green"/>
+    </svg>
+</body>
diff --git a/LayoutTests/svg/custom/image-load-event.html b/LayoutTests/svg/custom/image-load-event.html
new file mode 100644
index 0000000..32b5eb4
--- /dev/null
+++ b/LayoutTests/svg/custom/image-load-event.html
@@ -0,0 +1,27 @@
+<body>
+    <svg width="100" height="100">
+        <image width="100%" height="100%"/>
+    </svg>
+    <div id="log"></div>
+    <script>
+        function loadImage(href) {
+            return new Promise((resolve) => {
+                let image = document.querySelector('image');
+                image.onload = (() => {
+                    resolve();
+                });
+                image.setAttribute("href", href);
+            });
+        }
+
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        loadImage("resources/green-checker.png").then(() => {
+            loadImage("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' fill='green'/></svg>").then(() => {
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        });
+    </script>
+</body>
diff --git a/LayoutTests/svg/custom/loadevents-async-expected.txt b/LayoutTests/svg/custom/loadevents-async-expected.txt
deleted file mode 100644
index 554c0ed..0000000
--- a/LayoutTests/svg/custom/loadevents-async-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This test ensures that tree mutation on the load doesn't break consistency.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS invoked is false
-PASS invoked is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/LayoutTests/svg/custom/loadevents-async.html b/LayoutTests/svg/custom/loadevents-async.html
deleted file mode 100644
index 35e01d5..0000000
--- a/LayoutTests/svg/custom/loadevents-async.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<script src="../../resources/js-test-pre.js"></script>
-</head>
-<body>
-<script>
-description("This test ensures that tree mutation on the load doesn't break consistency.");
-var invoked = false;
-var spanElement = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
-var divElement = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
-var useElement = document.createElementNS("http://www.w3.org/2000/svg", "use");
-var emptyDocument = document.implementation.createDocument("", "", null);
-
-document.body.appendChild(spanElement);
-divElement.appendChild(useElement);
-useElement.addEventListener("load", function () { emptyDocument.adoptNode(useElement); invoked = true; }, false);
-spanElement.appendChild(divElement);
-document.body.appendChild(useElement);
-shouldBeFalse("invoked");
-
-jsTestIsAsync = true;
-setTimeout(function() {
-    shouldBeTrue("invoked");
-    finishJSTest();
-}, 1);
-
-</script>
-<script src="../../resources/js-test-post.js"></script>
-<body>
-</html>
diff --git a/LayoutTests/svg/custom/loadevents-capturing-expected.txt b/LayoutTests/svg/custom/loadevents-capturing-expected.txt
deleted file mode 100644
index 6cf4a41..0000000
--- a/LayoutTests/svg/custom/loadevents-capturing-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This tests that load dispatching works when there are no
-direct listeners, but there are capturing event listeners on an ancestor. Bug 16447
-Passed
diff --git a/LayoutTests/svg/custom/loadevents-capturing.svg b/LayoutTests/svg/custom/loadevents-capturing.svg
deleted file mode 100644
index 14b806f..0000000
--- a/LayoutTests/svg/custom/loadevents-capturing.svg
+++ /dev/null
@@ -1,35 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-  <script>
-    <![CDATA[
-      if (window.testRunner)
-        testRunner.dumpAsText();
-
-      var results = [ ];
-      function handler(event)
-      {
-        results.push(event.target.localName);
-      }
-      document.documentElement.addEventListener('load', handler, true);
-
-      function reportResults()
-      {
-        var console = document.getElementById("console");
-        var expected = [ "image", "text", "text", "text", "g", "svg" ];
-        for (var i = 0; i < expected.length; ++i) {
-            if (results[i] != expected[i]) {
-              console.appendChild(document.createTextNode("FAIL: " + i + " should be " + expected[i] + " but instead is " + results[i] + ".\n"));
-              return;
-            }
-        }
-        console.appendChild(document.createTextNode("Passed"));
-      }
-      document.documentElement.addEventListener('load', reportResults);
-    ]]>
-  </script>
-  <g>
-    <image externalResourcesRequired="false" id="image" width="100" height="100" xlink:href="resources/green-checker.png" />
-    <text y="130" x="20">This tests that load dispatching works when there are no</text>
-    <text y="150" x="20">direct listeners, but there are capturing event listeners on an ancestor. Bug 16447</text>
-    <text y="170" x="20" id="console" />
-  </g>
-</svg>
diff --git a/LayoutTests/svg/custom/loadevents-externalresourcesrequired-displaynone-expected.txt b/LayoutTests/svg/custom/loadevents-externalresourcesrequired-displaynone-expected.txt
deleted file mode 100644
index b4eb3e8..0000000
--- a/LayoutTests/svg/custom/loadevents-externalresourcesrequired-displaynone-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This tests load dispatching order with externalResourcesRequired and an image that does not render(display=none). Bug 16447
-Passed
diff --git a/LayoutTests/svg/custom/loadevents-externalresourcesrequired-displaynone.svg b/LayoutTests/svg/custom/loadevents-externalresourcesrequired-displaynone.svg
deleted file mode 100644
index a834350..0000000
--- a/LayoutTests/svg/custom/loadevents-externalresourcesrequired-displaynone.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="reportLoadEvent(this);runTest();">
-  <script>
-    <![CDATA[
-      if (window.testRunner)
-        testRunner.dumpAsText();
-
-      var results = new Array();
-
-      function reportLoadEvent(el) {
-        results.push(el.localName);
-      }
-      function runTest()
-      {
-        var test = document.getElementById("console");
-        if ( results.length != 4 || results[0] != "text" ||
-             results[1] != "image" || results[2] != "g" ||
-             results[3] != "svg") {
-          test.appendChild(document.createTextNode("Failed"));
-        } else {
-          test.appendChild(document.createTextNode("Passed"));
-        }
-      }
-    ]]>
-  </script>
-  <g onload="reportLoadEvent(this)">
-    <image display="none" externalResourcesRequired="true" id="image" onload="reportLoadEvent(this)" width="100" height="100" xlink:href="resources/green-checker.png" />
-    <text y="130" x="20">This tests load dispatching order with externalResourcesRequired and an image that does not render(display=none). Bug 16447</text>
-    <text y="150" x="20" id="console" onload="reportLoadEvent(this)"/>
-  </g>
-</svg>
diff --git a/LayoutTests/svg/custom/loadevents-externalresourcesrequired-expected.txt b/LayoutTests/svg/custom/loadevents-externalresourcesrequired-expected.txt
deleted file mode 100644
index 5234abe..0000000
--- a/LayoutTests/svg/custom/loadevents-externalresourcesrequired-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This tests load dispatching order with externalResourcesRequired. Bug 16447
-Passed
diff --git a/LayoutTests/svg/custom/loadevents-externalresourcesrequired.svg b/LayoutTests/svg/custom/loadevents-externalresourcesrequired.svg
deleted file mode 100644
index 40e27bc..0000000
--- a/LayoutTests/svg/custom/loadevents-externalresourcesrequired.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="reportLoadEvent(this);runTest();">
-  <script>
-    <![CDATA[
-      if (window.testRunner)
-        testRunner.dumpAsText();
-
-      var results = new Array();
-
-      function reportLoadEvent(el) {
-		results.push(el.localName);
-      }
-      function runTest()
-      {
-        var test = document.getElementById("console");
-        if ( results.length != 4 || results[0] != "text" ||
-             results[1] != "image" || results[2] != "g" ||
-             results[3] != "svg") {
-          test.appendChild(document.createTextNode("Failed"));
-        } else {
-          test.appendChild(document.createTextNode("Passed"));
-        }
-      }
-    ]]>
-  </script>
-  <g onload="reportLoadEvent(this)">
-    <image externalResourcesRequired="true" id="image" onload="reportLoadEvent(this)" width="100" height="100" xlink:href="resources/green-checker.png" />
-    <text y="130" x="20">This tests load dispatching order with externalResourcesRequired. Bug 16447</text>
-    <text y="150" x="20" id="console" onload="reportLoadEvent(this)"/>
-  </g>
-</svg>
diff --git a/LayoutTests/svg/custom/loadevents-normal-displaynone-expected.txt b/LayoutTests/svg/custom/loadevents-normal-displaynone-expected.txt
deleted file mode 100644
index 4dd6b3b..0000000
--- a/LayoutTests/svg/custom/loadevents-normal-displaynone-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This tests normal load dispatching order and an image that does not render(display=none). Bug 16447
-Passed
diff --git a/LayoutTests/svg/custom/loadevents-normal-displaynone.svg b/LayoutTests/svg/custom/loadevents-normal-displaynone.svg
deleted file mode 100644
index 75f5b55..0000000
--- a/LayoutTests/svg/custom/loadevents-normal-displaynone.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="reportLoadEvent(this);runTest();">
-  <script>
-    <![CDATA[
-      if (window.testRunner)
-        testRunner.dumpAsText();
-
-      var results = new Array();
-
-      function reportLoadEvent(el) {
-        results.push(el.localName);
-      }
-      function runTest()
-      {
-        var test = document.getElementById("console");
-        if ( results.length != 4 || results[0] != "image" ||
-             results[1] != "text" || results[2] != "g" ||
-             results[3] != "svg") {
-          test.appendChild(document.createTextNode("Failed"));
-        } else {
-          test.appendChild(document.createTextNode("Passed"));
-        }
-      }
-    ]]>
-  </script>
-  <g onload="reportLoadEvent(this)">
-    <image display="none" externalResourcesRequired="false" id="image" onload="reportLoadEvent(this)" width="100" height="100" xlink:href="resources/green-checker.png" />
-    <text y="130" x="20">This tests normal load dispatching order and an image that does not render(display=none). Bug 16447</text>
-    <text y="150" x="20" id="console" onload="reportLoadEvent(this)"/>
-  </g>
-</svg>
diff --git a/LayoutTests/svg/custom/loadevents-normal-expected.txt b/LayoutTests/svg/custom/loadevents-normal-expected.txt
deleted file mode 100644
index 68dd59b..0000000
--- a/LayoutTests/svg/custom/loadevents-normal-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This tests normal load dispatching order. Bug 16447
-Passed
diff --git a/LayoutTests/svg/custom/loadevents-normal.svg b/LayoutTests/svg/custom/loadevents-normal.svg
deleted file mode 100644
index df2dad4..0000000
--- a/LayoutTests/svg/custom/loadevents-normal.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="reportLoadEvent(this);runTest();">
-  <script>
-    <![CDATA[
-      if (window.testRunner)
-        testRunner.dumpAsText();
-
-      var results = new Array();
-
-      function reportLoadEvent(el) {
-        results.push(el.localName);
-      }
-      function runTest()
-      {
-        var test = document.getElementById("console");
-        if ( results.length != 4 || results[0] != "image" ||
-             results[1] != "text" || results[2] != "g" ||
-             results[3] != "svg") {
-          test.appendChild(document.createTextNode("Failed"));
-        } else {
-          test.appendChild(document.createTextNode("Passed"));
-        }
-      }
-    ]]>
-  </script>
-  <g onload="reportLoadEvent(this)">
-    <image externalResourcesRequired="false" id="image" onload="reportLoadEvent(this)" width="100" height="100" xlink:href="resources/green-checker.png" />
-    <text y="130" x="20">This tests normal load dispatching order. Bug 16447</text>
-    <text y="150" x="20" id="console" onload="reportLoadEvent(this)"/>
-  </g>
-</svg>
diff --git a/LayoutTests/svg/dom/SVGScriptElement/script-load-and-error-events.svg b/LayoutTests/svg/dom/SVGScriptElement/script-load-and-error-events.svg
index d6d4e23..252282e 100644
--- a/LayoutTests/svg/dom/SVGScriptElement/script-load-and-error-events.svg
+++ b/LayoutTests/svg/dom/SVGScriptElement/script-load-and-error-events.svg
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xhtml="http://www.w3.org/1999/xhtml" onerror="testGlobalErrorHandlerNotFired(evt)" onload="testLoadEventNotFired()">
+<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xhtml="http://www.w3.org/1999/xhtml" onerror="testGlobalErrorHandlerNotFired(evt)">
 <defs>
 <title>&lt;SCRIPT&gt; load and error events</title>
 <script type="text/javascript">
@@ -20,10 +20,6 @@
     status_[evt.target.id] += "G";
 }
 
-function testLoadEventNotFired() {
-    shouldContinue = 0;
-}
-
 function loadEventHandler(evt) {
     status_[evt.target.id] += "L";
 }
@@ -38,7 +34,7 @@
 function endTest() {
     var failures = "";
 
-    if (status_[0] != "LE")
+    if (status_[0] != "E")
         failures += "0 (actual result: " + status_[0] + ") ";
     if (status_[1] != "E")
         failures += "1 (actual result: " + status_[1] + ") ";
@@ -48,7 +44,7 @@
         failures += "3 (actual result: " + status_[3] + ") ";
     if (status_[4] != "L")
         failures += "4 (actual result: " + status_[4] + ") ";
-    if (status_[5] != "LE")
+    if (status_[5] != "E")
         failures += "5 (actual result: " + status_[5] + ") ";
     if (status_[6] != "E")
         failures += "6 (actual result: " + status_[6] + ")";
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 485648d..26b8db5 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,113 @@
+2019-10-18  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Load event must be fired only for the SVG structurally external elements and the outermost SVG element
+        https://bugs.webkit.org/show_bug.cgi?id=203044
+
+        Reviewed by Simon Fraser.
+
+        The SVG1.1 spec for SVGLoad event is:
+            https://www.w3.org/TR/SVG11/interact.html
+
+        The SVG2 spec for the load event is:
+            https://www.w3.org/TR/SVG/changes.html#interact
+            https://www.w3.org/TR/SVG/interact.html
+
+        SVG2 removes the SVGExternalResourcesRequired interface. It also simplifies
+        the rules for firing the load event and made them consistent with the HTML
+        specs. The plan is to remove SVGExternalResourcesRequired in a following
+        patch. This patch makes SVGExternalResourcesRequired have no effect on the
+        load event firing rules. It moves all the functionalities to SVGURIReference
+        as a step towards removing the SVGExternalResourcesRequired interface.
+
+        Test: svg/custom/image-load-event.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::implicitClose):
+        Do not use the SVGLoad term. It has been removed from the specs.
+
+        * dom/ScriptElement.cpp:
+        (WebCore::ScriptElement::ScriptElement):
+        * dom/ScriptElement.h:
+        (WebCore::ScriptElement::errorOccurred const):
+        (WebCore::ScriptElement::setErrorOccurred):
+        Add a method to track the occurrence  of loading error. errorOccurred()
+        || haveFiredLoadEvent() means no pending loading activity.
+
+        * svg/SVGDocumentExtensions.cpp:
+        (WebCore::SVGDocumentExtensions::dispatchLoadEventToOutermostSVGElements):
+        (WebCore::SVGDocumentExtensions::dispatchSVGLoadEventToOutermostSVGElements): Deleted.
+        * svg/SVGDocumentExtensions.h:
+        Do not use the SVGLoad term. 
+
+        * svg/SVGElement.cpp:
+        (WebCore::SVGElement::sendLoadEventIfPossible):
+        (WebCore::SVGElement::loadEventTimerFired):
+        (WebCore::SVGElement::loadEventTimer):
+        (WebCore::SVGElement::finishParsingChildren):
+        (WebCore::SVGElement::sendSVGLoadEventIfPossible): Deleted.
+        (WebCore::SVGElement::sendSVGLoadEventIfPossibleAsynchronously): Deleted.
+        (WebCore::SVGElement::svgLoadEventTimerFired): Deleted.
+        (WebCore::SVGElement::svgLoadEventTimer): Deleted.
+        * svg/SVGElement.h:
+        finishParsingChildren() won't fire 'load' event anymore. The 'load' event 
+        will be fired explicitly for the outermost SVG element from Document::implicitClose().
+
+        * svg/SVGExternalResourcesRequired.cpp:
+        (WebCore::SVGExternalResourcesRequired::svgAttributeChanged):
+        (WebCore::SVGExternalResourcesRequired::dispatchLoadEvent): Deleted.
+        (WebCore::SVGExternalResourcesRequired::insertedIntoDocument): Deleted.
+        (WebCore::SVGExternalResourcesRequired::finishParsingChildren): Deleted.
+        (WebCore::SVGExternalResourcesRequired::haveLoadedRequiredResources const): Deleted.
+        * svg/SVGExternalResourcesRequired.h:
+        (WebCore::SVGExternalResourcesRequired::setHaveFiredLoadEvent): Deleted.
+        (WebCore::SVGExternalResourcesRequired::isParserInserted const): Deleted.
+        (WebCore::SVGExternalResourcesRequired::haveFiredLoadEvent const): Deleted.
+        * svg/SVGImageElement.cpp:
+        (WebCore::SVGImageElement::haveLoadedRequiredResources):
+        * svg/SVGImageLoader.cpp:
+        (WebCore::SVGImageLoader::dispatchLoadEvent):
+        The value of externalResourcesRequired() no longer controls firing the
+        'load' event.
+
+        * svg/SVGScriptElement.cpp:
+        (WebCore::SVGScriptElement::SVGScriptElement):
+        (WebCore::SVGScriptElement::insertedIntoAncestor):
+        (WebCore::SVGScriptElement::dispatchErrorEvent):
+        (WebCore::SVGScriptElement::finishParsingChildren): Deleted.
+        * svg/SVGScriptElement.h:
+        dispatchErrorEvent() is now a virtual function. Let SVGScriptElement
+        overrides it so it can track when the loader finishes its activity.
+
+        * svg/SVGStyleElement.cpp:
+        (WebCore::SVGStyleElement::SVGStyleElement):
+        * svg/SVGStyleElement.h:
+
+        * svg/SVGURIReference.cpp:
+        (WebCore::SVGURIReference::contextElement const):
+        (WebCore::SVGURIReference::parseAttribute):
+        (WebCore::SVGURIReference::haveLoadedRequiredResources const):
+        (WebCore::SVGURIReference::dispatchLoadEvent):
+        * svg/SVGURIReference.h:
+        (WebCore::SVGURIReference::haveFiredLoadEvent const):
+        (WebCore::SVGURIReference::setHaveFiredLoadEvent):
+        (WebCore::SVGURIReference::errorOccurred const):
+        (WebCore::SVGURIReference::setErrorOccurred):
+        SVGURIReference will decide whether the 'load' event can be fired or not.
+
+        * svg/SVGUseElement.cpp:
+        (WebCore::SVGUseElement::SVGUseElement):
+        (WebCore::SVGUseElement::insertedIntoAncestor):
+        (WebCore::SVGUseElement::notifyFinished):
+        (WebCore::SVGUseElement::finishParsingChildren): Deleted.
+        (WebCore::SVGUseElement::isValid const): Deleted.
+        (WebCore::SVGUseElement::haveLoadedRequiredResources): Deleted.
+        (WebCore::SVGUseElement::setHaveFiredLoadEvent): Deleted.
+        (WebCore::SVGUseElement::haveFiredLoadEvent const): Deleted.
+        (WebCore::SVGUseElement::svgLoadEventTimer): Deleted.
+        * svg/SVGUseElement.h:
+        SVGUseElement needs to track firing the load event or error occurrence 
+        the same way SVGImageElement and SVGScriptElement do.
+
 2019-10-18  Antti Koivisto  <antti@apple.com>
 
         ElementRuleCollector function signature cleanups
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index c91bc198..37b7cc2 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -2971,11 +2971,8 @@
         HTMLLinkElement::dispatchPendingLoadEvents();
         HTMLStyleElement::dispatchPendingLoadEvents();
 
-        // To align the HTML load event and the SVGLoad event for the outermost <svg> element, fire it from
-        // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false",
-        // which is the default, for ='true' its fired at a later time, once all external resources finished loading).
         if (svgExtensions())
-            accessSVGExtensions().dispatchSVGLoadEventToOutermostSVGElements();
+            accessSVGExtensions().dispatchLoadEventToOutermostSVGElements();
     }
 
     dispatchWindowLoadEvent();
diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp
index 113abc4..e0d967b 100644
--- a/Source/WebCore/dom/ScriptElement.cpp
+++ b/Source/WebCore/dom/ScriptElement.cpp
@@ -66,6 +66,7 @@
     , m_isExternalScript(false)
     , m_alreadyStarted(alreadyStarted)
     , m_haveFiredLoad(false)
+    , m_errorOccurred(false)
     , m_willBeParserExecuted(false)
     , m_readyToBeParserExecuted(false)
     , m_willExecuteWhenDocumentFinishedParsing(false)
diff --git a/Source/WebCore/dom/ScriptElement.h b/Source/WebCore/dom/ScriptElement.h
index 4fed24c..548fb20 100644
--- a/Source/WebCore/dom/ScriptElement.h
+++ b/Source/WebCore/dom/ScriptElement.h
@@ -56,9 +56,10 @@
 
     // XML parser calls these
     virtual void dispatchLoadEvent() = 0;
-    void dispatchErrorEvent();
+    virtual void dispatchErrorEvent();
 
     bool haveFiredLoadEvent() const { return m_haveFiredLoad; }
+    bool errorOccurred() const { return m_errorOccurred; }
     bool willBeParserExecuted() const { return m_willBeParserExecuted; }
     bool readyToBeParserExecuted() const { return m_readyToBeParserExecuted; }
     bool willExecuteWhenDocumentFinishedParsing() const { return m_willExecuteWhenDocumentFinishedParsing; }
@@ -76,6 +77,7 @@
     ScriptElement(Element&, bool createdByParser, bool isEvaluated);
 
     void setHaveFiredLoadEvent(bool haveFiredLoad) { m_haveFiredLoad = haveFiredLoad; }
+    void setErrorOccurred(bool errorOccurred) { m_errorOccurred = errorOccurred; }
     bool isParserInserted() const { return m_parserInserted; }
     bool alreadyStarted() const { return m_alreadyStarted; }
     bool forceAsync() const { return m_forceAsync; }
@@ -122,6 +124,7 @@
     bool m_isExternalScript : 1;
     bool m_alreadyStarted : 1;
     bool m_haveFiredLoad : 1;
+    bool m_errorOccurred : 1;
     bool m_willBeParserExecuted : 1; // Same as "The parser will handle executing the script."
     bool m_readyToBeParserExecuted : 1;
     bool m_willExecuteWhenDocumentFinishedParsing : 1;
diff --git a/Source/WebCore/svg/SVGDocumentExtensions.cpp b/Source/WebCore/svg/SVGDocumentExtensions.cpp
index 25f3863..a71bb00 100644
--- a/Source/WebCore/svg/SVGDocumentExtensions.cpp
+++ b/Source/WebCore/svg/SVGDocumentExtensions.cpp
@@ -111,7 +111,7 @@
     m_areAnimationsPaused = false;
 }
 
-void SVGDocumentExtensions::dispatchSVGLoadEventToOutermostSVGElements()
+void SVGDocumentExtensions::dispatchLoadEventToOutermostSVGElements()
 {
     Vector<RefPtr<SVGSVGElement>> timeContainers;
     timeContainers.appendRange(m_timeContainers.begin(), m_timeContainers.end());
@@ -119,7 +119,7 @@
     for (auto& container : timeContainers) {
         if (!container->isOutermostSVGSVGElement())
             continue;
-        container->sendSVGLoadEventIfPossible();
+        container->sendLoadEventIfPossible();
     }
 }
 
diff --git a/Source/WebCore/svg/SVGDocumentExtensions.h b/Source/WebCore/svg/SVGDocumentExtensions.h
index 8fbdf3a..03563df 100644
--- a/Source/WebCore/svg/SVGDocumentExtensions.h
+++ b/Source/WebCore/svg/SVGDocumentExtensions.h
@@ -53,7 +53,7 @@
     void startAnimations();
     void pauseAnimations();
     void unpauseAnimations();
-    void dispatchSVGLoadEventToOutermostSVGElements();
+    void dispatchLoadEventToOutermostSVGElements();
     bool areAnimationsPaused() const { return m_areAnimationsPaused; }
 
     void reportWarning(const String&);
diff --git a/Source/WebCore/svg/SVGElement.cpp b/Source/WebCore/svg/SVGElement.cpp
index 16c3afc..b932bef 100644
--- a/Source/WebCore/svg/SVGElement.cpp
+++ b/Source/WebCore/svg/SVGElement.cpp
@@ -440,47 +440,23 @@
     return false;
 }
 
-void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
+void SVGElement::sendLoadEventIfPossible()
 {
     if (!isConnected() || !document().frame())
         return;
 
-    RefPtr<SVGElement> currentTarget = this;
-    while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
-        RefPtr<Element> parent;
-        if (sendParentLoadEvents)
-            parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
-        if (hasLoadListener(currentTarget.get()))
-            currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, Event::CanBubble::No, Event::IsCancelable::No));
-        currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
-        SVGElement* element = currentTarget.get();
-        if (!element || !element->isOutermostSVGSVGElement())
-            continue;
+    if (!haveLoadedRequiredResources() || !hasLoadListener(this))
+        return;
 
-        // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
-        // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
-        // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
-        ASSERT(sendParentLoadEvents);
-
-        // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
-        // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
-        // to be "ready to render", first.
-        if (!document().loadEventFinished())
-            break;
-    }
+    dispatchEvent(Event::create(eventNames().loadEvent, Event::CanBubble::No, Event::IsCancelable::No));
 }
 
-void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
+void SVGElement::loadEventTimerFired()
 {
-    svgLoadEventTimer()->startOneShot(0_s);
+    sendLoadEventIfPossible();
 }
 
-void SVGElement::svgLoadEventTimerFired()
-{
-    sendSVGLoadEventIfPossible();
-}
-
-Timer* SVGElement::svgLoadEventTimer()
+Timer* SVGElement::loadEventTimer()
 {
     ASSERT_NOT_REACHED();
     return nullptr;
@@ -490,14 +466,9 @@
 {
     StyledElement::finishParsingChildren();
 
-    // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
     if (isOutermostSVGSVGElement())
         return;
 
-    // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
-    // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
-    sendSVGLoadEventIfPossible();
-
     // Notify all the elements which have references to this element to rebuild their shadow and render
     // trees, e.g. a <use> element references a target element before this target element is defined.
     invalidateInstances();
diff --git a/Source/WebCore/svg/SVGElement.h b/Source/WebCore/svg/SVGElement.h
index 8cc6aac..9a57360 100644
--- a/Source/WebCore/svg/SVGElement.h
+++ b/Source/WebCore/svg/SVGElement.h
@@ -76,10 +76,9 @@
 
     virtual void svgAttributeChanged(const QualifiedName&);
 
-    void sendSVGLoadEventIfPossible(bool sendParentLoadEvents = false);
-    void sendSVGLoadEventIfPossibleAsynchronously();
-    void svgLoadEventTimerFired();
-    virtual Timer* svgLoadEventTimer();
+    void sendLoadEventIfPossible();
+    void loadEventTimerFired();
+    virtual Timer* loadEventTimer();
 
     virtual AffineTransform* supplementalTransform() { return nullptr; }
 
diff --git a/Source/WebCore/svg/SVGExternalResourcesRequired.cpp b/Source/WebCore/svg/SVGExternalResourcesRequired.cpp
index 1f23d90..b233b55 100644
--- a/Source/WebCore/svg/SVGExternalResourcesRequired.cpp
+++ b/Source/WebCore/svg/SVGExternalResourcesRequired.cpp
@@ -52,16 +52,6 @@
     if (!m_contextElement.isConnected())
         return;
 
-    // Handle dynamic updates of the 'externalResourcesRequired' attribute. Only possible case: changing from 'true' to 'false'
-    // causes an immediate dispatch of the SVGLoad event. If the attribute value was 'false' before inserting the script element
-    // in the document, the SVGLoad event has already been dispatched.
-    if (!externalResourcesRequiredAnimated().isAnimating() && !externalResourcesRequired() && !haveFiredLoadEvent() && !isParserInserted()) {
-        setHaveFiredLoadEvent(true);
-
-        ASSERT(m_contextElement.haveLoadedRequiredResources());
-        m_contextElement.sendSVGLoadEventIfPossible();
-    }
-
     auto* renderer = m_contextElement.renderer();
     if (renderer && is<RenderSVGShape>(renderer)) {
         SVGElement::InstanceInvalidationGuard guard(m_contextElement);
@@ -74,51 +64,4 @@
     supportedAttributes.add(SVGNames::externalResourcesRequiredAttr);
 }
 
-void SVGExternalResourcesRequired::dispatchLoadEvent()
-{
-    if (isParserInserted())
-        ASSERT(externalResourcesRequired() != haveFiredLoadEvent());
-    else if (haveFiredLoadEvent())
-        return;
-
-    // HTML and SVG differ completely in the 'onload' event handling of <script> elements.
-    // HTML fires the 'load' event after it sucessfully loaded a remote resource, otherwise an error event.
-    // SVG fires the SVGLoad event immediately after parsing the <script> element, if externalResourcesRequired
-    // is set to 'false', otherwise it dispatches the 'SVGLoad' event just after loading the remote resource.
-    if (!externalResourcesRequired())
-        return;
-
-    ASSERT(!haveFiredLoadEvent());
-
-    // Dispatch SVGLoad event
-    setHaveFiredLoadEvent(true);
-    ASSERT(m_contextElement.haveLoadedRequiredResources());
-
-    m_contextElement.sendSVGLoadEventIfPossible();
-}
-
-void SVGExternalResourcesRequired::insertedIntoDocument()
-{
-    if (isParserInserted())
-        return;
-
-    // Eventually send SVGLoad event now for the dynamically inserted script element.
-    if (externalResourcesRequired())
-        return;
-    setHaveFiredLoadEvent(true);
-    m_contextElement.sendSVGLoadEventIfPossibleAsynchronously();
-}
-
-void SVGExternalResourcesRequired::finishParsingChildren()
-{
-    // A SVGLoad event has been fired by SVGElement::finishParsingChildren.
-    if (!externalResourcesRequired())
-        setHaveFiredLoadEvent(true);
-}
-
-bool SVGExternalResourcesRequired::haveLoadedRequiredResources() const
-{
-    return !externalResourcesRequired() || haveFiredLoadEvent();
-}
-
 }
diff --git a/Source/WebCore/svg/SVGExternalResourcesRequired.h b/Source/WebCore/svg/SVGExternalResourcesRequired.h
index f8fadc0..800ba90 100644
--- a/Source/WebCore/svg/SVGExternalResourcesRequired.h
+++ b/Source/WebCore/svg/SVGExternalResourcesRequired.h
@@ -51,18 +51,8 @@
 
 protected:
     SVGExternalResourcesRequired(SVGElement* contextElement);
-
     static bool isKnownAttribute(const QualifiedName& attributeName) { return PropertyRegistry::isKnownAttribute(attributeName); }
 
-    virtual void setHaveFiredLoadEvent(bool) { }
-    virtual bool isParserInserted() const { return false; }
-    virtual bool haveFiredLoadEvent() const { return false; }
-
-    void dispatchLoadEvent();
-    void insertedIntoDocument();
-    void finishParsingChildren();
-    bool haveLoadedRequiredResources() const;
-
 private:
     SVGElement& m_contextElement;
     Ref<SVGAnimatedBoolean> m_externalResourcesRequired;
diff --git a/Source/WebCore/svg/SVGImageElement.cpp b/Source/WebCore/svg/SVGImageElement.cpp
index 7b64a02..491f2a0 100644
--- a/Source/WebCore/svg/SVGImageElement.cpp
+++ b/Source/WebCore/svg/SVGImageElement.cpp
@@ -136,7 +136,7 @@
 
 bool SVGImageElement::haveLoadedRequiredResources()
 {
-    return !externalResourcesRequired() || !m_imageLoader.hasPendingActivity();
+    return !m_imageLoader.hasPendingActivity();
 }
 
 void SVGImageElement::didAttachRenderers()
diff --git a/Source/WebCore/svg/SVGImageLoader.cpp b/Source/WebCore/svg/SVGImageLoader.cpp
index 42a35d4..d7cbef3 100644
--- a/Source/WebCore/svg/SVGImageLoader.cpp
+++ b/Source/WebCore/svg/SVGImageLoader.cpp
@@ -40,10 +40,8 @@
 {
     if (image()->errorOccurred())
         element().dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));
-    else {
-        if (downcast<SVGImageElement>(element()).externalResourcesRequired())
-            downcast<SVGImageElement>(ImageLoader::element()).sendSVGLoadEventIfPossible(true);
-    }
+    else
+        downcast<SVGImageElement>(ImageLoader::element()).sendLoadEventIfPossible();
 }
 
 String SVGImageLoader::sourceURI(const AtomString& attribute) const
diff --git a/Source/WebCore/svg/SVGScriptElement.cpp b/Source/WebCore/svg/SVGScriptElement.cpp
index 6f3a29b..4e16038 100644
--- a/Source/WebCore/svg/SVGScriptElement.cpp
+++ b/Source/WebCore/svg/SVGScriptElement.cpp
@@ -35,7 +35,7 @@
     , SVGExternalResourcesRequired(this)
     , SVGURIReference(this)
     , ScriptElement(*this, wasInsertedByParser, alreadyStarted)
-    , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired)
+    , m_loadEventTimer(*this, &SVGElement::loadEventTimerFired)
 {
     ASSERT(hasTagName(SVGNames::scriptTag));
 }
@@ -68,8 +68,6 @@
 Node::InsertedIntoAncestorResult SVGScriptElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
 {
     SVGElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
-    if (insertionType.connectedToDocument)
-        SVGExternalResourcesRequired::insertedIntoDocument();
     return ScriptElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
 }
 
@@ -84,12 +82,6 @@
     ScriptElement::childrenChanged(change);
 }
 
-void SVGScriptElement::finishParsingChildren()
-{
-    SVGElement::finishParsingChildren();
-    SVGExternalResourcesRequired::finishParsingChildren();
-}
-
 void SVGScriptElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
 {
     SVGElement::addSubresourceAttributeURLs(urls);
@@ -101,4 +93,10 @@
     return adoptRef(*new SVGScriptElement(tagQName(), targetDocument, false, alreadyStarted()));
 }
 
+void SVGScriptElement::dispatchErrorEvent()
+{
+    setErrorOccurred(true);
+    ScriptElement::dispatchErrorEvent();
+}
+
 }
diff --git a/Source/WebCore/svg/SVGScriptElement.h b/Source/WebCore/svg/SVGScriptElement.h
index 299d764..d038a08 100644
--- a/Source/WebCore/svg/SVGScriptElement.h
+++ b/Source/WebCore/svg/SVGScriptElement.h
@@ -51,11 +51,12 @@
     void childrenChanged(const ChildChange&) final;
 
     bool isURLAttribute(const Attribute& attribute) const final { return attribute.name() == sourceAttributeValue(); }
-    void finishParsingChildren() final;
     void addSubresourceAttributeURLs(ListHashSet<URL>&) const final;
 
-    bool haveLoadedRequiredResources() final { return SVGExternalResourcesRequired::haveLoadedRequiredResources(); }
+    Ref<Element> cloneElementWithoutAttributesAndChildren(Document&) final;
+    bool rendererIsNeeded(const RenderStyle&) final { return false; }
 
+    // ScriptElement
     String sourceAttributeValue() const final { return href(); }
     String charsetAttributeValue() const final { return String(); }
     String typeAttributeValue() const final { return getAttribute(SVGNames::typeAttr).string(); }
@@ -67,24 +68,25 @@
     bool hasNoModuleAttribute() const final { return false; }
     ReferrerPolicy referrerPolicy() const final { return ReferrerPolicy::EmptyString; }
     bool hasSourceAttribute() const final { return hasAttribute(SVGNames::hrefAttr) || hasAttribute(XLinkNames::hrefAttr); }
+    void dispatchLoadEvent() final { SVGURIReference::dispatchLoadEvent(); }
+    void dispatchErrorEvent() final;
 
-    void dispatchLoadEvent() final { SVGExternalResourcesRequired::dispatchLoadEvent(); }
+    // SVGElement
+    bool haveLoadedRequiredResources() final { return SVGURIReference::haveLoadedRequiredResources(); }
+    Timer* loadEventTimer() final { return &m_loadEventTimer; }
 
-    Ref<Element> cloneElementWithoutAttributesAndChildren(Document&) final;
-    bool rendererIsNeeded(const RenderStyle&) final { return false; }
-
-    // SVGExternalResourcesRequired
-    void setHaveFiredLoadEvent(bool haveFiredLoadEvent) final { ScriptElement::setHaveFiredLoadEvent(haveFiredLoadEvent); }
-    bool isParserInserted() const final { return ScriptElement::isParserInserted(); }
+    // SVGURIReference
     bool haveFiredLoadEvent() const final { return ScriptElement::haveFiredLoadEvent(); }
-    Timer* svgLoadEventTimer() final { return &m_svgLoadEventTimer; }
+    void setHaveFiredLoadEvent(bool haveFiredLoadEvent) final { ScriptElement::setHaveFiredLoadEvent(haveFiredLoadEvent); }
+    bool errorOccurred() const final { return ScriptElement::errorOccurred(); }
+    void setErrorOccurred(bool errorOccurred) final { ScriptElement::setErrorOccurred(errorOccurred); }
 
 #ifndef NDEBUG
     bool filterOutAnimatableAttribute(const QualifiedName& name) const final { return name == SVGNames::typeAttr; }
 #endif
 
     PropertyRegistry m_propertyRegistry { *this };
-    Timer m_svgLoadEventTimer;
+    Timer m_loadEventTimer;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/svg/SVGStyleElement.cpp b/Source/WebCore/svg/SVGStyleElement.cpp
index 45de879..6ce75ee 100644
--- a/Source/WebCore/svg/SVGStyleElement.cpp
+++ b/Source/WebCore/svg/SVGStyleElement.cpp
@@ -36,7 +36,7 @@
 inline SVGStyleElement::SVGStyleElement(const QualifiedName& tagName, Document& document, bool createdByParser)
     : SVGElement(tagName, document)
     , m_styleSheetOwner(document, createdByParser)
-    , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired)
+    , m_loadEventTimer(*this, &SVGElement::loadEventTimerFired)
 {
     ASSERT(hasTagName(SVGNames::styleTag));
 }
diff --git a/Source/WebCore/svg/SVGStyleElement.h b/Source/WebCore/svg/SVGStyleElement.h
index 1703943..3c4a60f 100644
--- a/Source/WebCore/svg/SVGStyleElement.h
+++ b/Source/WebCore/svg/SVGStyleElement.h
@@ -58,12 +58,12 @@
     virtual bool isLoading() const { return m_styleSheetOwner.isLoading(); }
     bool sheetLoaded() final { return m_styleSheetOwner.sheetLoaded(*this); }
     void startLoadingDynamicSheet() final { m_styleSheetOwner.startLoadingDynamicSheet(*this); }
-    Timer* svgLoadEventTimer() final { return &m_svgLoadEventTimer; }
+    Timer* loadEventTimer() final { return &m_loadEventTimer; }
 
     String title() const final;
 
     InlineStyleSheetOwner m_styleSheetOwner;
-    Timer m_svgLoadEventTimer;
+    Timer m_loadEventTimer;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/svg/SVGURIReference.cpp b/Source/WebCore/svg/SVGURIReference.cpp
index 8774a33..ee45a29 100644
--- a/Source/WebCore/svg/SVGURIReference.cpp
+++ b/Source/WebCore/svg/SVGURIReference.cpp
@@ -45,12 +45,16 @@
     return PropertyRegistry::isKnownAttribute(attributeName);
 }
 
+SVGElement& SVGURIReference::contextElement() const
+{
+    return *m_href->contextElement();
+}
+
 void SVGURIReference::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
-    auto* contextElement = m_href->contextElement();
     if (name.matches(SVGNames::hrefAttr))
-        m_href->setBaseValInternal(value.isNull() ? contextElement->getAttribute(XLinkNames::hrefAttr) : value);
-    else if (name.matches(XLinkNames::hrefAttr) && !contextElement->hasAttribute(SVGNames::hrefAttr))
+        m_href->setBaseValInternal(value.isNull() ? contextElement().getAttribute(XLinkNames::hrefAttr) : value);
+    else if (name.matches(XLinkNames::hrefAttr) && !contextElement().hasAttribute(SVGNames::hrefAttr))
         m_href->setBaseValInternal(value);
 }
 
@@ -100,4 +104,23 @@
     return { treeScope.getElementById(id), WTFMove(id) };
 }
 
+bool SVGURIReference::haveLoadedRequiredResources() const
+{
+    if (href().isEmpty() || !isExternalURIReference(href(), contextElement().document()))
+        return true;
+    return errorOccurred() || haveFiredLoadEvent();
+}
+
+void SVGURIReference::dispatchLoadEvent()
+{
+    if (haveFiredLoadEvent())
+        return;
+
+    // Dispatch the load event
+    setHaveFiredLoadEvent(true);
+    ASSERT(contextElement().haveLoadedRequiredResources());
+
+    contextElement().sendLoadEventIfPossible();
+}
+
 }
diff --git a/Source/WebCore/svg/SVGURIReference.h b/Source/WebCore/svg/SVGURIReference.h
index 0fd104f..300d56a 100644
--- a/Source/WebCore/svg/SVGURIReference.h
+++ b/Source/WebCore/svg/SVGURIReference.h
@@ -66,7 +66,17 @@
 
     static bool isKnownAttribute(const QualifiedName& attributeName);
 
+    virtual bool haveFiredLoadEvent() const { return false; }
+    virtual void setHaveFiredLoadEvent(bool) { }
+    virtual bool errorOccurred() const { return false; }
+    virtual void setErrorOccurred(bool) { }
+
+    bool haveLoadedRequiredResources() const;
+    void dispatchLoadEvent();
+
 private:
+    SVGElement& contextElement() const;
+
     Ref<SVGAnimatedString> m_href;
 };
 
diff --git a/Source/WebCore/svg/SVGUseElement.cpp b/Source/WebCore/svg/SVGUseElement.cpp
index ad923841..294b326 100644
--- a/Source/WebCore/svg/SVGUseElement.cpp
+++ b/Source/WebCore/svg/SVGUseElement.cpp
@@ -50,7 +50,7 @@
     : SVGGraphicsElement(tagName, document)
     , SVGExternalResourcesRequired(this)
     , SVGURIReference(this)
-    , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired)
+    , m_loadEventTimer(*this, &SVGElement::loadEventTimerFired)
 {
     ASSERT(hasCustomStyleResolveCallbacks());
     ASSERT(hasTagName(SVGNames::useTag));
@@ -101,7 +101,6 @@
     if (insertionType.connectedToDocument) {
         if (m_shadowTreeNeedsUpdate)
             document().addSVGUseElement(*this);
-        SVGExternalResourcesRequired::insertedIntoDocument();
         invalidateShadowTree();
         // FIXME: Move back the call to updateExternalDocument() here once notifyFinished is made always async.
         return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
@@ -554,16 +553,11 @@
 {
     ASSERT(ScriptDisallowedScope::InMainThread::isScriptAllowed());
     invalidateShadowTree();
-    if (resource.errorOccurred())
+    if (resource.errorOccurred()) {
+        setErrorOccurred(true);
         dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));
-    else if (!resource.wasCanceled())
-        SVGExternalResourcesRequired::dispatchLoadEvent();
-}
-
-void SVGUseElement::finishParsingChildren()
-{
-    SVGGraphicsElement::finishParsingChildren();
-    SVGExternalResourcesRequired::finishParsingChildren();
+    } else if (!resource.wasCanceled())
+        SVGURIReference::dispatchLoadEvent();
 }
 
 void SVGUseElement::updateExternalDocument()
@@ -597,29 +591,4 @@
     invalidateShadowTree();
 }
 
-bool SVGUseElement::isValid() const
-{
-    return SVGTests::isValid();
-}
-
-bool SVGUseElement::haveLoadedRequiredResources()
-{
-    return SVGExternalResourcesRequired::haveLoadedRequiredResources();
-}
-
-void SVGUseElement::setHaveFiredLoadEvent(bool haveFiredLoadEvent)
-{
-    m_haveFiredLoadEvent = haveFiredLoadEvent;
-}
-
-bool SVGUseElement::haveFiredLoadEvent() const
-{
-    return m_haveFiredLoadEvent;
-}
-
-Timer* SVGUseElement::svgLoadEventTimer()
-{
-    return &m_svgLoadEventTimer;
-}
-
 }
diff --git a/Source/WebCore/svg/SVGUseElement.h b/Source/WebCore/svg/SVGUseElement.h
index ab59cd3..5b5148f 100644
--- a/Source/WebCore/svg/SVGUseElement.h
+++ b/Source/WebCore/svg/SVGUseElement.h
@@ -57,7 +57,6 @@
 private:
     SVGUseElement(const QualifiedName&, Document&);
 
-    bool isValid() const override;
     InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) override;
     void didFinishInsertingNode() final;
     void removedFromAncestor(RemovalType, ContainerNode&) override;
@@ -71,12 +70,7 @@
 
     RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
     Path toClipPath() override;
-    bool haveLoadedRequiredResources() override;
-    void finishParsingChildren() override;
     bool selfHasRelativeLengths() const override;
-    void setHaveFiredLoadEvent(bool) override;
-    bool haveFiredLoadEvent() const override;
-    Timer* svgLoadEventTimer() override;
     void notifyFinished(CachedResource&) final;
 
     Document* externalDocument() const;
@@ -95,6 +89,15 @@
     void clearShadowTree();
     void invalidateDependentShadowTrees();
 
+    bool haveLoadedRequiredResources() override { return SVGURIReference::haveLoadedRequiredResources(); }
+    void setHaveFiredLoadEvent(bool haveFiredLoadEvent) override { m_haveFiredLoadEvent = haveFiredLoadEvent; }
+    bool haveFiredLoadEvent() const override { return m_haveFiredLoadEvent; }
+    void setErrorOccurred(bool errorOccurred) override { m_errorOccurred = errorOccurred; }
+    bool errorOccurred() const override { return m_errorOccurred; }
+    Timer* loadEventTimer() override { return &m_loadEventTimer; }
+
+    bool isValid() const override { return SVGTests::isValid(); }
+
     PropertyRegistry m_propertyRegistry { *this };
     Ref<SVGAnimatedLength> m_x { SVGAnimatedLength::create(this, SVGLengthMode::Width) };
     Ref<SVGAnimatedLength> m_y { SVGAnimatedLength::create(this, SVGLengthMode::Height) };
@@ -102,9 +105,10 @@
     Ref<SVGAnimatedLength> m_height { SVGAnimatedLength::create(this, SVGLengthMode::Height) };
 
     bool m_haveFiredLoadEvent { false };
+    bool m_errorOccurred { false };
     bool m_shadowTreeNeedsUpdate { true };
     CachedResourceHandle<CachedSVGDocument> m_externalDocument;
-    Timer m_svgLoadEventTimer;
+    Timer m_loadEventTimer;
 };
 
 }