aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/trace.rs12
-rw-r--r--components/script/dom/blob.rs58
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs2
-rw-r--r--components/script/dom/create.rs2
-rw-r--r--components/script/dom/domexception.rs3
-rw-r--r--components/script/dom/domtokenlist.rs46
-rw-r--r--components/script/dom/element.rs14
-rw-r--r--components/script/dom/event.rs6
-rw-r--r--components/script/dom/eventsource.rs17
-rw-r--r--components/script/dom/eventtarget.rs57
-rw-r--r--components/script/dom/globalscope.rs159
-rw-r--r--components/script/dom/gpubindgroup.rs58
-rw-r--r--components/script/dom/gpubuffer.rs14
-rw-r--r--components/script/dom/gpucommandbuffer.rs58
-rw-r--r--components/script/dom/gpucommandencoder.rs114
-rw-r--r--components/script/dom/gpucomputepassencoder.rs59
-rw-r--r--components/script/dom/gpucomputepipeline.rs55
-rw-r--r--components/script/dom/gpudevice.rs150
-rw-r--r--components/script/dom/gpupipelinelayout.rs6
-rw-r--r--components/script/dom/gpushadermodule.rs60
-rwxr-xr-xcomponents/script/dom/htmlbuttonelement.rs2
-rw-r--r--components/script/dom/htmlformcontrolscollection.rs21
-rw-r--r--components/script/dom/htmlformelement.rs26
-rw-r--r--components/script/dom/htmlimageelement.rs24
-rwxr-xr-xcomponents/script/dom/htmlinputelement.rs2
-rw-r--r--components/script/dom/identityhub.rs107
-rw-r--r--components/script/dom/mod.rs7
-rw-r--r--components/script/dom/node.rs5
-rw-r--r--components/script/dom/offscreencanvas.rs4
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs2
-rw-r--r--components/script/dom/paintrenderingcontext2d.rs2
-rw-r--r--components/script/dom/performance.rs15
-rw-r--r--components/script/dom/performanceentry.rs11
-rw-r--r--components/script/dom/performanceresourcetiming.rs24
-rw-r--r--components/script/dom/servoparser/prefetch.rs4
-rw-r--r--components/script/dom/submitevent.rs79
-rw-r--r--components/script/dom/vrframedata.rs7
-rw-r--r--components/script/dom/webidls/Blob.webidl3
-rw-r--r--components/script/dom/webidls/CanvasRenderingContext2D.webidl2
-rw-r--r--components/script/dom/webidls/GPUBindGroup.webidl31
-rw-r--r--components/script/dom/webidls/GPUCommandBuffer.webidl9
-rw-r--r--components/script/dom/webidls/GPUCommandEncoder.webidl45
-rw-r--r--components/script/dom/webidls/GPUComputePassEncoder.webidl15
-rw-r--r--components/script/dom/webidls/GPUComputePipeline.webidl22
-rw-r--r--components/script/dom/webidls/GPUDevice.webidl17
-rw-r--r--components/script/dom/webidls/GPUProgrammablePassEncoder.webidl19
-rw-r--r--components/script/dom/webidls/GPUShaderModule.webidl15
-rw-r--r--components/script/dom/webidls/SubmitEvent.webidl15
-rw-r--r--components/script/dom/webidls/Window.webidl4
-rw-r--r--components/script/dom/window.rs29
-rw-r--r--components/script/dom/xmlhttprequest.rs28
-rw-r--r--components/script/dom/xrsession.rs6
52 files changed, 1378 insertions, 174 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index ffd4a4952d0..a1cc4843021 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -152,7 +152,9 @@ use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec, Tm};
use uuid::Uuid;
use webgpu::{
- WebGPU, WebGPUAdapter, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice, WebGPUPipelineLayout,
+ WebGPU, WebGPUAdapter, WebGPUBindGroup, WebGPUBindGroupLayout, WebGPUBuffer,
+ WebGPUCommandBuffer, WebGPUCommandEncoder, WebGPUComputePipeline, WebGPUDevice,
+ WebGPUPipelineLayout, WebGPUShaderModule,
};
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
@@ -530,10 +532,16 @@ unsafe_no_jsmanaged_fields!(RefCell<Option<WebGPU>>);
unsafe_no_jsmanaged_fields!(RefCell<Identities>);
unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter);
-unsafe_no_jsmanaged_fields!(WebGPUDevice);
unsafe_no_jsmanaged_fields!(WebGPUBuffer);
+unsafe_no_jsmanaged_fields!(WebGPUBindGroup);
unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout);
+unsafe_no_jsmanaged_fields!(WebGPUComputePipeline);
unsafe_no_jsmanaged_fields!(WebGPUPipelineLayout);
+unsafe_no_jsmanaged_fields!(WebGPUShaderModule);
+unsafe_no_jsmanaged_fields!(WebGPUCommandBuffer);
+unsafe_no_jsmanaged_fields!(WebGPUCommandEncoder);
+unsafe_no_jsmanaged_fields!(WebGPUDevice);
+unsafe_no_jsmanaged_fields!(webgpu::wgpu::command::RawPass);
unsafe_no_jsmanaged_fields!(GPUBufferState);
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
unsafe_no_jsmanaged_fields!(MediaList);
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index f8b29b895fd..bc8799a3d8d 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::body::{run_array_buffer_data_algorithm, FetchedData};
use crate::dom::bindings::codegen::Bindings::BlobBinding;
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use crate::dom::bindings::codegen::UnionTypes::ArrayBufferOrArrayBufferViewOrBlobOrString;
@@ -12,12 +13,16 @@ use crate::dom::bindings::serializable::{Serializable, StorageKey};
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone::StructuredDataHolder;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::promise::Promise;
+use crate::realms::{AlreadyInRealm, InRealm};
use dom_struct::dom_struct;
+use encoding_rs::UTF_8;
use msg::constellation_msg::{BlobId, BlobIndex, PipelineNamespaceId};
use net_traits::filemanager_thread::RelativePos;
use script_traits::serializable::BlobImpl;
use std::collections::HashMap;
use std::num::NonZeroU32;
+use std::rc::Rc;
use uuid::Uuid;
// https://w3c.github.io/FileAPI/#blob
@@ -223,6 +228,59 @@ impl BlobMethods for Blob {
let blob_impl = BlobImpl::new_sliced(rel_pos, self.blob_id.clone(), type_string);
Blob::new(&*self.global(), blob_impl)
}
+
+ // https://w3c.github.io/FileAPI/#text-method-algo
+ fn Text(&self) -> Rc<Promise> {
+ let global = self.global();
+ let in_realm_proof = AlreadyInRealm::assert(&global);
+ let p = Promise::new_in_current_realm(&global, InRealm::Already(&in_realm_proof));
+ let id = self.get_blob_url_id();
+ global.read_file_async(
+ id,
+ p.clone(),
+ Box::new(|promise, bytes| match bytes {
+ Ok(b) => {
+ let (text, _, _) = UTF_8.decode(&b);
+ let text = DOMString::from(text);
+ promise.resolve_native(&text);
+ },
+ Err(e) => {
+ promise.reject_error(e);
+ },
+ }),
+ );
+ p
+ }
+
+ // https://w3c.github.io/FileAPI/#arraybuffer-method-algo
+ fn ArrayBuffer(&self) -> Rc<Promise> {
+ let global = self.global();
+ let in_realm_proof = AlreadyInRealm::assert(&global);
+ let p = Promise::new_in_current_realm(&global, InRealm::Already(&in_realm_proof));
+
+ let id = self.get_blob_url_id();
+
+ global.read_file_async(
+ id,
+ p.clone(),
+ Box::new(|promise, bytes| {
+ match bytes {
+ Ok(b) => {
+ let cx = promise.global().get_cx();
+ let result = run_array_buffer_data_algorithm(cx, b);
+
+ match result {
+ Ok(FetchedData::ArrayBuffer(a)) => promise.resolve_native(&a),
+ Err(e) => promise.reject_error(e),
+ _ => panic!("Unexpected result from run_array_buffer_data_algorithm"),
+ }
+ },
+ Err(e) => promise.reject_error(e),
+ };
+ }),
+ );
+ p
+ }
}
/// Get the normalized, MIME-parsable type string
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 371b31bbdb0..4c36a22f717 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -566,7 +566,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
&self,
image: CanvasImageSource,
repetition: DOMString,
- ) -> Fallible<DomRoot<CanvasPattern>> {
+ ) -> Fallible<Option<DomRoot<CanvasPattern>>> {
self.canvas_state
.borrow()
.create_pattern(&self.global(), image, repetition)
diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs
index d67550ee47f..f68a680483d 100644
--- a/components/script/dom/create.rs
+++ b/components/script/dom/create.rs
@@ -200,6 +200,8 @@ fn create_html_element(
None => {
if is_valid_custom_element_name(&*name.local) {
result.set_custom_element_state(CustomElementState::Undefined);
+ } else {
+ result.set_custom_element_state(CustomElementState::Uncustomized);
}
},
};
diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs
index e8d848d0b9f..e749541eace 100644
--- a/components/script/dom/domexception.rs
+++ b/components/script/dom/domexception.rs
@@ -32,6 +32,7 @@ pub enum DOMErrorName {
NetworkError = DOMExceptionConstants::NETWORK_ERR,
AbortError = DOMExceptionConstants::ABORT_ERR,
TypeMismatchError = DOMExceptionConstants::TYPE_MISMATCH_ERR,
+ URLMismatchError = DOMExceptionConstants::URL_MISMATCH_ERR,
QuotaExceededError = DOMExceptionConstants::QUOTA_EXCEEDED_ERR,
TimeoutError = DOMExceptionConstants::TIMEOUT_ERR,
InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR,
@@ -60,6 +61,7 @@ impl DOMErrorName {
"NetworkError" => Some(DOMErrorName::NetworkError),
"AbortError" => Some(DOMErrorName::AbortError),
"TypeMismatchError" => Some(DOMErrorName::TypeMismatchError),
+ "URLMismatchError" => Some(DOMErrorName::URLMismatchError),
"QuotaExceededError" => Some(DOMErrorName::QuotaExceededError),
"TimeoutError" => Some(DOMErrorName::TimeoutError),
"InvalidNodeTypeError" => Some(DOMErrorName::InvalidNodeTypeError),
@@ -102,6 +104,7 @@ impl DOMException {
DOMErrorName::NetworkError => "A network error occurred.",
DOMErrorName::AbortError => "The operation was aborted.",
DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
+ DOMErrorName::URLMismatchError => "The given URL does not match another URL.",
DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
DOMErrorName::TimeoutError => "The operation timed out.",
DOMErrorName::InvalidNodeTypeError => {
diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs
index b870ab4f16d..7f56f58c502 100644
--- a/components/script/dom/domtokenlist.rs
+++ b/components/script/dom/domtokenlist.rs
@@ -52,6 +52,17 @@ impl DOMTokenList {
slice => Ok(Atom::from(slice)),
}
}
+
+ // https://dom.spec.whatwg.org/#concept-dtl-update
+ fn perform_update_steps(&self, atoms: Vec<Atom>) {
+ // Step 1
+ if !self.element.has_attribute(&self.local_name) && atoms.len() == 0 {
+ return;
+ }
+ // step 2
+ self.element
+ .set_atomic_tokenlist_attribute(&self.local_name, atoms)
+ }
}
// https://dom.spec.whatwg.org/#domtokenlist
@@ -93,8 +104,7 @@ impl DOMTokenListMethods for DOMTokenList {
atoms.push(token);
}
}
- self.element
- .set_atomic_tokenlist_attribute(&self.local_name, atoms);
+ self.perform_update_steps(atoms);
Ok(())
}
@@ -108,8 +118,7 @@ impl DOMTokenListMethods for DOMTokenList {
.position(|atom| *atom == token)
.map(|index| atoms.remove(index));
}
- self.element
- .set_atomic_tokenlist_attribute(&self.local_name, atoms);
+ self.perform_update_steps(atoms);
Ok(())
}
@@ -122,8 +131,7 @@ impl DOMTokenListMethods for DOMTokenList {
Some(true) => Ok(true),
_ => {
atoms.remove(index);
- self.element
- .set_atomic_tokenlist_attribute(&self.local_name, atoms);
+ self.perform_update_steps(atoms);
Ok(false)
},
},
@@ -131,8 +139,7 @@ impl DOMTokenListMethods for DOMTokenList {
Some(false) => Ok(false),
_ => {
atoms.push(token);
- self.element
- .set_atomic_tokenlist_attribute(&self.local_name, atoms);
+ self.perform_update_steps(atoms);
Ok(true)
},
},
@@ -166,14 +173,27 @@ impl DOMTokenListMethods for DOMTokenList {
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
let mut result = false;
if let Some(pos) = atoms.iter().position(|atom| *atom == token) {
- if !atoms.contains(&new_token) {
- atoms[pos] = new_token;
+ if let Some(redundant_pos) = atoms.iter().position(|atom| *atom == new_token) {
+ if redundant_pos > pos {
+ // The replacement is already in the list, later,
+ // so we perform the replacement and remove the
+ // later copy.
+ atoms[pos] = new_token;
+ atoms.remove(redundant_pos);
+ } else if redundant_pos < pos {
+ // The replacement is already in the list, earlier,
+ // so we remove the index where we'd be putting the
+ // later copy.
+ atoms.remove(pos);
+ }
+ // else we are replacing the token with itself, nothing to change
} else {
- atoms.remove(pos);
+ // The replacement is not in the list already
+ atoms[pos] = new_token;
}
+
// Step 5.
- self.element
- .set_atomic_tokenlist_attribute(&self.local_name, atoms);
+ self.perform_update_steps(atoms);
result = true;
}
Ok(result)
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 29bdaf2f3bf..c26e492d544 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -324,14 +324,23 @@ impl Element {
}
pub fn set_custom_element_state(&self, state: CustomElementState) {
- self.ensure_rare_data().custom_element_state = state;
+ // no need to inflate rare data for uncustomized
+ if state != CustomElementState::Uncustomized || self.rare_data().is_some() {
+ self.ensure_rare_data().custom_element_state = state;
+ }
+ // https://dom.spec.whatwg.org/#concept-element-defined
+ let in_defined_state = match state {
+ CustomElementState::Uncustomized | CustomElementState::Custom => true,
+ _ => false,
+ };
+ self.set_state(ElementState::IN_DEFINED_STATE, in_defined_state)
}
pub fn get_custom_element_state(&self) -> CustomElementState {
if let Some(rare_data) = self.rare_data().as_ref() {
return rare_data.custom_element_state;
}
- CustomElementState::Undefined
+ CustomElementState::Uncustomized
}
pub fn set_custom_element_definition(&self, definition: Rc<CustomElementDefinition>) {
@@ -3039,6 +3048,7 @@ impl<'a> SelectorsElement for DomRoot<Element> {
NonTSPseudoClass::Focus |
NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Hover |
+ NonTSPseudoClass::Defined |
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked |
diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs
index e8e7ad7251c..3c6bf956e9e 100644
--- a/components/script/dom/event.rs
+++ b/components/script/dom/event.rs
@@ -10,7 +10,6 @@ use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeS
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceBinding::PerformanceMethods;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, DomSlice, MutNullableDom};
@@ -19,6 +18,7 @@ use crate::dom::document::Document;
use crate::dom::eventtarget::{CompiledEventListener, EventTarget, ListenerPhase};
use crate::dom::globalscope::GlobalScope;
use crate::dom::node::Node;
+use crate::dom::performance::reduce_timing_resolution;
use crate::dom::virtualmethods::vtable_for;
use crate::dom::window::Window;
use crate::task::TaskOnce;
@@ -333,7 +333,7 @@ impl EventMethods for Event {
// https://dom.spec.whatwg.org/#dom-event-timestamp
fn TimeStamp(&self) -> DOMHighResTimeStamp {
- Finite::wrap(
+ reduce_timing_resolution(
(self.precise_time_ns - (*self.global().performance().TimeOrigin()).round() as u64)
.to_ms(),
)
@@ -419,7 +419,7 @@ pub enum EventPhase {
/// helps us to prevent such events from being [sent to the constellation][msg] where it will be
/// handled once again for page scrolling (which is definitely not what we'd want).
///
-/// [msg]: https://doc.servo.org/script_traits/enum.ConstellationMsg.html#variant.KeyEvent
+/// [msg]: https://doc.servo.org/compositing/enum.ConstellationMsg.html#variant.KeyEvent
///
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
pub enum EventDefault {
diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs
index c3e3bbc339b..83866370527 100644
--- a/components/script/dom/eventsource.rs
+++ b/components/script/dom/eventsource.rs
@@ -32,7 +32,7 @@ use js::conversions::ToJSValConvertible;
use js::jsval::UndefinedValue;
use mime::{self, Mime};
use net_traits::request::{CacheMode, CorsSettings, Destination, RequestBuilder};
-use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata};
+use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FilteredMetadata};
use net_traits::{FetchResponseListener, FetchResponseMsg, NetworkError};
use net_traits::{ResourceFetchTiming, ResourceTimingType};
use servo_atoms::Atom;
@@ -339,7 +339,12 @@ impl FetchResponseListener for EventSourceContext {
Ok(fm) => {
let meta = match fm {
FetchMetadata::Unfiltered(m) => m,
- FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
+ FetchMetadata::Filtered { unsafe_, filtered } => match filtered {
+ FilteredMetadata::Opaque | FilteredMetadata::OpaqueRedirect => {
+ return self.fail_the_connection()
+ },
+ _ => unsafe_,
+ },
};
let mime = match meta.content_type {
None => return self.fail_the_connection(),
@@ -352,7 +357,13 @@ impl FetchResponseListener for EventSourceContext {
self.announce_the_connection();
},
Err(_) => {
- self.reestablish_the_connection();
+ // The spec advises failing here if reconnecting would be
+ // "futile", with no more specific advice; WPT tests
+ // consider a non-http(s) scheme to be futile.
+ match self.event_source.root().url.scheme() {
+ "http" | "https" => self.reestablish_the_connection(),
+ _ => self.fail_the_connection(),
+ }
},
}
}
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index 396ffb75441..1d80781a2fb 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -33,6 +33,7 @@ use crate::dom::htmlformelement::FormControlElementHelpers;
use crate::dom::node::document_from_node;
use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::window::Window;
+use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::enter_realm;
use dom_struct::dom_struct;
use fnv::FnvHasher;
@@ -152,9 +153,9 @@ pub enum CompiledEventListener {
impl CompiledEventListener {
// https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm
- pub fn call_or_handle_event<T: DomObject>(
+ pub fn call_or_handle_event(
&self,
- object: &T,
+ object: &EventTarget,
event: &Event,
exception_handle: ExceptionHandling,
) {
@@ -167,27 +168,29 @@ impl CompiledEventListener {
match *handler {
CommonEventHandler::ErrorEventHandler(ref handler) => {
if let Some(event) = event.downcast::<ErrorEvent>() {
- let cx = object.global().get_cx();
- rooted!(in(*cx) let error = event.Error(cx));
- let return_value = handler.Call_(
- object,
- EventOrString::String(event.Message()),
- Some(event.Filename()),
- Some(event.Lineno()),
- Some(event.Colno()),
- Some(error.handle()),
- exception_handle,
- );
- // Step 4
- if let Ok(return_value) = return_value {
- rooted!(in(*cx) let return_value = return_value);
- if return_value.handle().is_boolean() &&
- return_value.handle().to_boolean() == true
- {
- event.upcast::<Event>().PreventDefault();
+ if object.is::<Window>() || object.is::<WorkerGlobalScope>() {
+ let cx = object.global().get_cx();
+ rooted!(in(*cx) let error = event.Error(cx));
+ let return_value = handler.Call_(
+ object,
+ EventOrString::String(event.Message()),
+ Some(event.Filename()),
+ Some(event.Lineno()),
+ Some(event.Colno()),
+ Some(error.handle()),
+ exception_handle,
+ );
+ // Step 4
+ if let Ok(return_value) = return_value {
+ rooted!(in(*cx) let return_value = return_value);
+ if return_value.handle().is_boolean() &&
+ return_value.handle().to_boolean() == true
+ {
+ event.upcast::<Event>().PreventDefault();
+ }
}
+ return;
}
- return;
}
let _ = handler.Call_(
@@ -401,9 +404,15 @@ impl EventTarget {
});
match idx {
- Some(idx) => {
- entries[idx].listener =
- EventListenerType::Inline(listener.unwrap_or(InlineEventListener::Null));
+ Some(idx) => match listener {
+ // Replace if there's something to replace with,
+ // but remove entirely if there isn't.
+ Some(listener) => {
+ entries[idx].listener = EventListenerType::Inline(listener);
+ },
+ None => {
+ entries.remove(idx);
+ },
},
None => {
if let Some(listener) = listener {
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 77cded77230..f96f1101bca 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -8,9 +8,9 @@ use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
use crate::dom::bindings::conversions::{root_from_object, root_from_object_static};
-use crate::dom::bindings::error::{report_pending_exception, ErrorInfo};
+use crate::dom::bindings::error::{report_pending_exception, Error, ErrorInfo};
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::refcounted::Trusted;
+use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::settings_stack::{entry_global, incumbent_global, AutoEntryScript};
@@ -31,10 +31,12 @@ use crate::dom::messageevent::MessageEvent;
use crate::dom::messageport::MessagePort;
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::performance::Performance;
+use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::dom::workletglobalscope::WorkletGlobalScope;
use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask};
+use crate::realms::enter_realm;
use crate::script_module::ModuleTree;
use crate::script_runtime::{CommonScriptMsg, JSContext as SafeJSContext, ScriptChan, ScriptPort};
use crate::script_thread::{MainThreadScriptChan, ScriptThread};
@@ -69,7 +71,9 @@ use js::rust::{HandleValue, MutableHandleValue};
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
use msg::constellation_msg::{BlobId, MessagePortId, MessagePortRouterId, PipelineId};
use net_traits::blob_url_store::{get_blob_origin, BlobBuf};
-use net_traits::filemanager_thread::{FileManagerThreadMsg, ReadFileProgress, RelativePos};
+use net_traits::filemanager_thread::{
+ FileManagerResult, FileManagerThreadMsg, ReadFileProgress, RelativePos,
+};
use net_traits::image_cache::ImageCache;
use net_traits::{CoreResourceMsg, CoreResourceThread, IpcSend, ResourceThreads};
use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time};
@@ -94,7 +98,10 @@ use std::sync::Arc;
use time::{get_time, Timespec};
use uuid::Uuid;
use webgpu::wgpu::{
- id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
+ id::{
+ AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandEncoderId, ComputePipelineId,
+ DeviceId, PipelineLayoutId, ShaderModuleId,
+ },
Backend,
};
@@ -231,6 +238,23 @@ struct TimerListener {
context: Trusted<GlobalScope>,
}
+/// A wrapper for the handling of file data received by the ipc router
+struct FileListener {
+ /// State should progress as either of:
+ /// - Some(Empty) => Some(Receiving) => None
+ /// - Some(Empty) => None
+ state: Option<FileListenerState>,
+ task_source: FileReadingTaskSource,
+ task_canceller: TaskCanceller,
+}
+
+struct FileListenerCallback(Box<dyn Fn(Rc<Promise>, Result<Vec<u8>, Error>) + Send>);
+
+enum FileListenerState {
+ Empty(FileListenerCallback, TrustedPromise),
+ Receiving(Vec<u8>, FileListenerCallback, TrustedPromise),
+}
+
#[derive(JSTraceable, MallocSizeOf)]
/// A holder of a weak reference for a DOM blob or file.
pub enum BlobTracker {
@@ -389,6 +413,64 @@ impl MessageListener {
}
}
+impl FileListener {
+ fn handle(&mut self, msg: FileManagerResult<ReadFileProgress>) {
+ match msg {
+ Ok(ReadFileProgress::Meta(blob_buf)) => match self.state.take() {
+ Some(FileListenerState::Empty(callback, promise)) => {
+ self.state = Some(FileListenerState::Receiving(
+ blob_buf.bytes,
+ callback,
+ promise,
+ ));
+ },
+ _ => panic!(
+ "Unexpected FileListenerState when receiving ReadFileProgress::Meta msg."
+ ),
+ },
+ Ok(ReadFileProgress::Partial(mut bytes_in)) => match self.state.take() {
+ Some(FileListenerState::Receiving(mut bytes, callback, promise)) => {
+ bytes.append(&mut bytes_in);
+ self.state = Some(FileListenerState::Receiving(bytes, callback, promise));
+ },
+ _ => panic!(
+ "Unexpected FileListenerState when receiving ReadFileProgress::Partial msg."
+ ),
+ },
+ Ok(ReadFileProgress::EOF) => match self.state.take() {
+ Some(FileListenerState::Receiving(bytes, callback, trusted_promise)) => {
+ let _ = self.task_source.queue_with_canceller(
+ task!(resolve_promise: move || {
+ let promise = trusted_promise.root();
+ let _ac = enter_realm(&*promise.global());
+ callback.0(promise, Ok(bytes));
+ }),
+ &self.task_canceller,
+ );
+ },
+ _ => {
+ panic!("Unexpected FileListenerState when receiving ReadFileProgress::EOF msg.")
+ },
+ },
+ Err(_) => match self.state.take() {
+ Some(FileListenerState::Receiving(_, callback, trusted_promise)) |
+ Some(FileListenerState::Empty(callback, trusted_promise)) => {
+ let bytes = Err(Error::Network);
+ let _ = self.task_source.queue_with_canceller(
+ task!(reject_promise: move || {
+ let promise = trusted_promise.root();
+ let _ac = enter_realm(&*promise.global());
+ callback.0(promise, bytes);
+ }),
+ &self.task_canceller,
+ );
+ },
+ _ => panic!("Unexpected FileListenerState when receiving Err msg."),
+ },
+ }
+ }
+}
+
impl GlobalScope {
pub fn new_inherited(
pipeline_id: PipelineId,
@@ -1251,18 +1333,59 @@ impl GlobalScope {
}
fn read_file(&self, id: Uuid) -> Result<Vec<u8>, ()> {
+ let recv = self.send_msg(id);
+ GlobalScope::read_msg(recv)
+ }
+
+ pub fn read_file_async(
+ &self,
+ id: Uuid,
+ promise: Rc<Promise>,
+ callback: Box<dyn Fn(Rc<Promise>, Result<Vec<u8>, Error>) + Send>,
+ ) {
+ let recv = self.send_msg(id);
+
+ let trusted_promise = TrustedPromise::new(promise);
+ let task_canceller = self.task_canceller(TaskSourceName::FileReading);
+ let task_source = self.file_reading_task_source();
+
+ let mut file_listener = FileListener {
+ state: Some(FileListenerState::Empty(
+ FileListenerCallback(callback),
+ trusted_promise,
+ )),
+ task_source,
+ task_canceller,
+ };
+
+ ROUTER.add_route(
+ recv.to_opaque(),
+ Box::new(move |msg| {
+ file_listener.handle(
+ msg.to()
+ .expect("Deserialization of file listener msg failed."),
+ );
+ }),
+ );
+ }
+
+ fn send_msg(&self, id: Uuid) -> profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>> {
let resource_threads = self.resource_threads();
- let (chan, recv) =
- profile_ipc::channel(self.time_profiler_chan().clone()).map_err(|_| ())?;
+ let (chan, recv) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
let origin = get_blob_origin(&self.get_url());
let check_url_validity = false;
let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
+ recv
+ }
+ fn read_msg(
+ receiver: profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>>,
+ ) -> Result<Vec<u8>, ()> {
let mut bytes = vec![];
loop {
- match recv.recv().unwrap() {
+ match receiver.recv().unwrap() {
Ok(ReadFileProgress::Meta(mut blob_buf)) => {
bytes.append(&mut blob_buf.bytes);
},
@@ -1985,6 +2108,10 @@ impl GlobalScope {
self.gpu_id_hub.borrow_mut().create_adapter_ids()
}
+ pub fn wgpu_create_bind_group_id(&self, backend: Backend) -> BindGroupId {
+ self.gpu_id_hub.borrow_mut().create_bind_group_id(backend)
+ }
+
pub fn wgpu_create_bind_group_layout_id(&self, backend: Backend) -> BindGroupLayoutId {
self.gpu_id_hub
.borrow_mut()
@@ -2004,6 +2131,24 @@ impl GlobalScope {
.borrow_mut()
.create_pipeline_layout_id(backend)
}
+
+ pub fn wgpu_create_shader_module_id(&self, backend: Backend) -> ShaderModuleId {
+ self.gpu_id_hub
+ .borrow_mut()
+ .create_shader_module_id(backend)
+ }
+
+ pub fn wgpu_create_compute_pipeline_id(&self, backend: Backend) -> ComputePipelineId {
+ self.gpu_id_hub
+ .borrow_mut()
+ .create_compute_pipeline_id(backend)
+ }
+
+ pub fn wgpu_create_command_encoder_id(&self, backend: Backend) -> CommandEncoderId {
+ self.gpu_id_hub
+ .borrow_mut()
+ .create_command_encoder_id(backend)
+ }
}
fn timestamp_in_ms(time: Timespec) -> u64 {
diff --git a/components/script/dom/gpubindgroup.rs b/components/script/dom/gpubindgroup.rs
new file mode 100644
index 00000000000..c14ca7a23b5
--- /dev/null
+++ b/components/script/dom/gpubindgroup.rs
@@ -0,0 +1,58 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::{
+ GPUBindGroupBinding, GPUBindGroupMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use std::cell::Cell;
+use webgpu::WebGPUBindGroup;
+
+#[dom_struct]
+pub struct GPUBindGroup {
+ reflector_: Reflector,
+ label: DomRefCell<Option<DOMString>>,
+ bind_group: WebGPUBindGroup,
+ valid: Cell<bool>,
+}
+
+impl GPUBindGroup {
+ fn new_inherited(bind_group: WebGPUBindGroup, valid: bool) -> GPUBindGroup {
+ Self {
+ reflector_: Reflector::new(),
+ label: DomRefCell::new(None),
+ bind_group,
+ valid: Cell::new(valid),
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ bind_group: WebGPUBindGroup,
+ valid: bool,
+ ) -> DomRoot<GPUBindGroup> {
+ reflect_dom_object(
+ Box::new(GPUBindGroup::new_inherited(bind_group, valid)),
+ global,
+ GPUBindGroupBinding::Wrap,
+ )
+ }
+}
+
+impl GPUBindGroupMethods for GPUBindGroup {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs
index 160ef6cf79c..8cc9bc52249 100644
--- a/components/script/dom/gpubuffer.rs
+++ b/components/script/dom/gpubuffer.rs
@@ -79,6 +79,20 @@ impl GPUBuffer {
}
}
+impl GPUBuffer {
+ pub fn id(&self) -> WebGPUBuffer {
+ self.buffer
+ }
+
+ pub fn size(&self) -> GPUBufferSize {
+ self.size
+ }
+
+ pub fn usage(&self) -> u32 {
+ self.usage
+ }
+}
+
impl Drop for GPUBuffer {
fn drop(&mut self) {
self.Destroy()
diff --git a/components/script/dom/gpucommandbuffer.rs b/components/script/dom/gpucommandbuffer.rs
new file mode 100644
index 00000000000..5cc4c926547
--- /dev/null
+++ b/components/script/dom/gpucommandbuffer.rs
@@ -0,0 +1,58 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUCommandBufferBinding::{
+ self, GPUCommandBufferMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use webgpu::{WebGPU, WebGPUCommandBuffer};
+
+#[dom_struct]
+pub struct GPUCommandBuffer {
+ reflector_: Reflector,
+ #[ignore_malloc_size_of = "defined in webgpu"]
+ channel: WebGPU,
+ label: DomRefCell<Option<DOMString>>,
+ command_buffer: WebGPUCommandBuffer,
+}
+
+impl GPUCommandBuffer {
+ pub fn new_inherited(channel: WebGPU, command_buffer: WebGPUCommandBuffer) -> GPUCommandBuffer {
+ GPUCommandBuffer {
+ channel,
+ reflector_: Reflector::new(),
+ label: DomRefCell::new(None),
+ command_buffer,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ channel: WebGPU,
+ command_buffer: WebGPUCommandBuffer,
+ ) -> DomRoot<GPUCommandBuffer> {
+ reflect_dom_object(
+ Box::new(GPUCommandBuffer::new_inherited(channel, command_buffer)),
+ global,
+ GPUCommandBufferBinding::Wrap,
+ )
+ }
+}
+
+impl GPUCommandBufferMethods for GPUCommandBuffer {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/gpucommandencoder.rs b/components/script/dom/gpucommandencoder.rs
new file mode 100644
index 00000000000..5e86c0b8bfd
--- /dev/null
+++ b/components/script/dom/gpucommandencoder.rs
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUCommandEncoderBinding::{
+ self, GPUCommandBufferDescriptor, GPUCommandEncoderMethods, GPUComputePassDescriptor,
+};
+use crate::dom::bindings::reflector::DomObject;
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::gpubuffer::GPUBuffer;
+use crate::dom::gpucommandbuffer::GPUCommandBuffer;
+use crate::dom::gpucomputepassencoder::GPUComputePassEncoder;
+use dom_struct::dom_struct;
+use ipc_channel::ipc;
+use webgpu::{wgpu::command::RawPass, WebGPU, WebGPUCommandEncoder, WebGPURequest};
+
+#[dom_struct]
+pub struct GPUCommandEncoder {
+ reflector_: Reflector,
+ #[ignore_malloc_size_of = "defined in webgpu"]
+ channel: WebGPU,
+ label: DomRefCell<Option<DOMString>>,
+ encoder: WebGPUCommandEncoder,
+}
+
+impl GPUCommandEncoder {
+ pub fn new_inherited(channel: WebGPU, encoder: WebGPUCommandEncoder) -> GPUCommandEncoder {
+ GPUCommandEncoder {
+ channel,
+ reflector_: Reflector::new(),
+ label: DomRefCell::new(None),
+ encoder,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ channel: WebGPU,
+ encoder: WebGPUCommandEncoder,
+ ) -> DomRoot<GPUCommandEncoder> {
+ reflect_dom_object(
+ Box::new(GPUCommandEncoder::new_inherited(channel, encoder)),
+ global,
+ GPUCommandEncoderBinding::Wrap,
+ )
+ }
+}
+
+impl GPUCommandEncoderMethods for GPUCommandEncoder {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-begincomputepass
+ fn BeginComputePass(
+ &self,
+ _descriptor: &GPUComputePassDescriptor,
+ ) -> DomRoot<GPUComputePassEncoder> {
+ GPUComputePassEncoder::new(
+ &self.global(),
+ self.channel.clone(),
+ RawPass::new_compute(self.encoder.0),
+ )
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertobuffer
+ fn CopyBufferToBuffer(
+ &self,
+ source: &GPUBuffer,
+ source_offset: u64,
+ destination: &GPUBuffer,
+ destination_offset: u64,
+ size: u64,
+ ) {
+ self.channel
+ .0
+ .send(WebGPURequest::CopyBufferToBuffer(
+ self.encoder.0,
+ source.id().0,
+ source_offset,
+ destination.id().0,
+ destination_offset,
+ size,
+ ))
+ .expect("Failed to send CopyBufferToBuffer");
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-finish
+ fn Finish(&self, _descriptor: &GPUCommandBufferDescriptor) -> DomRoot<GPUCommandBuffer> {
+ let (sender, receiver) = ipc::channel().unwrap();
+ self.channel
+ .0
+ .send(WebGPURequest::CommandEncoderFinish(
+ sender,
+ self.encoder.0,
+ // TODO(zakorgy): We should use `_descriptor` here after it's not empty
+ // and the underlying wgpu-core struct is serializable
+ ))
+ .expect("Failed to send CopyBufferToBuffer");
+
+ let buffer = receiver.recv().unwrap();
+ GPUCommandBuffer::new(&self.global(), self.channel.clone(), buffer)
+ }
+}
diff --git a/components/script/dom/gpucomputepassencoder.rs b/components/script/dom/gpucomputepassencoder.rs
new file mode 100644
index 00000000000..ecdd4407a8d
--- /dev/null
+++ b/components/script/dom/gpucomputepassencoder.rs
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUComputePassEncoderBinding::{
+ self, GPUComputePassEncoderMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use webgpu::{wgpu::command::RawPass, WebGPU};
+
+#[dom_struct]
+pub struct GPUComputePassEncoder {
+ reflector_: Reflector,
+ #[ignore_malloc_size_of = "defined in webgpu"]
+ channel: WebGPU,
+ label: DomRefCell<Option<DOMString>>,
+ #[ignore_malloc_size_of = "defined in wgpu-core"]
+ pass: RawPass,
+}
+
+impl GPUComputePassEncoder {
+ pub fn new_inherited(channel: WebGPU, pass: RawPass) -> GPUComputePassEncoder {
+ GPUComputePassEncoder {
+ channel,
+ reflector_: Reflector::new(),
+ label: DomRefCell::new(None),
+ pass,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ channel: WebGPU,
+ pass: RawPass,
+ ) -> DomRoot<GPUComputePassEncoder> {
+ reflect_dom_object(
+ Box::new(GPUComputePassEncoder::new_inherited(channel, pass)),
+ global,
+ GPUComputePassEncoderBinding::Wrap,
+ )
+ }
+}
+
+impl GPUComputePassEncoderMethods for GPUComputePassEncoder {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/gpucomputepipeline.rs b/components/script/dom/gpucomputepipeline.rs
new file mode 100644
index 00000000000..32c0338a7e9
--- /dev/null
+++ b/components/script/dom/gpucomputepipeline.rs
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::{
+ GPUComputePipelineBinding, GPUComputePipelineMethods,
+};
+use crate::dom::bindings::reflector::reflect_dom_object;
+use crate::dom::bindings::reflector::Reflector;
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use webgpu::WebGPUComputePipeline;
+
+#[dom_struct]
+pub struct GPUComputePipeline {
+ reflector_: Reflector,
+ label: DomRefCell<Option<DOMString>>,
+ compute_pipeline: WebGPUComputePipeline,
+}
+
+impl GPUComputePipeline {
+ fn new_inherited(compute_pipeline: WebGPUComputePipeline) -> GPUComputePipeline {
+ Self {
+ reflector_: Reflector::new(),
+ label: DomRefCell::new(None),
+ compute_pipeline,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ compute_pipeline: WebGPUComputePipeline,
+ ) -> DomRoot<GPUComputePipeline> {
+ reflect_dom_object(
+ Box::new(GPUComputePipeline::new_inherited(compute_pipeline)),
+ global,
+ GPUComputePipelineBinding::Wrap,
+ )
+ }
+}
+
+impl GPUComputePipelineMethods for GPUComputePipeline {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs
index de3efec8117..514d6ad39d1 100644
--- a/components/script/dom/gpudevice.rs
+++ b/components/script/dom/gpudevice.rs
@@ -6,21 +6,32 @@
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits;
+use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::GPUBindGroupDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
GPUBindGroupLayoutBindings, GPUBindGroupLayoutDescriptor, GPUBindingType,
};
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
-use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{self, GPUDeviceMethods};
+use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineDescriptor;
+use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{
+ self, GPUCommandEncoderDescriptor, GPUDeviceMethods,
+};
use crate::dom::bindings::codegen::Bindings::GPUPipelineLayoutBinding::GPUPipelineLayoutDescriptor;
+use crate::dom::bindings::codegen::Bindings::GPUShaderModuleBinding::GPUShaderModuleDescriptor;
+use crate::dom::bindings::codegen::UnionTypes::Uint32ArrayOrString::{String, Uint32Array};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
+use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
+use crate::dom::gpubindgroup::GPUBindGroup;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
+use crate::dom::gpucommandencoder::GPUCommandEncoder;
+use crate::dom::gpucomputepipeline::GPUComputePipeline;
use crate::dom::gpupipelinelayout::GPUPipelineLayout;
+use crate::dom::gpushadermodule::GPUShaderModule;
use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct;
use ipc_channel::ipc;
@@ -29,7 +40,10 @@ use js::jsval::{JSVal, ObjectValue};
use js::typedarray::{ArrayBuffer, CreateWith};
use std::collections::{HashMap, HashSet};
use std::ptr::{self, NonNull};
-use webgpu::wgpu::binding_model::{BindGroupLayoutBinding, BindingType, ShaderStage};
+use webgpu::wgpu::binding_model::{
+ BindGroupBinding, BindGroupLayoutBinding, BindingResource, BindingType, BufferBinding,
+ ShaderStage,
+};
use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest};
@@ -463,4 +477,136 @@ impl GPUDeviceMethods for GPUDevice {
let pipeline_layout = receiver.recv().unwrap();
GPUPipelineLayout::new(&self.global(), bind_group_layouts, pipeline_layout, valid)
}
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup
+ fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> {
+ let alignment: u64 = 256;
+ let mut valid = descriptor.layout.bindings().len() == descriptor.bindings.len();
+
+ valid &= descriptor.bindings.iter().all(|bind| {
+ let buffer_size = bind.resource.buffer.size();
+ let resource_size = bind.resource.size.unwrap_or(buffer_size);
+ let length = bind.resource.offset.checked_add(resource_size);
+ let usage = BufferUsage::from_bits(bind.resource.buffer.usage()).unwrap();
+
+ length.is_some() &&
+ buffer_size >= length.unwrap() && // check buffer OOB
+ bind.resource.offset % alignment == 0 && // check alignment
+ bind.resource.offset < buffer_size && // on Vulkan offset must be less than size of buffer
+ descriptor.layout.bindings().iter().any(|layout_bind| {
+ let ty = match layout_bind.type_ {
+ GPUBindingType::Storage_buffer => BufferUsage::STORAGE,
+ // GPUBindingType::Readonly_storage_buffer => BufferUsage::STORAGE_READ,
+ GPUBindingType::Uniform_buffer => BufferUsage::UNIFORM,
+ _ => unimplemented!(),
+ };
+ // binding must be present in layout
+ layout_bind.binding == bind.binding &&
+ // binding must contain one buffer of its type
+ usage.contains(ty)
+ })
+ });
+
+ let bindings = descriptor
+ .bindings
+ .iter()
+ .map(|bind| BindGroupBinding {
+ binding: bind.binding,
+ resource: BindingResource::Buffer(BufferBinding {
+ buffer: bind.resource.buffer.id().0,
+ offset: bind.resource.offset,
+ size: bind.resource.size.unwrap_or(bind.resource.buffer.size()),
+ }),
+ })
+ .collect::<Vec<_>>();
+ let (sender, receiver) = ipc::channel().unwrap();
+ let id = self
+ .global()
+ .wgpu_create_bind_group_id(self.device.0.backend());
+ self.channel
+ .0
+ .send(WebGPURequest::CreateBindGroup(
+ sender,
+ self.device,
+ id,
+ descriptor.layout.id(),
+ bindings,
+ ))
+ .expect("Failed to create WebGPU BindGroup");
+
+ let bind_group = receiver.recv().unwrap();
+ GPUBindGroup::new(&self.global(), bind_group, valid)
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule
+ fn CreateShaderModule(
+ &self,
+ descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
+ ) -> DomRoot<GPUShaderModule> {
+ let (sender, receiver) = ipc::channel().unwrap();
+ let program: Vec<u32> = match &descriptor.code {
+ Uint32Array(program) => program.to_vec(),
+ String(program) => program.chars().map(|c| c as u32).collect::<Vec<u32>>(),
+ };
+ let id = self
+ .global()
+ .wgpu_create_shader_module_id(self.device.0.backend());
+ self.channel
+ .0
+ .send(WebGPURequest::CreateShaderModule(
+ sender,
+ self.device,
+ id,
+ program,
+ ))
+ .expect("Failed to create WebGPU ShaderModule");
+
+ let shader_module = receiver.recv().unwrap();
+ GPUShaderModule::new(&self.global(), shader_module)
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline
+ fn CreateComputePipeline(
+ &self,
+ descriptor: &GPUComputePipelineDescriptor,
+ ) -> DomRoot<GPUComputePipeline> {
+ let pipeline = descriptor.parent.layout.id();
+ let program = descriptor.computeStage.module.id();
+ let entry_point = descriptor.computeStage.entryPoint.to_string();
+ let id = self
+ .global()
+ .wgpu_create_compute_pipeline_id(self.device.0.backend());
+ let (sender, receiver) = ipc::channel().unwrap();
+ self.channel
+ .0
+ .send(WebGPURequest::CreateComputePipeline(
+ sender,
+ self.device,
+ id,
+ pipeline.0,
+ program.0,
+ entry_point,
+ ))
+ .expect("Failed to create WebGPU ComputePipeline");
+
+ let compute_pipeline = receiver.recv().unwrap();
+ GPUComputePipeline::new(&self.global(), compute_pipeline)
+ }
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcommandencoder
+ fn CreateCommandEncoder(
+ &self,
+ _descriptor: &GPUCommandEncoderDescriptor,
+ ) -> DomRoot<GPUCommandEncoder> {
+ let (sender, receiver) = ipc::channel().unwrap();
+ let id = self
+ .global()
+ .wgpu_create_command_encoder_id(self.device.0.backend());
+ self.channel
+ .0
+ .send(WebGPURequest::CreateCommandEncoder(sender, self.device, id))
+ .expect("Failed to create WebGPU command encoder");
+ let encoder = receiver.recv().unwrap();
+
+ GPUCommandEncoder::new(&self.global(), self.channel.clone(), encoder)
+ }
}
diff --git a/components/script/dom/gpupipelinelayout.rs b/components/script/dom/gpupipelinelayout.rs
index a52bbedb7b5..40f5fd9324d 100644
--- a/components/script/dom/gpupipelinelayout.rs
+++ b/components/script/dom/gpupipelinelayout.rs
@@ -56,6 +56,12 @@ impl GPUPipelineLayout {
}
}
+impl GPUPipelineLayout {
+ pub fn id(&self) -> WebGPUPipelineLayout {
+ self.pipeline_layout
+ }
+}
+
impl GPUPipelineLayoutMethods for GPUPipelineLayout {
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
diff --git a/components/script/dom/gpushadermodule.rs b/components/script/dom/gpushadermodule.rs
new file mode 100644
index 00000000000..241f0650245
--- /dev/null
+++ b/components/script/dom/gpushadermodule.rs
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUShaderModuleBinding::{
+ self, GPUShaderModuleMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use webgpu::WebGPUShaderModule;
+
+#[dom_struct]
+pub struct GPUShaderModule {
+ reflector_: Reflector,
+ label: DomRefCell<Option<DOMString>>,
+ shader_module: WebGPUShaderModule,
+}
+
+impl GPUShaderModule {
+ fn new_inherited(shader_module: WebGPUShaderModule) -> GPUShaderModule {
+ Self {
+ reflector_: Reflector::new(),
+ label: DomRefCell::new(None),
+ shader_module,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ shader_module: WebGPUShaderModule,
+ ) -> DomRoot<GPUShaderModule> {
+ reflect_dom_object(
+ Box::new(GPUShaderModule::new_inherited(shader_module)),
+ global,
+ GPUShaderModuleBinding::Wrap,
+ )
+ }
+}
+
+impl GPUShaderModule {
+ pub fn id(&self) -> WebGPUShaderModule {
+ self.shader_module
+ }
+}
+
+impl GPUShaderModuleMethods for GPUShaderModule {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs
index b7c7da1e9bf..49541a2d4a0 100755
--- a/components/script/dom/htmlbuttonelement.rs
+++ b/components/script/dom/htmlbuttonelement.rs
@@ -307,7 +307,7 @@ impl Activatable for HTMLButtonElement {
if let Some(owner) = self.form_owner() {
owner.submit(
SubmittedFrom::NotFromForm,
- FormSubmitter::ButtonElement(self.clone()),
+ FormSubmitter::ButtonElement(self),
);
}
},
diff --git a/components/script/dom/htmlformcontrolscollection.rs b/components/script/dom/htmlformcontrolscollection.rs
index 1cf969a2fdd..410244c52c1 100644
--- a/components/script/dom/htmlformcontrolscollection.rs
+++ b/components/script/dom/htmlformcontrolscollection.rs
@@ -5,10 +5,11 @@
use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use crate::dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding;
use crate::dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
+use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
use crate::dom::bindings::codegen::UnionTypes::RadioNodeListOrElement;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
-use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::element::Element;
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
@@ -21,25 +22,30 @@ use dom_struct::dom_struct;
#[dom_struct]
pub struct HTMLFormControlsCollection {
collection: HTMLCollection,
+ form: Dom<HTMLFormElement>,
}
impl HTMLFormControlsCollection {
fn new_inherited(
- root: &HTMLFormElement,
+ form: &HTMLFormElement,
filter: Box<dyn CollectionFilter + 'static>,
) -> HTMLFormControlsCollection {
+ let root_of_form = form
+ .upcast::<Node>()
+ .GetRootNode(&GetRootNodeOptions::empty());
HTMLFormControlsCollection {
- collection: HTMLCollection::new_inherited(root.upcast::<Node>(), filter),
+ collection: HTMLCollection::new_inherited(&*root_of_form, filter),
+ form: Dom::from_ref(form),
}
}
pub fn new(
window: &Window,
- root: &HTMLFormElement,
+ form: &HTMLFormElement,
filter: Box<dyn CollectionFilter + 'static>,
) -> DomRoot<HTMLFormControlsCollection> {
reflect_dom_object(
- Box::new(HTMLFormControlsCollection::new_inherited(root, filter)),
+ Box::new(HTMLFormControlsCollection::new_inherited(form, filter)),
window,
HTMLFormControlsCollectionBinding::Wrap,
)
@@ -80,14 +86,11 @@ impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
// Step 4-5
let global = self.global();
let window = global.as_window();
- // okay to unwrap: root's type was checked in the constructor
- let collection_root = self.collection.root_node();
- let form = collection_root.downcast::<HTMLFormElement>().unwrap();
// There is only one way to get an HTMLCollection,
// specifically HTMLFormElement::Elements(),
// and the collection filter excludes image inputs.
Some(RadioNodeListOrElement::RadioNodeList(
- RadioNodeList::new_controls_except_image_inputs(window, form, name),
+ RadioNodeList::new_controls_except_image_inputs(window, &*self.form, name),
))
}
// Step 3
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index ebbe1d49615..bf59dc0280b 100644
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -48,6 +48,7 @@ use crate::dom::node::{Node, NodeFlags, ShadowIncluding};
use crate::dom::node::{UnbindContext, VecPreOrderInsertionHelper};
use crate::dom::nodelist::{NodeList, RadioListMode};
use crate::dom::radionodelist::RadioNodeList;
+use crate::dom::submitevent::SubmitEvent;
use crate::dom::validitystate::ValidationFlags;
use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::window::Window;
@@ -604,10 +605,29 @@ impl HTMLFormElement {
}
}
// Step 7
+ // spec calls this "submitterButton" but it doesn't have to be a button,
+ // just not be the form itself
+ let submitter_button = match submitter {
+ FormSubmitter::FormElement(f) => {
+ if f == self {
+ None
+ } else {
+ Some(f.upcast::<HTMLElement>())
+ }
+ },
+ FormSubmitter::InputElement(i) => Some(i.upcast::<HTMLElement>()),
+ FormSubmitter::ButtonElement(b) => Some(b.upcast::<HTMLElement>()),
+ };
if submit_method_flag == SubmittedFrom::NotFromForm {
- let event = self
- .upcast::<EventTarget>()
- .fire_bubbling_cancelable_event(atom!("submit"));
+ let event = SubmitEvent::new(
+ &self.global(),
+ atom!("submit"),
+ true,
+ true,
+ submitter_button.map(|s| DomRoot::from_ref(s)),
+ );
+ let event = event.upcast::<Event>();
+ event.fire(self.upcast::<EventTarget>());
if event.DefaultPrevented() {
return;
}
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index a8ec28ac9cf..1cfecef1728 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -13,7 +13,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageE
use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
-use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject;
@@ -164,6 +164,26 @@ impl HTMLImageElement {
pub fn get_url(&self) -> Option<ServoUrl> {
self.current_request.borrow().parsed_url.clone()
}
+ // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
+ pub fn is_usable(&self) -> Fallible<bool> {
+ // If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad.
+ match &self.current_request.borrow().image {
+ Some(image) => {
+ if image.width == 0 || image.height == 0 {
+ return Ok(false);
+ }
+ },
+ None => return Ok(false),
+ }
+
+ match self.current_request.borrow().state {
+ // If image's current request's state is broken, then throw an "InvalidStateError" DOMException.
+ State::Broken => Err(Error::InvalidState),
+ State::CompletelyAvailable => Ok(true),
+ // If image is not fully decodable, then return bad.
+ State::PartiallyAvailable | State::Unavailable => Ok(false),
+ }
+ }
}
/// The context required for asynchronously loading an external image.
@@ -1293,7 +1313,7 @@ impl HTMLImageElement {
.filter_map(DomRoot::downcast::<HTMLMapElement>)
.find(|n| {
n.upcast::<Element>()
- .get_string_attribute(&LocalName::from("name")) ==
+ .get_string_attribute(&local_name!("name")) ==
last
});
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index a8587b58ed0..88b2e688d65 100755
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -2470,7 +2470,7 @@ impl Activatable for HTMLInputElement {
self.form_owner().map(|o| {
o.submit(
SubmittedFrom::NotFromForm,
- FormSubmitter::InputElement(self.clone()),
+ FormSubmitter::InputElement(self),
)
});
},
diff --git a/components/script/dom/identityhub.rs b/components/script/dom/identityhub.rs
index 91ead1acf0a..702172f6d72 100644
--- a/components/script/dom/identityhub.rs
+++ b/components/script/dom/identityhub.rs
@@ -5,7 +5,10 @@
use smallvec::SmallVec;
use webgpu::wgpu::{
hub::IdentityManager,
- id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
+ id::{
+ AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandEncoderId, ComputePipelineId,
+ DeviceId, PipelineLayoutId, ShaderModuleId,
+ },
Backend,
};
@@ -14,8 +17,12 @@ pub struct IdentityHub {
adapters: IdentityManager,
devices: IdentityManager,
buffers: IdentityManager,
+ bind_groups: IdentityManager,
bind_group_layouts: IdentityManager,
+ compute_pipelines: IdentityManager,
pipeline_layouts: IdentityManager,
+ shader_modules: IdentityManager,
+ command_encoders: IdentityManager,
backend: Backend,
}
@@ -25,8 +32,12 @@ impl IdentityHub {
adapters: IdentityManager::default(),
devices: IdentityManager::default(),
buffers: IdentityManager::default(),
+ bind_groups: IdentityManager::default(),
bind_group_layouts: IdentityManager::default(),
+ compute_pipelines: IdentityManager::default(),
pipeline_layouts: IdentityManager::default(),
+ shader_modules: IdentityManager::default(),
+ command_encoders: IdentityManager::default(),
backend,
}
}
@@ -43,13 +54,29 @@ impl IdentityHub {
self.buffers.alloc(self.backend)
}
+ fn create_bind_group_id(&mut self) -> BindGroupId {
+ self.bind_groups.alloc(self.backend)
+ }
+
fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
self.bind_group_layouts.alloc(self.backend)
}
+ fn create_compute_pipeline_id(&mut self) -> ComputePipelineId {
+ self.compute_pipelines.alloc(self.backend)
+ }
+
fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
self.pipeline_layouts.alloc(self.backend)
}
+
+ fn create_shader_module_id(&mut self) -> ShaderModuleId {
+ self.shader_modules.alloc(self.backend)
+ }
+
+ pub fn create_command_encoder_id(&mut self) -> CommandEncoderId {
+ self.command_encoders.alloc(self.backend)
+ }
}
#[derive(Debug)]
@@ -82,6 +109,20 @@ impl Identities {
}
}
+ fn select(&mut self, backend: Backend) -> &mut IdentityHub {
+ match backend {
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ Backend::Vulkan => &mut self.vk_hub,
+ #[cfg(target_os = "windows")]
+ Backend::Dx12 => &mut self.dx12_hub,
+ #[cfg(target_os = "windows")]
+ Backend::Dx11 => &mut self.dx11_hub,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Backend::Metal => &mut self.metal_hub,
+ _ => &mut self.dummy_hub,
+ }
+ }
+
fn hubs(&mut self) -> Vec<&mut IdentityHub> {
vec![
#[cfg(any(target_os = "linux", target_os = "windows"))]
@@ -97,17 +138,7 @@ impl Identities {
}
pub fn create_device_id(&mut self, backend: Backend) -> DeviceId {
- match backend {
- #[cfg(any(target_os = "linux", target_os = "windows"))]
- Backend::Vulkan => self.vk_hub.create_device_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx12 => self.dx12_hub.create_device_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx11 => self.dx11_hub.create_device_id(),
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- Backend::Metal => self.metal_hub.create_device_id(),
- _ => self.dummy_hub.create_device_id(),
- }
+ self.select(backend).create_device_id()
}
pub fn create_adapter_ids(&mut self) -> SmallVec<[AdapterId; 4]> {
@@ -119,44 +150,30 @@ impl Identities {
}
pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId {
- match backend {
- #[cfg(any(target_os = "linux", target_os = "windows"))]
- Backend::Vulkan => self.vk_hub.create_buffer_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx12 => self.dx12_hub.create_buffer_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx11 => self.dx11_hub.create_buffer_id(),
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- Backend::Metal => self.metal_hub.create_buffer_id(),
- _ => self.dummy_hub.create_buffer_id(),
- }
+ self.select(backend).create_buffer_id()
+ }
+
+ pub fn create_bind_group_id(&mut self, backend: Backend) -> BindGroupId {
+ self.select(backend).create_bind_group_id()
}
pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
- match backend {
- #[cfg(any(target_os = "linux", target_os = "windows"))]
- Backend::Vulkan => self.vk_hub.create_bind_group_layout_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx12 => self.dx12_hub.create_bind_group_layout_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx11 => self.dx11_hub.create_bind_group_layout_id(),
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- Backend::Metal => self.metal_hub.create_bind_group_layout_id(),
- _ => self.dummy_hub.create_bind_group_layout_id(),
- }
+ self.select(backend).create_bind_group_layout_id()
+ }
+
+ pub fn create_compute_pipeline_id(&mut self, backend: Backend) -> ComputePipelineId {
+ self.select(backend).create_compute_pipeline_id()
}
pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
- match backend {
- #[cfg(any(target_os = "linux", target_os = "windows"))]
- Backend::Vulkan => self.vk_hub.create_pipeline_layout_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx12 => self.dx12_hub.create_pipeline_layout_id(),
- #[cfg(target_os = "windows")]
- Backend::Dx11 => self.dx11_hub.create_pipeline_layout_id(),
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- Backend::Metal => self.metal_hub.create_pipeline_layout_id(),
- _ => self.dummy_hub.create_pipeline_layout_id(),
- }
+ self.select(backend).create_pipeline_layout_id()
+ }
+
+ pub fn create_shader_module_id(&mut self, backend: Backend) -> ShaderModuleId {
+ self.select(backend).create_shader_module_id()
+ }
+
+ pub fn create_command_encoder_id(&mut self, backend: Backend) -> CommandEncoderId {
+ self.select(backend).create_command_encoder_id()
}
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 2550eeda007..8636ede66ac 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -318,11 +318,17 @@ pub mod gamepadlist;
pub mod globalscope;
pub mod gpu;
pub mod gpuadapter;
+pub mod gpubindgroup;
pub mod gpubindgrouplayout;
pub mod gpubuffer;
pub mod gpubufferusage;
+pub mod gpucommandbuffer;
+pub mod gpucommandencoder;
+pub mod gpucomputepassencoder;
+pub mod gpucomputepipeline;
pub mod gpudevice;
pub mod gpupipelinelayout;
+pub mod gpushadermodule;
pub mod gpushaderstage;
pub mod hashchangeevent;
pub mod headers;
@@ -483,6 +489,7 @@ pub mod storageevent;
pub mod stylepropertymapreadonly;
pub mod stylesheet;
pub mod stylesheetlist;
+pub mod submitevent;
pub mod svgelement;
pub mod svggraphicselement;
pub mod svgsvgelement;
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 0c5de3f67fb..b6d4389d441 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -165,12 +165,11 @@ bitflags! {
#[doc = "Specifies whether this node needs style recalc on next reflow."]
const HAS_DIRTY_DESCENDANTS = 1 << 1;
- // TODO: find a better place to keep this (#4105)
- // https://critic.hoppipolla.co.uk/showcomment?chain=8873
- // Perhaps using a Set in Document?
+
#[doc = "Specifies whether or not there is an authentic click in progress on \
this element."]
const CLICK_IN_PROGRESS = 1 << 2;
+
#[doc = "Specifies whether this node is focusable and whether it is supposed \
to be reachable with using sequential focus navigation."]
const SEQUENTIALLY_FOCUSABLE = 1 << 3;
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index 70e0573a2c4..130d2b7c49a 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -138,6 +138,10 @@ impl OffscreenCanvas {
));
Some(context)
}
+
+ pub fn is_valid(&self) -> bool {
+ self.Width() != 0 && self.Height() != 0
+ }
}
impl OffscreenCanvasMethods for OffscreenCanvas {
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index 277b5925f27..31dc8b7dec5 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -210,7 +210,7 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
&self,
image: CanvasImageSource,
repetition: DOMString,
- ) -> Fallible<DomRoot<CanvasPattern>> {
+ ) -> Fallible<Option<DomRoot<CanvasPattern>>> {
self.canvas_state
.borrow()
.create_pattern(&self.global(), image, repetition)
diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs
index e4b0a3cf71e..b9adc23e52d 100644
--- a/components/script/dom/paintrenderingcontext2d.rs
+++ b/components/script/dom/paintrenderingcontext2d.rs
@@ -340,7 +340,7 @@ impl PaintRenderingContext2DMethods for PaintRenderingContext2D {
&self,
image: CanvasImageSource,
repetition: DOMString,
- ) -> Fallible<DomRoot<CanvasPattern>> {
+ ) -> Fallible<Option<DomRoot<CanvasPattern>>> {
self.context.CreatePattern(image, repetition)
}
diff --git a/components/script/dom/performance.rs b/components/script/dom/performance.rs
index 82eec0e4996..9de98852df7 100644
--- a/components/script/dom/performance.rs
+++ b/components/script/dom/performance.rs
@@ -426,12 +426,12 @@ impl PerformanceMethods for Performance {
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now
fn Now(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.now())
+ reduce_timing_resolution(self.now())
}
// https://www.w3.org/TR/hr-time-2/#dom-performance-timeorigin
fn TimeOrigin(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.navigation_start_precise as f64)
+ reduce_timing_resolution(self.navigation_start_precise as f64)
}
// https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
@@ -550,3 +550,14 @@ impl PerformanceMethods for Performance {
SetOnresourcetimingbufferfull
);
}
+
+// https://www.w3.org/TR/hr-time-2/#clock-resolution
+pub fn reduce_timing_resolution(exact: f64) -> DOMHighResTimeStamp {
+ // We need a granularity no finer than 5 microseconds.
+ // 5 microseconds isn't an exactly representable f64 so WPT tests
+ // might occasionally corner-case on rounding.
+ // web-platform-tests/wpt#21526 wants us to use an integer number of
+ // microseconds; the next divisor of milliseconds up from 5 microseconds
+ // is 10, which is 1/100th of a millisecond.
+ Finite::wrap((exact * 100.0).floor() / 100.0)
+}
diff --git a/components/script/dom/performanceentry.rs b/components/script/dom/performanceentry.rs
index 334d8b6de85..e41cbc81667 100644
--- a/components/script/dom/performanceentry.rs
+++ b/components/script/dom/performanceentry.rs
@@ -2,13 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
use crate::dom::bindings::codegen::Bindings::PerformanceEntryBinding;
use crate::dom::bindings::codegen::Bindings::PerformanceEntryBinding::PerformanceEntryMethods;
-use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::performance::reduce_timing_resolution;
use dom_struct::dom_struct;
#[dom_struct]
@@ -77,12 +78,12 @@ impl PerformanceEntryMethods for PerformanceEntry {
}
// https://w3c.github.io/performance-timeline/#dom-performanceentry-starttime
- fn StartTime(&self) -> Finite<f64> {
- Finite::wrap(self.start_time)
+ fn StartTime(&self) -> DOMHighResTimeStamp {
+ reduce_timing_resolution(self.start_time)
}
// https://w3c.github.io/performance-timeline/#dom-performanceentry-duration
- fn Duration(&self) -> Finite<f64> {
- Finite::wrap(self.duration)
+ fn Duration(&self) -> DOMHighResTimeStamp {
+ reduce_timing_resolution(self.duration)
}
}
diff --git a/components/script/dom/performanceresourcetiming.rs b/components/script/dom/performanceresourcetiming.rs
index 586515d4365..574016adc88 100644
--- a/components/script/dom/performanceresourcetiming.rs
+++ b/components/script/dom/performanceresourcetiming.rs
@@ -6,11 +6,11 @@ use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeS
use crate::dom::bindings::codegen::Bindings::PerformanceResourceTimingBinding::{
self, PerformanceResourceTimingMethods,
};
-use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::performance::reduce_timing_resolution;
use crate::dom::performanceentry::PerformanceEntry;
use dom_struct::dom_struct;
use net_traits::ResourceFetchTiming;
@@ -182,17 +182,17 @@ impl PerformanceResourceTimingMethods for PerformanceResourceTiming {
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-domainlookupstart
fn DomainLookupStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.domain_lookup_start)
+ reduce_timing_resolution(self.domain_lookup_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-domainlookupend
fn DomainLookupEnd(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.domain_lookup_end)
+ reduce_timing_resolution(self.domain_lookup_end)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-secureconnectionstart
fn SecureConnectionStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.secure_connection_start)
+ reduce_timing_resolution(self.secure_connection_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-transfersize
@@ -212,41 +212,41 @@ impl PerformanceResourceTimingMethods for PerformanceResourceTiming {
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-requeststart
fn RequestStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.request_start)
+ reduce_timing_resolution(self.request_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-redirectstart
fn RedirectStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.redirect_start)
+ reduce_timing_resolution(self.redirect_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-redirectend
fn RedirectEnd(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.redirect_end)
+ reduce_timing_resolution(self.redirect_end)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responsestart
fn ResponseStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.response_start)
+ reduce_timing_resolution(self.response_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-fetchstart
fn FetchStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.fetch_start)
+ reduce_timing_resolution(self.fetch_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-connectstart
fn ConnectStart(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.connect_start)
+ reduce_timing_resolution(self.connect_start)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-connectend
fn ConnectEnd(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.connect_end)
+ reduce_timing_resolution(self.connect_end)
}
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responseend
fn ResponseEnd(&self) -> DOMHighResTimeStamp {
- Finite::wrap(self.response_end)
+ reduce_timing_resolution(self.response_end)
}
}
diff --git a/components/script/dom/servoparser/prefetch.rs b/components/script/dom/servoparser/prefetch.rs
index d9de4d7036f..c7468be7c19 100644
--- a/components/script/dom/servoparser/prefetch.rs
+++ b/components/script/dom/servoparser/prefetch.rs
@@ -128,7 +128,7 @@ impl TokenSink for PrefetchSink {
self.origin.clone(),
self.pipeline_id,
self.get_cors_settings(tag, local_name!("crossorigin")),
- self.get_referrer_policy(tag, LocalName::from("referrerpolicy")),
+ self.get_referrer_policy(tag, local_name!("referrerpolicy")),
FromPictureOrSrcSet::No,
);
let _ = self
@@ -145,7 +145,7 @@ impl TokenSink for PrefetchSink {
let cors_setting =
self.get_cors_settings(tag, local_name!("crossorigin"));
let referrer_policy =
- self.get_referrer_policy(tag, LocalName::from("referrerpolicy"));
+ self.get_referrer_policy(tag, local_name!("referrerpolicy"));
let integrity_metadata = self
.get_attr(tag, local_name!("integrity"))
.map(|attr| String::from(&attr.value))
diff --git a/components/script/dom/submitevent.rs b/components/script/dom/submitevent.rs
new file mode 100644
index 00000000000..17f8e7fd003
--- /dev/null
+++ b/components/script/dom/submitevent.rs
@@ -0,0 +1,79 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
+use crate::dom::bindings::codegen::Bindings::SubmitEventBinding;
+use crate::dom::bindings::codegen::Bindings::SubmitEventBinding::SubmitEventMethods;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::event::Event;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::htmlelement::HTMLElement;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use servo_atoms::Atom;
+
+#[dom_struct]
+#[allow(non_snake_case)]
+pub struct SubmitEvent {
+ event: Event,
+ submitter: Option<DomRoot<HTMLElement>>,
+}
+
+impl SubmitEvent {
+ fn new_inherited(submitter: Option<DomRoot<HTMLElement>>) -> SubmitEvent {
+ SubmitEvent {
+ event: Event::new_inherited(),
+ submitter: submitter,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ type_: Atom,
+ bubbles: bool,
+ cancelable: bool,
+ submitter: Option<DomRoot<HTMLElement>>,
+ ) -> DomRoot<SubmitEvent> {
+ let ev = reflect_dom_object(
+ Box::new(SubmitEvent::new_inherited(submitter)),
+ global,
+ SubmitEventBinding::Wrap,
+ );
+ {
+ let event = ev.upcast::<Event>();
+ event.init_event(type_, bubbles, cancelable);
+ }
+ ev
+ }
+
+ #[allow(non_snake_case)]
+ pub fn Constructor(
+ window: &Window,
+ type_: DOMString,
+ init: &SubmitEventBinding::SubmitEventInit,
+ ) -> DomRoot<SubmitEvent> {
+ SubmitEvent::new(
+ &window.global(),
+ Atom::from(type_),
+ init.parent.bubbles,
+ init.parent.cancelable,
+ init.submitter.as_ref().map(|s| DomRoot::from_ref(&**s)),
+ )
+ }
+}
+
+impl SubmitEventMethods for SubmitEvent {
+ /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
+ fn IsTrusted(&self) -> bool {
+ self.event.IsTrusted()
+ }
+
+ /// https://html.spec.whatwg.org/multipage/#dom-submitevent-submitter
+ fn GetSubmitter(&self) -> Option<DomRoot<HTMLElement>> {
+ self.submitter.as_ref().map(|s| DomRoot::from_ref(&**s))
+ }
+}
diff --git a/components/script/dom/vrframedata.rs b/components/script/dom/vrframedata.rs
index d4e92433f10..32af3b394ef 100644
--- a/components/script/dom/vrframedata.rs
+++ b/components/script/dom/vrframedata.rs
@@ -2,13 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
use crate::dom::bindings::codegen::Bindings::VRFrameDataBinding;
use crate::dom::bindings::codegen::Bindings::VRFrameDataBinding::VRFrameDataMethods;
use crate::dom::bindings::error::Fallible;
-use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
+use crate::dom::performance::reduce_timing_resolution;
use crate::dom::vrpose::VRPose;
use crate::dom::window::Window;
use crate::script_runtime::JSContext;
@@ -119,8 +120,8 @@ impl VRFrameData {
impl VRFrameDataMethods for VRFrameData {
// https://w3c.github.io/webvr/#dom-vrframedata-timestamp
- fn Timestamp(&self) -> Finite<f64> {
- Finite::wrap(self.timestamp.get() - self.first_timestamp.get())
+ fn Timestamp(&self) -> DOMHighResTimeStamp {
+ reduce_timing_resolution(self.timestamp.get() - self.first_timestamp.get())
}
#[allow(unsafe_code)]
diff --git a/components/script/dom/webidls/Blob.webidl b/components/script/dom/webidls/Blob.webidl
index 15d28cadb99..8a3f5f5185e 100644
--- a/components/script/dom/webidls/Blob.webidl
+++ b/components/script/dom/webidls/Blob.webidl
@@ -16,6 +16,9 @@ interface Blob {
Blob slice(optional [Clamp] long long start,
optional [Clamp] long long end,
optional DOMString contentType);
+
+ [NewObject] Promise<DOMString> text();
+ [NewObject] Promise<ArrayBuffer> arrayBuffer();
};
dictionary BlobPropertyBag {
diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl
index 52e532e3a8b..bcc1b56396c 100644
--- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl
+++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl
@@ -93,7 +93,7 @@ interface mixin CanvasFillStrokeStyles {
[Throws]
CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
[Throws]
- CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
+ CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
};
[Exposed=(PaintWorklet, Window, Worker)]
diff --git a/components/script/dom/webidls/GPUBindGroup.webidl b/components/script/dom/webidls/GPUBindGroup.webidl
new file mode 100644
index 00000000000..537fda29a63
--- /dev/null
+++ b/components/script/dom/webidls/GPUBindGroup.webidl
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpubindgrouplayout
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUBindGroup {
+};
+GPUBindGroup includes GPUObjectBase;
+
+dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
+ required GPUBindGroupLayout layout;
+ required sequence<GPUBindGroupBindings> bindings;
+};
+
+typedef /*(GPUSampler or GPUTextureView or*/ GPUBufferBindings/*)*/ GPUBindingResource;
+
+// Note: Servo codegen doesn't like the name `GPUBindGroupBinding` because it's already occupied
+// dictionary GPUBindGroupBinding {
+dictionary GPUBindGroupBindings {
+ required unsigned long binding;
+ required GPUBindingResource resource;
+};
+
+// Note: Servo codegen doesn't like the name `GPUBufferBinding` because it's already occupied
+// dictionary GPUBufferBinding {
+dictionary GPUBufferBindings {
+ required GPUBuffer buffer;
+ GPUBufferSize offset = 0;
+ GPUBufferSize size;
+};
diff --git a/components/script/dom/webidls/GPUCommandBuffer.webidl b/components/script/dom/webidls/GPUCommandBuffer.webidl
new file mode 100644
index 00000000000..fc61ccf4d64
--- /dev/null
+++ b/components/script/dom/webidls/GPUCommandBuffer.webidl
@@ -0,0 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpucommandbuffer
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUCommandBuffer {
+};
+GPUCommandBuffer includes GPUObjectBase;
diff --git a/components/script/dom/webidls/GPUCommandEncoder.webidl b/components/script/dom/webidls/GPUCommandEncoder.webidl
new file mode 100644
index 00000000000..481c720260f
--- /dev/null
+++ b/components/script/dom/webidls/GPUCommandEncoder.webidl
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpucommandencoder
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUCommandEncoder {
+ // GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
+ GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
+
+ void copyBufferToBuffer(
+ GPUBuffer source,
+ GPUBufferSize sourceOffset,
+ GPUBuffer destination,
+ GPUBufferSize destinationOffset,
+ GPUBufferSize size);
+
+ // void copyBufferToTexture(
+ // GPUBufferCopyView source,
+ // GPUTextureCopyView destination,
+ // GPUExtent3D copySize);
+
+ // void copyTextureToBuffer(
+ // GPUTextureCopyView source,
+ // GPUBufferCopyView destination,
+ // GPUExtent3D copySize);
+
+ // void copyTextureToTexture(
+ // GPUTextureCopyView source,
+ // GPUTextureCopyView destination,
+ // GPUExtent3D copySize);
+
+ // void pushDebugGroup(DOMString groupLabel);
+ // void popDebugGroup();
+ // void insertDebugMarker(DOMString markerLabel);
+
+ GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {});
+};
+GPUCommandEncoder includes GPUObjectBase;
+
+dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
+};
+
+dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
+};
diff --git a/components/script/dom/webidls/GPUComputePassEncoder.webidl b/components/script/dom/webidls/GPUComputePassEncoder.webidl
new file mode 100644
index 00000000000..0c03436a7e4
--- /dev/null
+++ b/components/script/dom/webidls/GPUComputePassEncoder.webidl
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpucomputepassencoder
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUComputePassEncoder {
+ // void setPipeline(GPUComputePipeline pipeline);
+ // void dispatch(unsigned long x, optional unsigned long y = 1, optional unsigned long z = 1);
+ // void dispatchIndirect(GPUBuffer indirectBuffer, GPUBufferSize indirectOffset);
+
+ // void endPass();
+};
+GPUComputePassEncoder includes GPUObjectBase;
+GPUComputePassEncoder includes GPUProgrammablePassEncoder;
diff --git a/components/script/dom/webidls/GPUComputePipeline.webidl b/components/script/dom/webidls/GPUComputePipeline.webidl
new file mode 100644
index 00000000000..671c36ad351
--- /dev/null
+++ b/components/script/dom/webidls/GPUComputePipeline.webidl
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpucomputepipeline
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUComputePipeline {
+};
+GPUComputePipeline includes GPUObjectBase;
+
+dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
+ required GPUPipelineLayout layout;
+};
+
+dictionary GPUProgrammableStageDescriptor {
+ required GPUShaderModule module;
+ required DOMString entryPoint;
+};
+
+dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
+ required GPUProgrammableStageDescriptor computeStage;
+};
diff --git a/components/script/dom/webidls/GPUDevice.webidl b/components/script/dom/webidls/GPUDevice.webidl
index 85e8a3ea633..05fb449df8c 100644
--- a/components/script/dom/webidls/GPUDevice.webidl
+++ b/components/script/dom/webidls/GPUDevice.webidl
@@ -11,21 +11,24 @@ interface GPUDevice : EventTarget {
GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
- //Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
- //GPUTexture createTexture(GPUTextureDescriptor descriptor);
- //GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
+ // Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
+ // GPUTexture createTexture(GPUTextureDescriptor descriptor);
+ // GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
- /*GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
+ GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
- GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
+ // GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
- GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
+ // GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
- GPUQueue getQueue();*/
+ // GPUQueue getQueue();
};
GPUDevice includes GPUObjectBase;
+
+dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
+};
diff --git a/components/script/dom/webidls/GPUProgrammablePassEncoder.webidl b/components/script/dom/webidls/GPUProgrammablePassEncoder.webidl
new file mode 100644
index 00000000000..2a44e806065
--- /dev/null
+++ b/components/script/dom/webidls/GPUProgrammablePassEncoder.webidl
@@ -0,0 +1,19 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpuprogrammablepassencoder
+[Exposed=(Window, DedicatedWorker)]
+interface mixin GPUProgrammablePassEncoder {
+ // void setBindGroup(unsigned long index, GPUBindGroup bindGroup,
+ // optional sequence<unsigned long> dynamicOffsets = []);
+
+ // void setBindGroup(unsigned long index, GPUBindGroup bindGroup,
+ // Uint32Array dynamicOffsetsData,
+ // unsigned long long dynamicOffsetsDataStart,
+ // unsigned long long dynamicOffsetsDataLength);
+
+ // void pushDebugGroup(DOMString groupLabel);
+ // void popDebugGroup();
+ // void insertDebugMarker(DOMString markerLabel);
+};
diff --git a/components/script/dom/webidls/GPUShaderModule.webidl b/components/script/dom/webidls/GPUShaderModule.webidl
new file mode 100644
index 00000000000..0fdfc7c0327
--- /dev/null
+++ b/components/script/dom/webidls/GPUShaderModule.webidl
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpushadermodule
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUShaderModule {
+};
+GPUShaderModule includes GPUObjectBase;
+
+typedef (Uint32Array or DOMString) GPUShaderCode;
+
+dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
+ required GPUShaderCode code;
+};
diff --git a/components/script/dom/webidls/SubmitEvent.webidl b/components/script/dom/webidls/SubmitEvent.webidl
new file mode 100644
index 00000000000..f5b2c49257d
--- /dev/null
+++ b/components/script/dom/webidls/SubmitEvent.webidl
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://html.spec.whatwg.org/multipage/#submitevent
+[Exposed=Window]
+interface SubmitEvent : Event {
+ constructor(DOMString typeArg, optional SubmitEventInit eventInitDict = {});
+
+ readonly attribute HTMLElement? submitter;
+};
+
+dictionary SubmitEventInit : EventInit {
+ HTMLElement? submitter = null;
+};
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index afd5183de33..eb8e4232886 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -55,8 +55,8 @@
// user prompts
void alert(DOMString message);
void alert();
- //boolean confirm(optional DOMString message = "");
- //DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
+ boolean confirm(optional DOMString message = "");
+ DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
//void print();
//any showModalDialog(DOMString url, optional any argument);
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index dc30017e7d1..208d7f1d87e 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -74,7 +74,7 @@ use crossbeam_channel::{unbounded, Sender, TryRecvError};
use cssparser::{Parser, ParserInput, SourceLocation};
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
use dom_struct::dom_struct;
-use embedder_traits::{EmbedderMsg, EventLoopWaker};
+use embedder_traits::{EmbedderMsg, EventLoopWaker, PromptDefinition, PromptOrigin, PromptResult};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
use ipc_channel::ipc::{channel, IpcSender};
@@ -620,11 +620,32 @@ impl WindowMethods for Window {
}
let (sender, receiver) =
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
- let msg = EmbedderMsg::Alert(s.to_string(), sender);
+ let prompt = PromptDefinition::Alert(s.to_string(), sender);
+ let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
self.send_to_embedder(msg);
receiver.recv().unwrap();
}
+ // https://html.spec.whatwg.org/multipage/#dom-confirm
+ fn Confirm(&self, s: DOMString) -> bool {
+ let (sender, receiver) =
+ ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
+ let prompt = PromptDefinition::OkCancel(s.to_string(), sender);
+ let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
+ self.send_to_embedder(msg);
+ receiver.recv().unwrap() == PromptResult::Primary
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-prompt
+ fn Prompt(&self, message: DOMString, default: DOMString) -> Option<DOMString> {
+ let (sender, receiver) =
+ ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
+ let prompt = PromptDefinition::Input(message.to_string(), default.to_string(), sender);
+ let msg = EmbedderMsg::Prompt(prompt, PromptOrigin::Untrusted);
+ self.send_to_embedder(msg);
+ receiver.recv().unwrap().map(|s| s.into())
+ }
+
// https://html.spec.whatwg.org/multipage/#dom-window-stop
fn Stop(&self) {
// TODO: Cancel ongoing navigation.
@@ -1763,7 +1784,7 @@ impl Window {
}
pub fn client_rect_query(&self, node: &Node) -> UntypedRect<i32> {
- if !self.layout_reflow(QueryMsg::NodeGeometryQuery(node.to_opaque())) {
+ if !self.layout_reflow(QueryMsg::ClientRectQuery(node.to_opaque())) {
return Rect::zero();
}
self.layout_rpc.node_geometry().client_rect
@@ -2351,7 +2372,7 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow
&QueryMsg::ContentBoxQuery(_n) => "\tContentBoxQuery",
&QueryMsg::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
&QueryMsg::NodesFromPointQuery(..) => "\tNodesFromPointQuery",
- &QueryMsg::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
+ &QueryMsg::ClientRectQuery(_n) => "\tClientRectQuery",
&QueryMsg::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
&QueryMsg::NodeScrollIdQuery(_n) => "\tNodeScrollIdQuery",
&QueryMsg::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index 08b37c946c5..6c531e5b4d6 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -618,7 +618,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
}
// Substep 2
if !self.upload_complete.get() {
- self.dispatch_upload_progress_event(atom!("loadstart"), Some(0));
+ self.dispatch_upload_progress_event(atom!("loadstart"), Ok(Some(0)));
if self.generation_id.get() != gen_id {
return Ok(());
}
@@ -1062,11 +1062,11 @@ impl XMLHttpRequest {
self.upload_complete.set(true);
// Substeps 2-4
if !self.sync.get() {
- self.dispatch_upload_progress_event(atom!("progress"), None);
+ self.dispatch_upload_progress_event(atom!("progress"), Ok(None));
return_if_fetch_was_terminated!();
- self.dispatch_upload_progress_event(atom!("load"), None);
+ self.dispatch_upload_progress_event(atom!("load"), Ok(None));
return_if_fetch_was_terminated!();
- self.dispatch_upload_progress_event(atom!("loadend"), None);
+ self.dispatch_upload_progress_event(atom!("loadend"), Ok(None));
return_if_fetch_was_terminated!();
}
// Part of step 13, send() (processing response)
@@ -1164,9 +1164,9 @@ impl XMLHttpRequest {
let upload_complete = &self.upload_complete;
if !upload_complete.get() {
upload_complete.set(true);
- self.dispatch_upload_progress_event(Atom::from(errormsg), None);
+ self.dispatch_upload_progress_event(Atom::from(errormsg), Err(()));
return_if_fetch_was_terminated!();
- self.dispatch_upload_progress_event(atom!("loadend"), None);
+ self.dispatch_upload_progress_event(atom!("loadend"), Err(()));
return_if_fetch_was_terminated!();
}
self.dispatch_response_progress_event(Atom::from(errormsg));
@@ -1210,11 +1210,19 @@ impl XMLHttpRequest {
progressevent.upcast::<Event>().fire(target);
}
- fn dispatch_upload_progress_event(&self, type_: Atom, partial_load: Option<u64>) {
- // If partial_load is None, loading has completed and we can just use the value from the request body
+ fn dispatch_upload_progress_event(&self, type_: Atom, partial_load: Result<Option<u64>, ()>) {
+ // If partial_load is Ok(None), loading has completed and we can just use the value from the request body
+ // If an error occured, we pass 0 for both loaded and total
- let total = self.request_body_len.get() as u64;
- self.dispatch_progress_event(true, type_, partial_load.unwrap_or(total), Some(total));
+ let request_body_len = self.request_body_len.get() as u64;
+ let (loaded, total) = match partial_load {
+ Ok(l) => match l {
+ Some(loaded) => (loaded, Some(request_body_len)),
+ None => (request_body_len, Some(request_body_len)),
+ },
+ Err(()) => (0, None),
+ };
+ self.dispatch_progress_event(true, type_, loaded, total);
}
fn dispatch_response_progress_event(&self, type_: Atom) {
diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs
index 4814eb379ff..68fe5a442fd 100644
--- a/components/script/dom/xrsession.rs
+++ b/components/script/dom/xrsession.rs
@@ -19,7 +19,6 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRVisibilityState
use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods;
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
@@ -28,6 +27,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::node::Node;
use crate::dom::node::NodeDamage;
+use crate::dom::performance::reduce_timing_resolution;
use crate::dom::promise::Promise;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrinputsourcearray::XRInputSourceArray;
@@ -336,7 +336,7 @@ impl XRSession {
// Step 4-5
let mut callbacks = mem::replace(&mut *self.raf_callback_list.borrow_mut(), vec![]);
let start = self.global().as_window().get_navigation_start();
- let time = (frame.time_ns - start).to_ms();
+ let time = reduce_timing_resolution((frame.time_ns - start).to_ms());
let frame = XRFrame::new(&self.global(), self, frame);
// Step 6,7
@@ -347,7 +347,7 @@ impl XRSession {
self.outside_raf.set(false);
for (_, callback) in callbacks.drain(..) {
if let Some(callback) = callback {
- let _ = callback.Call__(Finite::wrap(time), &frame, ExceptionHandling::Report);
+ let _ = callback.Call__(time, &frame, ExceptionHandling::Report);
}
}
self.outside_raf.set(true);