WebHID: Add support for dedicated workers
This CL exposes the WebHID API to dedicated workers behind the blink
runtime feature WebHIDOnDedicatedWorkers.
Intent to prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/y__BOYfZWzI
Spec PR: https://github.com/WICG/webhid/pull/121
Spec issue: https://github.com/WICG/webhid/issues/120
Demo: https://webhid-worker.glitch.me/
Change-Id: If145f34faf9211a54c8b4a15fbe7e903411b8d1d
Bug: 365932453
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5841991
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Yoav Weiss (@Shopify) <yoavweiss@chromium.org>
Reviewed-by: Matt Reynolds <mattreynolds@chromium.org>
Commit-Queue: Fr <beaufort.francois@gmail.com>
Cr-Commit-Position: refs/heads/main@{#1357046}
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 1c4444d..a480e76 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -1343,6 +1343,8 @@
#if !BUILDFLAG(IS_ANDROID)
map->Add<blink::mojom::SerialService>(base::BindRepeating(
&DedicatedWorkerHost::BindSerialService, base::Unretained(host)));
+ map->Add<blink::mojom::HidService>(base::BindRepeating(
+ &DedicatedWorkerHost::BindHidService, base::Unretained(host)));
#endif // !BUILDFLAG(IS_ANDROID)
map->Add<blink::mojom::BucketManagerHost>(base::BindRepeating(
&DedicatedWorkerHost::CreateBucketManagerHost, base::Unretained(host)));
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index ca9cb1c..0a32fad 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -793,6 +793,20 @@
ancestor_render_frame_host->BindSerialService(std::move(receiver));
}
+
+void DedicatedWorkerHost::BindHidService(
+ mojo::PendingReceiver<blink::mojom::HidService> receiver) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHostImpl* ancestor_render_frame_host =
+ RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
+ // The ancestor frame may have already been closed. In that case, the worker
+ // will soon be terminated too, so abort the connection.
+ if (!ancestor_render_frame_host) {
+ return;
+ }
+
+ ancestor_render_frame_host->GetHidService(std::move(receiver));
+}
#endif
void DedicatedWorkerHost::CreateBucketManagerHost(
diff --git a/content/browser/worker_host/dedicated_worker_host.h b/content/browser/worker_host/dedicated_worker_host.h
index 35dccb2..546dd0c1 100644
--- a/content/browser/worker_host/dedicated_worker_host.h
+++ b/content/browser/worker_host/dedicated_worker_host.h
@@ -51,6 +51,7 @@
#if !BUILDFLAG(IS_ANDROID)
#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom-forward.h"
+#include "third_party/blink/public/mojom/hid/hid.mojom-forward.h"
#include "third_party/blink/public/mojom/serial/serial.mojom-forward.h"
#endif
@@ -174,6 +175,7 @@
#if !BUILDFLAG(IS_ANDROID)
void BindSerialService(
mojo::PendingReceiver<blink::mojom::SerialService> receiver);
+ void BindHidService(mojo::PendingReceiver<blink::mojom::HidService> receiver);
#endif
// PlzDedicatedWorker:
diff --git a/third_party/blink/renderer/modules/hid/hid.cc b/third_party/blink/renderer/modules/hid/hid.cc
index 702c3a9..fe7eb4e 100644
--- a/third_party/blink/renderer/modules/hid/hid.cc
+++ b/third_party/blink/renderer/modules/hid/hid.cc
@@ -19,6 +19,7 @@
#include "third_party/blink/renderer/core/execution_context/navigator_base.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/hid/hid_connection_event.h"
#include "third_party/blink/renderer/modules/hid/hid_device.h"
@@ -33,6 +34,25 @@
const char kFeaturePolicyBlocked[] =
"Access to the feature \"hid\" is disallowed by permissions policy.";
+bool IsContextSupported(ExecutionContext* context) {
+ // Since WebHID on Web Workers is in the process of being implemented, we
+ // check here if the runtime flag for the appropriate worker is enabled.
+ // TODO(https://crbug.com/365932453): Remove this check once the feature has
+ // shipped.
+ if (!context) {
+ return false;
+ }
+
+ DCHECK(context->IsWindow() || context->IsDedicatedWorkerGlobalScope() ||
+ context->IsServiceWorkerGlobalScope());
+ DCHECK(!context->IsDedicatedWorkerGlobalScope() ||
+ RuntimeEnabledFeatures::WebHIDOnDedicatedWorkersEnabled());
+ DCHECK(!context->IsServiceWorkerGlobalScope() ||
+ RuntimeEnabledFeatures::WebHIDOnServiceWorkersEnabled());
+
+ return true;
+}
+
// Carries out basic checks for the web-exposed APIs, to make sure the minimum
// requirements for them to be served are met. Returns true if any conditions
// fail to be met, generating an appropriate exception as well. Otherwise,
@@ -40,7 +60,7 @@
bool ShouldBlockHidServiceCall(LocalDOMWindow* window,
ExecutionContext* context,
ExceptionState* exception_state) {
- if (!context) {
+ if (!IsContextSupported(context)) {
if (exception_state) {
exception_state->ThrowDOMException(DOMExceptionCode::kNotSupportedError,
kContextGone);
@@ -48,14 +68,21 @@
return true;
}
- // The security origin must match the one checked by the browser process.
- // Service Workers do not use delegated permissions so we use their security
- // origin directly.
- DCHECK(context->IsWindow() || context->IsServiceWorkerGlobalScope());
- auto* security_origin =
- window
- ? window->GetFrame()->Top()->GetSecurityContext()->GetSecurityOrigin()
- : context->GetSecurityOrigin();
+ // For window and dedicated workers, reject the request if the top-level frame
+ // has an opaque origin. For Service Workers, we use their security origin
+ // directly as they do not use delegated permissions.
+ const SecurityOrigin* security_origin = nullptr;
+ if (context->IsWindow()) {
+ security_origin =
+ window->GetFrame()->Top()->GetSecurityContext()->GetSecurityOrigin();
+ } else if (context->IsDedicatedWorkerGlobalScope()) {
+ security_origin = static_cast<WorkerGlobalScope*>(context)
+ ->top_level_frame_security_origin();
+ } else if (context->IsServiceWorkerGlobalScope()) {
+ security_origin = context->GetSecurityOrigin();
+ } else {
+ NOTREACHED();
+ }
if (security_origin->IsOpaque()) {
if (exception_state) {
exception_state->ThrowSecurityError(
@@ -333,6 +360,8 @@
if (service_.is_bound())
return;
+ DCHECK(IsContextSupported(GetExecutionContext()));
+
auto task_runner =
GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
diff --git a/third_party/blink/renderer/modules/hid/hid.idl b/third_party/blink/renderer/modules/hid/hid.idl
index 48069a5d..94f1167 100644
--- a/third_party/blink/renderer/modules/hid/hid.idl
+++ b/third_party/blink/renderer/modules/hid/hid.idl
@@ -8,6 +8,7 @@
[
Exposed(ServiceWorker WebHIDOnServiceWorkers,
+ DedicatedWorker WebHIDOnDedicatedWorkers,
Window WebHID),
SecureContext
] interface HID : EventTarget {
diff --git a/third_party/blink/renderer/modules/hid/hid_connection_event.idl b/third_party/blink/renderer/modules/hid/hid_connection_event.idl
index 2594e0bb..a55b517 100644
--- a/third_party/blink/renderer/modules/hid/hid_connection_event.idl
+++ b/third_party/blink/renderer/modules/hid/hid_connection_event.idl
@@ -7,6 +7,7 @@
[
Exposed(ServiceWorker WebHIDOnServiceWorkers,
+ DedicatedWorker WebHIDOnDedicatedWorkers,
Window WebHID),
SecureContext
] interface HIDConnectionEvent : Event {
diff --git a/third_party/blink/renderer/modules/hid/hid_device.idl b/third_party/blink/renderer/modules/hid/hid_device.idl
index 9047961..fb2b15a 100644
--- a/third_party/blink/renderer/modules/hid/hid_device.idl
+++ b/third_party/blink/renderer/modules/hid/hid_device.idl
@@ -10,6 +10,7 @@
[
ActiveScriptWrappable,
Exposed(ServiceWorker WebHIDOnServiceWorkers,
+ DedicatedWorker WebHIDOnDedicatedWorkers,
Window WebHID),
SecureContext
] interface HIDDevice : EventTarget {
diff --git a/third_party/blink/renderer/modules/hid/hid_input_report_event.idl b/third_party/blink/renderer/modules/hid/hid_input_report_event.idl
index 3b01b30..bd948e2c 100644
--- a/third_party/blink/renderer/modules/hid/hid_input_report_event.idl
+++ b/third_party/blink/renderer/modules/hid/hid_input_report_event.idl
@@ -7,6 +7,7 @@
[
Exposed(ServiceWorker WebHIDOnServiceWorkers,
+ DedicatedWorker WebHIDOnDedicatedWorkers,
Window WebHID),
SecureContext
] interface HIDInputReportEvent : Event {
diff --git a/third_party/blink/renderer/modules/hid/worker_navigator_hid.idl b/third_party/blink/renderer/modules/hid/worker_navigator_hid.idl
index e803a63..21e60ea 100644
--- a/third_party/blink/renderer/modules/hid/worker_navigator_hid.idl
+++ b/third_party/blink/renderer/modules/hid/worker_navigator_hid.idl
@@ -5,7 +5,8 @@
// https://wicg.github.io/webhid/index.html#enumeration
[
- Exposed(ServiceWorker WebHIDOnServiceWorkers),
+ Exposed(ServiceWorker WebHIDOnServiceWorkers,
+ DedicatedWorker WebHIDOnDedicatedWorkers),
ImplementedAs=HID,
RuntimeEnabled=WebHID,
SecureContext
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 9a60fa3..fa5ea1b 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4689,6 +4689,11 @@
status: {"Android": "", "default": "stable"},
},
{
+ name: "WebHIDOnDedicatedWorkers",
+ status: "experimental",
+ depends_on: ["WebHID"],
+ },
+ {
// It is only enabled in extension environment for now.
name: "WebHIDOnServiceWorkers",
depends_on: ["WebHID"],
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webhid.idl b/third_party/blink/web_tests/external/wpt/interfaces/webhid.idl
index 03e72511..56e3161 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/webhid.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webhid.idl
@@ -7,12 +7,12 @@
[SameObject] readonly attribute HID hid;
};
-[Exposed=ServiceWorker, SecureContext]
+[Exposed=(DedicatedWorker,ServiceWorker), SecureContext]
partial interface WorkerNavigator {
[SameObject] readonly attribute HID hid;
};
-[Exposed=(Window,ServiceWorker), SecureContext]
+[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HID : EventTarget {
attribute EventHandler onconnect;
attribute EventHandler ondisconnect;
@@ -33,7 +33,7 @@
unsigned short usage;
};
-[Exposed=Window, SecureContext]
+[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HIDDevice : EventTarget {
attribute EventHandler oninputreport;
readonly attribute boolean opened;
@@ -51,7 +51,7 @@
Promise<DataView> receiveFeatureReport([EnforceRange] octet reportId);
};
-[Exposed=Window, SecureContext]
+[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HIDConnectionEvent : Event {
constructor(DOMString type, HIDConnectionEventInit eventInitDict);
[SameObject] readonly attribute HIDDevice device;
@@ -61,7 +61,7 @@
required HIDDevice device;
};
-[Exposed=Window, SecureContext]
+[Exposed=(DedicatedWorker,ServiceWorker,Window), SecureContext]
interface HIDInputReportEvent : Event {
constructor(DOMString type, HIDInputReportEventInit eventInitDict);
[SameObject] readonly attribute HIDDevice device;
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid-worker.html b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid-worker.html
new file mode 100644
index 0000000..9a0c1f94f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid-worker.html
@@ -0,0 +1,10 @@
+<script>
+'use strict';
+
+let worker = new Worker('permissions-policy-hid-worker.js');
+
+worker.onmessage = event => {
+ window.parent.postMessage(event.data, '*');
+};
+worker.postMessage({ type: 'ready' });
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid-worker.js b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid-worker.js
new file mode 100644
index 0000000..d7490b2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid-worker.js
@@ -0,0 +1,14 @@
+'use strict';
+
+// Dedicated worker
+if (typeof postMessage === 'function') {
+ onmessage = event => {
+ switch(event.data.type) {
+ case 'ready':
+ navigator.hid.getDevices().then(
+ () => postMessage({ type: 'availability-result', enabled: true }),
+ error => postMessage ({ type: 'availability-result', enabled: false }));
+ break;
+ }
+ };
+}
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid.html b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid.html
new file mode 100644
index 0000000..0b54d57
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-hid.html
@@ -0,0 +1,9 @@
+<script>
+'use strict';
+
+Promise.resolve().then(() => navigator.hid.getDevices()).then(devices => {
+ window.parent.postMessage({ type: 'availability-result', enabled: true }, '*');
+}, error => {
+ window.parent.postMessage({ type: 'availability-result', enabled: false }, '*');
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html
new file mode 100644
index 0000000..0a286ac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+const relative_path = '/permissions-policy/resources/permissions-policy-hid.html';
+const base_src = '/permissions-policy/resources/redirect-on-load.html#';
+const relative_worker_frame_path =
+ '/permissions-policy/resources/permissions-policy-hid-worker.html';
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const same_origin_src = base_src + relative_path;
+const cross_origin_src = base_src + sub + relative_path;
+const same_origin_worker_frame_src = base_src + relative_worker_frame_path;
+const cross_origin_worker_frame_src = base_src + sub +
+ relative_worker_frame_path;
+const header = 'Permissions-Policy allow="hid"';
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, same_origin_src,
+ expect_feature_available_default, 'hid');
+}, header + ' allows same-origin relocation.');
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, same_origin_worker_frame_src,
+ expect_feature_available_default, 'hid');
+}, header + ' allows workers in same-origin relocation.');
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, cross_origin_src,
+ expect_feature_unavailable_default, 'hid');
+}, header + ' disallows cross-origin relocation.');
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, cross_origin_worker_frame_src,
+ expect_feature_unavailable_default, 'hid');
+}, header + ' disallows workers in cross-origin relocation.');
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy-attribute.https.sub.html b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy-attribute.https.sub.html
new file mode 100644
index 0000000..f0963c4e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy-attribute.https.sub.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const same_origin_src = '/permissions-policy/resources/permissions-policy-hid.html';
+const cross_origin_src = sub + same_origin_src;
+const same_origin_worker_frame_src =
+ '/permissions-policy/resources/permissions-policy-hid-worker.html';
+const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
+const feature_name = 'Permissions policy "hid"';
+const header = 'allow="hid" attribute';
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, same_origin_src,
+ expect_feature_available_default, 'hid');
+}, feature_name + ' can be enabled in same-origin iframe using ' + header);
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, same_origin_worker_frame_src,
+ expect_feature_available_default, 'hid');
+}, feature_name + ' can be enabled in a worker in same-origin iframe using ' +
+ header);
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, cross_origin_src,
+ expect_feature_available_default, 'hid');
+}, feature_name + ' can be enabled in cross-origin iframe using ' + header);
+
+async_test(t => {
+ test_feature_availability(
+ 'hid.getDevices()', t, cross_origin_worker_frame_src,
+ expect_feature_available_default, 'hid');
+}, feature_name + ' can be enabled in a worker in cross-origin iframe using ' +
+ header);
+
+fetch_tests_from_worker(new Worker(
+ '/webhid/resources/hid-allowed-by-permissions-policy-worker.js'));
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy.https.sub.html
new file mode 100644
index 0000000..645989c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy.https.sub.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<body>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/permissions-policy/resources/permissions-policy.js></script>
+<script>
+'use strict';
+const sub = 'https://{{domains[www]}}:{{ports[https][0]}}';
+const same_origin_src = '/permissions-policy/resources/permissions-policy-hid.html';
+const cross_origin_src = sub + same_origin_src;
+const same_origin_worker_frame_src =
+ '/permissions-policy/resources/permissions-policy-hid-worker.html';
+const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
+const header = 'Permissions-Policy header hid=*';
+
+promise_test(
+ () => navigator.hid.getDevices(),
+ header + ' allows the top-level document.');
+
+async_test(t => {
+ test_feature_availability('hid.getDevices()', t, same_origin_src,
+ expect_feature_available_default);
+}, header + ' allows same-origin iframes.');
+
+async_test(t => {
+ test_feature_availability('hid.getDevices()', t, same_origin_worker_frame_src,
+ expect_feature_available_default);
+}, header + ' allows workers in same-origin iframes.');
+
+// Set allow="hid" on iframe element to delegate 'hid' to cross origin subframe.
+async_test(t => {
+ test_feature_availability('hid.getDevices()', t, cross_origin_src,
+ expect_feature_available_default, 'hid');
+}, header + ' allows cross-origin iframes.');
+
+// Set allow="hid" on iframe element to delegate 'hid' to cross origin subframe.
+async_test(t => {
+ test_feature_availability('hid.getDevices()', t,
+ cross_origin_worker_frame_src,
+ expect_feature_available_default, 'hid');
+}, header + ' allows workers in cross-origin iframes.');
+
+fetch_tests_from_worker(new Worker(
+ '/webhid/resources/hid-allowed-by-permissions-policy-worker.js'));
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy.https.sub.html.headers b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000..e365007
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/hid-allowed-by-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: hid=*
diff --git a/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window-expected.txt
rename to third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any.js
similarity index 63%
rename from third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window.js
rename to third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any.js
index bdc8419b..c0ed066 100644
--- a/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any.js
@@ -9,9 +9,14 @@
['webhid'],
['html', 'dom'],
idl_array => {
+ if (self.GLOBAL.isWindow()) {
+ idl_array.add_objects({ Navigator: ['navigator'] });
+ } else if (self.GLOBAL.isWorker()) {
+ idl_array.add_objects({ WorkerNavigator: ['navigator'] });
+ }
+
idl_array.add_objects({
HID: ['navigator.hid'],
- Navigator: ['navigator'],
// TODO: HIDConnectionEvent
// TODO: HIDInputReportEvent
// TODO: HIDDevice
diff --git a/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any.worker-expected.txt
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/webhid/idlharness.https.window-expected.txt
copy to third_party/blink/web_tests/external/wpt/webhid/idlharness.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/webhid/resources/hid-allowed-by-permissions-policy-worker.js b/third_party/blink/web_tests/external/wpt/webhid/resources/hid-allowed-by-permissions-policy-worker.js
new file mode 100644
index 0000000..20cdb5d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/resources/hid-allowed-by-permissions-policy-worker.js
@@ -0,0 +1,14 @@
+'use strict';
+
+importScripts('/resources/testharness.js');
+
+let workerType;
+
+if (typeof postMessage === 'function') {
+ workerType = 'dedicated';
+}
+
+promise_test(() => navigator.hid.getDevices(),
+ `Inherited header permissions policy allows ${workerType} workers.`);
+
+done();
diff --git a/third_party/blink/web_tests/external/wpt/webhid/resources/hid-disabled-by-permissions-policy-worker.js b/third_party/blink/web_tests/external/wpt/webhid/resources/hid-disabled-by-permissions-policy-worker.js
new file mode 100644
index 0000000..108a09d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/resources/hid-disabled-by-permissions-policy-worker.js
@@ -0,0 +1,17 @@
+'use strict';
+
+importScripts('/resources/testharness.js');
+
+const header = 'Permissions-Policy header hid=()';
+let workerType;
+
+if (typeof postMessage === 'function') {
+ workerType = 'dedicated';
+}
+
+promise_test(() => navigator.hid.getDevices().then(
+ () => assert_unreached('expected promise to reject with SecurityError'),
+ error => assert_equals(error.name, 'SecurityError')),
+ `Inherited ${header} disallows ${workerType} workers.`);
+
+done();
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 209c674..44bb337 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1030,6 +1030,40 @@
[Worker] interface GPUValidationError : GPUError
[Worker] attribute @@toStringTag
[Worker] method constructor
+[Worker] interface HID : EventTarget
+[Worker] attribute @@toStringTag
+[Worker] getter onconnect
+[Worker] getter ondisconnect
+[Worker] method constructor
+[Worker] method getDevices
+[Worker] setter onconnect
+[Worker] setter ondisconnect
+[Worker] interface HIDConnectionEvent : Event
+[Worker] attribute @@toStringTag
+[Worker] getter device
+[Worker] method constructor
+[Worker] interface HIDDevice : EventTarget
+[Worker] attribute @@toStringTag
+[Worker] getter collections
+[Worker] getter oninputreport
+[Worker] getter opened
+[Worker] getter productId
+[Worker] getter productName
+[Worker] getter vendorId
+[Worker] method close
+[Worker] method constructor
+[Worker] method forget
+[Worker] method open
+[Worker] method receiveFeatureReport
+[Worker] method sendFeatureReport
+[Worker] method sendReport
+[Worker] setter oninputreport
+[Worker] interface HIDInputReportEvent : Event
+[Worker] attribute @@toStringTag
+[Worker] getter data
+[Worker] getter device
+[Worker] getter reportId
+[Worker] method constructor
[Worker] interface Headers
[Worker] attribute @@toStringTag
[Worker] method @@iterator
@@ -3918,6 +3952,7 @@
[Worker] getter deviceMemory
[Worker] getter gpu
[Worker] getter hardwareConcurrency
+[Worker] getter hid
[Worker] getter language
[Worker] getter languages
[Worker] getter locks
diff --git a/third_party/blink/web_tests/wpt_internal/hid/hid_connectionEvents.https.window.js b/third_party/blink/web_tests/wpt_internal/hid/hid_connectionEvents.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/hid/hid_connectionEvents.https.window.js
rename to third_party/blink/web_tests/wpt_internal/hid/hid_connectionEvents.https.any.js
diff --git a/third_party/blink/web_tests/wpt_internal/hid/hid_getDevices.https.window.js b/third_party/blink/web_tests/wpt_internal/hid/hid_getDevices.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/hid/hid_getDevices.https.window.js
rename to third_party/blink/web_tests/wpt_internal/hid/hid_getDevices.https.any.js