Portals: Expose portalHost in predecessor
Exposing it in the activate callback ensures that the portalHost is
exposed when the promise callback is executed.
Bug: 948118, 921776
Change-Id: Ie654fdefd3e75187a06e8c06eba3de52f8276ff1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1548316
Reviewed-by: Nasko Oskov <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Jeremy Roman <[email protected]>
Reviewed-by: Lucas Gadani <[email protected]>
Commit-Queue: Adithya Srinivasan <[email protected]>
Cr-Commit-Position: refs/heads/master@{#652383}
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 7f26611..e0feb2d 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1048,9 +1048,10 @@
void RenderFrameHostImpl::OnPortalActivated(
const base::UnguessableToken& portal_token,
blink::mojom::PortalAssociatedPtrInfo portal,
- blink::TransferableMessage data) {
- GetNavigationControl()->OnPortalActivated(portal_token, std::move(portal),
- std::move(data));
+ blink::TransferableMessage data,
+ base::OnceCallback<void(bool)> callback) {
+ GetNavigationControl()->OnPortalActivated(
+ portal_token, std::move(portal), std::move(data), std::move(callback));
}
void RenderFrameHostImpl::ForwardMessageToPortalHost(
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 97eb8f9..3186e56 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -869,7 +869,8 @@
// PortalActivateEvent.
void OnPortalActivated(const base::UnguessableToken& portal_token,
blink::mojom::PortalAssociatedPtrInfo portal,
- blink::TransferableMessage data);
+ blink::TransferableMessage data,
+ base::OnceCallback<void(bool)> callback);
// Called on the main frame of a page embedded in a Portal to forward a
// message to the PortalHost object in the frame.
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index 55dcb5cf..d7faeb9 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -131,7 +131,7 @@
}
void Portal::Activate(blink::TransferableMessage data,
- base::OnceCallback<void()> callback) {
+ ActivateCallback callback) {
WebContentsImpl* outer_contents = static_cast<WebContentsImpl*>(
WebContents::FromRenderFrameHost(owner_render_frame_host_));
@@ -163,8 +163,8 @@
portal->SetPortalContents(std::move(predecessor_web_contents));
portal_contents_impl_->GetMainFrame()->OnPortalActivated(
- portal->portal_token_, portal_ptr.PassInterface(), std::move(data));
- std::move(callback).Run();
+ portal->portal_token_, portal_ptr.PassInterface(), std::move(data),
+ std::move(callback));
}
void Portal::PostMessage(blink::TransferableMessage message,
diff --git a/content/browser/portal/portal.h b/content/browser/portal/portal.h
index 5829af8..98b94182 100644
--- a/content/browser/portal/portal.h
+++ b/content/browser/portal/portal.h
@@ -56,7 +56,7 @@
// blink::mojom::Portal implementation.
void Navigate(const GURL& url) override;
void Activate(blink::TransferableMessage data,
- base::OnceCallback<void()> callback) override;
+ ActivateCallback callback) override;
void PostMessage(const blink::TransferableMessage message,
const base::Optional<url::Origin>& target_origin) override;
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc
index 07cdd163a..52f05325 100644
--- a/content/browser/portal/portal_browsertest.cc
+++ b/content/browser/portal/portal_browsertest.cc
@@ -46,7 +46,7 @@
static PortalInterceptorForTesting* From(content::Portal* portal);
void Activate(blink::TransferableMessage data,
- base::OnceCallback<void()> callback) override {
+ ActivateCallback callback) override {
portal_activated_ = true;
if (run_loop_) {
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index b2082e2..7deab3e 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -225,10 +225,12 @@
// activated. The frame has the option to adopt the previous page as a portal
// identified by |portal_token| with the interface |portal|. The activation
// can optionally include a message |data| dispatched with the
- // PortalActivateEvent.
+ // PortalActivateEvent. The return value |was_adopted| indicates if the portal
+ // for the predecessor (identified by |portal_token|) was adopted by the
+ // current frame.
OnPortalActivated(mojo_base.mojom.UnguessableToken portal_token,
associated blink.mojom.Portal portal,
- blink.mojom.TransferableMessage data);
+ blink.mojom.TransferableMessage data) => (bool was_adopted);
};
// Implemented by the frame (e.g. renderer processes).
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 8813916..c4321ec 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2667,8 +2667,10 @@
void RenderFrameImpl::OnPortalActivated(
const base::UnguessableToken& portal_token,
blink::mojom::PortalAssociatedPtrInfo portal,
- blink::TransferableMessage data) {
- frame_->OnPortalActivated(portal_token, portal.PassHandle(), std::move(data));
+ blink::TransferableMessage data,
+ OnPortalActivatedCallback callback) {
+ frame_->OnPortalActivated(portal_token, portal.PassHandle(), std::move(data),
+ std::move(callback));
}
void RenderFrameImpl::ForwardMessageToPortalHost(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 15ef0dce..4613ce47 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -648,7 +648,8 @@
JavaScriptExecuteRequestInIsolatedWorldCallback callback) override;
void OnPortalActivated(const base::UnguessableToken& portal_token,
blink::mojom::PortalAssociatedPtrInfo portal,
- blink::TransferableMessage data) override;
+ blink::TransferableMessage data,
+ OnPortalActivatedCallback callback) override;
// mojom::FullscreenVideoElementHandler implementation:
void RequestFullscreenVideoElement() override;
diff --git a/third_party/blink/public/mojom/portal/portal.mojom b/third_party/blink/public/mojom/portal/portal.mojom
index 6d414c8..4819ef2d 100644
--- a/third_party/blink/public/mojom/portal/portal.mojom
+++ b/third_party/blink/public/mojom/portal/portal.mojom
@@ -15,7 +15,7 @@
Navigate(url.mojom.Url url);
// When a portal is activated, it'll replace the current tab with the portal.
- Activate(TransferableMessage data) => ();
+ Activate(TransferableMessage data) => (bool was_adopted);
// Sends message to the browser process, where it can be forwarded to the
// portal's main frame.
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h
index fbfaf4b..6b17777 100644
--- a/third_party/blink/public/web/web_local_frame.h
+++ b/third_party/blink/public/web/web_local_frame.h
@@ -631,10 +631,12 @@
// portal's unique identifier, and the message pipe |portal_pipe| is the
// portal's mojo interface. |data| is an optional message sent together with
// the portal's activation.
+ using OnPortalActivatedCallback = base::OnceCallback<void(bool)>;
virtual void OnPortalActivated(
const base::UnguessableToken& portal_token,
mojo::ScopedInterfaceEndpointHandle portal_pipe,
- TransferableMessage data) = 0;
+ TransferableMessage data,
+ OnPortalActivatedCallback callback) = 0;
// Forwards message to the PortalHost associated with frame.
virtual void ForwardMessageToPortalHost(
diff --git a/third_party/blink/renderer/core/events/portal_activate_event.cc b/third_party/blink/renderer/core/events/portal_activate_event.cc
index 27bdeed..ad1d0b3 100644
--- a/third_party/blink/renderer/core/events/portal_activate_event.cc
+++ b/third_party/blink/renderer/core/events/portal_activate_event.cc
@@ -23,11 +23,13 @@
const base::UnguessableToken& predecessor_portal_token,
mojom::blink::PortalAssociatedPtr predecessor_portal_ptr,
scoped_refptr<SerializedScriptValue> data,
- MessagePortArray* ports) {
+ MessagePortArray* ports,
+ OnPortalActivatedCallback callback) {
return MakeGarbageCollected<PortalActivateEvent>(
frame->GetDocument(), predecessor_portal_token,
std::move(predecessor_portal_ptr),
- SerializedScriptValue::Unpack(std::move(data)), ports);
+ SerializedScriptValue::Unpack(std::move(data)), ports,
+ std::move(callback));
}
PortalActivateEvent* PortalActivateEvent::Create(
@@ -41,7 +43,8 @@
const base::UnguessableToken& predecessor_portal_token,
mojom::blink::PortalAssociatedPtr predecessor_portal_ptr,
UnpackedSerializedScriptValue* data,
- MessagePortArray* ports)
+ MessagePortArray* ports,
+ OnPortalActivatedCallback callback)
: Event(event_type_names::kPortalactivate,
Bubbles::kNo,
Cancelable::kNo,
@@ -50,7 +53,8 @@
predecessor_portal_token_(predecessor_portal_token),
predecessor_portal_ptr_(std::move(predecessor_portal_ptr)),
data_(data),
- ports_(ports) {}
+ ports_(ports),
+ on_portal_activated_callback_(std::move(callback)) {}
PortalActivateEvent::PortalActivateEvent(const AtomicString& type,
const PortalActivateEventInit* init)
@@ -120,7 +124,15 @@
HTMLPortalElement* portal = MakeGarbageCollected<HTMLPortalElement>(
*document_, predecessor_portal_token_,
std::move(predecessor_portal_ptr_));
+ std::move(on_portal_activated_callback_).Run(true);
return portal;
}
+void PortalActivateEvent::DetachPortalIfNotAdopted() {
+ if (predecessor_portal_ptr_) {
+ std::move(on_portal_activated_callback_).Run(false);
+ predecessor_portal_ptr_.reset();
+ }
+}
+
} // namespace blink
diff --git a/third_party/blink/renderer/core/events/portal_activate_event.h b/third_party/blink/renderer/core/events/portal_activate_event.h
index 117a8c6..5a53b69 100644
--- a/third_party/blink/renderer/core/events/portal_activate_event.h
+++ b/third_party/blink/renderer/core/events/portal_activate_event.h
@@ -26,6 +26,7 @@
class PortalActivateEventInit;
class ScriptState;
class ScriptValue;
+using OnPortalActivatedCallback = base::OnceCallback<void(bool)>;
class CORE_EXPORT PortalActivateEvent : public Event {
DEFINE_WRAPPERTYPEINFO();
@@ -37,7 +38,8 @@
const base::UnguessableToken& predecessor_portal_token,
mojom::blink::PortalAssociatedPtr predecessor_portal_ptr,
scoped_refptr<SerializedScriptValue> data,
- MessagePortArray* ports);
+ MessagePortArray* ports,
+ OnPortalActivatedCallback callback);
// Web-exposed and called directly by authors.
static PortalActivateEvent* Create(const AtomicString& type,
@@ -47,7 +49,8 @@
const base::UnguessableToken& predecessor_portal_token,
mojom::blink::PortalAssociatedPtr predecessor_portal_ptr,
UnpackedSerializedScriptValue* data,
- MessagePortArray*);
+ MessagePortArray*,
+ OnPortalActivatedCallback callback);
PortalActivateEvent(const AtomicString& type, const PortalActivateEventInit*);
~PortalActivateEvent() override;
@@ -61,6 +64,8 @@
ScriptValue data(ScriptState*);
HTMLPortalElement* adoptPredecessor(ExceptionState& exception_state);
+ void DetachPortalIfNotAdopted();
+
private:
Member<Document> document_;
base::UnguessableToken predecessor_portal_token_;
@@ -77,6 +82,7 @@
// |data_from_init_|.
HeapHashMap<WeakMember<ScriptState>, TraceWrapperV8Reference<v8::Value>>
v8_data_;
+ OnPortalActivatedCallback on_portal_activated_callback_;
};
} // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index c572b6f76..5161840 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2571,7 +2571,8 @@
void WebLocalFrameImpl::OnPortalActivated(
const base::UnguessableToken& portal_token,
mojo::ScopedInterfaceEndpointHandle portal_pipe,
- TransferableMessage data) {
+ TransferableMessage data,
+ OnPortalActivatedCallback callback) {
GetFrame()->GetPage()->SetInsidePortal(false);
LocalDOMWindow* window = GetFrame()->DomWindow();
@@ -2587,7 +2588,7 @@
frame_.Get(), portal_token,
mojom::blink::PortalAssociatedPtr(mojom::blink::PortalAssociatedPtrInfo(
std::move(portal_pipe), mojom::blink::Portal::Version_)),
- std::move(blink_data.message), ports);
+ std::move(blink_data.message), ports, std::move(callback));
ThreadDebugger* debugger = MainThreadDebugger::Instance();
if (debugger)
@@ -2595,6 +2596,7 @@
GetFrame()->DomWindow()->DispatchEvent(*event);
if (debugger)
debugger->ExternalAsyncTaskFinished(blink_data.sender_stack_trace_id);
+ event->DetachPortalIfNotAdopted();
}
void WebLocalFrameImpl::ForwardMessageToPortalHost(
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 06f3aee..04874b6 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -306,7 +306,8 @@
const WebMediaPlayerAction&) override;
void OnPortalActivated(const base::UnguessableToken& portal_token,
mojo::ScopedInterfaceEndpointHandle portal_pipe,
- TransferableMessage data) override;
+ TransferableMessage data,
+ OnPortalActivatedCallback callback) override;
void ForwardMessageToPortalHost(
TransferableMessage message,
const WebSecurityOrigin& source_origin,
diff --git a/third_party/blink/renderer/core/html/portal/html_portal_element.cc b/third_party/blink/renderer/core/html/portal/html_portal_element.cc
index 21566f1..ab3210d 100644
--- a/third_party/blink/renderer/core/html/portal/html_portal_element.cc
+++ b/third_party/blink/renderer/core/html/portal/html_portal_element.cc
@@ -214,17 +214,20 @@
// PortalPtr stays alive until the callback is called.
is_activating_ = true;
auto* raw_portal_ptr = portal_ptr_.get();
- raw_portal_ptr->Activate(std::move(data),
- WTF::Bind(
- [](HTMLPortalElement* portal,
- mojom::blink::PortalAssociatedPtr portal_ptr,
- ScriptPromiseResolver* resolver) {
- resolver->Resolve();
- portal->is_activating_ = false;
- portal->ConsumePortal();
- },
- WrapPersistent(this), std::move(portal_ptr_),
- WrapPersistent(resolver)));
+ raw_portal_ptr->Activate(
+ std::move(data),
+ WTF::Bind(
+ [](HTMLPortalElement* portal,
+ mojom::blink::PortalAssociatedPtr portal_ptr,
+ ScriptPromiseResolver* resolver, bool was_adopted) {
+ if (was_adopted)
+ portal->GetDocument().GetPage()->SetInsidePortal(true);
+ resolver->Resolve();
+ portal->is_activating_ = false;
+ portal->ConsumePortal();
+ },
+ WrapPersistent(this), std::move(portal_ptr_),
+ WrapPersistent(resolver)));
return promise;
}
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html b/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html
index 0d8ec33..d352826 100644
--- a/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html
+++ b/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html
@@ -19,8 +19,9 @@
portal.src = new URL('resources/portal-activate-data-portal.html?logic=' + encodeURIComponent(logic), location.href);
w.document.body.appendChild(portal);
assert_equals((await nextMessage(bc)).data, 'ready');
+ let replyPromise = nextMessage(bc);
await portal.activate(activateOptions);
- return (await nextMessage(bc)).data;
+ return (await replyPromise).data;
} finally {
w.close();
bc.close();
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-resolution.html b/third_party/blink/web_tests/external/wpt/portals/portals-activate-resolution.html
new file mode 100644
index 0000000..9fb99e42
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-activate-resolution.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ promise_test(async () => {
+ var win = window.open();
+ var portal = win.document.createElement("portal");
+ portal.src = new URL("resources/simple-portal.html", location.href)
+
+ await new Promise((resolve, reject) => {
+ var bc = new BroadcastChannel("simple-portal");
+ bc.onmessage = () => {
+ bc.close();
+ resolve();
+ }
+ win.document.body.appendChild(portal);
+ });
+
+ return portal.activate();
+ });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html b/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html
index 99c44f0..27e4052 100644
--- a/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html
@@ -10,7 +10,6 @@
assert_equals(e.data, "passed");
bc.close();
});
- var portalUrl = encodeURIComponent(`portal-activate-event-portal.html?test=${test}`);
window.open(`resources/portals-adopt-predecessor.html?test=${test}`);
}, "Tests that a portal can adopt its predecessor.");
@@ -21,7 +20,6 @@
assert_equals(e.data, "passed");
bc.close();
});
- var portalUrl = encodeURIComponent(`portal-activate-event-portal.html?test=${test}`);
window.open(`resources/portals-adopt-predecessor.html?test=${test}`);
}, "Tests that trying to adopt the predecessor twice will throw an exception.");
</script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-create-orphaned.html b/third_party/blink/web_tests/external/wpt/portals/portals-create-orphaned.html
deleted file mode 100644
index 903186f..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-create-orphaned.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<body>
- <script>
- promise_test(async () => {
- let waitForMessage = new Promise((resolve, reject) => {
- var bc = new BroadcastChannel("portals-create-orphaned");
- bc.onmessage = e => {
- bc.close();
- resolve(e.data);
- }
- });
- window.open("resources/portal-create-orphaned.html");
- let message = await waitForMessage;
- assert_equals(message, "portal loaded");
- }, "creating a portal from an orphaned portal should succeed");
- </script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-create-orphaned.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-create-orphaned.html
deleted file mode 100644
index 89b927f..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-create-orphaned.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<body>
- <script>
- var portal = document.createElement("portal");
- portal.src = "simple-portal.html";
- let waitForMessage = new Promise((resolve, reject) => {
- var bc_portal = new BroadcastChannel("simple-portal");
- bc_portal.onmessage = e => {
- bc_portal.close();
- portal.activate();
- var portal2 = document.createElement("portal");
- portal2.src = "simple-portal.html";
- document.body.appendChild(portal2);
- var bc2 = new BroadcastChannel("simple-portal");
- bc2.onmessage = e => {
- bc2.close();
- resolve("portal loaded");
- }
- }
- });
- document.body.appendChild(portal);
- waitForMessage.then(message => {
- var bc = new BroadcastChannel("portals-create-orphaned");
- bc.postMessage(message);
- bc.close();
- });
- </script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor-portal.html b/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor-portal.html
index 96de3b7..14d1018 100644
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor-portal.html
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor-portal.html
@@ -2,7 +2,6 @@
<script>
var searchParams = new URL(location).searchParams;
var test = searchParams.get("test");
- var bc = new BroadcastChannel(`portal-${test}`);
window.onportalactivate = function(e) {
var portal = e.adoptPredecessor();
@@ -10,19 +9,19 @@
if (test == "adopt-once") {
if (portal instanceof HTMLPortalElement) {
- bc.postMessage("passed");
- bc.close();
+ portal.postMessage("adopted", "*");
}
}
if (test == "adopt-twice") {
try {
- portal = e.adoptPredecessor();
+ e.adoptPredecessor();
} catch(e) {
- bc.postMessage("passed");
- bc.close();
+ portal.postMessage("passed", "*");
}
}
}
+ var bc = new BroadcastChannel(`portal-${test}`);
bc.postMessage("loaded");
+ bc.close();
</script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor.html b/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor.html
index b92ad8a..287ba2c3 100644
--- a/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor.html
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portals-adopt-predecessor.html
@@ -5,18 +5,15 @@
var searchParams = new URL(location).searchParams;
var test = searchParams.get("test");
var bc = new BroadcastChannel(`portal-${test}`);
- bc.onmessage = function(e) {
- switch (e.data) {
- case "loaded":
- document.querySelector("portal").activate();
- break;
-
- case "passed":
- bc.close();
+ bc.onmessage = e => {
+ bc.close();
+ document.querySelector("portal").activate().then(() => {
+ window.portalHost.addEventListener("message", () => {
var bc_test = new BroadcastChannel(`test-${test}`);
bc_test.postMessage("passed");
bc_test.close();
- }
+ });
+ });
}
var portal = document.createElement("portal");
diff --git a/third_party/blink/web_tests/wpt_internal/portals/portals-create-orphaned.html b/third_party/blink/web_tests/wpt_internal/portals/portals-create-orphaned.html
new file mode 100644
index 0000000..0a3a66f
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/portals/portals-create-orphaned.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+ <script>
+ function createPortal(doc, src, channel) {
+ var portal = doc.createElement("portal");
+ portal.src = new URL(src, location.href);
+ return new Promise((resolve, reject) => {
+ var bc = new BroadcastChannel(channel);
+ bc.onmessage = () => {
+ bc.close();
+ resolve(portal);
+ }
+ doc.body.appendChild(portal);
+ });
+ }
+
+ promise_test(async () => {
+ var w = window.open();
+ var doc = w.document;
+ var portal = await createPortal(doc,
+ "resources/portals-create-orphaned-portal.html",
+ "create-orphaned-portal");
+ portal.activate();
+ return createPortal(doc, "resources/simple-portal.html", "simple-portal");
+ }, "creating a portal from an orphaned portal should succeed");
+ </script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/portals/resources/portals-create-orphaned-portal.html b/third_party/blink/web_tests/wpt_internal/portals/resources/portals-create-orphaned-portal.html
new file mode 100644
index 0000000..ff18d5e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/portals/resources/portals-create-orphaned-portal.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+ window.onportalactivate = e => {
+ // Busy-loop to keep the predecessor in the "orphaned" state. This only
+ // works if we create portals in a separate process.
+ while (true) {}
+ }
+ var bc = new BroadcastChannel("create-orphaned-portal");
+ bc.postMessage("loaded");
+ bc.close();
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/portals/resources/simple-portal.html b/third_party/blink/web_tests/wpt_internal/portals/resources/simple-portal.html
new file mode 100644
index 0000000..957a8f2
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/portals/resources/simple-portal.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+ var bc = new BroadcastChannel("simple-portal");
+ bc.postMessage("loaded");
+ bc.close();
+</script>