diff options
author | Patrick Shaughnessy <pshaughn@comcast.net> | 2019-11-23 22:08:43 -0500 |
---|---|---|
committer | Patrick Shaughnessy <pshaughn@comcast.net> | 2019-11-23 22:08:43 -0500 |
commit | a2a3ecac93563bffdc34bd747332da6c8d5f0552 (patch) | |
tree | 9829168e2d90d86c2cff1da65589db5e5cccc08c | |
parent | f1b34aa9950a0d240bee76aa13ad729429a0bcd7 (diff) | |
parent | a562808ebb0a7b30a570a0302c1f7e69e00a3b4a (diff) | |
download | servo-a2a3ecac93563bffdc34bd747332da6c8d5f0552.tar.gz servo-a2a3ecac93563bffdc34bd747332da6c8d5f0552.zip |
Merge branch 'master' of https://github.com/pshaughn/servo
80 files changed, 1681 insertions, 138 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0947f0385e9..a501e46e194 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,12 +126,33 @@ dependencies = [ ] [[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] name = "ascii" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" [[package]] +name = "ash" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5" +dependencies = [ + "shared_library", +] + +[[package]] +name = "atom" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" + +[[package]] name = "atomic_refcell" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -672,6 +693,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d" [[package]] +name = "colorful" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bca1619ff57dd7a56b58a8e25ef4199f123e78e503fe1653410350a1b98ae65" + +[[package]] name = "combine" version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -754,6 +781,7 @@ dependencies = [ "servo_remutex", "servo_url", "style_traits", + "webgpu", "webrender_api", "webvr_traits", "webxr-api", @@ -783,6 +811,12 @@ dependencies = [ ] [[package]] +name = "copyless" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127" + +[[package]] name = "core-foundation" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -866,7 +900,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", "cfg-if", "crossbeam-utils", "lazy_static", @@ -942,6 +976,17 @@ dependencies = [ ] [[package]] +name = "d3d12" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7ed48e89905e5e146bcc1951cc3facb9e44aea9adf5dc01078cda1bd24b662" +dependencies = [ + "bitflags", + "libloading", + "winapi", +] + +[[package]] name = "darling" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1497,6 +1542,12 @@ dependencies = [ ] [[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] name = "generic-array" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1566,6 +1617,123 @@ dependencies = [ ] [[package]] +name = "gfx-auxil" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572eee952a9a23c99cfe3e4fd95d277784058a89ac3c77ff6fa3d80a4e321919" +dependencies = [ + "fxhash", + "gfx-hal", + "spirv_cross", +] + +[[package]] +name = "gfx-backend-dx11" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66c77836ff26cf9916e5c8745715a22eae1fc61d994ffa0bea8a7dbd708ece2" +dependencies = [ + "bitflags", + "gfx-auxil", + "gfx-hal", + "libloading", + "log", + "parking_lot", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi", + "wio", +] + +[[package]] +name = "gfx-backend-dx12" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e913cc800fb12eaba2c420091a02aca9aafbefd672600dfc5b52654343d341" +dependencies = [ + "bitflags", + "d3d12", + "gfx-auxil", + "gfx-hal", + "log", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi", +] + +[[package]] +name = "gfx-backend-empty" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d383e6bc48867cb37d298a20139fd1eec298f8f6d594690cd1c50ef25470cc7" +dependencies = [ + "gfx-hal", + "raw-window-handle", +] + +[[package]] +name = "gfx-backend-metal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de5c71f18ba805c95b84d6c78c472ef44485a6fc46e3b49fe1e6739c8d7b0c0" +dependencies = [ + "arrayvec 0.5.1", + "bitflags", + "block", + "cocoa 0.19.1", + "copyless", + "core-graphics", + "foreign-types", + "gfx-auxil", + "gfx-hal", + "lazy_static", + "log", + "metal", + "objc", + "parking_lot", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "storage-map", +] + +[[package]] +name = "gfx-backend-vulkan" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62538fedd66a78968a162e8e1a29d085ffbc97f8782634684b2f7da7aea59207" +dependencies = [ + "arrayvec 0.5.1", + "ash", + "byteorder", + "core-graphics", + "gfx-hal", + "lazy_static", + "log", + "objc", + "raw-window-handle", + "smallvec", + "winapi", + "x11", +] + +[[package]] +name = "gfx-hal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88981665c780447bb08eb099e1ded330754a7246719bab927ee4a949c0ba7f" +dependencies = [ + "bitflags", + "raw-window-handle", + "smallvec", +] + +[[package]] name = "gfx_traits" version = "0.0.1" dependencies = [ @@ -2131,6 +2299,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] +name = "hibitset" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e7292fd9f7fe89fa35c98048f2d0a69b79ed243604234d18f6f8a1aa6f408d" +dependencies = [ + "atom", +] + +[[package]] name = "histogram" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2293,7 +2470,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7371aa3c98fad60de2d9b517e2e1ed45593c32b0c77249310fa507749a2a318b" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", "byteorder", "num-traits", ] @@ -2517,17 +2694,21 @@ dependencies = [ "cssparser", "euclid", "gfx", + "gfx_traits", "ipc-channel", "libc", "msg", + "range", "rayon", "rayon_croissant", "script_layout_interface", "script_traits", "serde", "servo_arc", + "servo_geometry", "style", "style_traits", + "unicode-script", "webrender_api", ] @@ -2764,6 +2945,7 @@ dependencies = [ "style_traits", "surfman", "webdriver_server", + "webgpu", "webrender", "webrender_api", "webrender_traits", @@ -2833,7 +3015,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69589b8844c0b3745cc031a35b62bc33b0fb9e5ba7613756d802c52861dcdb4c" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", "euclid", "num-traits", ] @@ -2989,6 +3171,21 @@ dependencies = [ ] [[package]] +name = "metal" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf8052f20601c7af6293d3f7bf7b9159aee5974804fe65d871d437f933ec1eb" +dependencies = [ + "bitflags", + "block", + "cocoa 0.19.1", + "core-graphics", + "foreign-types", + "log", + "objc", +] + +[[package]] name = "metrics" version = "0.0.1" dependencies = [ @@ -3393,6 +3590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" dependencies = [ "malloc_buf", + "objc_exception", ] [[package]] @@ -3407,6 +3605,15 @@ dependencies = [ ] [[package]] +name = "objc_exception" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc" +dependencies = [ + "gcc", +] + +[[package]] name = "objc_id" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3893,6 +4100,12 @@ dependencies = [ ] [[package]] +name = "range-alloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9" + +[[package]] name = "raqote" version = "0.7.4-alpha.0" source = "git+https://github.com/jrmuizel/raqote#2a801bca7253e053767ef5ea11b0ee77c52617c9" @@ -3906,6 +4119,15 @@ dependencies = [ ] [[package]] +name = "raw-window-handle" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9db80d08d3ed847ce4fb3def46de0af4bfb6155bd09bd6eaf28b5ac72541c1f1" +dependencies = [ + "libc", +] + +[[package]] name = "rayon" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3989,6 +4211,16 @@ dependencies = [ ] [[package]] +name = "relevant" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc232e13d37f4547f5b9b42a5efc380cabe5dbc1807f8b893580640b2ab0308" +dependencies = [ + "cfg-if", + "log", +] + +[[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3998,6 +4230,33 @@ dependencies = [ ] [[package]] +name = "rendy-descriptor" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f475bcc0505946e998590f1f0545c52ef4b559174a1b353a7ce6638def8b621e" +dependencies = [ + "gfx-hal", + "log", + "relevant", + "smallvec", +] + +[[package]] +name = "rendy-memory" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed492161a819feae7f27f418bb16035276ac20649c60d756699152cb5c1960ec" +dependencies = [ + "colorful", + "gfx-hal", + "hibitset", + "log", + "relevant", + "slab", + "smallvec", +] + +[[package]] name = "rle-decode-fast" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4077,7 +4336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20" dependencies = [ "approx", - "arrayvec", + "arrayvec 0.4.6", "ordered-float", "stb_truetype", ] @@ -4199,6 +4458,7 @@ dependencies = [ "utf-8", "uuid", "webdriver", + "webgpu", "webrender_api", "webvr_traits", "webxr-api", @@ -4291,6 +4551,7 @@ dependencies = [ "time", "url", "webdriver", + "webgpu", "webrender_api", "webvr_traits", "webxr-api", @@ -4905,6 +5166,14 @@ dependencies = [ ] [[package]] +name = "spirv_cross" +version = "0.16.0" +source = "git+https://github.com/kvark/spirv_cross?branch=wgpu#636677bad724797789239c16e6d332e9b4d97b86" +dependencies = [ + "cc", +] + +[[package]] name = "stable_deref_trait" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4927,6 +5196,15 @@ dependencies = [ ] [[package]] +name = "storage-map" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e" +dependencies = [ + "lock_api", +] + +[[package]] name = "string" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4971,7 +5249,7 @@ name = "style" version = "0.0.1" dependencies = [ "app_units", - "arrayvec", + "arrayvec 0.4.6", "atomic_refcell", "bindgen", "bitflags", @@ -5583,7 +5861,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2606e9192f308ddc4f0b3c5d1bf3400e28a70fff956e9d9f46d23b094746d9f" dependencies = [ - "arrayvec", + "arrayvec 0.4.6", ] [[package]] @@ -5897,6 +6175,19 @@ dependencies = [ ] [[package]] +name = "webgpu" +version = "0.0.1" +dependencies = [ + "embedder_traits", + "ipc-channel", + "log", + "malloc_size_of", + "serde", + "servo_config", + "wgpu-native", +] + +[[package]] name = "webrender" version = "0.60.0" source = "git+https://github.com/servo/webrender#4f2d78adb6e07e3e5ab2da9765613ecf9e07eee0" @@ -6038,6 +6329,30 @@ dependencies = [ ] [[package]] +name = "wgpu-native" +version = "0.4.0" +source = "git+https://github.com/zakorgy/wgpu?branch=v0.4#128a16b9887a60a087a9d41ff68b20ce07cf6265" +dependencies = [ + "arrayvec 0.5.1", + "bitflags", + "copyless", + "fxhash", + "gfx-backend-dx11", + "gfx-backend-dx12", + "gfx-backend-empty", + "gfx-backend-metal", + "gfx-backend-vulkan", + "gfx-hal", + "log", + "parking_lot", + "rendy-descriptor", + "rendy-memory", + "serde", + "smallvec", + "vec_map", +] + +[[package]] name = "which" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index ee35ba935a9..3bb824b3417 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,5 @@ opt-level = 3 mio = { git = "https://github.com/servo/mio.git", branch = "servo" } # https://github.com/retep998/winapi-rs/pull/816 winapi = { git = "https://github.com/servo/winapi-rs", branch = "patch-1" } +spirv_cross = { git = "https://github.com/kvark/spirv_cross", branch = "wgpu" } +wgpu-native = { git = "https://github.com/zakorgy/wgpu", branch = "v0.4" } diff --git a/components/config/opts.rs b/components/config/opts.rs index 292d06c67dc..fb4e3112837 100644 --- a/components/config/opts.rs +++ b/components/config/opts.rs @@ -713,6 +713,12 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR "A preference to set to enable", "dom.bluetooth.enabled", ); + opts.optmulti( + "", + "pref", + "A preference to set to enable", + "dom.webgpu.enabled", + ); opts.optflag("b", "no-native-titlebar", "Do not use native titlebar"); opts.optflag("w", "webrender", "Use webrender backend"); opts.optopt("G", "graphics", "Select graphics backend (gl or es2)", "gl"); diff --git a/components/config/prefs.rs b/components/config/prefs.rs index 7e4fb7551a5..a1e8f96b906 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -159,6 +159,9 @@ mod gen { }, }, dom: { + webgpu: { + enabled: bool, + }, bluetooth: { enabled: bool, testing: { diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index ec360006aad..893930c701a 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -47,6 +47,7 @@ servo_geometry = {path = "../geometry"} servo_rand = {path = "../rand"} servo_remutex = {path = "../remutex"} servo_url = {path = "../url"} +webgpu = {path = "../webgpu"} webvr_traits = {path = "../webvr_traits"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 82b99938f3b..3bd77ebf137 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -172,6 +172,7 @@ use std::sync::Arc; use std::thread; use style_traits::viewport::ViewportConstraints; use style_traits::CSSPixel; +use webgpu::WebGPU; use webvr_traits::{WebVREvent, WebVRMsg}; type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, HistoryEntryReplacement)>; @@ -440,6 +441,10 @@ pub struct Constellation<Message, LTF, STF> { /// Entry point to create and get channels to a WebGLThread. webgl_threads: Option<WebGLThreads>, + /// An IPC channel for the constellation to send messages to the + /// WebGPU threads. + webgpu: Option<WebGPU>, + /// A channel through which messages can be sent to the webvr thread. webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -521,6 +526,9 @@ pub struct InitialConstellationState { /// Entry point to create and get channels to a WebGLThread. pub webgl_threads: Option<WebGLThreads>, + /// A channel to the WebGPU threads. + pub webgpu: Option<WebGPU>, + /// A channel to the webgl thread. pub webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -836,6 +844,7 @@ where (rng, prob) }), webgl_threads: state.webgl_threads, + webgpu: state.webgpu, webvr_chan: state.webvr_chan, webxr_registry: state.webxr_registry, canvas_chan: CanvasPaintThread::start(), @@ -1090,6 +1099,7 @@ where .webgl_threads .as_ref() .map(|threads| threads.pipeline()), + webgpu: self.webgpu.clone(), webvr_chan: self.webvr_chan.clone(), webxr_registry: self.webxr_registry.clone(), player_context: self.player_context.clone(), @@ -2355,6 +2365,17 @@ where } } + if let Some(webgpu) = self.webgpu.as_ref() { + debug!("Exiting WebGPU thread."); + let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!"); + if let Err(e) = webgpu.exit(sender) { + warn!("Exit WebGPU Thread failed ({})", e); + } + if let Err(e) = receiver.recv() { + warn!("Failed to receive exit response from WebGPU ({})", e); + } + } + if let Some(chan) = self.webvr_chan.as_ref() { debug!("Exiting WebVR thread."); if let Err(e) = chan.send(WebVRMsg::Exit) { diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 3ac5ded15ed..fd7202aa9ec 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -46,6 +46,7 @@ use std::process; use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::Arc; +use webgpu::WebGPU; use webvr_traits::WebVRMsg; /// A `Pipeline` is the constellation's view of a `Document`. Each pipeline has an @@ -188,6 +189,9 @@ pub struct InitialPipelineState { /// A channel to the WebGL thread. pub webgl_chan: Option<WebGLPipeline>, + /// A channel to the WebGPU threads. + pub webgpu: Option<WebGPU>, + /// A channel to the webvr thread. pub webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -299,6 +303,7 @@ impl Pipeline { webrender_document: state.webrender_document, webgl_chan: state.webgl_chan, webvr_chan: state.webvr_chan, + webgpu: state.webgpu, webxr_registry: state.webxr_registry, player_context: state.player_context, }; @@ -504,6 +509,7 @@ pub struct UnprivilegedPipelineContent { webrender_api_sender: webrender_api::RenderApiSender, webrender_document: webrender_api::DocumentId, webgl_chan: Option<WebGLPipeline>, + webgpu: Option<WebGPU>, webvr_chan: Option<IpcSender<WebVRMsg>>, webxr_registry: webxr_api::Registry, player_context: WindowGLContext, @@ -556,6 +562,7 @@ impl UnprivilegedPipelineContent { pipeline_namespace_id: self.pipeline_namespace_id, content_process_shutdown_chan: content_process_shutdown_chan, webgl_chan: self.webgl_chan, + webgpu: self.webgpu, webvr_chan: self.webvr_chan, webxr_registry: self.webxr_registry, webrender_document: self.webrender_document, diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index 52faf0c5480..7492064e3f7 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -453,6 +453,11 @@ impl<'a> GlyphStore { } #[inline] + pub fn total_advance(&self) -> Au { + self.total_advance + } + + #[inline] pub fn len(&self) -> ByteIndex { ByteIndex(self.entry_buffer.len() as isize) } diff --git a/components/layout_2020/Cargo.toml b/components/layout_2020/Cargo.toml index 69b0bea014e..f7167b638d5 100644 --- a/components/layout_2020/Cargo.toml +++ b/components/layout_2020/Cargo.toml @@ -18,15 +18,19 @@ atomic_refcell = "0.1" cssparser = "0.27" euclid = "0.20" gfx = {path = "../gfx"} +gfx_traits = {path = "../gfx_traits"} ipc-channel = "0.12" libc = "0.2" msg = {path = "../msg"} +range = {path = "../range"} rayon = "1" rayon_croissant = "0.1.1" script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} serde = "1.0" servo_arc = { path = "../servo_arc" } +servo_geometry = {path = "../geometry"} style = {path = "../style", features = ["servo", "servo-layout-2020"]} style_traits = {path = "../style_traits"} +unicode-script = {version = "0.3", features = ["harfbuzz"]} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/layout_2020/context.rs b/components/layout_2020/context.rs index 0e96797f4d7..5bde114ca57 100644 --- a/components/layout_2020/context.rs +++ b/components/layout_2020/context.rs @@ -3,7 +3,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use gfx::font_cache_thread::FontCacheThread; +use gfx::font_context::FontContext; use msg::constellation_msg::PipelineId; +use std::cell::{RefCell, RefMut}; use std::sync::Mutex; use style::context::SharedStyleContext; @@ -19,3 +21,18 @@ impl<'a> LayoutContext<'a> { &self.style_context } } + +pub(crate) type LayoutFontContext = FontContext<FontCacheThread>; + +thread_local!(static FONT_CONTEXT: RefCell<Option<LayoutFontContext>> = RefCell::new(None)); + +pub(crate) fn with_thread_local_font_context<F, R>(layout_context: &LayoutContext, f: F) -> R +where + F: FnOnce(&mut LayoutFontContext) -> R, +{ + FONT_CONTEXT.with(|font_context| { + f(font_context.borrow_mut().get_or_insert_with(|| { + FontContext::new(layout_context.font_cache_thread.lock().unwrap().clone()) + })) + }) +} diff --git a/components/layout_2020/display_list.rs b/components/layout_2020/display_list.rs index c153b04294c..5dc5ecb96ad 100644 --- a/components/layout_2020/display_list.rs +++ b/components/layout_2020/display_list.rs @@ -6,7 +6,10 @@ use crate::fragments::{BoxFragment, Fragment}; use crate::geom::physical::{Rect, Vec2}; use crate::style_ext::ComputedValuesExt; use app_units::Au; -use euclid::{self, SideOffsets2D}; +use euclid::{Point2D, SideOffsets2D}; +use gfx::text::glyph::GlyphStore; +use servo_geometry::MaxRect; +use std::sync::Arc; use style::values::computed::{BorderStyle, Length}; use webrender_api::{self as wr, units, CommonItemProperties, PrimitiveFlags}; @@ -50,9 +53,30 @@ impl Fragment { child.build_display_list(builder, is_contentful, &rect) } }, - Fragment::Text(_) => { + Fragment::Text(t) => { is_contentful.0 = true; - // FIXME + let rect = t + .content_rect + .to_physical(t.parent_style.writing_mode(), containing_block) + .translate(&containing_block.top_left); + let mut baseline_origin = rect.top_left.clone(); + baseline_origin.y += t.ascent; + let common = CommonItemProperties { + clip_rect: rect.clone().into(), + clip_id: wr::ClipId::root(builder.pipeline_id), + spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id), + hit_info: None, + // TODO(gw): Make use of the WR backface visibility functionality. + flags: PrimitiveFlags::default(), + }; + let glyphs = glyphs(&t.glyphs, baseline_origin); + if glyphs.is_empty() { + return; + } + let color = t.parent_style.clone_color(); + builder + .wr + .push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None); }, } } @@ -154,3 +178,28 @@ fn rgba(rgba: cssparser::RGBA) -> wr::ColorF { rgba.alpha_f32(), ) } + +fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> { + use gfx_traits::ByteIndex; + use range::Range; + + let mut glyphs = vec![]; + for run in glyph_runs { + for glyph in run.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), run.len())) { + if !run.is_whitespace() { + let glyph_offset = glyph.offset().unwrap_or(Point2D::zero()); + let point = units::LayoutPoint::new( + origin.x.px() + glyph_offset.x.to_f32_px(), + origin.y.px() + glyph_offset.y.to_f32_px(), + ); + let glyph = wr::GlyphInstance { + index: glyph.id(), + point, + }; + glyphs.push(glyph); + } + origin.x += Length::from(glyph.advance()); + } + } + glyphs +} diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 133654f32b7..e410fa269ec 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -2,9 +2,12 @@ * 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::context::LayoutContext; use crate::flow::float::FloatBox; use crate::flow::FlowChildren; -use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; +use crate::fragments::{ + AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment, +}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; use crate::replaced::ReplacedContent; @@ -81,6 +84,7 @@ struct LinesBoxes { impl InlineFormattingContext { pub(super) fn layout<'a>( &'a self, + layout_context: &LayoutContext, containing_block: &ContainingBlock, tree_rank: usize, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, @@ -107,7 +111,7 @@ impl InlineFormattingContext { let partial = inline.start_layout(&mut ifc); ifc.partial_inline_boxes_stack.push(partial) }, - InlineLevelBox::TextRun(run) => run.layout(&mut ifc), + InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc), InlineLevelBox::Atomic { style: _, contents } => { // FIXME match *contents {} @@ -284,7 +288,141 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { } impl TextRun { - fn layout(&self, _ifc: &mut InlineFormattingContextState) { - // TODO + fn layout(&self, layout_context: &LayoutContext, ifc: &mut InlineFormattingContextState) { + use gfx::font::{ShapingFlags, ShapingOptions}; + use style::computed_values::text_rendering::T as TextRendering; + use style::computed_values::word_break::T as WordBreak; + use style::values::generics::text::LineHeight; + + let font_style = self.parent_style.clone_font(); + let inherited_text_style = self.parent_style.get_inherited_text(); + let letter_spacing = if inherited_text_style.letter_spacing.0.px() != 0. { + Some(app_units::Au::from(inherited_text_style.letter_spacing.0)) + } else { + None + }; + + let mut flags = ShapingFlags::empty(); + if letter_spacing.is_some() { + flags.insert(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG); + } + if inherited_text_style.text_rendering == TextRendering::Optimizespeed { + flags.insert(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG); + flags.insert(ShapingFlags::DISABLE_KERNING_SHAPING_FLAG) + } + if inherited_text_style.word_break == WordBreak::KeepAll { + flags.insert(ShapingFlags::KEEP_ALL_FLAG); + } + + let shaping_options = gfx::font::ShapingOptions { + letter_spacing, + word_spacing: inherited_text_style.word_spacing.to_hash_key(), + script: unicode_script::Script::Common, + flags, + }; + + let (font_ascent, font_line_gap, font_key, runs) = + crate::context::with_thread_local_font_context(layout_context, |font_context| { + let font_group = font_context.font_group(font_style); + let font = font_group + .borrow_mut() + .first(font_context) + .expect("could not find font"); + let mut font = font.borrow_mut(); + + let (runs, _break_at_start) = gfx::text::text_run::TextRun::break_and_shape( + &mut font, + &self.text, + &shaping_options, + &mut None, + ); + + ( + font.metrics.ascent, + font.metrics.line_gap, + font.font_key, + runs, + ) + }); + + let font_size = self.parent_style.get_font().font_size.size.0; + let mut runs = runs.iter(); + loop { + let mut glyphs = vec![]; + let mut advance_width = Length::zero(); + let mut last_break_opportunity = None; + loop { + let next = runs.next(); + if next + .as_ref() + .map_or(true, |run| run.glyph_store.is_whitespace()) + { + if advance_width > ifc.containing_block.inline_size - ifc.inline_position { + if let Some((len, width, iter)) = last_break_opportunity.take() { + glyphs.truncate(len); + advance_width = width; + runs = iter; + } + break; + } + } + if let Some(run) = next { + if run.glyph_store.is_whitespace() { + last_break_opportunity = Some((glyphs.len(), advance_width, runs.clone())); + } + glyphs.push(run.glyph_store.clone()); + advance_width += Length::from(run.glyph_store.total_advance()); + } else { + break; + } + } + let line_height = match self.parent_style.get_inherited_text().line_height { + LineHeight::Normal => font_line_gap.into(), + LineHeight::Number(n) => font_size * n.0, + LineHeight::Length(l) => l.0, + }; + let content_rect = Rect { + start_corner: Vec2 { + block: Length::zero(), + inline: ifc.inline_position - ifc.current_nesting_level.inline_start, + }, + size: Vec2 { + block: line_height, + inline: advance_width, + }, + }; + ifc.inline_position += advance_width; + ifc.current_nesting_level + .max_block_size_of_fragments_so_far + .max_assign(line_height); + ifc.current_nesting_level + .fragments_so_far + .push(Fragment::Text(TextFragment { + parent_style: self.parent_style.clone(), + content_rect, + ascent: font_ascent.into(), + font_key, + glyphs, + })); + if runs.is_empty() { + break; + } else { + // New line + ifc.current_nesting_level.inline_start = Length::zero(); + let mut nesting_level = &mut ifc.current_nesting_level; + for partial in ifc.partial_inline_boxes_stack.iter_mut().rev() { + partial.finish_layout(nesting_level, &mut ifc.inline_position, true); + partial.start_corner.inline = Length::zero(); + partial.padding.inline_start = Length::zero(); + partial.border.inline_start = Length::zero(); + partial.margin.inline_start = Length::zero(); + partial.parent_nesting_level.inline_start = Length::zero(); + nesting_level = &mut partial.parent_nesting_level; + } + ifc.line_boxes + .finish_line(nesting_level, ifc.containing_block); + ifc.inline_position = Length::zero(); + } + } } } diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 2395380c5eb..b690e447cd7 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -4,6 +4,7 @@ //! Flow layout, also known as block-and-inline layout. +use crate::context::LayoutContext; use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::inline::InlineFormattingContext; use crate::fragments::{ @@ -67,6 +68,7 @@ struct CollapsibleWithParentStartMargin(bool); impl BlockFormattingContext { pub(super) fn layout<'a>( &'a self, + layout_context: &LayoutContext, containing_block: &ContainingBlock, tree_rank: usize, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, @@ -79,6 +81,7 @@ impl BlockFormattingContext { None }; let mut flow_children = self.contents.layout( + layout_context, containing_block, tree_rank, absolutely_positioned_fragments, @@ -97,6 +100,7 @@ impl BlockFormattingContext { impl BlockContainer { fn layout<'a>( &'a self, + layout_context: &LayoutContext, containing_block: &ContainingBlock, tree_rank: usize, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, @@ -105,6 +109,7 @@ impl BlockContainer { ) -> FlowChildren { match self { BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children( + layout_context, child_boxes, containing_block, tree_rank, @@ -112,14 +117,18 @@ impl BlockContainer { float_context, collapsible_with_parent_start_margin, ), - BlockContainer::InlineFormattingContext(ifc) => { - ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments) - }, + BlockContainer::InlineFormattingContext(ifc) => ifc.layout( + layout_context, + containing_block, + tree_rank, + absolutely_positioned_fragments, + ), } } } fn layout_block_level_children<'a>( + layout_context: &LayoutContext, child_boxes: &'a [Arc<BlockLevelBox>], containing_block: &ContainingBlock, tree_rank: usize, @@ -201,6 +210,7 @@ fn layout_block_level_children<'a>( .enumerate() .map(|(tree_rank, box_)| { let mut fragment = box_.layout( + layout_context, containing_block, tree_rank, absolutely_positioned_fragments, @@ -218,6 +228,7 @@ fn layout_block_level_children<'a>( absolutely_positioned_fragments, |abspos_fragments, (tree_rank, box_)| { box_.layout( + layout_context, containing_block, tree_rank, abspos_fragments, @@ -255,6 +266,7 @@ fn layout_block_level_children<'a>( impl BlockLevelBox { fn layout<'a>( &'a self, + layout_context: &LayoutContext, containing_block: &ContainingBlock, tree_rank: usize, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, @@ -263,12 +275,14 @@ impl BlockLevelBox { match self { BlockLevelBox::SameFormattingContextBlock { style, contents } => { Fragment::Box(layout_in_flow_non_replaced_block_level( + layout_context, containing_block, absolutely_positioned_fragments, style, BlockLevelKind::SameFormattingContextBlock, |containing_block, nested_abspos, collapsible_with_parent_start_margin| { contents.layout( + layout_context, containing_block, tree_rank, nested_abspos, @@ -284,12 +298,13 @@ impl BlockLevelBox { match *replaced {} }, Err(contents) => Fragment::Box(layout_in_flow_non_replaced_block_level( + layout_context, containing_block, absolutely_positioned_fragments, style, BlockLevelKind::EstablishesAnIndependentFormattingContext, |containing_block, nested_abspos, _| { - contents.layout(containing_block, tree_rank, nested_abspos) + contents.layout(layout_context, containing_block, tree_rank, nested_abspos) }, )), }, @@ -314,6 +329,7 @@ enum BlockLevelKind { /// https://drafts.csswg.org/css2/visudet.html#blockwidth /// https://drafts.csswg.org/css2/visudet.html#normal-block fn layout_in_flow_non_replaced_block_level<'a>( + layout_context: &LayoutContext, containing_block: &ContainingBlock, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, style: &Arc<ComputedValues>, @@ -433,6 +449,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( }; if style.get_box().position == Position::Relative { AbsolutelyPositionedFragment::in_positioned_containing_block( + layout_context, &nested_abspos, &mut flow_children.fragments, &content_rect.size, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 54cc1eef07f..a1831c6433a 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.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::context::LayoutContext; use crate::display_list::IsContentful; use crate::dom_traversal::{Contents, NodeExt}; use crate::flow::construct::ContainsFloats; @@ -98,7 +99,11 @@ fn construct_for_root_element<'dom>( } impl BoxTreeRoot { - pub fn layout(&self, viewport: geom::Size<CSSPixel>) -> FragmentTreeRoot { + pub fn layout( + &self, + layout_context: &LayoutContext, + viewport: geom::Size<CSSPixel>, + ) -> FragmentTreeRoot { let initial_containing_block_size = Vec2 { inline: Length::new(viewport.width), block: Length::new(viewport.height), @@ -114,6 +119,7 @@ impl BoxTreeRoot { let dummy_tree_rank = 0; let mut absolutely_positioned_fragments = vec![]; let mut flow_children = self.0.layout( + layout_context, &initial_containing_block, dummy_tree_rank, &mut absolutely_positioned_fragments, @@ -126,7 +132,7 @@ impl BoxTreeRoot { flow_children.fragments.par_extend( absolutely_positioned_fragments .par_iter() - .map(|a| a.layout(&initial_containing_block)), + .map(|a| a.layout(layout_context, &initial_containing_block)), ); FragmentTreeRoot(flow_children.fragments) } diff --git a/components/layout_2020/fragments.rs b/components/layout_2020/fragments.rs index ceb2fdf7971..a0ea097abb6 100644 --- a/components/layout_2020/fragments.rs +++ b/components/layout_2020/fragments.rs @@ -4,11 +4,13 @@ use crate::geom::flow_relative::{Rect, Sides}; use crate::style_ext::{Direction, WritingMode}; -// use crate::text::ShapedSegment; -use servo_arc::Arc; +use gfx::text::glyph::GlyphStore; +use servo_arc::Arc as ServoArc; +use std::sync::Arc; use style::properties::ComputedValues; use style::values::computed::Length; use style::Zero; +use webrender_api::FontInstanceKey; pub(crate) enum Fragment { Box(BoxFragment), @@ -17,7 +19,7 @@ pub(crate) enum Fragment { } pub(crate) struct BoxFragment { - pub style: Arc<ComputedValues>, + pub style: ServoArc<ComputedValues>, pub children: Vec<Fragment>, /// From the containing block’s start corner…? @@ -52,9 +54,11 @@ pub(crate) struct AnonymousFragment { } pub(crate) struct TextFragment { - pub parent_style: Arc<ComputedValues>, + pub parent_style: ServoArc<ComputedValues>, pub content_rect: Rect<Length>, - // pub text: ShapedSegment, + pub ascent: Length, + pub font_key: FontInstanceKey, + pub glyphs: Vec<Arc<GlyphStore>>, } impl AnonymousFragment { diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 052cb4b0540..c0892553f35 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -7,6 +7,7 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![deny(unsafe_code)] +#![feature(exact_size_is_empty)] #[macro_use] extern crate serde; @@ -33,6 +34,7 @@ pub mod wrapper; pub use flow::{BoxTreeRoot, FragmentTreeRoot}; +use crate::context::LayoutContext; use crate::dom_traversal::{Contents, NodeExt}; use crate::flow::{BlockFormattingContext, FlowChildren}; use crate::geom::flow_relative::Vec2; @@ -87,13 +89,19 @@ impl IndependentFormattingContext { fn layout<'a>( &'a self, + layout_context: &LayoutContext, containing_block: &ContainingBlock, tree_rank: usize, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, ) -> FlowChildren { match self.as_replaced() { Ok(replaced) => match *replaced {}, - Err(ifc) => ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments), + Err(ifc) => ifc.layout( + layout_context, + containing_block, + tree_rank, + absolutely_positioned_fragments, + ), } } } @@ -101,14 +109,18 @@ impl IndependentFormattingContext { impl<'a> NonReplacedIFC<'a> { fn layout( &self, + layout_context: &LayoutContext, containing_block: &ContainingBlock, tree_rank: usize, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, ) -> FlowChildren { match self { - NonReplacedIFC::Flow(bfc) => { - bfc.layout(containing_block, tree_rank, absolutely_positioned_fragments) - }, + NonReplacedIFC::Flow(bfc) => bfc.layout( + layout_context, + containing_block, + tree_rank, + absolutely_positioned_fragments, + ), } } } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 55888fb8842..b37a5ed4a70 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.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::context::LayoutContext; use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::style_ext::{ComputedValuesExt, Direction, WritingMode}; @@ -94,6 +95,7 @@ impl AbsolutelyPositionedBox { impl<'a> AbsolutelyPositionedFragment<'a> { pub(crate) fn in_positioned_containing_block( + layout_context: &LayoutContext, absolute: &[Self], fragments: &mut Vec<Fragment>, content_rect_size: &Vec2<Length>, @@ -116,14 +118,18 @@ impl<'a> AbsolutelyPositionedFragment<'a> { fragments.push(Fragment::Anonymous(AnonymousFragment { children: absolute .par_iter() - .map(|a| a.layout(&containing_block)) + .map(|a| a.layout(layout_context, &containing_block)) .collect(), rect: padding_rect, mode, })) } - pub(crate) fn layout(&self, containing_block: &DefiniteContainingBlock) -> Fragment { + pub(crate) fn layout( + &self, + layout_context: &LayoutContext, + containing_block: &DefiniteContainingBlock, + ) -> Fragment { let style = &self.absolutely_positioned_box.style; let cbis = containing_block.size.inline; let cbbs = containing_block.size.block; @@ -269,6 +275,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> { let dummy_tree_rank = 0; let mut absolutely_positioned_fragments = vec![]; let mut flow_children = self.absolutely_positioned_box.contents.layout( + layout_context, &containing_block_for_children, dummy_tree_rank, &mut absolutely_positioned_fragments, @@ -297,6 +304,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> { }; AbsolutelyPositionedFragment::in_positioned_containing_block( + layout_context, &absolutely_positioned_fragments, &mut flow_children.fragments, &content_rect.size, diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index bf18c584231..e8fdb1cfccd 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -88,7 +88,7 @@ use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo}; use style::dom::{TDocument, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; -use style::global_style_data::GLOBAL_STYLE_DATA; +use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; use style::invalidation::element::restyle_hints::RestyleHint; use style::media_queries::{Device, MediaList, MediaType}; use style::properties::PropertyId; @@ -1087,16 +1087,29 @@ impl LayoutThread { RecalcStyle::pre_traverse(element, shared) }; - if token.should_traverse() { + let rayon_pool = STYLE_THREAD_POOL.pool(); + let rayon_pool = rayon_pool.as_ref().unwrap(); + + let box_tree = if token.should_traverse() { driver::traverse_dom(&traversal, token, None); let shared = DomTraversal::<ServoLayoutElement>::shared_context(&traversal); - let box_tree = - BoxTreeRoot::construct(shared, document.root_element().unwrap().as_node()); - let fragment_tree = box_tree.layout(Size2D::new( + let root_node = document.root_element().unwrap().as_node(); + let box_tree = rayon_pool.install(|| BoxTreeRoot::construct(shared, root_node)); + Some(box_tree) + } else { + None + }; + + layout_context = traversal.destroy(); + + if let Some(box_tree) = box_tree { + let viewport_size = Size2D::new( self.viewport_size.width.to_f32_px(), self.viewport_size.height.to_f32_px(), - )); + ); + let fragment_tree = + rayon_pool.install(|| box_tree.layout(&layout_context, viewport_size)); *self.box_tree_root.borrow_mut() = Some(box_tree); *self.fragment_tree_root.borrow_mut() = Some(fragment_tree); } @@ -1105,8 +1118,6 @@ impl LayoutThread { unsafe { element.unset_snapshot_flags() } } - layout_context = traversal.destroy(); - // GC the rule tree if some heuristics are met. unsafe { layout_context.style_context.stylist.rule_tree().maybe_gc(); diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index c44a9a06a54..855d3d4dbc8 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -113,6 +113,7 @@ utf-8 = "0.7" uuid = {version = "0.8", features = ["v4"]} xml5ever = "0.16" webdriver = "0.40" +webgpu = {path = "../webgpu"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 3ff7a044b53..5dc9e141ed5 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -134,7 +134,10 @@ DOMInterfaces = { 'XR': { 'inCompartments': ['SupportsSessionMode', 'RequestSession'], -} +}, +'GPU': { + 'inCompartments': ['RequestAdapter'], +} } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2051a1a19d8..fbd4da02d5b 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -145,6 +145,7 @@ use tendril::stream::LossyDecoder; use tendril::{StrTendril, TendrilSink}; use time::{Duration, Timespec}; use uuid::Uuid; +use webgpu::{WebGPU, WebGPUAdapter}; use webrender_api::{DocumentId, ImageKey, RenderApiSender}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; use webxr_api::SwapChainId as WebXRSwapChainId; @@ -502,6 +503,8 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId); unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); +unsafe_no_jsmanaged_fields!(WebGPU); +unsafe_no_jsmanaged_fields!(WebGPUAdapter); unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); diff --git a/components/script/dom/formdataevent.rs b/components/script/dom/formdataevent.rs index f7ebb57bbfb..c380abf217a 100644 --- a/components/script/dom/formdataevent.rs +++ b/components/script/dom/formdataevent.rs @@ -5,7 +5,7 @@ use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; use crate::dom::bindings::codegen::Bindings::FormDataEventBinding; use crate::dom::bindings::codegen::Bindings::FormDataEventBinding::FormDataEventMethods; -use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::error::Fallible; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; @@ -56,21 +56,12 @@ impl FormDataEvent { let bubbles = EventBubbles::from(init.parent.bubbles); let cancelable = EventCancelable::from(init.parent.cancelable); - let form_data = match init.formData { - Some(ref form_data) => form_data.clone(), - None => { - return Err(Error::Type( - "required member formData is undefined".to_string(), - )); - }, - }; - let event = FormDataEvent::new( &window.global(), Atom::from(type_), bubbles, cancelable, - &*form_data, + &*init.formData.clone(), ); Ok(event) diff --git a/components/script/dom/gpu.rs b/components/script/dom/gpu.rs new file mode 100644 index 00000000000..cbde108bc01 --- /dev/null +++ b/components/script/dom/gpu.rs @@ -0,0 +1,158 @@ +/* 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::compartments::InCompartment; +use crate::dom::bindings::codegen::Bindings::GPUBinding::GPURequestAdapterOptions; +use crate::dom::bindings::codegen::Bindings::GPUBinding::{self, GPUMethods, GPUPowerPreference}; +use crate::dom::bindings::error::Error; +use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; +use crate::dom::globalscope::GlobalScope; +use crate::dom::gpuadapter::GPUAdapter; +use crate::dom::promise::Promise; +use crate::task_source::TaskSource; +use dom_struct::dom_struct; +use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::router::ROUTER; +use js::jsapi::Heap; +use std::rc::Rc; +use webgpu::wgpu; +use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUResponseResult}; + +#[dom_struct] +pub struct GPU { + reflector_: Reflector, +} + +impl GPU { + pub fn new_inherited() -> GPU { + GPU { + reflector_: Reflector::new(), + } + } + + pub fn new(global: &GlobalScope) -> DomRoot<GPU> { + reflect_dom_object(Box::new(GPU::new_inherited()), global, GPUBinding::Wrap) + } + + fn wgpu_channel(&self) -> Option<WebGPU> { + self.global().as_window().webgpu_channel() + } +} + +pub trait AsyncWGPUListener { + fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>); +} + +struct WGPUResponse<T: AsyncWGPUListener + DomObject> { + trusted: TrustedPromise, + receiver: Trusted<T>, +} + +impl<T: AsyncWGPUListener + DomObject> WGPUResponse<T> { + #[allow(unrooted_must_root)] + fn response(self, response: WebGPUResponseResult) { + let promise = self.trusted.root(); + match response { + Ok(response) => self.receiver.root().handle_response(response, &promise), + Err(error) => promise.reject_error(Error::Type(format!( + "Received error from WebGPU thread: {}", + error + ))), + } + } +} + +pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>( + promise: &Rc<Promise>, + receiver: &T, +) -> IpcSender<WebGPUResponseResult> { + let (action_sender, action_receiver) = ipc::channel().unwrap(); + let (task_source, canceller) = receiver + .global() + .as_window() + .task_manager() + .dom_manipulation_task_source_with_canceller(); + let mut trusted = Some(TrustedPromise::new(promise.clone())); + let trusted_receiver = Trusted::new(receiver); + ROUTER.add_route( + action_receiver.to_opaque(), + Box::new(move |message| { + let trusted = if let Some(trusted) = trusted.take() { + trusted + } else { + error!("WebGPU callback called twice!"); + return; + }; + + let context = WGPUResponse { + trusted, + receiver: trusted_receiver.clone(), + }; + let result = task_source.queue_with_canceller( + task!(process_webgpu_task: move|| { + context.response(message.to().unwrap()); + }), + &canceller, + ); + if let Err(err) = result { + error!("Failed to queue GPU listener-task: {:?}", err); + } + }), + ); + action_sender +} + +impl GPUMethods for GPU { + // https://gpuweb.github.io/gpuweb/#dom-gpu-requestadapter + fn RequestAdapter( + &self, + options: &GPURequestAdapterOptions, + comp: InCompartment, + ) -> Rc<Promise> { + let promise = Promise::new_in_current_compartment(&self.global(), comp); + let sender = response_async(&promise, self); + let power_preference = match options.powerPreference { + Some(GPUPowerPreference::Low_power) => wgpu::PowerPreference::LowPower, + Some(GPUPowerPreference::High_performance) => wgpu::PowerPreference::HighPerformance, + None => wgpu::PowerPreference::Default, + }; + + match self.wgpu_channel() { + Some(channel) => { + channel + .0 + .send(WebGPURequest::RequestAdapter( + sender, + wgpu::RequestAdapterOptions { power_preference }, + )) + .unwrap(); + }, + None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())), + }; + promise + } +} + +impl AsyncWGPUListener for GPU { + fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) { + match response { + WebGPUResponse::RequestAdapter(name, adapter) => { + let adapter = GPUAdapter::new( + &self.global(), + DOMString::from(name), + Heap::default(), + adapter, + ); + promise.resolve_native(&adapter); + }, + response => promise.reject_error(Error::Type(format!( + "Wrong response received for GPU from WebGPU thread {:?}", + response, + ))), + } + } +} diff --git a/components/script/dom/gpuadapter.rs b/components/script/dom/gpuadapter.rs new file mode 100644 index 00000000000..ec970439e8a --- /dev/null +++ b/components/script/dom/gpuadapter.rs @@ -0,0 +1,63 @@ +/* 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::GPUAdapterBinding::{self, GPUAdapterMethods}; +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::script_runtime::JSContext as SafeJSContext; +use dom_struct::dom_struct; +use js::jsapi::{Heap, JSObject}; +use std::ptr::NonNull; +use webgpu::WebGPUAdapter; + +#[dom_struct] +pub struct GPUAdapter { + reflector_: Reflector, + name: DOMString, + #[ignore_malloc_size_of = "mozjs"] + extensions: Heap<*mut JSObject>, + adapter: WebGPUAdapter, +} + +impl GPUAdapter { + pub fn new_inherited( + name: DOMString, + extensions: Heap<*mut JSObject>, + adapter: WebGPUAdapter, + ) -> GPUAdapter { + GPUAdapter { + reflector_: Reflector::new(), + name, + extensions, + adapter, + } + } + + pub fn new( + global: &GlobalScope, + name: DOMString, + extensions: Heap<*mut JSObject>, + adapter: WebGPUAdapter, + ) -> DomRoot<GPUAdapter> { + reflect_dom_object( + Box::new(GPUAdapter::new_inherited(name, extensions, adapter)), + global, + GPUAdapterBinding::Wrap, + ) + } +} + +impl GPUAdapterMethods for GPUAdapter { + // https://gpuweb.github.io/gpuweb/#dom-gpuadapter-name + fn Name(&self) -> DOMString { + self.name.clone() + } + + // https://gpuweb.github.io/gpuweb/#dom-gpuadapter-extensions + fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> { + NonNull::new(self.extensions.get()).unwrap() + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index ef562931bee..9fbf2e0cc6e 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -315,6 +315,8 @@ pub mod gamepadbuttonlist; pub mod gamepadevent; pub mod gamepadlist; pub mod globalscope; +pub mod gpu; +pub mod gpuadapter; pub mod hashchangeevent; pub mod headers; pub mod history; diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 127883dd956..cb8fb2365cd 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::bluetooth::Bluetooth; use crate::dom::gamepadlist::GamepadList; +use crate::dom::gpu::GPU; use crate::dom::mediadevices::MediaDevices; use crate::dom::mediasession::MediaSession; use crate::dom::mimetypearray::MimeTypeArray; @@ -36,6 +37,7 @@ pub struct Navigator { gamepads: MutNullableDom<GamepadList>, permissions: MutNullableDom<Permissions>, mediasession: MutNullableDom<MediaSession>, + gpu: MutNullableDom<GPU>, } impl Navigator { @@ -51,6 +53,7 @@ impl Navigator { gamepads: Default::default(), permissions: Default::default(), mediasession: Default::default(), + gpu: Default::default(), } } @@ -205,4 +208,9 @@ impl NavigatorMethods for Navigator { MediaSession::new(window) }) } + + // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu + fn Gpu(&self) -> DomRoot<GPU> { + self.gpu.or_init(|| GPU::new(&self.global())) + } } diff --git a/components/script/dom/webidls/FormDataEvent.webidl b/components/script/dom/webidls/FormDataEvent.webidl index 5160a396081..0cb81b93962 100644 --- a/components/script/dom/webidls/FormDataEvent.webidl +++ b/components/script/dom/webidls/FormDataEvent.webidl @@ -5,10 +5,10 @@ // https://html.spec.whatwg.org/multipage/#the-formdataevent-interface [Exposed=Window] interface FormDataEvent : Event { - [Throws] constructor(DOMString type, optional FormDataEventInit eventInitDict = {}); + [Throws] constructor(DOMString type, FormDataEventInit eventInitDict); readonly attribute FormData formData; }; dictionary FormDataEventInit : EventInit { - /*required*/ FormData formData; + required FormData formData; }; diff --git a/components/script/dom/webidls/GPU.webidl b/components/script/dom/webidls/GPU.webidl new file mode 100644 index 00000000000..856c5027569 --- /dev/null +++ b/components/script/dom/webidls/GPU.webidl @@ -0,0 +1,21 @@ +/* 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/#gpu-interface +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPU { + // May reject with DOMException // TODO: DOMException("OperationError")? + Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {}); +}; + +// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions +dictionary GPURequestAdapterOptions { + GPUPowerPreference powerPreference; +}; + +// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference +enum GPUPowerPreference { + "low-power", + "high-performance" +}; diff --git a/components/script/dom/webidls/GPUAdapter.webidl b/components/script/dom/webidls/GPUAdapter.webidl new file mode 100644 index 00000000000..0c2118a5f56 --- /dev/null +++ b/components/script/dom/webidls/GPUAdapter.webidl @@ -0,0 +1,14 @@ +/* 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/#gpuadapter +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPUAdapter { + readonly attribute DOMString name; + readonly attribute object extensions; + //readonly attribute GPULimits limits; Don’t expose higher limits for now. + + // May reject with DOMException // TODO: DOMException("OperationError")? + // Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {}); +}; diff --git a/components/script/dom/webidls/Navigator.webidl b/components/script/dom/webidls/Navigator.webidl index 6b5b1e1f283..b51e2ba52f0 100644 --- a/components/script/dom/webidls/Navigator.webidl +++ b/components/script/dom/webidls/Navigator.webidl @@ -75,3 +75,8 @@ partial interface Navigator { partial interface Navigator { [Pref="dom.gamepad.enabled"] GamepadList getGamepads(); }; + +[Exposed=Window] +partial interface Navigator { + [SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu; +}; diff --git a/components/script/dom/webidls/WorkerNavigator.webidl b/components/script/dom/webidls/WorkerNavigator.webidl index 119e22ea11f..5be43960802 100644 --- a/components/script/dom/webidls/WorkerNavigator.webidl +++ b/components/script/dom/webidls/WorkerNavigator.webidl @@ -15,3 +15,8 @@ WorkerNavigator includes NavigatorLanguage; partial interface WorkerNavigator { [Pref="dom.permissions.enabled"] readonly attribute Permissions permissions; }; + +[Exposed=DedicatedWorker] +partial interface WorkerNavigator { + [SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu; +}; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 0c3a2db0899..4ae94520f1f 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -136,6 +136,7 @@ use style::str::HTML_SPACE_CHARACTERS; use style::stylesheets::CssRuleType; use style_traits::{CSSPixel, DevicePixel, ParsingMode}; use url::Position; +use webgpu::WebGPU; use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel}; use webrender_api::{DocumentId, ExternalScrollId, RenderApiSender}; use webvr_traits::WebVRMsg; @@ -267,6 +268,10 @@ pub struct Window { #[ignore_malloc_size_of = "channels are hard"] webgl_chan: Option<WebGLChan>, + #[ignore_malloc_size_of = "channels are hard"] + /// A handle for communicating messages to the WebGPU threads. + webgpu: Option<WebGPU>, + /// A handle for communicating messages to the webvr thread, if available. #[ignore_malloc_size_of = "channels are hard"] webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -462,6 +467,10 @@ impl Window { .map(|chan| WebGLCommandSender::new(chan.clone(), self.get_event_loop_waker())) } + pub fn webgpu_channel(&self) -> Option<WebGPU> { + self.webgpu.clone() + } + pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> { self.webvr_chan.clone() } @@ -2206,6 +2215,7 @@ impl Window { navigation_start: u64, navigation_start_precise: u64, webgl_chan: Option<WebGLChan>, + webgpu: Option<WebGPU>, webvr_chan: Option<IpcSender<WebVRMsg>>, webxr_registry: webxr_api::Registry, microtask_queue: Rc<MicrotaskQueue>, @@ -2285,6 +2295,7 @@ impl Window { media_query_lists: DOMTracker::new(), test_runner: Default::default(), webgl_chan, + webgpu, webvr_chan, webxr_registry, permission_state_invocation_results: Default::default(), diff --git a/components/script/dom/workernavigator.rs b/components/script/dom/workernavigator.rs index 92dfa9951e5..cc1dfee13bd 100644 --- a/components/script/dom/workernavigator.rs +++ b/components/script/dom/workernavigator.rs @@ -7,6 +7,7 @@ use crate::dom::bindings::codegen::Bindings::WorkerNavigatorBinding::WorkerNavig use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; +use crate::dom::gpu::GPU; use crate::dom::navigatorinfo; use crate::dom::permissions::Permissions; use crate::dom::workerglobalscope::WorkerGlobalScope; @@ -17,6 +18,7 @@ use dom_struct::dom_struct; pub struct WorkerNavigator { reflector_: Reflector, permissions: MutNullableDom<Permissions>, + gpu: MutNullableDom<GPU>, } impl WorkerNavigator { @@ -24,6 +26,7 @@ impl WorkerNavigator { WorkerNavigator { reflector_: Reflector::new(), permissions: Default::default(), + gpu: Default::default(), } } @@ -97,4 +100,9 @@ impl WorkerNavigatorMethods for WorkerNavigator { self.permissions .or_init(|| Permissions::new(&self.global())) } + + // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu + fn Gpu(&self) -> DomRoot<GPU> { + self.gpu.or_init(|| GPU::new(&self.global())) + } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index eb6e267c740..b69eb851f2f 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -163,6 +163,7 @@ use style::dom::OpaqueNode; use style::thread_state::{self, ThreadState}; use time::{at_utc, get_time, precise_time_ns, Timespec}; use url::Position; +use webgpu::WebGPU; use webrender_api::units::LayoutPixel; use webrender_api::{DocumentId, RenderApiSender}; use webvr_traits::{WebVREvent, WebVRMsg}; @@ -629,6 +630,9 @@ pub struct ScriptThread { /// A handle to the WebGL thread webgl_chan: Option<WebGLPipeline>, + /// A handle to the WebGPU threads + webgpu: Option<WebGPU>, + /// A handle to the webvr thread, if available webvr_chan: Option<IpcSender<WebVRMsg>>, @@ -1338,6 +1342,7 @@ impl ScriptThread { layout_to_constellation_chan: state.layout_to_constellation_chan, webgl_chan: state.webgl_chan, + webgpu: state.webgpu, webvr_chan: state.webvr_chan, webxr_registry: state.webxr_registry, @@ -3247,6 +3252,7 @@ impl ScriptThread { incomplete.navigation_start, incomplete.navigation_start_precise, self.webgl_chan.as_ref().map(|chan| chan.channel()), + self.webgpu.clone(), self.webvr_chan.clone(), self.webxr_registry.clone(), self.microtask_queue.clone(), diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 3fbdfd1f918..6d736ff3492 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -39,6 +39,7 @@ style_traits = {path = "../style_traits", features = ["servo"]} time = "0.1.12" url = "2.0" webdriver = "0.40" +webgpu = {path = "../webgpu"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]} diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index a8a19b5a40a..efa877adb17 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -60,6 +60,7 @@ use std::sync::Arc; use std::time::Duration; use style_traits::CSSPixel; use style_traits::SpeculativePainter; +use webgpu::WebGPU; use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel}; use webrender_api::{DocumentId, ExternalScrollId, ImageKey, RenderApiSender}; use webvr_traits::{WebVREvent, WebVRMsg}; @@ -656,6 +657,8 @@ pub struct InitialScriptState { pub content_process_shutdown_chan: Sender<()>, /// A channel to the WebGL thread used in this pipeline. pub webgl_chan: Option<WebGLPipeline>, + /// A channel to the WebGPU threads. + pub webgpu: Option<WebGPU>, /// A channel to the webvr thread, if available. pub webvr_chan: Option<IpcSender<WebVRMsg>>, /// The XR device registry diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 458ffb114a0..83f298fb96b 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -79,6 +79,7 @@ servo_url = {path = "../url"} sparkle = "0.1" style = {path = "../style", features = ["servo"]} style_traits = {path = "../style_traits", features = ["servo"]} +webgpu = {path = "../webgpu"} webrender = {git = "https://github.com/servo/webrender"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webrender_traits = {path = "../webrender_traits"} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index d201bc2d757..811a4a002d9 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -49,6 +49,7 @@ pub use servo_geometry; pub use servo_url; pub use style; pub use style_traits; +pub use webgpu; pub use webrender_api; pub use webrender_traits; pub use webvr; @@ -863,6 +864,8 @@ fn create_constellation( let resource_sender = public_resource_threads.sender(); + let webgpu = webgpu::WebGPU::new(); + let initial_state = InitialConstellationState { compositor_proxy, embedder_proxy, @@ -877,6 +880,7 @@ fn create_constellation( webrender_document, webrender_api_sender, webgl_threads, + webgpu, webvr_chan, webxr_registry, glplayer_threads, diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index a68b179c4c0..b8b6cbc8c34 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -63,6 +63,7 @@ ${helpers.predefined_type( "Float", "computed::Float::None", engines="gecko servo-2013 servo-2020", + servo_2020_pref="layout.2020.unimplemented", initial_specified_value="specified::Float::None", spec="https://drafts.csswg.org/css-box/#propdef-float", animation_value_type="discrete", diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index b4b2ab0598c..7e0bff6fbbe 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -11,7 +11,6 @@ ${helpers.predefined_type( "font-family", "FontFamily", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", initial_value="computed::FontFamily::serif()", animation_value_type="discrete", spec="https://drafts.csswg.org/css-fonts/#propdef-font-family", @@ -22,7 +21,6 @@ ${helpers.predefined_type( "font-style", "FontStyle", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", initial_value="computed::FontStyle::normal()", initial_specified_value="specified::FontStyle::normal()", animation_value_type="FontStyle", @@ -40,7 +38,6 @@ ${helpers.single_keyword_system( "font-variant-caps", "normal small-caps", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", extra_gecko_values="all-small-caps petite-caps all-petite-caps unicase titling-caps", gecko_constant_prefix="NS_FONT_VARIANT_CAPS", gecko_ffi_name="mFont.variantCaps", @@ -54,7 +51,6 @@ ${helpers.predefined_type( "font-weight", "FontWeight", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", initial_value="computed::FontWeight::normal()", initial_specified_value="specified::FontWeight::normal()", animation_value_type="Number", @@ -97,7 +93,6 @@ ${helpers.predefined_type( "font-stretch", "FontStretch", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", initial_value="computed::FontStretch::hundred()", initial_specified_value="specified::FontStretch::normal()", animation_value_type="Percentage", diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index 18f5c466d1a..428b40a101f 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -21,7 +21,6 @@ ${helpers.predefined_type( "LineHeight", "computed::LineHeight::normal()", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", animation_value_type="LineHeight", spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height", servo_restyle_damage="reflow" @@ -167,7 +166,7 @@ ${helpers.predefined_type( "letter-spacing", "LetterSpacing", "computed::LetterSpacing::normal()", - engines="gecko servo-2013", + engines="gecko servo-2013 servo-2020", animation_value_type="ComputedValue", spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing", servo_restyle_damage="rebuild_and_reflow", @@ -177,7 +176,7 @@ ${helpers.predefined_type( "word-spacing", "WordSpacing", "computed::WordSpacing::zero()", - engines="gecko servo-2013", + engines="gecko servo-2013 servo-2020", animation_value_type="ComputedValue", spec="https://drafts.csswg.org/css-text/#propdef-word-spacing", servo_restyle_damage="rebuild_and_reflow", @@ -360,7 +359,7 @@ ${helpers.single_keyword( ${helpers.single_keyword( "text-rendering", "auto optimizespeed optimizelegibility geometricprecision", - engines="gecko servo-2013", + engines="gecko servo-2013 servo-2020", gecko_enum_prefix="StyleTextRendering", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty", diff --git a/components/style/properties/shorthands/font.mako.rs b/components/style/properties/shorthands/font.mako.rs index e3b44d86a36..1feed113875 100644 --- a/components/style/properties/shorthands/font.mako.rs +++ b/components/style/properties/shorthands/font.mako.rs @@ -8,7 +8,6 @@ <%helpers:shorthand name="font" engines="gecko servo-2013 servo-2020" - servo_2020_pref="layout.2020.unimplemented" sub_properties=" font-style font-variant-caps diff --git a/components/webgpu/Cargo.toml b/components/webgpu/Cargo.toml new file mode 100644 index 00000000000..7581cf768bd --- /dev/null +++ b/components/webgpu/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "webgpu" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +edition = "2018" +publish = false + +[lib] +name = "webgpu" +path = "lib.rs" + +[dependencies] +embedder_traits = {path = "../embedder_traits"} +ipc-channel = "0.12" +log = "0.4" +malloc_size_of = { path = "../malloc_size_of" } +serde = "1.0" +servo_config = {path = "../config"} +wgpu-native = { version = "0.4.0", features = ["serde"] } diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs new file mode 100644 index 00000000000..5cb449c6c3c --- /dev/null +++ b/components/webgpu/lib.rs @@ -0,0 +1,153 @@ +/* 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/. */ + +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde; +#[macro_use] +pub extern crate wgpu_native as wgpu; + +use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use servo_config::pref; +use wgpu::adapter_get_info; +use wgpu::TypedId; + +#[derive(Debug, Deserialize, Serialize)] +pub enum WebGPUResponse { + RequestAdapter(String, WebGPUAdapter), + RequestDevice, +} + +pub type WebGPUResponseResult = Result<WebGPUResponse, String>; + +#[derive(Debug, Deserialize, Serialize)] +pub enum WebGPURequest { + RequestAdapter(IpcSender<WebGPUResponseResult>, wgpu::RequestAdapterOptions), + RequestDevice, + Exit(IpcSender<()>), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct WebGPU(pub IpcSender<WebGPURequest>); + +impl WebGPU { + pub fn new() -> Option<Self> { + if !pref!(dom.webgpu.enabled) { + return None; + } + let (sender, receiver) = match ipc::channel() { + Ok(sender_and_receiver) => sender_and_receiver, + Err(e) => { + warn!( + "Failed to create sender and receiciver for WGPU thread ({})", + e + ); + return None; + }, + }; + + if let Err(e) = std::thread::Builder::new() + .name("WGPU".to_owned()) + .spawn(move || { + WGPU::new(receiver).run(); + }) + { + warn!("Failed to spwan WGPU thread ({})", e); + return None; + } + Some(WebGPU(sender)) + } + + pub fn exit(&self, sender: IpcSender<()>) -> Result<(), &'static str> { + self.0 + .send(WebGPURequest::Exit(sender)) + .map_err(|_| "Failed to send Exit message") + } +} + +struct WGPU { + receiver: IpcReceiver<WebGPURequest>, + global: wgpu::Global, + adapters: Vec<WebGPUAdapter>, + // Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid + _invalid_adapters: Vec<WebGPUAdapter>, +} + +impl WGPU { + fn new(receiver: IpcReceiver<WebGPURequest>) -> Self { + WGPU { + receiver, + global: wgpu::Global::new("webgpu-native"), + adapters: Vec::new(), + _invalid_adapters: Vec::new(), + } + } + + fn deinit(self) { + self.global.delete() + } + + fn run(mut self) { + while let Ok(msg) = self.receiver.recv() { + match msg { + WebGPURequest::RequestAdapter(sender, options) => { + let adapter_id = match wgpu::request_adapter( + &self.global, + &options, + // TODO: The ids we pass here should be generated by the client + &[ + wgpu::Id::zip(0, 0, wgpu::Backend::Vulkan), + wgpu::Id::zip(0, 0, wgpu::Backend::Metal), + wgpu::Id::zip(0, 0, wgpu::Backend::Dx12), + ], + ) { + Some(id) => id, + None => { + if let Err(e) = + sender.send(Err("Failed to get webgpu adapter".to_string())) + { + warn!( + "Failed to send response to WebGPURequest::RequestAdapter ({})", + e + ) + } + return; + }, + }; + let adapter = WebGPUAdapter(adapter_id); + self.adapters.push(adapter); + let info = + gfx_select!(adapter_id => adapter_get_info(&self.global, adapter_id)); + if let Err(e) = + sender.send(Ok(WebGPUResponse::RequestAdapter(info.name, adapter))) + { + warn!( + "Failed to send response to WebGPURequest::RequestAdapter ({})", + e + ) + } + }, + WebGPURequest::RequestDevice => {}, + WebGPURequest::Exit(sender) => { + self.deinit(); + if let Err(e) = sender.send(()) { + warn!("Failed to send response to WebGPURequest::Exit ({})", e) + } + return; + }, + } + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct WebGPUAdapter(pub wgpu::AdapterId); + +impl MallocSizeOf for WebGPUAdapter { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} diff --git a/docs/ORGANIZATION.md b/docs/ORGANIZATION.md index 2ec15f28b1c..d369a0b50b3 100644 --- a/docs/ORGANIZATION.md +++ b/docs/ORGANIZATION.md @@ -54,6 +54,8 @@ * assorted utility methods and types that are commonly used throughout the project. * webdriver_server * In-process server to allow manipulating browser instances via a WebDriver client. + * webgpu + * Implementation of threads for the WebGPU API. * etc * Useful tools and scripts for developers. * mach diff --git a/python/tidy/servo_tidy/tidy.py b/python/tidy/servo_tidy/tidy.py index f14112df5da..d2840cc884c 100644 --- a/python/tidy/servo_tidy/tidy.py +++ b/python/tidy/servo_tidy/tidy.py @@ -100,6 +100,7 @@ WEBIDL_STANDARDS = [ "//webaudio.github.io", "//immersive-web.github.io/", "//github.com/immersive-web/webxr-test-api/", + "//gpuweb.github.io", # Not a URL "// This interface is entirely internal to Servo, and should not be" + " accessible to\n// web pages." diff --git a/resources/prefs.json b/resources/prefs.json index d715ffab76f..8d5cd69c407 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -26,6 +26,7 @@ "dom.testing.htmlinputelement.select_files.enabled": false, "dom.webgl.dom_to_texture.enabled": false, "dom.webgl2.enabled": false, + "dom.webgpu.enabled": false, "dom.webrtc.enabled": false, "dom.webvr.enabled": false, "dom.webvr.event_polling_interval": 500, diff --git a/servo-tidy.toml b/servo-tidy.toml index 46181a8bf54..71f9fb08e36 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -27,6 +27,7 @@ rand = [ [ignore] # Ignored packages with duplicated versions packages = [ + "arrayvec", "cgl", "cocoa", "gleam", diff --git a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini index a9e46713244..76b398963ae 100644 --- a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini +++ b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini @@ -7,7 +7,7 @@ expected: FAIL [Opening a blob URL in a new window immediately before revoking it works.] - expected: TIMEOUT + expected: FAIL [Opening a blob URL in a noopener about:blank window immediately before revoking it works.] expected: FAIL diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 3bf07accd5a..85c96a326f6 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -206661,6 +206661,30 @@ {} ] ], + "quirks/percentage-height-quirk-excludes-flex-grid-001.html": [ + [ + "quirks/percentage-height-quirk-excludes-flex-grid-001.html", + [ + [ + "/quirks/reference/percentage-height-quirk-excludes-flex-grid-001-ref.html", + "==" + ] + ], + {} + ] + ], + "quirks/percentage-height-quirk-excludes-flex-grid-002.html": [ + [ + "quirks/percentage-height-quirk-excludes-flex-grid-002.html", + [ + [ + "/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html", + "==" + ] + ], + {} + ] + ], "quirks/table-cell-width-calculation-abspos.html": [ [ "quirks/table-cell-width-calculation-abspos.html", @@ -212784,6 +212808,18 @@ ], {} ] + ], + "quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html": [ + [ + "quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html", + [ + [ + "/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-notref.html", + "!=" + ] + ], + {} + ] ] }, "support": { @@ -279057,6 +279093,12 @@ "quirks/reference/green-100px-square-no-red.html": [ [] ], + "quirks/reference/percentage-height-quirk-excludes-flex-grid-001-ref.html": [ + [] + ], + "quirks/reference/percentage-height-quirk-excludes-flex-grid-002-notref.html": [ + [] + ], "quirks/reference/table-cell-width-calculation-abspos-ref.html": [ [] ], @@ -657627,7 +657669,7 @@ "support" ], "html/semantics/forms/form-submission-0/form-submission-algorithm.html": [ - "df39b57353c67ebb02014865f28d739bbf24c690", + "2d5ac276374370dd594d3d8f98c1b85e8186eb26", "testharness" ], "html/semantics/forms/form-submission-0/getactionurl.html": [ @@ -680954,10 +680996,30 @@ "e56a03b4b41b72edca91ff261e766fc9d2cc5426", "testharness" ], + "quirks/percentage-height-quirk-excludes-flex-grid-001.html": [ + "cb0f772b1fa2fed26992f288cc345e7ab418d919", + "reftest" + ], + "quirks/percentage-height-quirk-excludes-flex-grid-002.html": [ + "88df89d0932e8f347ffad8faa4e5da9dc2e71b56", + "reftest" + ], "quirks/reference/green-100px-square-no-red.html": [ "159d9a52a01a0b328680a530603cb496ab2d5fcf", "support" ], + "quirks/reference/percentage-height-quirk-excludes-flex-grid-001-ref.html": [ + "29f8e26a67f27e9ae250e464c05a8f3af1e0b9a5", + "support" + ], + "quirks/reference/percentage-height-quirk-excludes-flex-grid-002-notref.html": [ + "19aa243a0045f4378b55a00dd3b2431fc9a9ec23", + "support" + ], + "quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html": [ + "c63bc0efa85f59eb496875072970016cf77d3c9d", + "reftest_node" + ], "quirks/reference/table-cell-width-calculation-abspos-ref.html": [ "41d2203b4a08323a2d6b9894f1ad133e35130265", "support" diff --git a/tests/wpt/metadata/css/css-transforms/animation/perspective-interpolation.html.ini b/tests/wpt/metadata/css/css-transforms/animation/perspective-interpolation.html.ini index 1193e3dfa5c..03f2f3fe9d1 100644 --- a/tests/wpt/metadata/css/css-transforms/animation/perspective-interpolation.html.ini +++ b/tests/wpt/metadata/css/css-transforms/animation/perspective-interpolation.html.ini @@ -1,5 +1,5 @@ [perspective-interpolation.html] - expected: ERROR + expected: CRASH [ perspective interpolation] expected: FAIL diff --git a/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini b/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini index c364dd10b5c..668c3f52a5b 100644 --- a/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini +++ b/tests/wpt/metadata/css/cssom-view/elementFromPoint-list-001.html.ini @@ -14,6 +14,3 @@ [<li>Outside 3</li>] expected: FAIL - [<li>Inside 1</li>] - expected: FAIL - diff --git a/tests/wpt/metadata/encoding/single-byte-decoder.html.ini b/tests/wpt/metadata/encoding/single-byte-decoder.html.ini index 3d135f3bd66..939a36eb9d9 100644 --- a/tests/wpt/metadata/encoding/single-byte-decoder.html.ini +++ b/tests/wpt/metadata/encoding/single-byte-decoder.html.ini @@ -2,7 +2,6 @@ type: testharness [single-byte-decoder.html?document] - expected: TIMEOUT [ISO-8859-4: iso_8859-4:1988 (document.characterSet and document.inputEncoding)] expected: FAIL diff --git a/tests/wpt/metadata/fetch/content-type/response.window.js.ini b/tests/wpt/metadata/fetch/content-type/response.window.js.ini index 284ea0dcf02..9abfe827b60 100644 --- a/tests/wpt/metadata/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/response.window.js.ini @@ -312,24 +312,18 @@ [<iframe>: combined response Content-Type: */* text/html] expected: FAIL - [<iframe>: combined response Content-Type: text/html */*] - expected: FAIL - [<iframe>: separate response Content-Type: text/html;" text/plain] expected: FAIL - [<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html] - expected: FAIL - - [<iframe>: separate response Content-Type: text/html */*;charset=gbk] + [<iframe>: separate response Content-Type: text/plain */*] expected: FAIL - [<iframe>: separate response Content-Type: text/html */*] + [<iframe>: combined response Content-Type: text/html */*;charset=gbk] expected: FAIL - [<iframe>: separate response Content-Type: text/plain */*] + [<iframe>: combined response Content-Type: text/html;" \\" text/plain] expected: FAIL - [<iframe>: separate response Content-Type: text/html;" \\" text/plain] + [<iframe>: combined response Content-Type: text/html;x=" text/plain] expected: FAIL diff --git a/tests/wpt/metadata/fetch/content-type/script.window.js.ini b/tests/wpt/metadata/fetch/content-type/script.window.js.ini index d2df9b78483..e67f0406fc3 100644 --- a/tests/wpt/metadata/fetch/content-type/script.window.js.ini +++ b/tests/wpt/metadata/fetch/content-type/script.window.js.ini @@ -53,6 +53,3 @@ [combined text/javascript ] expected: FAIL - [separate text/javascript x/x] - expected: FAIL - diff --git a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini index b7052af5b5c..87c807a49ff 100644 --- a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini +++ b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini @@ -11,6 +11,3 @@ [X-Content-Type-Options%3A%20nosniff%0C] expected: FAIL - [X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini deleted file mode 100644 index dc2e45516de..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[traverse_the_history_5.html] - [Multiple history traversals, last would be aborted] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini deleted file mode 100644 index 16fa2c5cfc1..00000000000 --- a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[creating_browsing_context_test_01.html] - [first argument: absolute url] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html.ini index bf50d59df41..e02f179ec25 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-innerwidth-innerheight.html.ini @@ -1,5 +1,24 @@ [open-features-negative-innerwidth-innerheight.html] type: testharness + expected: TIMEOUT [HTML: window.open `features`: negative values for legacy `innerwidth`, `innerheight`] expected: FAIL + [features "innerheight=-404.5" should NOT set "height=404"] + expected: TIMEOUT + + [features "innerwidth=-404.5" should NOT set "width=404"] + expected: TIMEOUT + + [features "innerwidth=-404" should NOT set "width=404"] + expected: TIMEOUT + + [features "innerheight=-404e1" should NOT set "height=404"] + expected: TIMEOUT + + [features "innerheight=-404" should NOT set "height=404"] + expected: TIMEOUT + + [features "innerwidth=-404e1" should NOT set "width=404"] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html.ini index ad8840fbb68..940516ddd33 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-top-left.html.ini @@ -1,5 +1,24 @@ [open-features-negative-top-left.html] type: testharness + expected: TIMEOUT [HTML: window.open `features`: negative values for `top`, `left`] expected: FAIL + [features "top=-204" should NOT set "top=204"] + expected: TIMEOUT + + [features "top=-204.5" should NOT set "top=204"] + expected: TIMEOUT + + [features "left=-204" should NOT set "left=204"] + expected: TIMEOUT + + [features "top=-0" should NOT set "top=204"] + expected: TIMEOUT + + [features "left=-204.5" should NOT set "left=204"] + expected: TIMEOUT + + [features "left=-0" should NOT set "left=204"] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html.ini index 9027336b453..d1ed9088b2b 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-negative-width-height.html.ini @@ -1,24 +1,5 @@ [open-features-negative-width-height.html] type: testharness - expected: TIMEOUT [HTML: window.open `features`: negative values for `width`, `height`] expected: FAIL - [features "height=-404" should NOT set "height=404"] - expected: TIMEOUT - - [features "height=-404e1" should NOT set "height=404"] - expected: TIMEOUT - - [features "height=-404.5" should NOT set "height=404"] - expected: TIMEOUT - - [features "width=-404" should NOT set "width=404"] - expected: TIMEOUT - - [features "width=-404e1" should NOT set "width=404"] - expected: TIMEOUT - - [features "width=-404.5" should NOT set "width=404"] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html.ini index 10f617db69e..8540f53d8d6 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-top.html.ini @@ -1,32 +1,42 @@ [open-features-non-integer-top.html] type: testharness + expected: TIMEOUT [HTML: window.open `features`: non-integer values for feature `top`] expected: FAIL [features "top=105/5" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105*3" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105LLl" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105e-1" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105.32" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105e1" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105 " should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105^4" should set "top=105"] - expected: FAIL + expected: TIMEOUT [features "top=105.5" should set "top=105"] - expected: FAIL + expected: TIMEOUT + + [features "top=/104" should NOT set "top=104"] + expected: TIMEOUT + + [features "top=_104" should NOT set "top=104"] + expected: TIMEOUT + + [features "top=L104" should NOT set "top=104"] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html.ini index 28f93ee71b5..9d841e61bc0 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-width.html.ini @@ -1,32 +1,48 @@ [open-features-non-integer-width.html] type: testharness + expected: TIMEOUT [HTML: window.open `features`: non-integer values for feature `width`] expected: FAIL [features "width=405^4" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405.5" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405e1" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405 " should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405.32" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405LLl" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405*3" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405e-1" should set "width=405"] - expected: FAIL + expected: TIMEOUT [features "width=405/5" should set "width=405"] - expected: FAIL + expected: TIMEOUT + + [top=0,left=0: absence of feature "width" should be treated same as "width=0"] + expected: TIMEOUT + + [features "width=_404" should NOT set "width=404"] + expected: TIMEOUT + + [top=0,left=0,height=401,: absence of feature "width" should be treated same as "width=0"] + expected: TIMEOUT + + [features "width=/404" should NOT set "width=404"] + expected: TIMEOUT + + [features "width=L404" should NOT set "width=404"] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini b/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini index 2532dceabac..fd369192a02 100644 --- a/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini +++ b/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini @@ -1,5 +1,5 @@ [embedded-opener-remove-frame.html] - expected: CRASH + expected: TIMEOUT [opener and "removed" embedded documents] expected: FAIL @@ -7,5 +7,5 @@ expected: FAIL [opener of discarded auxiliary browsing context] - expected: FAIL + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/dom/idlharness.https.html.ini b/tests/wpt/metadata/html/dom/idlharness.https.html.ini index 5459bedf48d..692dc849677 100644 --- a/tests/wpt/metadata/html/dom/idlharness.https.html.ini +++ b/tests/wpt/metadata/html/dom/idlharness.https.html.ini @@ -1409,9 +1409,6 @@ [SubmitEvent interface: existence and properties of interface prototype object's "constructor" property] expected: FAIL - [FormDataEvent interface object length] - expected: FAIL - [idlharness.https.html?include=(Document|Window)] [Document interface: documentWithHandlers must inherit property "queryCommandEnabled(DOMString)" with the proper type] diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini index 9df1ac56f2a..963d4cd20ef 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini @@ -1,6 +1,6 @@ [iframe_sandbox_popups_nonescaping-1.html] type: testharness - expected: TIMEOUT + expected: CRASH [Check that popups from a sandboxed iframe do not escape the sandbox] expected: NOTRUN diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini new file mode 100644 index 00000000000..8cc42056d34 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/non-active-document.html.ini @@ -0,0 +1,10 @@ +[non-active-document.html] + [DOMParser] + expected: FAIL + + [createHTMLDocument] + expected: FAIL + + [<template>] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini index df89cd21511..941d0dee0c8 100644 --- a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini @@ -1,5 +1,5 @@ [form-double-submit-3.html] expected: ERROR [<button> should have the same double-submit protection as <input type=submit>] - expected: FAIL + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini index dce74c6dd71..47a7bbb7975 100644 --- a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit.html.ini @@ -1,5 +1,5 @@ [form-double-submit.html] expected: ERROR [default submit action should supersede onclick submit()] - expected: FAIL + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini new file mode 100644 index 00000000000..178680e5d14 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/script-onerror-insertion-point-2.html.ini @@ -0,0 +1,2 @@ +[script-onerror-insertion-point-2.html] + expected: TIMEOUT diff --git a/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html.ini b/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html.ini new file mode 100644 index 00000000000..1e9b11d3487 --- /dev/null +++ b/tests/wpt/metadata/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html.ini @@ -0,0 +1,5 @@ +[promise-rejection-events-onerror.html] + expected: TIMEOUT + [Throwing inside an unhandledrejection handler invokes the error handler.] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/quirks/percentage-height-quirk-excludes-flex-grid-002.html.ini b/tests/wpt/metadata/quirks/percentage-height-quirk-excludes-flex-grid-002.html.ini new file mode 100644 index 00000000000..cb37c253dd0 --- /dev/null +++ b/tests/wpt/metadata/quirks/percentage-height-quirk-excludes-flex-grid-002.html.ini @@ -0,0 +1,2 @@ +[percentage-height-quirk-excludes-flex-grid-002.html] + expected: FAIL diff --git a/tests/wpt/metadata/webmessaging/with-ports/018.html.ini b/tests/wpt/metadata/webmessaging/with-ports/018.html.ini new file mode 100644 index 00000000000..663a1f8fa30 --- /dev/null +++ b/tests/wpt/metadata/webmessaging/with-ports/018.html.ini @@ -0,0 +1,5 @@ +[018.html] + expected: TIMEOUT + [origin of the script that invoked the method, javascript:] + expected: TIMEOUT + diff --git a/tests/wpt/metadata/webmessaging/without-ports/017.html.ini b/tests/wpt/metadata/webmessaging/without-ports/017.html.ini new file mode 100644 index 00000000000..064cf47545b --- /dev/null +++ b/tests/wpt/metadata/webmessaging/without-ports/017.html.ini @@ -0,0 +1,5 @@ +[017.html] + expected: TIMEOUT + [origin of the script that invoked the method, about:blank] + expected: TIMEOUT + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-submission-algorithm.html b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-submission-algorithm.html index df39b57353c..2d5ac276374 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-submission-algorithm.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-submission-algorithm.html @@ -18,6 +18,21 @@ test(() => { assert_equals(counter, 2); }, 'If constructing entry list flag of form is true, then return'); +test(() => { + let form = populateForm('<input><input type=submit>'); + let submitter1 = form.querySelector('input[type=submit]'); + let valid = form.elements[0]; + let counter = 0; + valid.oninvalid = () => { + ++counter; + }; + form.onsubmit = () => { + valid.required = true; + submitter1.dispatchEvent(new MouseEvent("click")); + }; + submitter1.dispatchEvent(new MouseEvent("click")); + assert_equals(counter, 0); +}, "If firing submission events flag of form is true, then return"); test(() => { let form = populateForm('<input required><input type=submit><button type=submit></button>'); diff --git a/tests/wpt/web-platform-tests/quirks/percentage-height-quirk-excludes-flex-grid-001.html b/tests/wpt/web-platform-tests/quirks/percentage-height-quirk-excludes-flex-grid-001.html new file mode 100644 index 00000000000..cb0f772b1fa --- /dev/null +++ b/tests/wpt/web-platform-tests/quirks/percentage-height-quirk-excludes-flex-grid-001.html @@ -0,0 +1,78 @@ +<html> +<head> + <meta charset="utf-8"> + <title>Test: Percent height quirk does not traverse flex/grid containers</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" href="https://mozilla.org" title="Mozilla"> + <link rel="help" href="https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk"> + <link rel="match" href="reference/percentage-height-quirk-excludes-flex-grid-001-ref.html"> + <meta name="assert" content="This quirk is specific to block boxes and table wrapper boxes; if it hits another type of box, it doesn't traverse further. So this file should look the same whether in quirks or standards mode."> + <style> + .fixed-height-outer { + height: 80px; + border: 1px solid gray; + margin-bottom: 5px; + } + + .row-flex { + display: flex; + flex-direction: row + } + + .column-flex { + display: flex; + flex-direction: column + } + + .grid { + display: grid; + } + + .container { + border: 3px solid black; + } + + .pct { + height: 75%; + min-height: 10px; + width: 50px; + display: inline-block; + vertical-align: top; + background: purple; + } + .px { + height: 50px; + width: 50px; + display: inline-block; + vertical-align: top; + background: blue + } + </style> +</head> +<body> + <div class="fixed-height-outer"> + <div class="container column-flex"> + <div> + <div class="pct"></div> + <div class="px"></div> + </div> + </div> + </div> + <div class="fixed-height-outer"> + <div class="container row-flex"> + <div> + <div class="pct"></div> + <div class="px"></div> + </div> + </div> + </div> + <div class="fixed-height-outer"> + <div class="container grid"> + <div> + <div class="pct"></div> + <div class="px"></div> + </div> + </div> + </div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/quirks/percentage-height-quirk-excludes-flex-grid-002.html b/tests/wpt/web-platform-tests/quirks/percentage-height-quirk-excludes-flex-grid-002.html new file mode 100644 index 00000000000..88df89d0932 --- /dev/null +++ b/tests/wpt/web-platform-tests/quirks/percentage-height-quirk-excludes-flex-grid-002.html @@ -0,0 +1,56 @@ +<html> +<head> + <meta charset="utf-8"> + <title>Test: Percent height quirk applies for percent heights on flex/grid containers</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" href="https://mozilla.org" title="Mozilla"> + <link rel="help" href="https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk"> + <link rel="match" href="reference/percentage-height-quirk-excludes-flex-grid-002-ref.html"> + <meta name="assert" content="This quirk only starts differentiating by box-type when looking at the containing block of the percent-height thing. So, the quirk applies to percent-heights on flex/grid containers, when the ancestors are all blocks up to the nearest definite height."> + <style> + .fixed-height-outer { + height: 80px; + border: 1px solid gray; + margin-bottom: 5px; + } + + .row-flex { + display: flex; + flex-direction: row + } + + .column-flex { + display: flex; + flex-direction: column + } + + .grid { + display: grid; + } + + .pct { + height: 75%; + min-height: 10px; + width: 50px; + background: purple; + } + </style> +</head> +<body> + <div class="fixed-height-outer"> + <div> + <div class="column-flex pct"></div> + </div> + </div> + <div class="fixed-height-outer"> + <div> + <div class="row-flex pct"></div> + </div> + </div> + <div class="fixed-height-outer"> + <div> + <div class="grid pct"></div> + </div> + </div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-001-ref.html b/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-001-ref.html new file mode 100644 index 00000000000..29f8e26a67f --- /dev/null +++ b/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-001-ref.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Reference: Percent height quirk does not traverse flex/grid containers</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" href="https://mozilla.org" title="Mozilla"> + <style> + .fixed-height-outer { + height: 80px; + border: 1px solid gray; + margin-bottom: 5px; + } + + .row-flex { + display: flex; + flex-direction: row + } + + .column-flex { + display: flex; + flex-direction: column + } + + .grid { + display: grid; + } + + .container { + border: 3px solid black; + } + + .pct { + height: 75%; + min-height: 10px; + width: 50px; + display: inline-block; + vertical-align: top; + background: purple; + } + .px { + height: 50px; + width: 50px; + display: inline-block; + vertical-align: top; + background: blue + } + </style> +</head> +<body> + <div class="fixed-height-outer"> + <div class="container column-flex"> + <div> + <div class="pct"></div> + <div class="px"></div> + </div> + </div> + </div> + <div class="fixed-height-outer"> + <div class="container row-flex"> + <div> + <div class="pct"></div> + <div class="px"></div> + </div> + </div> + </div> + <div class="fixed-height-outer"> + <div class="container grid"> + <div> + <div class="pct"></div> + <div class="px"></div> + </div> + </div> + </div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-notref.html b/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-notref.html new file mode 100644 index 00000000000..19aa243a004 --- /dev/null +++ b/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-notref.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Not-reference case: Percent height quirk applies for percent heights on flex/grid containers</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" href="https://mozilla.org" title="Mozilla"> + <style> + .fixed-height-outer { + height: 80px; + border: 1px solid gray; + margin-bottom: 5px; + } + + .row-flex { + display: flex; + flex-direction: row + } + + .column-flex { + display: flex; + flex-direction: column + } + + .grid { + display: grid; + } + + .pct { + height: 75%; + min-height: 10px; + width: 50px; + background: purple; + } + </style> +</head> +<body> + <div class="fixed-height-outer"> + <div> + <div class="column-flex pct"></div> + </div> + </div> + <div class="fixed-height-outer"> + <div> + <div class="row-flex pct"></div> + </div> + </div> + <div class="fixed-height-outer"> + <div> + <div class="grid pct"></div> + </div> + </div> +</body> +</html> diff --git a/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html b/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html new file mode 100644 index 00000000000..c63bc0efa85 --- /dev/null +++ b/tests/wpt/web-platform-tests/quirks/reference/percentage-height-quirk-excludes-flex-grid-002-ref.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Reference case: Percent height quirk applies for percent heights on flex/grid containers</title> + <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"> + <link rel="author" href="https://mozilla.org" title="Mozilla"> + <link rel="mismatch" href="percentage-height-quirk-excludes-flex-grid-002-notref.html"> + <style> + .fixed-height-outer { + height: 80px; + border: 1px solid gray; + margin-bottom: 5px; + } + + .row-flex { + display: flex; + flex-direction: row + } + + .column-flex { + display: flex; + flex-direction: column + } + + .grid { + display: grid; + } + + .pct { + height: 75%; + min-height: 10px; + width: 50px; + background: purple; + } + </style> +</head> +<body> + <div class="fixed-height-outer"> + <div class="column-flex pct"></div> + </div> + <div class="fixed-height-outer"> + <div class="row-flex pct"></div> + </div> + <div class="fixed-height-outer"> + <div class="grid pct"></div> + </div> +</body> +</html> |