Bug 1677474 - Part 3: Trigger blur steps when window needs to adjust its focused element; draft
authorEdgar Chen <echen@mozilla.com>
Thu, 18 Feb 2021 13:44:10 +0100
changeset 3548275 5bdfb06a9a122f37de317dc62e545d843b6bf6b0
parent 3548274 321f9ad70d2214fb208de040369aa21f418d49f8
child 3548276 364d2badcc1780629aec1dc0683ac609ccaba91e
push id656959
push userechen@mozilla.com
push dateThu, 18 Feb 2021 19:00:41 +0000
treeherdertry@20dceee2c2be [default view] [failures only]
bugs1677474
milestone87.0a1
Bug 1677474 - Part 3: Trigger blur steps when window needs to adjust its focused element; Differential Revision: https://phabricator.services.mozilla.com/D104538
dom/base/nsFocusManager.cpp
testing/web-platform/tests/focus/focus-event-after-iframe-gets-focus.html
testing/web-platform/tests/focus/support/focus-event-after-different-site-iframe-gets-focus-outer.sub.html
testing/web-platform/tests/focus/support/focus-event-after-iframe-gets-focus-inner.html
testing/web-platform/tests/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-middle.sub.html
testing/web-platform/tests/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-outer.sub.html
testing/web-platform/tests/focus/support/focus-event-after-same-site-iframe-gets-focus-outer.html
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1858,17 +1858,28 @@ void nsFocusManager::AdjustWindowFocusIn
     // When aCheckPermission is true, we should check whether the caller can
     // access the window or not.  If it cannot access, we should stop the
     // adjusting.
     if (aCheckPermission && !nsContentUtils::LegacyIsCallerNativeCode() &&
         !nsContentUtils::CanCallerAccess(window->GetCurrentInnerWindow())) {
       return;
     }
 
-    window->SetFocusedElement(frameElement);
+    if (frameElement != window->GetFocusedElement()) {
+      window->SetFocusedElement(frameElement);
+
+      RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(frameElement);
+      MOZ_ASSERT(loaderOwner);
+      RefPtr<nsFrameLoader> loader = loaderOwner->GetFrameLoader();
+      if (loader && loader->IsRemoteFrame() &&
+          GetFocusedBrowsingContext() == bc) {
+        Blur(nullptr, nullptr, true, true,
+             nsFocusManager::GenerateFocusActionId());
+      }
+    }
   }
 }
 
 void nsFocusManager::AdjustWindowFocus(BrowsingContext* aBrowsingContext,
                                        bool aCheckPermission, bool aIsVisible) {
   AdjustWindowFocusInProcess(aBrowsingContext, aCheckPermission, aIsVisible);
   if (XRE_IsContentProcess()) {
     // The containing <iframe> isn't in this process and we are in a child
copy from testing/web-platform/tests/focus/focus-event-after-focusing-iframes.html
copy to testing/web-platform/tests/focus/focus-event-after-iframe-gets-focus.html
--- a/testing/web-platform/tests/focus/focus-event-after-focusing-iframes.html
+++ b/testing/web-platform/tests/focus/focus-event-after-iframe-gets-focus.html
@@ -1,11 +1,11 @@
 <!doctype html>
 <meta charset=utf-8>
-<title>Test focus event after focusing iframe</title>
+<title>Test focus event after iframe gets focus</title>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
 function waitForEvent(target, event, checkFn) {
   return new Promise(resolve => {
     target.addEventListener(event, e => {
       if (checkFn && !checkFn(e)) {
         return;
@@ -29,27 +29,32 @@ async function getLog(w) {
   }, 0);
   await waitForEvent(window, "message", (e) => {
     log = e.data;
     return true;
   });
   return log;
 }
 
-async function runTest(t, url) {
+async function runTest(t, url, expectResult) {
   let w = window.open(url);
   t.add_cleanup(() => { w.close(); });
   await waitForEvent(window, "message", e => e.data === "ready");
   focusIframe(w);
-  assert_equals(await getLog(w), 'outerlog:willfocusiframe,windowblur,didfocusiframe,innerlog:windowfocus,');
-  focusIframe(w);
-  assert_equals(await getLog(w), 'outerlog:willfocusiframe,windowblur,didfocusiframe,willfocusiframe,didfocusiframe,innerlog:windowfocus,');
+  assert_equals(await getLog(w), expectResult);
 }
 
 promise_test(async t => {
-  await runTest(t, "support/focus-event-after-focusing-different-site-iframes-outer.sub.html");
-}, "Check focus event after focusing different site iframe");
+  await runTest(t, "support/focus-event-after-same-site-iframe-gets-focus-outer.html",
+                "outerlog:windowblur,innerlog:willfocuswindow,windowfocus,didfocuswindow,");
+}, "Check focus event after same site iframe gets focus");
 
 promise_test(async t => {
-  await runTest(t, "support/focus-event-after-focusing-same-site-iframes-outer.html");
-}, "Check focus event after focusing same site iframe");
+  await runTest(t, "support/focus-event-after-different-site-iframe-gets-focus-outer.sub.html",
+                "outerlog:windowblur,innerlog:willfocuswindow,windowfocus,didfocuswindow,");
+}, "Check focus event after different site iframe gets focus");
+
+promise_test(async t => {
+  await runTest(t, "support/focus-event-after-innermost-different-site-iframe-gets-focus-outer.sub.html",
+                "outerlog:windowblur,middlelog:innerlog:willfocuswindow,windowfocus,didfocuswindow,");
+}, "Check focus event after innermost different site iframe gets focus");
 
 </script>
copy from testing/web-platform/tests/focus/support/focus-event-after-focusing-different-site-iframes-outer.sub.html
copy to testing/web-platform/tests/focus/support/focus-event-after-different-site-iframe-gets-focus-outer.sub.html
--- a/testing/web-platform/tests/focus/support/focus-event-after-focusing-different-site-iframes-outer.sub.html
+++ b/testing/web-platform/tests/focus/support/focus-event-after-different-site-iframe-gets-focus-outer.sub.html
@@ -1,21 +1,19 @@
 <!doctype html>
 <meta charset="utf-8">
-<title>Focus event after focusing different site iframes outer</title>
-<iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/focus/support/focus-event-after-focusing-iframes-inner.html"></iframe>
+<title>Focus event after different site iframe gets focus outer</title>
+<iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/focus/support/focus-event-after-iframe-gets-focus-inner.html"></iframe>
 <script>
 let outerlog = "outerlog:";
 
 let iframe = document.querySelector("iframe");
 window.onmessage = function(e) {
   if (e.data == "focus") {
-    outerlog += "willfocusiframe,";
-    iframe.focus();
-    outerlog += "didfocusiframe,";
+    iframe.contentWindow.postMessage("focus", "*");
   } else if (e.data == "getlog") {
     iframe.contentWindow.postMessage("getlog", "*");
   } else {
     opener.postMessage(outerlog + e.data, "*");
   }
 };
 
 window.onload = function() {
copy from testing/web-platform/tests/focus/support/focus-event-after-focusing-iframes-inner.html
copy to testing/web-platform/tests/focus/support/focus-event-after-iframe-gets-focus-inner.html
--- a/testing/web-platform/tests/focus/support/focus-event-after-focusing-iframes-inner.html
+++ b/testing/web-platform/tests/focus/support/focus-event-after-iframe-gets-focus-inner.html
@@ -5,17 +5,21 @@
   <title>Focus event inner document</title>
 </head>
 <body>
 <h1>Inner</h1>
 <script>
 let innerlog = "innerlog:";
 
 window.onmessage = function(e) {
-  if (e.data == "getlog") {
+  if (e.data == "focus") {
+    innerlog += "willfocuswindow,";
+    window.focus();
+    innerlog += "didfocuswindow,";
+  } else if (e.data == "getlog") {
     parent.postMessage(innerlog, "*");
   }
 };
 
 window.onfocus = function() {
   innerlog += "windowfocus,";
 };
 
copy from testing/web-platform/tests/focus/support/focus-event-after-focusing-different-site-iframes-outer.sub.html
copy to testing/web-platform/tests/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-middle.sub.html
--- a/testing/web-platform/tests/focus/support/focus-event-after-focusing-different-site-iframes-outer.sub.html
+++ b/testing/web-platform/tests/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-middle.sub.html
@@ -1,32 +1,27 @@
 <!doctype html>
 <meta charset="utf-8">
-<title>Focus event after focusing different site iframes outer</title>
-<iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/focus/support/focus-event-after-focusing-iframes-inner.html"></iframe>
+<title>Focus event after different site iframe gets focus middle</title>
+<h1>Middle</h1><br>
+<iframe src="https://{{hosts[][www]}}:{{ports[https][0]}}/focus/support/focus-event-after-iframe-gets-focus-inner.html"></iframe>
 <script>
-let outerlog = "outerlog:";
+let middlelog = "middlelog:";
 
 let iframe = document.querySelector("iframe");
 window.onmessage = function(e) {
   if (e.data == "focus") {
-    outerlog += "willfocusiframe,";
-    iframe.focus();
-    outerlog += "didfocusiframe,";
+    iframe.contentWindow.postMessage("focus", "*");
   } else if (e.data == "getlog") {
     iframe.contentWindow.postMessage("getlog", "*");
   } else {
-    opener.postMessage(outerlog + e.data, "*");
+    parent.postMessage(middlelog + e.data, "*");
   }
 };
 
-window.onload = function() {
-  window.onfocus = function() {
-    outerlog += "windowfocus,";
-  };
+window.onfocus = function() {
+  middlelog += "windowfocus,";
+};
 
-  window.onblur = function() {
-    outerlog += "windowblur,";
-  };
-
-  opener.postMessage("ready", "*");
+window.onblur = function() {
+  middlelog += "windowblur,";
 };
 </script>
copy from testing/web-platform/tests/focus/support/focus-event-after-focusing-different-site-iframes-outer.sub.html
copy to testing/web-platform/tests/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-outer.sub.html
--- a/testing/web-platform/tests/focus/support/focus-event-after-focusing-different-site-iframes-outer.sub.html
+++ b/testing/web-platform/tests/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-outer.sub.html
@@ -1,21 +1,19 @@
 <!doctype html>
 <meta charset="utf-8">
-<title>Focus event after focusing different site iframes outer</title>
-<iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/focus/support/focus-event-after-focusing-iframes-inner.html"></iframe>
+<title>Focus event after innermost different site iframe gets focus outer</title>
+<iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/focus/support/focus-event-after-innermost-different-site-iframe-gets-focus-middle.sub.html"></iframe>
 <script>
 let outerlog = "outerlog:";
 
 let iframe = document.querySelector("iframe");
 window.onmessage = function(e) {
   if (e.data == "focus") {
-    outerlog += "willfocusiframe,";
-    iframe.focus();
-    outerlog += "didfocusiframe,";
+    iframe.contentWindow.postMessage("focus", "*");
   } else if (e.data == "getlog") {
     iframe.contentWindow.postMessage("getlog", "*");
   } else {
     opener.postMessage(outerlog + e.data, "*");
   }
 };
 
 window.onload = function() {
copy from testing/web-platform/tests/focus/support/focus-event-after-focusing-same-site-iframes-outer.html
copy to testing/web-platform/tests/focus/support/focus-event-after-same-site-iframe-gets-focus-outer.html
--- a/testing/web-platform/tests/focus/support/focus-event-after-focusing-same-site-iframes-outer.html
+++ b/testing/web-platform/tests/focus/support/focus-event-after-same-site-iframe-gets-focus-outer.html
@@ -1,21 +1,19 @@
 <!doctype html>
 <meta charset="utf-8">
-<title>Focus event after focusing same site iframes outer</title>
-<iframe src="focus-event-after-focusing-iframes-inner.html"></iframe>
+<title>Focus event after same site iframe gets focus outer</title>
+<iframe src="focus-event-after-iframe-gets-focus-inner.html"></iframe>
 <script>
 let outerlog = "outerlog:";
 
 let iframe = document.querySelector("iframe");
 window.onmessage = function(e) {
   if (e.data == "focus") {
-    outerlog += "willfocusiframe,";
-    document.querySelector("iframe").focus();
-    outerlog += "didfocusiframe,";
+    iframe.contentWindow.postMessage("focus", "*");
   } else if (e.data == "getlog") {
     iframe.contentWindow.postMessage("getlog", "*");
   } else {
     opener.postMessage(outerlog + e.data, "*");
   }
 };
 
 window.onload = function() {