Title: [236862] trunk
Revision
236862
Author
[email protected]
Date
2018-10-04 17:19:46 -0700 (Thu, 04 Oct 2018)

Log Message

A Document / Window should lose its browsing context as soon as its iframe is removed from the document
https://bugs.webkit.org/show_bug.cgi?id=190282

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

Rebaseline several WPT tests that are now passing. I have verified that those tests are also passing in
Firefox and Chrome.

* web-platform-tests/html/browsers/windows/nested-browsing-contexts/window-parent-null-expected.txt:
* web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard-expected.txt:

Source/WebCore:

A Document / Window should lose its browsing context (aka Frame) as soon as its iframe is removed from
the document. In WebKit, a Document / Window's Frame was only getting nulled out when the frame gets
destroyed, which happens later usually after a GC happens.

Specification:
- https://html.spec.whatwg.org/#the-iframe-element
"""
When an iframe element is removed from a document, the user agent must discard the element's nested browsing
context, if it is not null, and then set the element's nested browsing context to null.
"""

This was not consistent with the specification or other browsers (tested Chrome and Firefox) so this
patch is aligning our behavior.

In a follow-up, I am planning to look into making the Window not be a FrameDestructionObserver, and instead
get its frame from the Document. This should make the code simpler.

No new tests, rebaselined existing tests.

* Modules/mediastream/MediaDevices.cpp:
(WebCore::MediaDevices::getUserMedia const):
* Modules/mediastream/MediaDevices.h:
Update getUserMedia() to reject a the Promise with an InvalidStateError when calling after the
document has been detached, instead of throwing an InvalidStateError. This behavior is as per
specification:
- https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia (Step 4)
I needed to make this change to keep one of our layout tests passing.

* dom/Document.cpp:
(WebCore::Document::attachToCachedFrame):
(WebCore::Document::detachFromFrame):
* dom/Document.h:
* page/DOMWindow.cpp:
(WebCore::DOMWindow::didSecureTransitionTo):
(WebCore::DOMWindow::willDetachDocumentFromFrame):
(WebCore::DOMWindow::setStatus):
(WebCore::DOMWindow::detachFromFrame):
(WebCore::DOMWindow::attachToFrame):
* page/DOMWindow.h:
* page/DOMWindowProperty.cpp:
(WebCore::DOMWindowProperty::disconnectFrameForDocumentSuspension):
(WebCore::DOMWindowProperty::willDestroyGlobalObjectInCachedFrame):
(WebCore::DOMWindowProperty::willDestroyGlobalObjectInFrame):
* page/Frame.cpp:
(WebCore::Frame::disconnectOwnerElement):

* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::drawText):
Calling drawText() with a null String hits an assertion in debug. This was triggered by one of
our layout tests so I made sure we only call drawText when the String is not null.

LayoutTests:

Update existing layout test to reflect behavior change.

* fast/dom/Window/BarInfo-after-frame-removed.html:
* fast/dom/Window/dom-access-from-closure-iframe-expected.txt:
* fast/dom/Window/dom-access-from-closure-window-expected.txt:
* fast/dom/Window/dom-access-from-closure-window-with-gc-expected.txt:
* fast/dom/Window/resources/dom-access-from-closure-iframe-child.html:
* fast/dom/Window/resources/dom-access-from-closure-window-child.html:
* fast/events/resources/before-unload-return-string-conversion-frame.html:
* fast/parser/resources/set-parent-to-_javascript_-url.html:
* http/tests/media/media-stream/disconnected-frame.html:
* http/tests/security/contentSecurityPolicy/resources/checkDidSameOriginChildWindowLoad.js:
(checkDidLoad):
* http/tests/security/named-window-property-from-same-origin-inactive-document-expected.txt:
* http/tests/security/named-window-property-from-same-origin-inactive-document.html:
* http/tests/security/xss-DENIED-contentWindow-eval-expected.txt:
* http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document-expected.txt:
* http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (236861 => 236862)


--- trunk/LayoutTests/ChangeLog	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/ChangeLog	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,3 +1,29 @@
+2018-10-04  Chris Dumez  <[email protected]>
+
+        A Document / Window should lose its browsing context as soon as its iframe is removed from the document
+        https://bugs.webkit.org/show_bug.cgi?id=190282
+
+        Reviewed by Ryosuke Niwa.
+
+        Update existing layout test to reflect behavior change.
+
+        * fast/dom/Window/BarInfo-after-frame-removed.html:
+        * fast/dom/Window/dom-access-from-closure-iframe-expected.txt:
+        * fast/dom/Window/dom-access-from-closure-window-expected.txt:
+        * fast/dom/Window/dom-access-from-closure-window-with-gc-expected.txt:
+        * fast/dom/Window/resources/dom-access-from-closure-iframe-child.html:
+        * fast/dom/Window/resources/dom-access-from-closure-window-child.html:
+        * fast/events/resources/before-unload-return-string-conversion-frame.html:
+        * fast/parser/resources/set-parent-to-_javascript_-url.html:
+        * http/tests/media/media-stream/disconnected-frame.html:
+        * http/tests/security/contentSecurityPolicy/resources/checkDidSameOriginChildWindowLoad.js:
+        (checkDidLoad):
+        * http/tests/security/named-window-property-from-same-origin-inactive-document-expected.txt:
+        * http/tests/security/named-window-property-from-same-origin-inactive-document.html:
+        * http/tests/security/xss-DENIED-contentWindow-eval-expected.txt:
+        * http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document-expected.txt:
+        * http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document.html:
+
 2018-10-04  Ross Kirsling  <[email protected]>
 
         Unreviewed test gardening for WinCairo (and one cross-platform test). 

Modified: trunk/LayoutTests/fast/dom/Window/BarInfo-after-frame-removed.html (236861 => 236862)


--- trunk/LayoutTests/fast/dom/Window/BarInfo-after-frame-removed.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/dom/Window/BarInfo-after-frame-removed.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -15,7 +15,9 @@
         var frame = document.getElementById("frame");
         var childWindow = frame.contentWindow;
         frame.parentNode.removeChild(frame);
-        childWindow.toolbar.visible;
+        try {
+            childWindow.toolbar.visible;
+        } catch (e) { }
         
         document.getElementById("console").firstChild.data = "" RAN";
     }

Modified: trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-iframe-expected.txt (236861 => 236862)


--- trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-iframe-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-iframe-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,5 +1,5 @@
 document.URL: LayoutTests/fast/dom/Window/resources/dom-access-from-closure-iframe-child.html
 window.document.URL: LayoutTests/fast/dom/Window/resources/notify-parent-done.html
-name: child
+name: 
 window.name: child
 

Modified: trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-window-expected.txt (236861 => 236862)


--- trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-window-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-window-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,5 +1,5 @@
 document.URL: LayoutTests/fast/dom/Window/resources/dom-access-from-closure-window-child.html
 window.document.URL: LayoutTests/fast/dom/Window/resources/notify-opener-done.html
-name: child
+name: 
 window.name: child
 

Modified: trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-window-with-gc-expected.txt (236861 => 236862)


--- trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-window-with-gc-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/dom/Window/dom-access-from-closure-window-with-gc-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,5 +1,5 @@
 document.URL: LayoutTests/fast/dom/Window/resources/dom-access-from-closure-window-child.html
 window.document.URL: LayoutTests/fast/dom/Window/resources/notify-opener-done.html
-name: child
+name: 
 window.name: child
 

Modified: trunk/LayoutTests/fast/dom/Window/resources/dom-access-from-closure-iframe-child.html (236861 => 236862)


--- trunk/LayoutTests/fast/dom/Window/resources/dom-access-from-closure-iframe-child.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/dom/Window/resources/dom-access-from-closure-iframe-child.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,4 +1,6 @@
 <script>
+    const parent = window.parent; // Save parent as the window will be detached when accessFrame() is called.
+
     parent.accessFrame = function()
     {
         function normalizeURL(url)

Modified: trunk/LayoutTests/fast/dom/Window/resources/dom-access-from-closure-window-child.html (236861 => 236862)


--- trunk/LayoutTests/fast/dom/Window/resources/dom-access-from-closure-window-child.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/dom/Window/resources/dom-access-from-closure-window-child.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,4 +1,6 @@
 <script>
+    const opener = window.opener; // Save opener as the window will be detached when accessFrame() is called.
+
     opener.accessFrame = function()
     {
         function normalizeURL(url)

Modified: trunk/LayoutTests/fast/events/resources/before-unload-return-string-conversion-frame.html (236861 => 236862)


--- trunk/LayoutTests/fast/events/resources/before-unload-return-string-conversion-frame.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/events/resources/before-unload-return-string-conversion-frame.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -14,9 +14,7 @@
         parent.shouldBeTrue("event.defaultPrevented");
         parent.shouldBeEqualToString("event.returnValue", "PASS");
         parent.shouldBeTrue("toStringCalled");
-        parent.setTimeout(function() {
-            parent.finishJSTest();
-        }, 0);
+        parent.finishJSTest();
     }
 
     window.addEventListener("beforeunload", listener);

Modified: trunk/LayoutTests/fast/parser/resources/set-parent-to-_javascript_-url.html (236861 => 236862)


--- trunk/LayoutTests/fast/parser/resources/set-parent-to-_javascript_-url.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/fast/parser/resources/set-parent-to-_javascript_-url.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,4 +1,5 @@
 <script>
+const parent = window.parent;
 alert(1);
 parent.document.getElementsByTagName('iframe')[0].src = ""
 alert(4);

Modified: trunk/LayoutTests/http/tests/media/media-stream/disconnected-frame.html (236861 => 236862)


--- trunk/LayoutTests/http/tests/media/media-stream/disconnected-frame.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/media/media-stream/disconnected-frame.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -12,27 +12,29 @@
     testRunner.setUserMediaPermission(true);
 
 function onIframeLoaded() {
-    iframeNavigator = iframe.contentWindow.navigator;
+    iframeMediaDevices = iframe.contentWindow.navigator.mediaDevices;
     iframe.remove();
     onIframeUnloaded();
 }
 
 function onIframeUnloaded() {
+    handle = setTimeout(function() {
+        testFailed('Timeout: promise resolve and reject functions not called.');
+        finishJSTest();
+    }, 100);
+
     var options = {audio: true, video: true};
-    iframeNavigator.mediaDevices.getUserMedia(options)
+    iframeMediaDevices.getUserMedia(options)
         .then(stream => {
             testFailed('Promise resolved unexpectedly.');
+            clearTimeout(handle);
             finishJSTest();
         })
         .catch(err => {
             testPassed('Promise rejected as expected.');
+            clearTimeout(handle);
             finishJSTest();
         });
-
-    setTimeout(function() {
-        testFailed('Timeout: promise resolve and reject functions not called.');
-        finishJSTest();
-    }, 100);
 }
 
 var iframe = document.createElement('iframe');

Modified: trunk/LayoutTests/http/tests/security/contentSecurityPolicy/resources/checkDidSameOriginChildWindowLoad.js (236861 => 236862)


--- trunk/LayoutTests/http/tests/security/contentSecurityPolicy/resources/checkDidSameOriginChildWindowLoad.js	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/security/contentSecurityPolicy/resources/checkDidSameOriginChildWindowLoad.js	2018-10-05 00:19:46 UTC (rev 236862)
@@ -8,12 +8,5 @@
 
 function checkDidSameOriginChildWindowLoad(childWindow, callback)
 {
-    function checkDidLoad() {
-        if (childWindow.document.location.origin !== document.location.origin)
-            return;
-        // Child window did load
-        window.clearInterval(intervalID);
-        callback()
-    }
-    intervalID = window.setInterval(checkDidLoad, 10);
+    childWindow._onload_ = callback;
 }

Modified: trunk/LayoutTests/http/tests/security/named-window-property-from-same-origin-inactive-document-expected.txt (236861 => 236862)


--- trunk/LayoutTests/http/tests/security/named-window-property-from-same-origin-inactive-document-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/security/named-window-property-from-same-origin-inactive-document-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -5,10 +5,10 @@
 
 Lookup named element whose name corresponds to an element in the initial about:blank document:
 PASS frame.contentDocument.getElementById('A') is not elementAInInactiveDocument
-PASS elementAInActiveDocumentFunction() is frame.contentDocument.getElementById('A')
+PASS elementAInDetachedWindowFunction() threw exception ReferenceError: Can't find variable: A.
 
 Lookup named element whose name does not correspond to an element in the initial about:blank document:
-PASS elementBInActiveDocumentFunction() is frame.contentDocument.getElementById('B')
+PASS elementBInDetachedWindowFunction() threw exception ReferenceError: Can't find variable: B.
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/http/tests/security/named-window-property-from-same-origin-inactive-document.html (236861 => 236862)


--- trunk/LayoutTests/http/tests/security/named-window-property-from-same-origin-inactive-document.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/security/named-window-property-from-same-origin-inactive-document.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -17,17 +17,17 @@
 elementAInInactiveDocument.id = "A";
 frameDocument.body.appendChild(elementAInInactiveDocument);
 
-var elementAInActiveDocumentFunction = frame.contentWindow.Function("return A;");
-var elementBInActiveDocumentFunction = frame.contentWindow.Function("return B;");
+var elementAInDetachedWindowFunction = frame.contentWindow.Function("return A;");
+var elementBInDetachedWindowFunction = frame.contentWindow.Function("return B;");
 
 frame._onload_ = function ()
 {
     debug("Lookup named element whose name corresponds to an element in the initial about:blank document:");
     shouldNotBe("frame.contentDocument.getElementById('A')", "elementAInInactiveDocument");
-    shouldBe("elementAInActiveDocumentFunction()", "frame.contentDocument.getElementById('A')");
+    shouldThrowErrorName("elementAInDetachedWindowFunction()", "ReferenceError");
 
     debug("<br>Lookup named element whose name does not correspond to an element in the initial about:blank document:");
-    shouldBe("elementBInActiveDocumentFunction()", "frame.contentDocument.getElementById('B')");
+    shouldThrowErrorName("elementBInDetachedWindowFunction()", "ReferenceError");
 
     finishJSTest();
 }

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-contentWindow-eval-expected.txt (236861 => 236862)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-contentWindow-eval-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-contentWindow-eval-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,2 +1 @@
-CONSOLE MESSAGE: line 1: TypeError: Type error
 This test passes if alert() is not called. 

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document-expected.txt (236861 => 236862)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -4,10 +4,10 @@
 
 
 Lookup named element whose name corresponds to an element in the initial about:blank document:
-PASS elementAInActiveDocumentFunction() threw exception SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame. Protocols, domains, and ports must match..
+PASS elementAInDetachedWindowFunction() threw exception ReferenceError: Can't find variable: A.
 
 Lookup named element whose name does not correspond to an element in the initial about:blank document:
-PASS elementBInActiveDocumentFunction() threw exception SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame. Protocols, domains, and ports must match..
+PASS elementBInDetachedWindowFunction() threw exception ReferenceError: Can't find variable: B.
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document.html (236861 => 236862)


--- trunk/LayoutTests/http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document.html	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/http/tests/security/xss-DENIED-named-window-property-from-cross-origin-inactive-document.html	2018-10-05 00:19:46 UTC (rev 236862)
@@ -17,16 +17,16 @@
 elementAInInactiveDocument.id = "A";
 frameDocument.body.appendChild(elementAInInactiveDocument);
 
-var elementAInActiveDocumentFunction = frame.contentWindow.Function("return A;");
-var elementBInActiveDocumentFunction = frame.contentWindow.Function("return B;");
+var elementAInDetachedWindowFunction = frame.contentWindow.Function("return A;");
+var elementBInDetachedWindowFunction = frame.contentWindow.Function("return B;");
 
 frame._onload_ = function ()
 {
     debug("Lookup named element whose name corresponds to an element in the initial about:blank document:")
-    shouldThrowErrorName("elementAInActiveDocumentFunction()", 'SecurityError');
+    shouldThrowErrorName("elementAInDetachedWindowFunction()", 'ReferenceError');
 
     debug("<br>Lookup named element whose name does not correspond to an element in the initial about:blank document:");
-    shouldThrowErrorName("elementBInActiveDocumentFunction()", 'SecurityError');
+    shouldThrowErrorName("elementBInDetachedWindowFunction()", 'ReferenceError');
 
     finishJSTest();
 }

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (236861 => 236862)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,3 +1,16 @@
+2018-10-04  Chris Dumez  <[email protected]>
+
+        A Document / Window should lose its browsing context as soon as its iframe is removed from the document
+        https://bugs.webkit.org/show_bug.cgi?id=190282
+
+        Reviewed by Ryosuke Niwa.
+
+        Rebaseline several WPT tests that are now passing. I have verified that those tests are also passing in
+        Firefox and Chrome.
+
+        * web-platform-tests/html/browsers/windows/nested-browsing-contexts/window-parent-null-expected.txt:
+        * web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard-expected.txt:
+
 2018-10-04  YUHAN WU  <[email protected]>
 
         runtime flag and IDL for MediaRecorder

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/nested-browsing-contexts/window-parent-null-expected.txt (236861 => 236862)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/nested-browsing-contexts/window-parent-null-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/windows/nested-browsing-contexts/window-parent-null-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,4 +1,4 @@
 
-FAIL `window.parent` is null when browsing context container element removed assert_equals: expected null but got object "[object Window]"
-FAIL `window.parent` null when parent browsing context container removed assert_equals: expected null but got object "[object Window]"
-
+PASS `window.parent` is null when browsing context container element removed 
+PASS `window.parent` null when parent browsing context container removed 
+ 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard-expected.txt (236861 => 236862)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard-expected.txt	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard-expected.txt	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,3 +1,3 @@
 
-FAIL IFrame discards are processed synchronously assert_equals: child window should be discarded expected null but got object "[object Window]"
+PASS IFrame discards are processed synchronously 
 

Modified: trunk/Source/WebCore/ChangeLog (236861 => 236862)


--- trunk/Source/WebCore/ChangeLog	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/ChangeLog	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1,3 +1,61 @@
+2018-10-04  Chris Dumez  <[email protected]>
+
+        A Document / Window should lose its browsing context as soon as its iframe is removed from the document
+        https://bugs.webkit.org/show_bug.cgi?id=190282
+
+        Reviewed by Ryosuke Niwa.
+
+        A Document / Window should lose its browsing context (aka Frame) as soon as its iframe is removed from
+        the document. In WebKit, a Document / Window's Frame was only getting nulled out when the frame gets
+        destroyed, which happens later usually after a GC happens.
+
+        Specification:
+        - https://html.spec.whatwg.org/#the-iframe-element
+        """
+        When an iframe element is removed from a document, the user agent must discard the element's nested browsing
+        context, if it is not null, and then set the element's nested browsing context to null.
+        """
+
+        This was not consistent with the specification or other browsers (tested Chrome and Firefox) so this
+        patch is aligning our behavior.
+
+        In a follow-up, I am planning to look into making the Window not be a FrameDestructionObserver, and instead
+        get its frame from the Document. This should make the code simpler.
+
+        No new tests, rebaselined existing tests.
+
+        * Modules/mediastream/MediaDevices.cpp:
+        (WebCore::MediaDevices::getUserMedia const):
+        * Modules/mediastream/MediaDevices.h:
+        Update getUserMedia() to reject a the Promise with an InvalidStateError when calling after the
+        document has been detached, instead of throwing an InvalidStateError. This behavior is as per
+        specification:
+        - https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia (Step 4)
+        I needed to make this change to keep one of our layout tests passing.
+
+        * dom/Document.cpp:
+        (WebCore::Document::attachToCachedFrame):
+        (WebCore::Document::detachFromFrame):
+        * dom/Document.h:
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::didSecureTransitionTo):
+        (WebCore::DOMWindow::willDetachDocumentFromFrame):
+        (WebCore::DOMWindow::setStatus):
+        (WebCore::DOMWindow::detachFromFrame):
+        (WebCore::DOMWindow::attachToFrame):
+        * page/DOMWindow.h:
+        * page/DOMWindowProperty.cpp:
+        (WebCore::DOMWindowProperty::disconnectFrameForDocumentSuspension):
+        (WebCore::DOMWindowProperty::willDestroyGlobalObjectInCachedFrame):
+        (WebCore::DOMWindowProperty::willDestroyGlobalObjectInFrame):
+        * page/Frame.cpp:
+        (WebCore::Frame::disconnectOwnerElement):
+
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSource::drawText):
+        Calling drawText() with a null String hits an assertion in debug. This was triggered by one of
+        our layout tests so I made sure we only call drawText when the String is not null.
+
 2018-10-04  Jeremy Jones  <[email protected]>
 
         Unify implementation in VideoFullscreenInterfaceAVKit

Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp (236861 => 236862)


--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp	2018-10-05 00:19:46 UTC (rev 236862)
@@ -96,11 +96,13 @@
     );
 }
 
-ExceptionOr<void> MediaDevices::getUserMedia(const StreamConstraints& constraints, Promise&& promise) const
+void MediaDevices::getUserMedia(const StreamConstraints& constraints, Promise&& promise) const
 {
     auto* document = this->document();
-    if (!document)
-        return Exception { InvalidStateError };
+    if (!document) {
+        promise.reject(Exception { InvalidStateError });
+        return;
+    }
 
     auto audioConstraints = createMediaConstraints(constraints.audio);
     auto videoConstraints = createMediaConstraints(constraints.video);
@@ -111,7 +113,7 @@
     if (request)
         request->start();
 
-    return { };
+    return;
 }
 
 ExceptionOr<void> MediaDevices::getDisplayMedia(const StreamConstraints& constraints, Promise&& promise) const

Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.h (236861 => 236862)


--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.h	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.h	2018-10-05 00:19:46 UTC (rev 236862)
@@ -74,7 +74,7 @@
         Variant<bool, MediaTrackConstraints> video;
         Variant<bool, MediaTrackConstraints> audio;
     };
-    ExceptionOr<void> getUserMedia(const StreamConstraints&, Promise&&) const;
+    void getUserMedia(const StreamConstraints&, Promise&&) const;
     ExceptionOr<void> getDisplayMedia(const StreamConstraints&, Promise&&) const;
     void enumerateDevices(EnumerateDevicesPromise&&) const;
     MediaTrackSupportedConstraints getSupportedConstraints();

Modified: trunk/Source/WebCore/dom/Document.cpp (236861 => 236862)


--- trunk/Source/WebCore/dom/Document.cpp	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/dom/Document.cpp	2018-10-05 00:19:46 UTC (rev 236862)
@@ -2341,6 +2341,8 @@
     ASSERT(cachedFrame.view());
     ASSERT(m_pageCacheState == Document::InPageCache);
     observeFrame(&cachedFrame.view()->frame());
+    if (auto* window = domWindow())
+        window->attachToFrame(cachedFrame.view()->frame());
 }
 
 void Document::detachFromCachedFrame(CachedFrameBase& cachedFrame)
@@ -8245,4 +8247,12 @@
     return m_CSSRegisteredPropertySet.add(prop.name, std::make_unique<CSSRegisteredCustomProperty>(WTFMove(prop))).isNewEntry;
 }
 
+void Document::detachFromFrame()
+{
+    if (auto* window = domWindow())
+        window->willDetachDocumentFromFrame();
+
+    observeFrame(nullptr);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Document.h (236861 => 236862)


--- trunk/Source/WebCore/dom/Document.h	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/dom/Document.h	2018-10-05 00:19:46 UTC (rev 236862)
@@ -1505,6 +1505,8 @@
     void setAsRunningUserScripts() { m_isRunningUserScripts = true; }
     bool isRunningUserScripts() const { return m_isRunningUserScripts; }
 
+    void detachFromFrame();
+
 protected:
     enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
     Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);
@@ -1522,8 +1524,6 @@
 
     bool shouldInheritContentSecurityPolicyFromOwner() const;
 
-    void detachFromFrame() { observeFrame(nullptr); }
-
     void updateTitleElement(Element& changingTitleElement);
     void frameDestroyed() final;
 

Modified: trunk/Source/WebCore/page/DOMWindow.cpp (236861 => 236862)


--- trunk/Source/WebCore/page/DOMWindow.cpp	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/page/DOMWindow.cpp	2018-10-05 00:19:46 UTC (rev 236862)
@@ -414,6 +414,7 @@
 void DOMWindow::didSecureTransitionTo(Document& document)
 {
     observeContext(&document);
+    observeFrame(document.frame());
 }
 
 DOMWindow::~DOMWindow()
@@ -511,6 +512,8 @@
 
     if (m_performance)
         m_performance->clearResourceTimings();
+
+    detachFromFrame();
 }
 
 #if ENABLE(GAMEPAD)
@@ -1402,7 +1405,17 @@
 
     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
     page->chrome().setStatusbarText(*m_frame, m_status);
-} 
+}
+
+void DOMWindow::detachFromFrame()
+{
+    observeFrame(nullptr);
+}
+
+void DOMWindow::attachToFrame(Frame& frame)
+{
+    observeFrame(&frame);
+}
     
 void DOMWindow::setDefaultStatus(const String& string) 
 {

Modified: trunk/Source/WebCore/page/DOMWindow.h (236861 => 236862)


--- trunk/Source/WebCore/page/DOMWindow.h	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/page/DOMWindow.h	2018-10-05 00:19:46 UTC (rev 236862)
@@ -333,6 +333,9 @@
     void willDetachDocumentFromFrame();
     void willDestroyCachedFrame();
 
+    void attachToFrame(Frame&);
+    void detachFromFrame();
+
     void enableSuddenTermination();
     void disableSuddenTermination();
 

Modified: trunk/Source/WebCore/page/DOMWindowProperty.cpp (236861 => 236862)


--- trunk/Source/WebCore/page/DOMWindowProperty.cpp	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/page/DOMWindowProperty.cpp	2018-10-05 00:19:46 UTC (rev 236862)
@@ -57,9 +57,6 @@
 
 void DOMWindowProperty::disconnectFrameForDocumentSuspension()
 {
-    // If this property is being disconnected from its Frame to enter the PageCache, it must have
-    // been created with a Frame in the first place.
-    ASSERT(m_frame);
     ASSERT(m_associatedDOMWindow);
 
     m_frame = nullptr;
@@ -93,8 +90,6 @@
 
 void DOMWindowProperty::willDestroyGlobalObjectInFrame()
 {
-    // If the property is getting this callback it must have been created with a Frame/DOMWindow and it should still have them.
-    ASSERT(m_frame);
     ASSERT(m_associatedDOMWindow);
 
     // DOMWindowProperty lifetime isn't tied directly to the DOMWindow itself so it is important that it unregister
@@ -107,9 +102,7 @@
 
 void DOMWindowProperty::willDetachGlobalObjectFromFrame()
 {
-    // If the property is getting this callback it must have been created with a Frame/DOMWindow and it should still have them.
-    ASSERT(m_frame);
-    ASSERT(m_associatedDOMWindow);
+    m_frame = nullptr;
 }
 
 }

Modified: trunk/Source/WebCore/page/Frame.cpp (236861 => 236862)


--- trunk/Source/WebCore/page/Frame.cpp	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/page/Frame.cpp	2018-10-05 00:19:46 UTC (rev 236862)
@@ -831,6 +831,9 @@
             m_page->decrementSubframeCount();
     }
     m_ownerElement = nullptr;
+
+    if (auto* document = this->document())
+        document->detachFromFrame();
 }
 
 String Frame::displayStringModifiedByEncoding(const String& str) const

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp (236861 => 236862)


--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp	2018-10-05 00:17:49 UTC (rev 236861)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp	2018-10-05 00:19:46 UTC (rev 236862)
@@ -372,7 +372,7 @@
         string = String::format("Camera: %s", camera);
         statsLocation.move(0, m_statsFontSize);
         context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
-    } else {
+    } else if (!name().isNull()) {
         statsLocation.move(0, m_statsFontSize);
         context.drawText(statsFont, TextRun { name() }, statsLocation);
     }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to