Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3745,14 +3745,7 @@ struct v8_dom_runtime::implementation final {
local_context->Global()->Set(local_context, js_string(isolate, "structuredClone"),
v8::Function::New(local_context, structured_clone, {}, 1).ToLocalChecked()).Check();
install_performance_timeline(local_context);
auto worker_constructor=v8::Function::New(local_context, worker_construct, {}, 1).ToLocalChecked();
v8::Local<v8::Value> event_target,worker_prototype,event_prototype;
if(local_context->Global()->Get(local_context,js_string(isolate,"EventTarget")).ToLocal(&event_target)
&&event_target->IsFunction()
&&worker_constructor->Get(local_context,js_string(isolate,"prototype")).ToLocal(&worker_prototype)
&&event_target.As<v8::Object>()->Get(local_context,js_string(isolate,"prototype")).ToLocal(&event_prototype))
worker_prototype.As<v8::Object>()->SetPrototype(local_context,event_prototype).FromMaybe(false);
local_context->Global()->Set(local_context, js_string(isolate, "Worker"),worker_constructor).Check();
install_worker_constructor(local_context);
install_clipboard_api(local_context);
install_websocket_globals(local_context);
install_editor_web_platform_globals(local_context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1900,6 +1900,7 @@
install_websocket_globals(local_context);
install_editor_web_platform_globals(local_context);
install_message_channel(local_context);
install_worker_constructor(local_context);
install_tree_walker_platform(local_context);
install_custom_elements_platform(local_context);
install_fetch_globals(local_context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,35 @@
static constexpr size_t maximum_worker_errors = 16U;
static constexpr size_t maximum_worker_error_length = 4096U;

void install_worker_constructor(v8::Local<v8::Context> local_context) {
auto worker_constructor = v8::Function::New(
local_context,
worker_construct,
{},
1).ToLocalChecked();
v8::Local<v8::Value> event_target;
v8::Local<v8::Value> worker_prototype;
v8::Local<v8::Value> event_prototype;
if (local_context->Global()->Get(
local_context,
js_string(isolate, "EventTarget")).ToLocal(&event_target)
&& event_target->IsFunction()
&& worker_constructor->Get(
local_context,
js_string(isolate, "prototype")).ToLocal(&worker_prototype)
&& event_target.As<v8::Object>()->Get(
local_context,
js_string(isolate, "prototype")).ToLocal(&event_prototype)) {
worker_prototype.As<v8::Object>()->SetPrototype(
local_context,
event_prototype).FromMaybe(false);
}
local_context->Global()->Set(
local_context,
js_string(isolate, "Worker"),
worker_constructor).Check();
}

static v8::MaybeLocal<v8::Value> worker_transfer(
const v8::FunctionCallbackInfo<v8::Value>& info) {
if (info.Length() < 2) return v8::Undefined(info.GetIsolate());
Expand Down Expand Up @@ -337,6 +366,8 @@
auto realm=child->context.Get(child->isolate);v8::Context::Scope scope(realm);
if(packet&&!child->dispatch_worker_message(realm,realm->Global(),&*packet))report(child->last_error);
child->drain_tasks();
child->perform_microtask_checkpoint();
if (!child->promote_pending_promise_error()) report(child->last_error);
}
{std::lock_guard lock(raw->mutex);raw->running_isolate=nullptr;}
child->isolate->CancelTerminateExecution();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ void test_iframe_worker_extension_host_port_bootstrap() {
const child = frame.contentDocument;
child.open();
child.write(`<!doctype html><script>
if (typeof Worker !== 'function') {
throw Error('Worker is not installed in the iframe realm');
}
onmessage = event => {
if (event.origin !== origin || !(event.data.port instanceof MessagePort)
|| !(event.data.port instanceof EventTarget)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1126,14 +1126,14 @@ void test_v8_inspector_raw_cdp_session(webscene_engine* engine)
session_id,
std::string{"{\"id\":650,\"method\":\"Runtime.evaluate\",\"params\":{\"contextId\":"}
+ std::to_string(frame_context_id)
+ R"(,"expression":"parent.__websceneDetachedFrameCallbacks = 0; const record = () => ++parent.__websceneDetachedFrameCallbacks; setTimeout(record, 100); setInterval(record, 100); requestAnimationFrame(record); const originalTimeout = globalThis.setTimeout; globalThis.setTimeout = callback => originalTimeout(callback, 100); const channel = new MessageChannel(); channel.port1.onmessage = record; channel.port2.postMessage('queued'); globalThis.setTimeout = originalTimeout;","returnByValue":true}})" );
+ R"(,"expression":"parent.__websceneDetachedFrameCallbacks = 0; parent.__websceneInspectorFrameDetached = false; const record = () => { if (parent.__websceneInspectorFrameDetached) ++parent.__websceneDetachedFrameCallbacks; }; setTimeout(record, 100); setInterval(record, 100); requestAnimationFrame(record); const originalTimeout = globalThis.setTimeout; globalThis.setTimeout = callback => originalTimeout(callback, 100); const channel = new MessageChannel(); channel.port1.onmessage = record; channel.port2.postMessage('queued'); globalThis.setTimeout = originalTimeout;","returnByValue":true}})" );
require(
wait_for_inspector_message(messages, R"("id":650)"),
"Inspector could not schedule detached-frame task fixtures");
dispatch_inspector_test_message(
engine,
session_id,
R"({"id":66,"method":"Runtime.evaluate","params":{"expression":"document.body.removeChild(globalThis.__inspectorLifecycleFrame); delete globalThis.__inspectorLifecycleFrame;","returnByValue":true}})");
R"({"id":66,"method":"Runtime.evaluate","params":{"expression":"globalThis.__websceneInspectorFrameDetached = true; document.body.removeChild(globalThis.__inspectorLifecycleFrame); delete globalThis.__inspectorLifecycleFrame;","returnByValue":true}})");
require(
wait_for_inspector_message(messages, R"("id":66)"),
"Inspector iframe removal did not complete");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ int main()
test_idle_v8_foreground_completion();
return 0;
}
#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8_INSPECTOR)
if (selected == "iframe-worker-inspector-detach") {
auto* focused_engine = webscene_engine_create(0);
require(focused_engine != nullptr,
"iframe Worker Inspector engine creation failed");
test_v8_inspector_raw_cdp_session(focused_engine);
webscene_engine_destroy(focused_engine);
return 0;
}
#endif
if(selected=="modal-backdrop") {
auto* focused_engine=webscene_engine_create(0);
require(focused_engine!=nullptr,"backdrop engine creation failed");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!doctype html>
<title>Iframe extension host creates a module Worker</title>
<script>
window.__webSceneWptState = {complete:false,harness:null,results:[],errors:[],diagnostics:[]};
window.record = (name, condition) => __webSceneWptState.results.push({
name,status:condition?'PASS':'FAIL',message:condition?null:'Contract failed',stack:null
});
window.finish = () => {
const s=__webSceneWptState;
s.harness={status:s.results.some(r=>r.status!=='PASS')?1:0,message:null,stack:null};
s.complete=true;
};

addEventListener('message', event => {
if (event.data && event.data.type === 'worker-error') {
__webSceneWptState.errors.push(event.data.message);
record('Iframe-created module Worker completed without errors', false);
finish();
return;
}
if (event.data && event.data.type === 'worker-started') {
record('Iframe-created module Worker starts in its isolated realm', true);
return;
}
if (event.data !== 'vscode.bootstrap.nls') return;
const frame = document.querySelector('iframe');
record('Extension-host iframe preserves source Window identity',
event.source === frame.contentWindow);
record('Extension-host iframe uses the parent origin', event.origin === origin);
const channel = new MessageChannel();
channel.port1.onmessage = response => {
record('Iframe-created module Worker bridges its transferred port', response.data === 42);
channel.port1.close();
finish();
};
event.source.postMessage(
{type:'vscode.init', port:channel.port2}, origin, [channel.port2]);
channel.port1.postMessage(41);
});

try {
const frame = document.createElement('iframe');
document.body.appendChild(frame);
const child = frame.contentDocument;
child.open();
child.write(`<script>
const workerModuleUrl = new URL(
'./resources/aureon/iframe-worker-extension-host-module.js', location.href).href;
const source = \`await import(\${JSON.stringify(workerModuleUrl)});\`;
const blob = new Blob([source], {type:'application/javascript'});
const worker = new Worker(URL.createObjectURL(blob), {
name:'LocalWebWorker', type:'module'
});
if (!(worker instanceof Worker) || !(worker instanceof EventTarget))
throw Error('iframe Worker interface identity changed');
worker.onerror = event => parent.postMessage({
type:'worker-error', message:event.message
}, '*');
worker.onmessage = event => {
if (event.data === 'worker-started') {
parent.postMessage({type:'worker-started'}, '*');
}
};
onmessage = event => worker.postMessage(event.data, event.ports);
parent.postMessage('vscode.bootstrap.nls', '*');
<\/script>`);
child.close();
} catch (error) {
__webSceneWptState.errors.push(String(error));
record('Iframe extension-host Worker bootstrap completed', false);
finish();
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
postMessage('worker-started');
self.onmessage = event => {
const port = event.data.port;
if (!(port instanceof MessagePort)) throw Error('worker port transfer failed');
port.onmessage = message => port.postMessage(message.data + 1);
port.start();
};
11 changes: 11 additions & 0 deletions tests/WebPlatformSubset/webscene-aureon-runtime-profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@
"reason": "Focused Code OSS iframe bootstrap candidate matching the extension-host MessagePort handoff.",
"nativeNavigation": true
},
{
"path": "contracts/iframe-worker-extension-host.html",
"type": "contract",
"capabilities": [
"iframe-worker-constructor",
"module-workers",
"messageport-transfer"
],
"reason": "Code OSS-shaped regression proving its hydrated extension-host iframe can construct a module Worker and bridge the transferred bootstrap port.",
"nativeNavigation": true
},
{
"path": "contracts/worker-termination-queue-messageerror.html",
"type": "contract",
Expand Down
Loading