diff options
81 files changed, 926 insertions, 502 deletions
diff --git a/Cargo.lock b/Cargo.lock index 2ef3a70babd..59001b76b45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a9f2b517b96b19d8f91c1ff5b1cf498e688850b32eae5d58e02d15c4d4fdc0c" +checksum = "1052e1c3b8d4d80eb84a8b94f0a1498797b5fb96314c001156a1c761940ef4ec" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -755,6 +755,7 @@ dependencies = [ name = "compositing" version = "0.0.1" dependencies = [ + "app_units", "canvas", "crossbeam-channel", "embedder_traits", @@ -1637,9 +1638,12 @@ checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +dependencies = [ + "once_cell", +] [[package]] name = "futures-util" @@ -1892,10 +1896,12 @@ dependencies = [ name = "gfx_traits" version = "0.0.1" dependencies = [ + "app_units", "malloc_size_of", "malloc_size_of_derive", "range", "serde", + "webrender_api", ] [[package]] @@ -3018,6 +3024,7 @@ dependencies = [ name = "libservo" version = "0.0.1" dependencies = [ + "app_units", "background_hang_monitor", "bluetooth", "bluetooth_traits", @@ -3034,6 +3041,7 @@ dependencies = [ "euclid", "gaol", "gfx", + "gfx_traits", "gleam 0.11.0", "gstreamer", "ipc-channel", @@ -3606,6 +3614,7 @@ dependencies = [ "pixels", "serde", "servo_arc", + "servo_rand", "servo_url", "std_test_override", "time", @@ -3616,12 +3625,9 @@ dependencies = [ [[package]] name = "new_debug_unreachable" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4" -dependencies = [ - "unreachable", -] +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nix" @@ -3758,6 +3764,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" [[package]] +name = "once_cell" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" + +[[package]] name = "opaque-debug" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3928,7 +3940,7 @@ dependencies = [ [[package]] name = "peek-poke" version = "0.2.0" -source = "git+https://github.com/servo/webrender#01082a9091ab98c392af8934d04271eb1dd546df" +source = "git+https://github.com/servo/webrender#de3999583ab20aad7c57ea35a3e0394ed45be627" dependencies = [ "euclid", "peek-poke-derive 0.2.1 (git+https://github.com/servo/webrender)", @@ -3946,7 +3958,7 @@ dependencies = [ [[package]] name = "peek-poke-derive" version = "0.2.1" -source = "git+https://github.com/servo/webrender#01082a9091ab98c392af8934d04271eb1dd546df" +source = "git+https://github.com/servo/webrender#de3999583ab20aad7c57ea35a3e0394ed45be627" dependencies = [ "proc-macro2 1.0.17", "quote 1.0.2", @@ -4413,15 +4425,6 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "ron" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399" -dependencies = [ - "serde", -] - -[[package]] -name = "ron" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5" @@ -6401,7 +6404,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.61.0" -source = "git+https://github.com/servo/webrender#01082a9091ab98c392af8934d04271eb1dd546df" +source = "git+https://github.com/servo/webrender#de3999583ab20aad7c57ea35a3e0394ed45be627" dependencies = [ "base64 0.10.1", "bincode", @@ -6427,7 +6430,7 @@ dependencies = [ "num-traits", "plane-split", "rayon", - "ron 0.1.7", + "ron", "serde", "serde_json", "smallvec 1.3.0", @@ -6443,7 +6446,7 @@ dependencies = [ [[package]] name = "webrender_api" version = "0.61.0" -source = "git+https://github.com/servo/webrender#01082a9091ab98c392af8934d04271eb1dd546df" +source = "git+https://github.com/servo/webrender#de3999583ab20aad7c57ea35a3e0394ed45be627" dependencies = [ "app_units", "bitflags", @@ -6464,7 +6467,7 @@ dependencies = [ [[package]] name = "webrender_build" version = "0.0.1" -source = "git+https://github.com/servo/webrender#01082a9091ab98c392af8934d04271eb1dd546df" +source = "git+https://github.com/servo/webrender#de3999583ab20aad7c57ea35a3e0394ed45be627" dependencies = [ "bitflags", "lazy_static", @@ -6544,7 +6547,7 @@ dependencies = [ "naga", "parking_lot 0.10.2", "peek-poke 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ron 0.5.1", + "ron", "serde", "smallvec 1.3.0", "spirv_headers", @@ -6644,7 +6647,7 @@ dependencies = [ [[package]] name = "wr_malloc_size_of" version = "0.0.1" -source = "git+https://github.com/servo/webrender#01082a9091ab98c392af8934d04271eb1dd546df" +source = "git+https://github.com/servo/webrender#de3999583ab20aad7c57ea35a3e0394ed45be627" dependencies = [ "app_units", "euclid", diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 9c3aae1d0be..1a4d1ccfc98 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -2,7 +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::canvas_paint_thread::AntialiasMode; +use crate::canvas_paint_thread::{AntialiasMode, ImageUpdate, WebrenderApi}; use crate::raqote_backend::Repetition; use canvas_traits::canvas::*; use cssparser::RGBA; @@ -13,7 +13,6 @@ use num_traits::ToPrimitive; use std::marker::PhantomData; use std::mem; use std::sync::Arc; -use webrender::api::DirtyRect; use webrender_api::units::RectExt as RectExt_; /// The canvas data stores a state machine for the current status of @@ -367,8 +366,7 @@ pub struct CanvasData<'a> { path_state: Option<PathState>, state: CanvasPaintState<'a>, saved_states: Vec<CanvasPaintState<'a>>, - webrender_api: webrender_api::RenderApi, - webrender_doc: webrender_api::DocumentId, + webrender_api: Box<dyn WebrenderApi>, image_key: Option<webrender_api::ImageKey>, /// An old webrender image key that can be deleted when the next epoch ends. old_image_key: Option<webrender_api::ImageKey>, @@ -384,22 +382,19 @@ fn create_backend() -> Box<dyn Backend> { impl<'a> CanvasData<'a> { pub fn new( size: Size2D<u64>, - webrender_api_sender: webrender_api::RenderApiSender, - webrender_doc: webrender_api::DocumentId, + webrender_api: Box<dyn WebrenderApi>, antialias: AntialiasMode, canvas_id: CanvasId, ) -> CanvasData<'a> { let backend = create_backend(); let draw_target = backend.create_drawtarget(size); - let webrender_api = webrender_api_sender.create_api(); CanvasData { backend, drawtarget: draw_target, path_state: None, state: CanvasPaintState::new(antialias), saved_states: vec![], - webrender_api: webrender_api, - webrender_doc, + webrender_api, image_key: None, old_image_key: None, very_old_image_key: None, @@ -979,27 +974,28 @@ impl<'a> CanvasData<'a> { let data = self.drawtarget.snapshot_data_owned(); let data = webrender_api::ImageData::Raw(Arc::new(data)); - let mut txn = webrender_api::Transaction::new(); + let mut updates = vec![]; match self.image_key { Some(image_key) => { debug!("Updating image {:?}.", image_key); - txn.update_image(image_key, descriptor, data, &DirtyRect::All); + updates.push(ImageUpdate::Update(image_key, descriptor, data)); }, None => { - self.image_key = Some(self.webrender_api.generate_image_key()); + let key = self.webrender_api.generate_key(); + updates.push(ImageUpdate::Add(key, descriptor, data)); + self.image_key = Some(key); debug!("New image {:?}.", self.image_key); - txn.add_image(self.image_key.unwrap(), descriptor, data, None); }, } if let Some(image_key) = mem::replace(&mut self.very_old_image_key, self.old_image_key.take()) { - txn.delete_image(image_key); + updates.push(ImageUpdate::Delete(image_key)); } - self.webrender_api.send_transaction(self.webrender_doc, txn); + self.webrender_api.update_images(updates); let data = CanvasImageData { image_key: self.image_key.unwrap(), @@ -1110,16 +1106,15 @@ impl<'a> CanvasData<'a> { impl<'a> Drop for CanvasData<'a> { fn drop(&mut self) { - let mut txn = webrender_api::Transaction::new(); - + let mut updates = vec![]; if let Some(image_key) = self.old_image_key.take() { - txn.delete_image(image_key); + updates.push(ImageUpdate::Delete(image_key)); } if let Some(image_key) = self.very_old_image_key.take() { - txn.delete_image(image_key); + updates.push(ImageUpdate::Delete(image_key)); } - self.webrender_api.send_transaction(self.webrender_doc, txn); + self.webrender_api.update_images(updates); } } diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index f73d8f7b9a8..6832a5cddc8 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -12,35 +12,52 @@ use ipc_channel::router::ROUTER; use std::borrow::ToOwned; use std::collections::HashMap; use std::thread; +use webrender_api::{ImageData, ImageDescriptor, ImageKey}; pub enum AntialiasMode { Default, None, } +pub enum ImageUpdate { + Add(ImageKey, ImageDescriptor, ImageData), + Update(ImageKey, ImageDescriptor, ImageData), + Delete(ImageKey), +} + +pub trait WebrenderApi { + fn generate_key(&self) -> webrender_api::ImageKey; + fn update_images(&self, updates: Vec<ImageUpdate>); + fn clone(&self) -> Box<dyn WebrenderApi>; +} + pub struct CanvasPaintThread<'a> { canvases: HashMap<CanvasId, CanvasData<'a>>, next_canvas_id: CanvasId, + webrender_api: Box<dyn WebrenderApi>, } impl<'a> CanvasPaintThread<'a> { - fn new() -> CanvasPaintThread<'a> { + fn new(webrender_api: Box<dyn WebrenderApi>) -> CanvasPaintThread<'a> { CanvasPaintThread { canvases: HashMap::new(), next_canvas_id: CanvasId(0), + webrender_api, } } /// Creates a new `CanvasPaintThread` and returns an `IpcSender` to /// communicate with it. - pub fn start() -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) { + pub fn start( + webrender_api: Box<dyn WebrenderApi + Send>, + ) -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) { let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap(); let msg_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_receiver); let (create_sender, create_receiver) = unbounded(); thread::Builder::new() .name("CanvasThread".to_owned()) .spawn(move || { - let mut canvas_paint_thread = CanvasPaintThread::new(); + let mut canvas_paint_thread = CanvasPaintThread::new(webrender_api); loop { select! { recv(msg_receiver) -> msg => { @@ -74,16 +91,9 @@ impl<'a> CanvasPaintThread<'a> { Ok(ConstellationCanvasMsg::Create { id_sender: creator, size, - webrender_sender: webrenderer_api_sender, - webrender_doc, antialias }) => { - let canvas_id = canvas_paint_thread.create_canvas( - size, - webrenderer_api_sender, - webrender_doc, - antialias, - ); + let canvas_id = canvas_paint_thread.create_canvas(size, antialias); creator.send(canvas_id).unwrap(); }, Ok(ConstellationCanvasMsg::Exit) => break, @@ -101,13 +111,7 @@ impl<'a> CanvasPaintThread<'a> { (create_sender, ipc_sender) } - pub fn create_canvas( - &mut self, - size: Size2D<u64>, - webrender_api_sender: webrender_api::RenderApiSender, - webrender_doc: webrender_api::DocumentId, - antialias: bool, - ) -> CanvasId { + pub fn create_canvas(&mut self, size: Size2D<u64>, antialias: bool) -> CanvasId { let antialias = if antialias { AntialiasMode::Default } else { @@ -119,8 +123,7 @@ impl<'a> CanvasPaintThread<'a> { let canvas_data = CanvasData::new( size, - webrender_api_sender, - webrender_doc, + self.webrender_api.clone(), antialias, canvas_id.clone(), ); diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 9b7b4ed4683..0d8bc69cb77 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -655,7 +655,7 @@ impl WebGLThread { ); let image_key = Self::create_wr_external_image( - &self.webrender_api, + &mut self.webrender_api, self.webrender_doc, size.to_i32(), has_alpha, @@ -718,7 +718,7 @@ impl WebGLThread { .contains(ContextAttributeFlags::ALPHA); let texture_target = current_wr_texture_target(&self.device); Self::update_wr_external_image( - &self.webrender_api, + &mut self.webrender_api, self.webrender_doc, size.to_i32(), has_alpha, @@ -1021,7 +1021,7 @@ impl WebGLThread { /// Creates a `webrender_api::ImageKey` that uses shared textures. fn create_wr_external_image( - webrender_api: &webrender_api::RenderApi, + webrender_api: &mut webrender_api::RenderApi, webrender_doc: webrender_api::DocumentId, size: Size2D<i32>, alpha: bool, @@ -1041,7 +1041,7 @@ impl WebGLThread { /// Updates a `webrender_api::ImageKey` that uses shared textures. fn update_wr_external_image( - webrender_api: &webrender_api::RenderApi, + webrender_api: &mut webrender_api::RenderApi, webrender_doc: webrender_api::DocumentId, size: Size2D<i32>, alpha: bool, diff --git a/components/canvas_traits/lib.rs b/components/canvas_traits/lib.rs index ec510e6281d..467eb432e0f 100644 --- a/components/canvas_traits/lib.rs +++ b/components/canvas_traits/lib.rs @@ -26,8 +26,6 @@ pub enum ConstellationCanvasMsg { Create { id_sender: Sender<CanvasId>, size: Size2D<u64>, - webrender_sender: webrender_api::RenderApiSender, - webrender_doc: webrender_api::DocumentId, antialias: bool, }, Exit, diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index 027d16233bf..97419f37752 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -16,6 +16,7 @@ default = [] gl = ["gleam", "pixels"] [dependencies] +app_units = "0.7" canvas = { path = "../canvas" } crossbeam-channel = "0.4" embedder_traits = { path = "../embedder_traits" } diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index c3c545af4bb..f1f0149ec6b 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -3,7 +3,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::compositor_thread::CompositorReceiver; -use crate::compositor_thread::{InitialCompositorState, Msg}; +use crate::compositor_thread::{ + InitialCompositorState, Msg, WebrenderCanvasMsg, WebrenderFontMsg, WebrenderMsg, +}; #[cfg(feature = "gl")] use crate::gl; use crate::touch::{TouchAction, TouchHandler}; @@ -11,10 +13,11 @@ use crate::windowing::{ self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods, }; use crate::{CompositionPipeline, ConstellationMsg, SendableFrameTree}; +use canvas::canvas_paint_thread::ImageUpdate; use crossbeam_channel::Sender; use embedder_traits::Cursor; use euclid::{Point2D, Rect, Scale, Vector2D}; -use gfx_traits::Epoch; +use gfx_traits::{Epoch, FontData}; #[cfg(feature = "gl")] use image::{DynamicImage, ImageFormat}; use ipc_channel::ipc; @@ -40,8 +43,6 @@ use std::fs::{create_dir_all, File}; use std::io::Write; use std::num::NonZeroU32; use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; use style_traits::viewport::ViewportConstraints; use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor}; use time::{now, precise_time_ns, precise_time_s}; @@ -218,7 +219,7 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> { /// True if a WR frame render has been requested. Screenshots /// taken before the render is complete will not reflect the /// most up to date rendering. - waiting_on_pending_frame: Arc<AtomicBool>, + waiting_on_pending_frame: bool, } #[derive(Clone, Copy)] @@ -334,7 +335,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> { is_running_problem_test, exit_after_load, convert_mouse_to_touch, - waiting_on_pending_frame: state.pending_wr_frame, + waiting_on_pending_frame: false, } } @@ -443,7 +444,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> { }, (Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => { - self.waiting_on_pending_frame.store(false, Ordering::SeqCst); + self.waiting_on_pending_frame = false; self.composition_request = CompositionRequest::CompositeNow(reason) }, @@ -474,7 +475,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> { self.ready_to_save_state, ReadyState::WaitingForConstellationReply ); - if is_ready && !self.waiting_on_pending_frame.load(Ordering::SeqCst) { + if is_ready && !self.waiting_on_pending_frame { self.ready_to_save_state = ReadyState::ReadyToSaveImage; if self.is_running_problem_test { println!("ready to save image!"); @@ -569,6 +570,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> { } }, + (Msg::Webrender(msg), ShutdownState::NotShuttingDown) => { + self.handle_webrender_message(msg); + }, + // When we are shutting_down, we need to avoid performing operations // such as Paint that may crash because we have begun tearing down // the rest of our resources. @@ -578,6 +583,146 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> { true } + /// Accept messages from content processes that need to be relayed to the WebRender + /// instance in the parent process. + fn handle_webrender_message(&mut self, msg: WebrenderMsg) { + match msg { + WebrenderMsg::Layout(script_traits::WebrenderMsg::SendInitialTransaction(pipeline)) => { + self.waiting_on_pending_frame = true; + let mut txn = webrender_api::Transaction::new(); + txn.set_display_list( + webrender_api::Epoch(0), + None, + Default::default(), + (pipeline, Default::default(), Default::default()), + false, + ); + self.webrender_api + .send_transaction(self.webrender_document, txn); + }, + + WebrenderMsg::Layout(script_traits::WebrenderMsg::SendScrollNode( + point, + scroll_id, + clamping, + )) => { + let mut txn = webrender_api::Transaction::new(); + txn.scroll_node_with_id(point, scroll_id, clamping); + self.webrender_api + .send_transaction(self.webrender_document, txn); + }, + + WebrenderMsg::Layout(script_traits::WebrenderMsg::SendDisplayList( + epoch, + size, + pipeline, + size2, + data, + descriptor, + )) => { + self.waiting_on_pending_frame = true; + let mut txn = webrender_api::Transaction::new(); + txn.set_display_list( + epoch, + None, + size, + ( + pipeline, + size2, + webrender_api::BuiltDisplayList::from_data(data, descriptor), + ), + true, + ); + txn.generate_frame(); + self.webrender_api + .send_transaction(self.webrender_document, txn); + }, + + WebrenderMsg::Layout(script_traits::WebrenderMsg::HitTest( + pipeline, + point, + flags, + sender, + )) => { + let result = + self.webrender_api + .hit_test(self.webrender_document, pipeline, point, flags); + let _ = sender.send(result); + }, + + WebrenderMsg::Layout(script_traits::WebrenderMsg::GenerateImageKey(sender)) | + WebrenderMsg::Net(net_traits::WebrenderImageMsg::GenerateImageKey(sender)) => { + let _ = sender.send(self.webrender_api.generate_image_key()); + }, + + WebrenderMsg::Layout(script_traits::WebrenderMsg::UpdateImages(updates)) => { + let mut txn = webrender_api::Transaction::new(); + for update in updates { + match update { + script_traits::ImageUpdate::AddImage(key, desc, data) => { + txn.add_image(key, desc, data, None) + }, + script_traits::ImageUpdate::DeleteImage(key) => txn.delete_image(key), + script_traits::ImageUpdate::UpdateImage(key, desc, data) => { + txn.update_image(key, desc, data, &webrender_api::DirtyRect::All) + }, + } + } + self.webrender_api + .send_transaction(self.webrender_document, txn); + }, + + WebrenderMsg::Net(net_traits::WebrenderImageMsg::AddImage(key, desc, data)) => { + let mut txn = webrender_api::Transaction::new(); + txn.add_image(key, desc, data, None); + self.webrender_api + .send_transaction(self.webrender_document, txn); + }, + + WebrenderMsg::Font(WebrenderFontMsg::AddFontInstance(font_key, size, sender)) => { + let key = self.webrender_api.generate_font_instance_key(); + let mut txn = webrender_api::Transaction::new(); + txn.add_font_instance(key, font_key, size, None, None, Vec::new()); + self.webrender_api + .send_transaction(self.webrender_document, txn); + let _ = sender.send(key); + }, + + WebrenderMsg::Font(WebrenderFontMsg::AddFont(data, sender)) => { + let font_key = self.webrender_api.generate_font_key(); + let mut txn = webrender_api::Transaction::new(); + match data { + FontData::Raw(bytes) => txn.add_raw_font(font_key, bytes, 0), + FontData::Native(native_font) => txn.add_native_font(font_key, native_font), + } + self.webrender_api + .send_transaction(self.webrender_document, txn); + let _ = sender.send(font_key); + }, + + WebrenderMsg::Canvas(WebrenderCanvasMsg::GenerateKey(sender)) => { + let _ = sender.send(self.webrender_api.generate_image_key()); + }, + + WebrenderMsg::Canvas(WebrenderCanvasMsg::UpdateImages(updates)) => { + let mut txn = webrender_api::Transaction::new(); + for update in updates { + match update { + ImageUpdate::Add(key, descriptor, data) => { + txn.add_image(key, descriptor, data, None) + }, + ImageUpdate::Update(key, descriptor, data) => { + txn.update_image(key, descriptor, data, &webrender_api::DirtyRect::All) + }, + ImageUpdate::Delete(key) => txn.delete_image(key), + } + } + self.webrender_api + .send_transaction(self.webrender_document, txn); + }, + } + } + /// Sets or unsets the animations-running flag for the given pipeline, and schedules a /// recomposite if necessary. fn change_running_animations_state( diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index cbd715af0dd..01fb92a544e 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -6,6 +6,7 @@ use crate::compositor::CompositingReason; use crate::{ConstellationMsg, SendableFrameTree}; +use canvas::canvas_paint_thread::ImageUpdate; use crossbeam_channel::{Receiver, Sender}; use embedder_traits::EventLoopWaker; use euclid::Rect; @@ -18,8 +19,6 @@ use profile_traits::time; use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType}; use std::fmt::{Debug, Error, Formatter}; use std::rc::Rc; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; use style_traits::viewport::ViewportConstraints; use style_traits::CSSPixel; use webrender_api; @@ -122,6 +121,30 @@ pub enum Msg { GetScreenSize(IpcSender<DeviceIntSize>), /// Get screen available size. GetScreenAvailSize(IpcSender<DeviceIntSize>), + + /// Webrender operations requested from non-compositor threads. + Webrender(WebrenderMsg), +} + +pub enum WebrenderFontMsg { + AddFontInstance( + webrender_api::FontKey, + app_units::Au, + Sender<webrender_api::FontInstanceKey>, + ), + AddFont(gfx_traits::FontData, Sender<webrender_api::FontKey>), +} + +pub enum WebrenderCanvasMsg { + GenerateKey(Sender<webrender_api::ImageKey>), + UpdateImages(Vec<ImageUpdate>), +} + +pub enum WebrenderMsg { + Layout(script_traits::WebrenderMsg), + Net(net_traits::WebrenderImageMsg), + Font(WebrenderFontMsg), + Canvas(WebrenderCanvasMsg), } impl Debug for Msg { @@ -148,6 +171,7 @@ impl Debug for Msg { Msg::GetClientWindow(..) => write!(f, "GetClientWindow"), Msg::GetScreenSize(..) => write!(f, "GetScreenSize"), Msg::GetScreenAvailSize(..) => write!(f, "GetScreenAvailSize"), + Msg::Webrender(..) => write!(f, "Webrender"), } } } @@ -171,5 +195,4 @@ pub struct InitialCompositorState { pub webrender_surfman: WebrenderSurfman, pub webrender_gl: Rc<dyn gleam::gl::Gl>, pub webxr_main_thread: webxr::MainThreadRegistry, - pub pending_wr_frame: Arc<AtomicBool>, } diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index d7408ac549e..1ea79bc3209 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -109,6 +109,7 @@ use canvas_traits::webgl::WebGLThreads; use canvas_traits::ConstellationCanvasMsg; use compositing::compositor_thread::CompositorProxy; use compositing::compositor_thread::Msg as ToCompositorMsg; +use compositing::compositor_thread::WebrenderMsg; use compositing::{ConstellationMsg as FromCompositorMsg, SendableFrameTree}; use crossbeam_channel::{after, never, unbounded, Receiver, Sender}; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg}; @@ -171,7 +172,6 @@ use std::marker::PhantomData; use std::mem::replace; use std::process; use std::rc::{Rc, Weak}; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; use style_traits::viewport::ViewportConstraints; @@ -384,10 +384,6 @@ pub struct Constellation<Message, LTF, STF, SWF> { /// A single WebRender document the constellation operates on. webrender_document: webrender_api::DocumentId, - /// A channel for the constellation to send messages to the - /// WebRender thread. - webrender_api_sender: webrender_api::RenderApiSender, - /// A channel for content processes to send messages that will /// be relayed to the WebRender thread. webrender_api_ipc_sender: script_traits::WebrenderIpcSender, @@ -537,9 +533,6 @@ pub struct InitialConstellationState { /// Webrender document ID. pub webrender_document: webrender_api::DocumentId, - /// Webrender API. - pub webrender_api_sender: webrender_api::RenderApiSender, - /// Entry point to create and get channels to a WebGLThread. pub webgl_threads: Option<WebGLThreads>, @@ -554,9 +547,6 @@ pub struct InitialConstellationState { /// Mechanism to force the compositor to process events. pub event_loop_waker: Option<Box<dyn EventLoopWaker>>, - /// A flag share with the compositor to indicate that a WR frame is in progress. - pub pending_wr_frame: Arc<AtomicBool>, - /// User agent string to report in network requests. pub user_agent: Cow<'static, str>, } @@ -726,113 +716,6 @@ where mpsc_receiver } -enum WebrenderMsg { - Layout(script_traits::WebrenderMsg), - Net(net_traits::WebrenderImageMsg), -} - -/// Accept messages from content processes that need to be relayed to the WebRender -/// instance in the parent process. -fn handle_webrender_message( - pending_wr_frame: &AtomicBool, - webrender_api: &webrender_api::RenderApi, - webrender_doc: webrender_api::DocumentId, - msg: WebrenderMsg, -) { - match msg { - WebrenderMsg::Layout(script_traits::WebrenderMsg::SendInitialTransaction( - doc, - pipeline, - )) => { - pending_wr_frame.store(true, Ordering::SeqCst); - let mut txn = webrender_api::Transaction::new(); - txn.set_display_list( - webrender_api::Epoch(0), - None, - Default::default(), - (pipeline, Default::default(), Default::default()), - false, - ); - webrender_api.send_transaction(doc, txn); - }, - - WebrenderMsg::Layout(script_traits::WebrenderMsg::SendScrollNode( - doc, - point, - scroll_id, - clamping, - )) => { - let mut txn = webrender_api::Transaction::new(); - txn.scroll_node_with_id(point, scroll_id, clamping); - webrender_api.send_transaction(doc, txn); - }, - - WebrenderMsg::Layout(script_traits::WebrenderMsg::SendDisplayList( - doc, - epoch, - size, - pipeline, - size2, - data, - descriptor, - )) => { - pending_wr_frame.store(true, Ordering::SeqCst); - let mut txn = webrender_api::Transaction::new(); - txn.set_display_list( - epoch, - None, - size, - ( - pipeline, - size2, - webrender_api::BuiltDisplayList::from_data(data, descriptor), - ), - true, - ); - txn.generate_frame(); - webrender_api.send_transaction(doc, txn); - }, - - WebrenderMsg::Layout(script_traits::WebrenderMsg::HitTest( - doc, - pipeline, - point, - flags, - sender, - )) => { - let result = webrender_api.hit_test(doc, pipeline, point, flags); - let _ = sender.send(result); - }, - - WebrenderMsg::Layout(script_traits::WebrenderMsg::GenerateImageKey(sender)) | - WebrenderMsg::Net(net_traits::WebrenderImageMsg::GenerateImageKey(sender)) => { - let _ = sender.send(webrender_api.generate_image_key()); - }, - - WebrenderMsg::Layout(script_traits::WebrenderMsg::UpdateImages(updates)) => { - let mut txn = webrender_api::Transaction::new(); - for update in updates { - match update { - script_traits::ImageUpdate::AddImage(key, desc, data) => { - txn.add_image(key, desc, data, None) - }, - script_traits::ImageUpdate::DeleteImage(key) => txn.delete_image(key), - script_traits::ImageUpdate::UpdateImage(key, desc, data) => { - txn.update_image(key, desc, data, &webrender_api::DirtyRect::All) - }, - } - } - webrender_api.send_transaction(webrender_doc, txn); - }, - - WebrenderMsg::Net(net_traits::WebrenderImageMsg::AddImage(key, desc, data)) => { - let mut txn = webrender_api::Transaction::new(); - txn.add_image(key, desc, data, None); - webrender_api.send_transaction(webrender_doc, txn); - }, - } -} - impl<Message, LTF, STF, SWF> Constellation<Message, LTF, STF, SWF> where LTF: LayoutThreadFactory<Message = Message>, @@ -931,32 +814,23 @@ where let (webrender_image_ipc_sender, webrender_image_ipc_receiver) = ipc::channel().expect("ipc channel failure"); - let webrender_api = state.webrender_api_sender.create_api(); - let webrender_doc = state.webrender_document; - let pending_wr_frame_clone = state.pending_wr_frame.clone(); + let compositor_proxy = state.compositor_proxy.clone(); ROUTER.add_route( webrender_ipc_receiver.to_opaque(), Box::new(move |message| { - handle_webrender_message( - &pending_wr_frame_clone, - &webrender_api, - webrender_doc, + let _ = compositor_proxy.send(ToCompositorMsg::Webrender( WebrenderMsg::Layout(message.to().expect("conversion failure")), - ) + )); }), ); - let webrender_api = state.webrender_api_sender.create_api(); - let pending_wr_frame_clone = state.pending_wr_frame.clone(); + let compositor_proxy = state.compositor_proxy.clone(); ROUTER.add_route( webrender_image_ipc_receiver.to_opaque(), Box::new(move |message| { - handle_webrender_message( - &pending_wr_frame_clone, - &webrender_api, - webrender_doc, + let _ = compositor_proxy.send(ToCompositorMsg::Webrender( WebrenderMsg::Net(message.to().expect("conversion failure")), - ) + )); }), ); @@ -1009,7 +883,6 @@ where scheduler_receiver, document_states: HashMap::new(), webrender_document: state.webrender_document, - webrender_api_sender: state.webrender_api_sender, webrender_api_ipc_sender: script_traits::WebrenderIpcSender::new( webrender_ipc_sender, ), @@ -1474,10 +1347,10 @@ where )) } recv(self.swmanager_receiver) -> msg => { - msg.expect("Unexpected panic channel panic in constellation").map(Request::FromSWManager) + msg.expect("Unexpected SW channel panic in constellation").map(Request::FromSWManager) } recv(self.scheduler_receiver) -> msg => { - msg.expect("Unexpected panic channel panic in constellation").map(Request::Timer) + msg.expect("Unexpected schedule channel panic in constellation").map(Request::Timer) } recv(scheduler_timeout) -> _ => { // Note: by returning, we go back to the top, @@ -4386,14 +4259,11 @@ where size: UntypedSize2D<u64>, response_sender: IpcSender<(IpcSender<CanvasMsg>, CanvasId)>, ) { - let webrender_api = self.webrender_api_sender.clone(); let (canvas_id_sender, canvas_id_receiver) = unbounded(); if let Err(e) = self.canvas_chan.send(ConstellationCanvasMsg::Create { id_sender: canvas_id_sender, size, - webrender_sender: webrender_api, - webrender_doc: self.webrender_document, antialias: self.enable_canvas_antialiasing, }) { return warn!("Create canvas paint thread failed ({})", e); diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index f4c2aefdc73..4fa5d6e2fd9 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -606,7 +606,6 @@ impl UnprivilegedPipelineContent { self.time_profiler_chan, self.mem_profiler_chan, self.webrender_api_sender, - self.webrender_document, paint_time_metrics, layout_thread_busy_flag.clone(), self.opts.load_webfonts_synchronously, diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs index 48d4c9e2889..45eead2357d 100644 --- a/components/gfx/font_cache_thread.rs +++ b/components/gfx/font_cache_thread.rs @@ -12,6 +12,7 @@ use crate::platform::font_list::system_default_family; use crate::platform::font_list::SANS_SERIF_FONT_FAMILY; use crate::platform::font_template::FontTemplateData; use app_units::Au; +use gfx_traits::{FontData, WebrenderApi}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use net_traits::request::{Destination, RequestBuilder}; use net_traits::{fetch_async, CoreResourceThread, FetchResponseMsg}; @@ -135,9 +136,8 @@ struct FontCache { web_families: HashMap<LowercaseString, FontTemplates>, font_context: FontContextHandle, core_resource_thread: CoreResourceThread, - webrender_api: webrender_api::RenderApi, + webrender_api: Box<dyn WebrenderApi>, webrender_fonts: HashMap<Atom, webrender_api::FontKey>, - webrender_doc: webrender_api::DocumentId, font_instances: HashMap<(webrender_api::FontKey, Au), webrender_api::FontInstanceKey>, } @@ -181,19 +181,11 @@ impl FontCache { }, Command::GetFontInstance(font_key, size, result) => { let webrender_api = &self.webrender_api; - let doc = self.webrender_doc; - - let instance_key = - *self - .font_instances - .entry((font_key, size)) - .or_insert_with(|| { - let key = webrender_api.generate_font_instance_key(); - let mut txn = webrender_api::Transaction::new(); - txn.add_font_instance(key, font_key, size, None, None, Vec::new()); - webrender_api.send_transaction(doc, txn); - key - }); + + let instance_key = *self + .font_instances + .entry((font_key, size)) + .or_insert_with(|| webrender_api.add_font_instance(font_key, size)); let _ = result.send(instance_key); }, @@ -391,21 +383,17 @@ impl FontCache { fn get_font_template_info(&mut self, template: Arc<FontTemplateData>) -> FontTemplateInfo { let webrender_api = &self.webrender_api; - let doc = self.webrender_doc; let webrender_fonts = &mut self.webrender_fonts; let font_key = *webrender_fonts .entry(template.identifier.clone()) .or_insert_with(|| { - let font_key = webrender_api.generate_font_key(); - let mut txn = webrender_api::Transaction::new(); - match (template.bytes_if_in_memory(), template.native_font()) { - (Some(bytes), _) => txn.add_raw_font(font_key, bytes, 0), - (None, Some(native_font)) => txn.add_native_font(font_key, native_font), - (None, None) => txn.add_raw_font(font_key, template.bytes(), 0), - } - webrender_api.send_transaction(doc, txn); - font_key + let font = match (template.bytes_if_in_memory(), template.native_font()) { + (Some(bytes), _) => FontData::Raw(bytes), + (None, Some(native_font)) => FontData::Native(native_font), + (None, None) => FontData::Raw(template.bytes()), + }; + webrender_api.add_font(font) }); FontTemplateInfo { @@ -444,8 +432,7 @@ pub struct FontCacheThread { impl FontCacheThread { pub fn new( core_resource_thread: CoreResourceThread, - webrender_api: webrender_api::RenderApi, - webrender_doc: webrender_api::DocumentId, + webrender_api: Box<dyn WebrenderApi + Send>, ) -> FontCacheThread { let (chan, port) = ipc::channel().unwrap(); @@ -465,7 +452,6 @@ impl FontCacheThread { font_context: FontContextHandle::new(), core_resource_thread, webrender_api, - webrender_doc, webrender_fonts: HashMap::new(), font_instances: HashMap::new(), }; diff --git a/components/gfx_traits/Cargo.toml b/components/gfx_traits/Cargo.toml index ff83cc79406..5d7acdd1b61 100644 --- a/components/gfx_traits/Cargo.toml +++ b/components/gfx_traits/Cargo.toml @@ -11,7 +11,9 @@ name = "gfx_traits" path = "lib.rs" [dependencies] +app_units = "0.7" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = "0.1" range = { path = "../range" } serde = "1.0" +webrender_api = { git = "https://github.com/servo/webrender" } diff --git a/components/gfx_traits/lib.rs b/components/gfx_traits/lib.rs index 165059c7996..447be6e5dc2 100644 --- a/components/gfx_traits/lib.rs +++ b/components/gfx_traits/lib.rs @@ -103,3 +103,17 @@ pub fn node_id_from_scroll_id(id: usize) -> Option<usize> { } None } + +pub enum FontData { + Raw(Vec<u8>), + Native(webrender_api::NativeFontHandle), +} + +pub trait WebrenderApi { + fn add_font_instance( + &self, + font_key: webrender_api::FontKey, + size: app_units::Au, + ) -> webrender_api::FontInstanceKey; + fn add_font(&self, data: FontData) -> webrender_api::FontKey; +} diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 9d5f1e100ab..0be8183e2a7 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -1571,6 +1571,11 @@ impl Fragment { return; } + // If this fragment takes up no space, we don't need to build any display items for it. + if self.has_non_invertible_transform() { + return; + } + debug!( "Fragment::build_display_list at rel={:?}, abs={:?}: {:?}", self.border_box, stacking_relative_border_box, self @@ -2376,6 +2381,11 @@ impl BlockFlow { state: &mut StackingContextCollectionState, flags: StackingContextCollectionFlags, ) { + // This block flow produces no stacking contexts if it takes up no space. + if self.has_non_invertible_transform() { + return; + } + let mut preserved_state = SavedStackingContextCollectionState::new(state); let stacking_context_type = self.stacking_context_type(flags); diff --git a/components/layout/display_list/items.rs b/components/layout/display_list/items.rs index 27b4ec1fa88..4800abe7e53 100644 --- a/components/layout/display_list/items.rs +++ b/components/layout/display_list/items.rs @@ -217,6 +217,12 @@ impl StackingContext { parent_clipping_and_scrolling: ClippingAndScrolling, established_reference_frame: Option<ClipScrollNodeIndex>, ) -> StackingContext { + if let Some(ref t) = transform { + // These are used as scale values by webrender, and it can't handle + // divisors of 0 when scaling. + assert_ne!(t.m11, 0.); + assert_ne!(t.m22, 0.); + } StackingContext { id, context_type, diff --git a/components/layout/display_list/webrender_helpers.rs b/components/layout/display_list/webrender_helpers.rs index dd187cf3704..9495b2ab166 100644 --- a/components/layout/display_list/webrender_helpers.rs +++ b/components/layout/display_list/webrender_helpers.rs @@ -234,6 +234,12 @@ impl DisplayItem { builder.push_iter(&stacking_context.filters); } + // TODO(jdm): WebRender now requires us to create stacking context items + // with the IS_BLEND_CONTAINER flag enabled if any children + // of the stacking context have a blend mode applied. + // This will require additional tracking during layout + // before we start collecting stacking contexts so that + // information will be available when we reach this point. let wr_item = PushStackingContextDisplayItem { origin: bounds.origin, spatial_id, @@ -243,9 +249,7 @@ impl DisplayItem { mix_blend_mode: stacking_context.mix_blend_mode, clip_id: None, raster_space: RasterSpace::Screen, - // TODO(pcwalton): Enable picture caching? - cache_tiles: false, - is_backdrop_root: false, + flags: Default::default(), }, }; diff --git a/components/layout/flow.rs b/components/layout/flow.rs index c2d01b7f9f9..acea20ad4d4 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -273,6 +273,22 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static { might_have_floats_in_or_out } + fn has_non_invertible_transform(&self) -> bool { + if !self.class().is_block_like() || + self.as_block() + .fragment + .style + .get_box() + .transform + .0 + .is_empty() + { + return false; + } + + self.as_block().fragment.has_non_invertible_transform() + } + fn get_overflow_in_parent_coordinates(&self) -> Overflow { // FIXME(#2795): Get the real container size. let container_size = Size2D::zero(); @@ -1160,7 +1176,9 @@ impl BaseFlow { state: &mut StackingContextCollectionState, ) { for kid in self.children.iter_mut() { - kid.collect_stacking_contexts(state); + if !kid.has_non_invertible_transform() { + kid.collect_stacking_contexts(state); + } } } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 062db9c0a7e..10c0fb072cc 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -2730,6 +2730,12 @@ impl Fragment { self.style().get_box().perspective != Perspective::None } + /// Returns true if this fragment has a transform applied that causes it to take up no space. + pub fn has_non_invertible_transform(&self) -> bool { + self.transform_matrix(&Rect::default()) + .map_or(false, |matrix| !matrix.is_invertible()) + } + /// Returns true if this fragment establishes a new stacking context and false otherwise. pub fn establishes_stacking_context(&self) -> bool { // Text fragments shouldn't create stacking contexts. diff --git a/components/layout/inline.rs b/components/layout/inline.rs index dfdb20e309b..ee9980c4f1a 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -1871,6 +1871,11 @@ impl Flow for InlineFlow { let previous_cb_clipping_and_scrolling = state.containing_block_clipping_and_scrolling; for fragment in self.fragments.fragments.iter_mut() { + // If a particular fragment would establish a stacking context but has a transform + // applied that causes it to take up no space, we can skip it entirely. + if fragment.has_non_invertible_transform() { + continue; + } state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling; let abspos_containing_block = fragment.style.get_box().position != Position::Static; diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 88a6514433b..5c66004bc1a 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -346,6 +346,10 @@ pub struct BuildDisplayList<'a> { impl<'a> BuildDisplayList<'a> { #[inline] pub fn traverse(&mut self, flow: &mut dyn Flow) { + if flow.has_non_invertible_transform() { + return; + } + let parent_stacking_context_id = self.state.current_stacking_context_id; self.state.current_stacking_context_id = flow.base().stacking_context_id; diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index fce6fb6caec..371b20e25ac 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -234,6 +234,12 @@ impl StackingContext { )); } + // TODO(jdm): WebRender now requires us to create stacking context items + // with the IS_BLEND_CONTAINER flag enabled if any children + // of the stacking context have a blend mode applied. + // This will require additional tracking during layout + // before we start collecting stacking contexts so that + // information will be available when we reach this point. builder.wr.push_stacking_context( LayoutPoint::zero(), // origin self.spatial_id, @@ -245,8 +251,7 @@ impl StackingContext { &vec![], // filter_datas &vec![], // filter_primitives wr::RasterSpace::Screen, - false, // cache_tiles, - false, // false + wr::StackingContextFlags::empty(), ); true @@ -447,6 +452,14 @@ impl Fragment { return; } + // If this fragment has a transform applied that makes it take up no spae + // then we don't need to create any stacking contexts for it. + let has_non_invertible_transform = + fragment.has_non_invertible_transform(&containing_block_info.rect.to_untyped()); + if has_non_invertible_transform { + return; + } + fragment.build_stacking_context_tree( fragment_ref, builder, @@ -775,6 +788,15 @@ impl BoxFragment { }) } + /// Returns true if the given style contains a transform that is not invertible. + fn has_non_invertible_transform(&self, containing_block: &Rect<Length>) -> bool { + let list = &self.style.get_box().transform; + match list.to_transform_3d_matrix(Some(containing_block)) { + Ok(t) => !t.0.is_invertible(), + Err(_) => false, + } + } + /// Returns the 4D matrix representing this fragment's transform. pub fn calculate_transform_matrix( &self, @@ -783,6 +805,10 @@ impl BoxFragment { let list = &self.style.get_box().transform; let transform = LayoutTransform::from_untyped(&list.to_transform_3d_matrix(Some(&border_rect)).ok()?.0); + // WebRender will end up dividing by the scale value of this transform, so we + // want to ensure we don't feed it a divisor of 0. + assert_ne!(transform.m11, 0.); + assert_ne!(transform.m22, 0.); let transform_origin = &self.style.get_box().transform_origin; let transform_origin_x = transform_origin diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 6676cb39f1e..f3d0e45e3b7 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -275,7 +275,7 @@ impl InlineFormattingContext { loop { if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() { - match &*child.borrow() { + match &mut *child.borrow_mut() { InlineLevelBox::InlineBox(inline) => { let partial = inline.start_layout(child.clone(), &mut ifc); ifc.partial_inline_boxes_stack.push(partial) @@ -529,7 +529,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { fn layout_atomic( layout_context: &LayoutContext, ifc: &mut InlineFormattingContextState, - atomic: &IndependentFormattingContext, + atomic: &mut IndependentFormattingContext, ) { let pbm = atomic.style.padding_border_margin(&ifc.containing_block); let margin = pbm.margin.auto_is(Length::zero); diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 2443e91a0c8..be56a3e2226 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -206,7 +206,7 @@ fn layout_block_level_children( .iter() .enumerate() .map(|(tree_rank, box_)| { - let mut fragment = box_.borrow().layout( + let mut fragment = box_.borrow_mut().layout( layout_context, positioning_context, containing_block, @@ -226,7 +226,7 @@ fn layout_block_level_children( .mapfold_reduce_into( positioning_context, |positioning_context, (tree_rank, box_)| { - box_.borrow().layout( + box_.borrow_mut().layout( layout_context, positioning_context, containing_block, @@ -259,7 +259,7 @@ fn layout_block_level_children( impl BlockLevelBox { fn layout( - &self, + &mut self, layout_context: &LayoutContext, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 2217bcaf621..6819027564c 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -212,9 +212,6 @@ pub struct LayoutThread { /// Webrender interface. webrender_api: WebrenderIpcSender, - /// Webrender document. - webrender_document: webrender_api::DocumentId, - /// Paint time metrics. paint_time_metrics: PaintTimeMetrics, @@ -276,7 +273,6 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan: profile_time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, webrender_api_sender: WebrenderIpcSender, - webrender_document: webrender_api::DocumentId, paint_time_metrics: PaintTimeMetrics, busy: Arc<AtomicBool>, load_webfonts_synchronously: bool, @@ -325,7 +321,6 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan, mem_profiler_chan.clone(), webrender_api_sender, - webrender_document, paint_time_metrics, busy, load_webfonts_synchronously, @@ -495,7 +490,6 @@ impl LayoutThread { time_profiler_chan: profile_time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, webrender_api: WebrenderIpcSender, - webrender_document: webrender_api::DocumentId, paint_time_metrics: PaintTimeMetrics, busy: Arc<AtomicBool>, load_webfonts_synchronously: bool, @@ -510,7 +504,7 @@ impl LayoutThread { dump_flow_tree: bool, ) -> LayoutThread { // Let webrender know about this pipeline by sending an empty display list. - webrender_api.send_initial_transaction(webrender_document, id.to_webrender()); + webrender_api.send_initial_transaction(id.to_webrender()); let device = Device::new( MediaType::screen(), @@ -553,7 +547,6 @@ impl LayoutThread { epoch: Cell::new(Epoch(1)), viewport_size: Size2D::new(Au(0), Au(0)), webrender_api, - webrender_document, stylist: Stylist::new(device, QuirksMode::NoQuirks), rw_data: Arc::new(Mutex::new(LayoutThreadData { constellation_chan: constellation_chan, @@ -773,7 +766,6 @@ impl LayoutThread { let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y); self.webrender_api.send_scroll_node( - self.webrender_document, webrender_api::units::LayoutPoint::from_untyped(point), state.scroll_id, webrender_api::ScrollClamping::ToContentBounds, @@ -882,7 +874,6 @@ impl LayoutThread { self.time_profiler_chan.clone(), self.mem_profiler_chan.clone(), self.webrender_api.clone(), - self.webrender_document, info.paint_time_metrics, info.layout_is_busy, self.load_webfonts_synchronously, @@ -1171,12 +1162,8 @@ impl LayoutThread { self.paint_time_metrics .maybe_observe_paint_time(self, epoch, is_contentful.0); - self.webrender_api.send_display_list( - self.webrender_document, - epoch, - viewport_size, - builder.finalize(), - ); + self.webrender_api + .send_display_list(epoch, viewport_size, builder.finalize()); }, ); } @@ -1578,7 +1565,6 @@ impl LayoutThread { let client_point = webrender_api::units::WorldPoint::from_untyped(client_point); let results = self.webrender_api.hit_test( - self.webrender_document, Some(self.id.to_webrender()), client_point, flags, diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index fd0d22fc67b..3bb0a7a3353 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -191,9 +191,6 @@ pub struct LayoutThread { /// Webrender interface. webrender_api: WebrenderIpcSender, - /// Webrender document. - webrender_document: webrender_api::DocumentId, - /// Paint time metrics. paint_time_metrics: PaintTimeMetrics, @@ -245,7 +242,6 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan: profile_time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, webrender_api_sender: WebrenderIpcSender, - webrender_document: webrender_api::DocumentId, paint_time_metrics: PaintTimeMetrics, busy: Arc<AtomicBool>, load_webfonts_synchronously: bool, @@ -294,7 +290,6 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan, mem_profiler_chan.clone(), webrender_api_sender, - webrender_document, paint_time_metrics, busy, load_webfonts_synchronously, @@ -463,7 +458,6 @@ impl LayoutThread { time_profiler_chan: profile_time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, webrender_api_sender: WebrenderIpcSender, - webrender_document: webrender_api::DocumentId, paint_time_metrics: PaintTimeMetrics, busy: Arc<AtomicBool>, load_webfonts_synchronously: bool, @@ -477,7 +471,7 @@ impl LayoutThread { trace_layout: bool, ) -> LayoutThread { // Let webrender know about this pipeline by sending an empty display list. - webrender_api_sender.send_initial_transaction(webrender_document, id.to_webrender()); + webrender_api_sender.send_initial_transaction(id.to_webrender()); // The device pixel ratio is incorrect (it does not have the hidpi value), // but it will be set correctly when the initial reflow takes place. @@ -521,7 +515,6 @@ impl LayoutThread { epoch: Cell::new(Epoch(1)), viewport_size: Size2D::new(Au(0), Au(0)), webrender_api: webrender_api_sender, - webrender_document, stylist: Stylist::new(device, QuirksMode::NoQuirks), rw_data: Arc::new(Mutex::new(LayoutThreadData { constellation_chan: constellation_chan, @@ -737,7 +730,6 @@ impl LayoutThread { let point = Point2D::new(-state.scroll_offset.x, -state.scroll_offset.y); self.webrender_api.send_scroll_node( - self.webrender_document, webrender_api::units::LayoutPoint::from_untyped(point), state.scroll_id, webrender_api::ScrollClamping::ToContentBounds, @@ -823,7 +815,6 @@ impl LayoutThread { self.time_profiler_chan.clone(), self.mem_profiler_chan.clone(), self.webrender_api.clone(), - self.webrender_document, info.paint_time_metrics, info.layout_is_busy, self.load_webfonts_synchronously, @@ -1231,7 +1222,6 @@ impl LayoutThread { let client_point = webrender_api::units::WorldPoint::from_untyped(client_point); let results = self.webrender_api.hit_test( - self.webrender_document, Some(self.id.to_webrender()), client_point, flags, @@ -1349,12 +1339,8 @@ impl LayoutThread { self.viewport_size.width.to_f32_px(), self.viewport_size.height.to_f32_px(), )); - self.webrender_api.send_display_list( - self.webrender_document, - epoch, - viewport_size, - display_list.wr.finalize(), - ); + self.webrender_api + .send_display_list(epoch, viewport_size, display_list.wr.finalize()); if self.trace_layout { layout_debug::end_trace(self.generation.get()); diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index 2ee0021df96..c33aa3e47aa 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -44,7 +44,6 @@ pub trait LayoutThreadFactory { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, webrender_api_sender: WebrenderIpcSender, - webrender_document: webrender_api::DocumentId, paint_time_metrics: PaintTimeMetrics, busy: Arc<AtomicBool>, load_webfonts_synchronously: bool, diff --git a/components/net/connector.rs b/components/net/connector.rs index 058a27c47d6..dc44002a85a 100644 --- a/components/net/connector.rs +++ b/components/net/connector.rs @@ -8,8 +8,13 @@ use hyper::client::HttpConnector as HyperHttpConnector; use hyper::rt::Future; use hyper::{Body, Client}; use hyper_openssl::HttpsConnector; -use openssl::ssl::{SslConnector, SslConnectorBuilder, SslMethod, SslOptions}; -use openssl::x509; +use openssl::ex_data::Index; +use openssl::ssl::{ + Ssl, SslConnector, SslConnectorBuilder, SslContext, SslMethod, SslOptions, SslVerifyMode, +}; +use openssl::x509::{self, X509StoreContext}; +use std::collections::hash_map::{Entry, HashMap}; +use std::sync::{Arc, Mutex}; use tokio::prelude::future::Executor; pub const BUF_SIZE: usize = 32768; @@ -30,6 +35,38 @@ const SIGNATURE_ALGORITHMS: &'static str = concat!( "RSA+SHA512:RSA+SHA384:RSA+SHA256" ); +#[derive(Clone)] +pub struct ConnectionCerts { + certs: Arc<Mutex<HashMap<String, (Vec<u8>, u32)>>>, +} + +impl ConnectionCerts { + pub fn new() -> Self { + Self { + certs: Arc::new(Mutex::new(HashMap::new())), + } + } + + fn store(&self, host: String, cert_bytes: Vec<u8>) { + let mut certs = self.certs.lock().unwrap(); + let entry = certs.entry(host).or_insert((cert_bytes, 0)); + entry.1 += 1; + } + + pub(crate) fn remove(&self, host: String) -> Option<Vec<u8>> { + match self.certs.lock().unwrap().entry(host) { + Entry::Vacant(_) => return None, + Entry::Occupied(mut e) => { + e.get_mut().1 -= 1; + if e.get().1 == 0 { + return Some((e.remove_entry().1).0); + } + Some(e.get().0.clone()) + }, + } + } +} + pub struct HttpConnector { inner: HyperHttpConnector, } @@ -60,7 +97,34 @@ impl Connect for HttpConnector { pub type Connector = HttpsConnector<HttpConnector>; pub type TlsConfig = SslConnectorBuilder; -pub fn create_tls_config(certs: &str, alpn: &[u8]) -> TlsConfig { +#[derive(Clone)] +pub struct ExtraCerts(Arc<Mutex<Vec<Vec<u8>>>>); + +impl ExtraCerts { + pub fn new() -> Self { + Self(Arc::new(Mutex::new(vec![]))) + } + + pub fn add(&self, bytes: Vec<u8>) { + self.0.lock().unwrap().push(bytes); + } +} + +struct Host(String); + +lazy_static! { + static ref EXTRA_INDEX: Index<SslContext, ExtraCerts> = SslContext::new_ex_index().unwrap(); + static ref CONNECTION_INDEX: Index<SslContext, ConnectionCerts> = + SslContext::new_ex_index().unwrap(); + static ref HOST_INDEX: Index<Ssl, Host> = Ssl::new_ex_index().unwrap(); +} + +pub fn create_tls_config( + certs: &str, + alpn: &[u8], + extra_certs: ExtraCerts, + connection_certs: ConnectionCerts, +) -> TlsConfig { // certs include multiple certificates. We could add all of them at once, // but if any of them were already added, openssl would fail to insert all // of them. @@ -104,6 +168,44 @@ pub fn create_tls_config(certs: &str, alpn: &[u8]) -> TlsConfig { SslOptions::NO_COMPRESSION, ); + cfg.set_ex_data(*EXTRA_INDEX, extra_certs); + cfg.set_ex_data(*CONNECTION_INDEX, connection_certs); + cfg.set_verify_callback(SslVerifyMode::PEER, |verified, x509_store_context| { + if verified { + return true; + } + + let ssl_idx = X509StoreContext::ssl_idx().unwrap(); + let ssl = x509_store_context.ex_data(ssl_idx).unwrap(); + + // Obtain the cert bytes for this connection. + let cert = match x509_store_context.current_cert() { + Some(cert) => cert, + None => return false, + }; + let pem = match cert.to_pem() { + Ok(pem) => pem, + Err(_) => return false, + }; + + let ssl_context = ssl.ssl_context(); + + // Ensure there's an entry stored in the set of known connection certs for this connection. + if let Some(host) = ssl.ex_data(*HOST_INDEX) { + let connection_certs = ssl_context.ex_data(*CONNECTION_INDEX).unwrap(); + connection_certs.store((*host).0.clone(), pem.clone()); + } + + // Fall back to the dynamic set of allowed certs. + let extra_certs = ssl_context.ex_data(*EXTRA_INDEX).unwrap(); + for cert in &*extra_certs.0.lock().unwrap() { + if pem == *cert { + return true; + } + } + false + }); + cfg } @@ -111,7 +213,11 @@ pub fn create_http_client<E>(tls_config: TlsConfig, executor: E) -> Client<Conne where E: Executor<Box<dyn Future<Error = (), Item = ()> + Send + 'static>> + Sync + Send + 'static, { - let connector = HttpsConnector::with_connector(HttpConnector::new(), tls_config).unwrap(); + let mut connector = HttpsConnector::with_connector(HttpConnector::new(), tls_config).unwrap(); + connector.set_callback(|configuration, destination| { + configuration.set_ex_data(*HOST_INDEX, Host(destination.host().to_owned())); + Ok(()) + }); Client::builder() .http1_title_case_headers(true) diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index 457b462bc0b..c25ab10cbe6 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -15,17 +15,19 @@ use headers::{AccessControlExposeHeaders, ContentType, HeaderMapExt, Range}; use http::header::{self, HeaderMap, HeaderName}; use hyper::Method; use hyper::StatusCode; -use ipc_channel::ipc::IpcReceiver; +use ipc_channel::ipc::{self, IpcReceiver}; use mime::{self, Mime}; use net_traits::blob_url_store::{parse_blob_url, BlobURLStoreError}; use net_traits::filemanager_thread::{FileTokenCheck, RelativePos}; use net_traits::request::{ is_cors_safelisted_method, is_cors_safelisted_request_header, Origin, ResponseTainting, Window, }; -use net_traits::request::{CredentialsMode, Destination, Referrer, Request, RequestMode}; +use net_traits::request::{ + BodyChunkRequest, CredentialsMode, Destination, Referrer, Request, RequestMode, +}; use net_traits::response::{Response, ResponseBody, ResponseType}; use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceFetchTiming}; -use net_traits::{ResourceAttribute, ResourceTimeValue}; +use net_traits::{ResourceAttribute, ResourceTimeValue, ResourceTimingType}; use servo_arc::Arc as ServoArc; use servo_url::ServoUrl; use std::borrow::Cow; @@ -282,7 +284,10 @@ pub fn main_fetch( false }; - if (same_origin && !cors_flag) || current_url.scheme() == "data" { + if (same_origin && !cors_flag) || + current_url.scheme() == "data" || + current_url.scheme() == "chrome" + { // Substep 1. request.response_tainting = ResponseTainting::Basic; @@ -606,6 +611,17 @@ fn range_not_satisfiable_error(response: &mut Response) { response.raw_status = Some((StatusCode::RANGE_NOT_SATISFIABLE.as_u16(), reason.into())); } +fn create_blank_reply(url: ServoUrl, timing_type: ResourceTimingType) -> Response { + let mut response = Response::new(url, ResourceFetchTiming::new(timing_type)); + response + .headers + .typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8)); + *response.body.lock().unwrap() = ResponseBody::Done(vec![]); + response.status = Some((StatusCode::OK, "OK".to_string())); + response.raw_status = Some((StatusCode::OK.as_u16(), b"OK".to_vec())); + response +} + /// [Scheme fetch](https://fetch.spec.whatwg.org#scheme-fetch) fn scheme_fetch( request: &mut Request, @@ -617,15 +633,31 @@ fn scheme_fetch( let url = request.current_url(); match url.scheme() { - "about" if url.path() == "blank" => { - let mut response = Response::new(url, ResourceFetchTiming::new(request.timing_type())); - response - .headers - .typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8)); - *response.body.lock().unwrap() = ResponseBody::Done(vec![]); - response.status = Some((StatusCode::OK, "OK".to_string())); - response.raw_status = Some((StatusCode::OK.as_u16(), b"OK".to_vec())); - response + "about" if url.path() == "blank" => create_blank_reply(url, request.timing_type()), + + "chrome" if url.path() == "allowcert" => { + let data = request.body.as_mut().and_then(|body| { + let stream = body.take_stream(); + let (body_chan, body_port) = ipc::channel().unwrap(); + let _ = stream.send(BodyChunkRequest::Connect(body_chan)); + let _ = stream.send(BodyChunkRequest::Chunk); + body_port.recv().ok() + }); + let data = data.as_ref().and_then(|b| { + let idx = b.iter().position(|b| *b == b'&')?; + Some(b.split_at(idx)) + }); + + if let Some((secret, bytes)) = data { + let secret = str::from_utf8(secret).ok().and_then(|s| s.parse().ok()); + if secret == Some(*net_traits::PRIVILEGED_SECRET) { + if let Ok(bytes) = base64::decode(&bytes[1..]) { + context.state.extra_certs.add(bytes); + } + } + } + + create_blank_reply(url, request.timing_type()) }, "http" | "https" => http_fetch( diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 44b36c1bb4d..d69f418006c 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -2,7 +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::connector::{create_http_client, Connector, TlsConfig}; +use crate::connector::{create_http_client, ConnectionCerts, Connector, ExtraCerts, TlsConfig}; use crate::cookie; use crate::cookie_storage::CookieStorage; use crate::decoder::Decoder; @@ -89,6 +89,8 @@ pub struct HttpState { pub auth_cache: RwLock<AuthCache>, pub history_states: RwLock<HashMap<HistoryStateId, Vec<u8>>>, pub client: Client<Connector, Body>, + pub extra_certs: ExtraCerts, + pub connection_certs: ConnectionCerts, } impl HttpState { @@ -104,6 +106,8 @@ impl HttpState { tls_config, HANDLE.lock().unwrap().as_ref().unwrap().executor(), ), + extra_certs: ExtraCerts::new(), + connection_certs: ConnectionCerts::new(), } } } @@ -527,11 +531,19 @@ fn obtain_response( let method = method.clone(); let send_start = precise_time_ms(); + let host = request.uri().host().unwrap_or("").to_owned(); + let host_clone = request.uri().host().unwrap_or("").to_owned(); + let connection_certs = context.state.connection_certs.clone(); + let connection_certs_clone = context.state.connection_certs.clone(); + let headers = headers.clone(); Box::new( client .request(request) .and_then(move |res| { + // We no longer need to track the cert for this connection. + connection_certs.remove(host); + let send_end = precise_time_ms(); // TODO(#21271) response_start: immediately after receiving first byte of response @@ -564,7 +576,9 @@ fn obtain_response( }; Ok((Decoder::detect(res), msg)) }) - .map_err(move |e| NetworkError::from_hyper_error(&e)), + .map_err(move |e| { + NetworkError::from_hyper_error(&e, connection_certs_clone.remove(host_clone)) + }), ) } @@ -1557,7 +1571,7 @@ fn http_network_fetch( &url, &request.method, &request.headers, - request.body.as_mut().and_then(|body| body.take_stream()), + request.body.as_mut().map(|body| body.take_stream()), &request.pipeline_id, request_id.as_ref().map(Deref::deref), is_xhr, diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index 28a397e78e6..94184c3a046 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -4,7 +4,9 @@ //! A thread that takes a URL and streams back the binary data. -use crate::connector::{create_http_client, create_tls_config, ALPN_H2_H1}; +use crate::connector::{ + create_http_client, create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H2_H1, +}; use crate::cookie; use crate::cookie_storage::CookieStorage; use crate::fetch::cors_cache::CorsCache; @@ -143,6 +145,9 @@ fn create_http_states( None => resources::read_string(Resource::SSLCertificates), }; + let extra_certs = ExtraCerts::new(); + let connection_certs = ConnectionCerts::new(); + let http_state = HttpState { hsts_list: RwLock::new(hsts_list), cookie_jar: RwLock::new(cookie_jar), @@ -151,11 +156,21 @@ fn create_http_states( http_cache: RwLock::new(http_cache), http_cache_state: Mutex::new(HashMap::new()), client: create_http_client( - create_tls_config(&certs, ALPN_H2_H1), + create_tls_config( + &certs, + ALPN_H2_H1, + extra_certs.clone(), + connection_certs.clone(), + ), HANDLE.lock().unwrap().as_ref().unwrap().executor(), ), + extra_certs, + connection_certs, }; + let extra_certs = ExtraCerts::new(); + let connection_certs = ConnectionCerts::new(); + let private_http_state = HttpState { hsts_list: RwLock::new(HstsList::from_servo_preload()), cookie_jar: RwLock::new(CookieStorage::new(150)), @@ -164,9 +179,16 @@ fn create_http_states( http_cache: RwLock::new(HttpCache::new()), http_cache_state: Mutex::new(HashMap::new()), client: create_http_client( - create_tls_config(&certs, ALPN_H2_H1), + create_tls_config( + &certs, + ALPN_H2_H1, + extra_certs.clone(), + connection_certs.clone(), + ), HANDLE.lock().unwrap().as_ref().unwrap().executor(), ), + extra_certs, + connection_certs, }; (Arc::new(http_state), Arc::new(private_http_state)) @@ -705,6 +727,8 @@ impl CoreResourceManager { action_receiver, http_state.clone(), self.certificate_path.clone(), + http_state.extra_certs.clone(), + http_state.connection_certs.clone(), ); } } diff --git a/components/net/tests/fetch.rs b/components/net/tests/fetch.rs index 38797cf027b..dc4c0f032c0 100644 --- a/components/net/tests/fetch.rs +++ b/components/net/tests/fetch.rs @@ -22,7 +22,7 @@ use hyper::body::Body; use hyper::{Request as HyperRequest, Response as HyperResponse}; use mime::{self, Mime}; use msg::constellation_msg::TEST_PIPELINE_ID; -use net::connector::{create_tls_config, ALPN_H2_H1}; +use net::connector::{create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H2_H1}; use net::fetch::cors_cache::CorsCache; use net::fetch::methods::{self, CancellationListener, FetchContext}; use net::filemanager_thread::FileManager; @@ -682,7 +682,12 @@ fn test_fetch_with_hsts() { let (server, url) = make_ssl_server(handler, cert_path.clone(), key_path.clone()); let certs = fs::read_to_string(cert_path).expect("Couldn't find certificate file"); - let tls_config = create_tls_config(&certs, ALPN_H2_H1); + let tls_config = create_tls_config( + &certs, + ALPN_H2_H1, + ExtraCerts::new(), + ConnectionCerts::new(), + ); let mut context = FetchContext { state: Arc::new(HttpState::new(tls_config)), @@ -735,7 +740,12 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() { url.as_mut_url().set_scheme("https").unwrap(); let certs = fs::read_to_string(cert_path).expect("Couldn't find certificate file"); - let tls_config = create_tls_config(&certs, ALPN_H2_H1); + let tls_config = create_tls_config( + &certs, + ALPN_H2_H1, + ExtraCerts::new(), + ConnectionCerts::new(), + ); let mut context = FetchContext { state: Arc::new(HttpState::new(tls_config)), @@ -777,6 +787,85 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() { } #[test] +fn test_fetch_self_signed() { + let handler = move |_: HyperRequest<Body>, response: &mut HyperResponse<Body>| { + *response.body_mut() = b"Yay!".to_vec().into(); + }; + let client_cert_path = Path::new("../../resources/certs").canonicalize().unwrap(); + let cert_path = Path::new("../../resources/self_signed_certificate_for_testing.crt") + .canonicalize() + .unwrap(); + let key_path = Path::new("../../resources/privatekey_for_testing.key") + .canonicalize() + .unwrap(); + let (_server, mut url) = make_ssl_server(handler, cert_path.clone(), key_path.clone()); + url.as_mut_url().set_scheme("https").unwrap(); + + let cert_data = fs::read_to_string(cert_path.clone()).expect("Couldn't find certificate file"); + let client_cert_data = + fs::read_to_string(client_cert_path.clone()).expect("Couldn't find certificate file"); + let extra_certs = ExtraCerts::new(); + let tls_config = create_tls_config( + &client_cert_data, + ALPN_H2_H1, + extra_certs.clone(), + ConnectionCerts::new(), + ); + + let mut context = FetchContext { + state: Arc::new(HttpState::new(tls_config)), + user_agent: DEFAULT_USER_AGENT.into(), + devtools_chan: None, + filemanager: FileManager::new(create_embedder_proxy(), Weak::new()), + file_token: FileTokenCheck::NotRequired, + cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))), + timing: ServoArc::new(Mutex::new(ResourceFetchTiming::new( + ResourceTimingType::Navigation, + ))), + }; + + let mut request = RequestBuilder::new(url.clone()) + .method(Method::GET) + .body(None) + .destination(Destination::Document) + .origin(url.clone().origin()) + .pipeline_id(Some(TEST_PIPELINE_ID)) + .build(); + + let response = fetch_with_context(&mut request, &mut context); + + assert!(matches!( + response.get_network_error(), + Some(NetworkError::SslValidation(..)) + )); + + extra_certs.add(cert_data.as_bytes().into()); + + // FIXME: something weird happens inside the SSL server after the first + // connection encounters a verification error, and it no longer + // accepts new connections that should work fine. We are forced + // to start a new server and connect to that to verfiy that + // the self-signed cert is now accepted. + + let (server, mut url) = make_ssl_server(handler, cert_path.clone(), key_path.clone()); + url.as_mut_url().set_scheme("https").unwrap(); + + let mut request = RequestBuilder::new(url.clone()) + .method(Method::GET) + .body(None) + .destination(Destination::Document) + .origin(url.clone().origin()) + .pipeline_id(Some(TEST_PIPELINE_ID)) + .build(); + + let response = fetch_with_context(&mut request, &mut context); + + assert!(response.status.unwrap().0.is_success()); + + let _ = server.close(); +} + +#[test] fn test_fetch_with_sri_network_error() { static MESSAGE: &'static [u8] = b"alert('Hello, Network Error');"; let handler = move |_: HyperRequest<Body>, response: &mut HyperResponse<Body>| { diff --git a/components/net/tests/main.rs b/components/net/tests/main.rs index c48ac873729..7583fdf0fc5 100644 --- a/components/net/tests/main.rs +++ b/components/net/tests/main.rs @@ -29,7 +29,7 @@ use hyper::server::conn::Http; use hyper::server::Server as HyperServer; use hyper::service::service_fn_ok; use hyper::{Body, Request as HyperRequest, Response as HyperResponse}; -use net::connector::{create_tls_config, ALPN_H2_H1}; +use net::connector::{create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H2_H1}; use net::fetch::cors_cache::CorsCache; use net::fetch::methods::{self, CancellationListener, FetchContext}; use net::filemanager_thread::FileManager; @@ -91,7 +91,12 @@ fn new_fetch_context( pool_handle: Option<Weak<CoreResourceThreadPool>>, ) -> FetchContext { let certs = resources::read_string(Resource::SSLCertificates); - let tls_config = create_tls_config(&certs, ALPN_H2_H1); + let tls_config = create_tls_config( + &certs, + ALPN_H2_H1, + ExtraCerts::new(), + ConnectionCerts::new(), + ); let sender = fc.unwrap_or_else(|| create_embedder_proxy()); FetchContext { diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs index 69d3c430fcb..bece51173bb 100644 --- a/components/net/websocket_loader.rs +++ b/components/net/websocket_loader.rs @@ -2,7 +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::connector::{create_tls_config, ALPN_H1}; +use crate::connector::{create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H1}; use crate::cookie::Cookie; use crate::fetch::methods::should_be_blocked_due_to_bad_port; use crate::hosts::replace_host; @@ -38,6 +38,8 @@ struct Client<'a> { event_sender: &'a IpcSender<WebSocketNetworkEvent>, protocol_in_use: Option<String>, certificate_path: Option<String>, + extra_certs: ExtraCerts, + connection_certs: ConnectionCerts, } impl<'a> Factory for Client<'a> { @@ -167,7 +169,12 @@ impl<'a> Handler for Client<'a> { WebSocketErrorKind::Protocol, format!("Unable to parse domain from {}. Needed for SSL.", url), ))?; - let tls_config = create_tls_config(&certs, ALPN_H1); + let tls_config = create_tls_config( + &certs, + ALPN_H1, + self.extra_certs.clone(), + self.connection_certs.clone(), + ); tls_config .build() .connect(domain, stream) @@ -181,6 +188,8 @@ pub fn init( dom_action_receiver: IpcReceiver<WebSocketDomAction>, http_state: Arc<HttpState>, certificate_path: Option<String>, + extra_certs: ExtraCerts, + connection_certs: ConnectionCerts, ) { thread::Builder::new() .name(format!("WebSocket connection to {}", req_builder.url)) @@ -229,6 +238,8 @@ pub fn init( event_sender: &resource_event_sender, protocol_in_use: None, certificate_path, + extra_certs, + connection_certs, }; let mut ws = WebSocket::new(client).unwrap(); diff --git a/components/net_traits/Cargo.toml b/components/net_traits/Cargo.toml index 543d2b538c9..0e663b91bfd 100644 --- a/components/net_traits/Cargo.toml +++ b/components/net_traits/Cargo.toml @@ -33,6 +33,7 @@ piston_image = { package = "image", version = "0.23" } pixels = { path = "../pixels" } serde = "1.0" servo_arc = { path = "../servo_arc" } +servo_rand = { path = "../rand" } servo_url = { path = "../url" } time = "0.1" url = "2.0" diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 3222daceff0..6dea965d7f8 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -30,6 +30,7 @@ use ipc_channel::router::ROUTER; use ipc_channel::Error as IpcError; use mime::Mime; use msg::constellation_msg::HistoryStateId; +use servo_rand::RngCore; use servo_url::{ImmutableOrigin, ServoUrl}; use time::precise_time_ns; use webrender_api::{ImageData, ImageDescriptor, ImageKey}; @@ -712,12 +713,17 @@ pub enum NetworkError { Internal(String), LoadCancelled, /// SSL validation error that has to be handled in the HTML parser - SslValidation(ServoUrl, String), + SslValidation(String, Vec<u8>), } impl NetworkError { - pub fn from_hyper_error(error: &HyperError) -> Self { - NetworkError::Internal(error.to_string()) + pub fn from_hyper_error(error: &HyperError, cert_bytes: Option<Vec<u8>>) -> Self { + let s = error.to_string(); + if s.contains("the handshake failed") { + NetworkError::SslValidation(s, cert_bytes.unwrap_or_default()) + } else { + NetworkError::Internal(s) + } } pub fn from_http_error(error: &HttpError) -> Self { @@ -806,3 +812,7 @@ impl WebrenderIpcSender { } } } + +lazy_static! { + pub static ref PRIVILEGED_SECRET: u32 = servo_rand::ServoRng::new().next_u32(); +} diff --git a/components/net_traits/request.rs b/components/net_traits/request.rs index 8906f4f038f..7af3855720d 100644 --- a/components/net_traits/request.rs +++ b/components/net_traits/request.rs @@ -164,7 +164,7 @@ impl RequestBody { } } - pub fn take_stream(&mut self) -> Option<IpcSender<BodyChunkRequest>> { + pub fn take_stream(&mut self) -> IpcSender<BodyChunkRequest> { if self.read_from { match self.source { BodySource::Null => panic!( @@ -174,12 +174,12 @@ impl RequestBody { let (chan, port) = ipc::channel().unwrap(); let _ = self.chan.send(BodyChunkRequest::Extract(port)); self.chan = chan.clone(); - return Some(chan); + return chan; }, } } self.read_from = true; - Some(self.chan.clone()) + self.chan.clone() } pub fn source_is_null(&self) -> bool { diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 0bcf2f45d0f..3a5e9880375 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -213,7 +213,10 @@ impl VideoFrameRenderer for MediaFrameRenderer { Some((ref mut image_key, ref mut width, ref mut height)) => { self.old_frame = Some(*image_key); - let new_image_key = self.api.generate_image_key(); + let new_image_key = match self.api.generate_image_key() { + Ok(key) => key, + Err(()) => return, + }; /* update current_frame */ *image_key = new_image_key; @@ -243,7 +246,10 @@ impl VideoFrameRenderer for MediaFrameRenderer { updates.push(ImageUpdate::AddImage(new_image_key, descriptor, image_data)); }, None => { - let image_key = self.api.generate_image_key(); + let image_key = match self.api.generate_image_key() { + Ok(key) => key, + Err(()) => return, + }; self.current_frame = Some((image_key, frame.get_width(), frame.get_height())); let image_data = if frame.is_gl_texture() && self.player_id.is_some() { diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index d1a4a18df18..3949f70c53e 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -731,9 +731,9 @@ impl FetchResponseListener for ParserContext { FetchMetadata::Unfiltered(m) => m, FetchMetadata::Filtered { unsafe_, .. } => unsafe_, }), - Err(NetworkError::SslValidation(url, reason)) => { - ssl_error = Some(reason); - let mut meta = Metadata::default(url); + Err(NetworkError::SslValidation(reason, cert_bytes)) => { + ssl_error = Some((reason, cert_bytes)); + let mut meta = Metadata::default(self.url.clone()); let mime: Option<Mime> = "text/html".parse().ok(); meta.set_content_type(mime.as_ref()); Some(meta) @@ -815,10 +815,14 @@ impl FetchResponseListener for ParserContext { }, Some(ref mime) if mime.type_() == mime::TEXT && mime.subtype() == mime::HTML => { // Handle text/html - if let Some(reason) = ssl_error { + if let Some((reason, bytes)) = ssl_error { self.is_synthesized_document = true; let page = resources::read_string(Resource::BadCertHTML); let page = page.replace("${reason}", &reason); + let page = + page.replace("${bytes}", std::str::from_utf8(&bytes).unwrap_or_default()); + let page = + page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string()); parser.push_string_input_chunk(page); parser.parse_sync(); } diff --git a/components/script/dom/webidls/XMLHttpRequest.webidl b/components/script/dom/webidls/XMLHttpRequest.webidl index 097b4f7177c..2c043b9407a 100644 --- a/components/script/dom/webidls/XMLHttpRequest.webidl +++ b/components/script/dom/webidls/XMLHttpRequest.webidl @@ -12,8 +12,11 @@ * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0. */ +// https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit +typedef (Blob or BufferSource or FormData or DOMString or URLSearchParams) XMLHttpRequestBodyInit; + // https://fetch.spec.whatwg.org/#bodyinit -typedef (Blob or BufferSource or FormData or DOMString or URLSearchParams or ReadableStream) BodyInit; +typedef (ReadableStream or XMLHttpRequestBodyInit) BodyInit; enum XMLHttpRequestResponseType { "", @@ -54,7 +57,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget { attribute boolean withCredentials; readonly attribute XMLHttpRequestUpload upload; [Throws] - void send(optional (Document or BodyInit)? data = null); + void send(optional (Document or XMLHttpRequestBodyInit)? data = null); void abort(); // response diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 553cfcb40b0..03a5f5c7bff 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -8,7 +8,7 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestMethods; use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestResponseType; -use crate::dom::bindings::codegen::UnionTypes::DocumentOrBodyInit; +use crate::dom::bindings::codegen::UnionTypes::DocumentOrXMLHttpRequestBodyInit; use crate::dom::bindings::conversions::ToJSValConvertible; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; @@ -547,7 +547,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { } // https://xhr.spec.whatwg.org/#the-send()-method - fn Send(&self, data: Option<DocumentOrBodyInit>) -> ErrorResult { + fn Send(&self, data: Option<DocumentOrXMLHttpRequestBodyInit>) -> ErrorResult { // Step 1, 2 if self.ready_state.get() != XMLHttpRequestState::Opened || self.send_flag.get() { return Err(Error::InvalidState); @@ -560,7 +560,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { }; // Step 4 (first half) let mut extracted_or_serialized = match data { - Some(DocumentOrBodyInit::Document(ref doc)) => { + Some(DocumentOrXMLHttpRequestBodyInit::Document(ref doc)) => { let bytes = Vec::from(serialize_document(&doc)?.as_ref()); let content_type = if doc.is_html_document() { "text/html;charset=UTF-8" @@ -577,7 +577,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { source: BodySource::Object, }) }, - Some(DocumentOrBodyInit::Blob(ref b)) => { + Some(DocumentOrXMLHttpRequestBodyInit::Blob(ref b)) => { let extracted_body = b.extract(&self.global()).expect("Couldn't extract body."); if !extracted_body.in_memory() && self.sync.get() { warn!("Sync XHR with not in-memory Blob as body not supported"); @@ -586,20 +586,20 @@ impl XMLHttpRequestMethods for XMLHttpRequest { Some(extracted_body) } }, - Some(DocumentOrBodyInit::FormData(ref formdata)) => Some( + Some(DocumentOrXMLHttpRequestBodyInit::FormData(ref formdata)) => Some( formdata .extract(&self.global()) .expect("Couldn't extract body."), ), - Some(DocumentOrBodyInit::String(ref str)) => { + Some(DocumentOrXMLHttpRequestBodyInit::String(ref str)) => { Some(str.extract(&self.global()).expect("Couldn't extract body.")) }, - Some(DocumentOrBodyInit::URLSearchParams(ref urlsp)) => Some( + Some(DocumentOrXMLHttpRequestBodyInit::URLSearchParams(ref urlsp)) => Some( urlsp .extract(&self.global()) .expect("Couldn't extract body."), ), - Some(DocumentOrBodyInit::ArrayBuffer(ref typedarray)) => { + Some(DocumentOrXMLHttpRequestBodyInit::ArrayBuffer(ref typedarray)) => { let bytes = typedarray.to_vec(); let total_bytes = bytes.len(); let global = self.global(); @@ -611,7 +611,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { source: BodySource::Object, }) }, - Some(DocumentOrBodyInit::ArrayBufferView(ref typedarray)) => { + Some(DocumentOrXMLHttpRequestBodyInit::ArrayBufferView(ref typedarray)) => { let bytes = typedarray.to_vec(); let total_bytes = bytes.len(); let global = self.global(); @@ -623,25 +623,6 @@ impl XMLHttpRequestMethods for XMLHttpRequest { source: BodySource::Object, }) }, - Some(DocumentOrBodyInit::ReadableStream(ref stream)) => { - if self.sync.get() { - warn!("Sync XHR with ReadableStream as body not supported"); - None - } else { - if stream.is_locked() || stream.is_disturbed() { - return Err(Error::Type( - "The body's stream is disturbed or locked".to_string(), - )); - } - - Some(ExtractedBody { - stream: stream.clone(), - total_bytes: None, - content_type: None, - source: BodySource::Null, - }) - } - }, None => None, }; @@ -725,7 +706,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest { match content_type { Some(content_type) => { let encoding = match data { - Some(DocumentOrBodyInit::String(_)) | Some(DocumentOrBodyInit::Document(_)) => + Some(DocumentOrXMLHttpRequestBodyInit::String(_)) | + Some(DocumentOrXMLHttpRequestBodyInit::Document(_)) => // XHR spec differs from http, and says UTF-8 should be in capitals, // instead of "utf-8", which is what Hyper defaults to. So not // using content types provided by Hyper. diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index fc532ff2866..b3e92cbce21 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -1100,12 +1100,11 @@ impl From<i32> for MediaSessionActionType { #[derive(Deserialize, Serialize)] pub enum WebrenderMsg { /// Inform WebRender of the existence of this pipeline. - SendInitialTransaction(DocumentId, webrender_api::PipelineId), + SendInitialTransaction(webrender_api::PipelineId), /// Perform a scroll operation. - SendScrollNode(DocumentId, LayoutPoint, ExternalScrollId, ScrollClamping), + SendScrollNode(LayoutPoint, ExternalScrollId, ScrollClamping), /// Inform WebRender of a new display list for the given pipeline. SendDisplayList( - DocumentId, webrender_api::Epoch, LayoutSize, webrender_api::PipelineId, @@ -1116,7 +1115,6 @@ pub enum WebrenderMsg { /// Perform a hit test operation. The result will be returned via /// the provided channel sender. HitTest( - DocumentId, Option<webrender_api::PipelineId>, WorldPoint, HitTestFlags, @@ -1140,15 +1138,8 @@ impl WebrenderIpcSender { } /// Inform WebRender of the existence of this pipeline. - pub fn send_initial_transaction( - &self, - document: DocumentId, - pipeline: webrender_api::PipelineId, - ) { - if let Err(e) = self - .0 - .send(WebrenderMsg::SendInitialTransaction(document, pipeline)) - { + pub fn send_initial_transaction(&self, pipeline: webrender_api::PipelineId) { + if let Err(e) = self.0.send(WebrenderMsg::SendInitialTransaction(pipeline)) { warn!("Error sending initial transaction: {}", e); } } @@ -1156,14 +1147,14 @@ impl WebrenderIpcSender { /// Perform a scroll operation. pub fn send_scroll_node( &self, - document: DocumentId, point: LayoutPoint, scroll_id: ExternalScrollId, clamping: ScrollClamping, ) { - if let Err(e) = self.0.send(WebrenderMsg::SendScrollNode( - document, point, scroll_id, clamping, - )) { + if let Err(e) = self + .0 + .send(WebrenderMsg::SendScrollNode(point, scroll_id, clamping)) + { warn!("Error sending scroll node: {}", e); } } @@ -1171,14 +1162,12 @@ impl WebrenderIpcSender { /// Inform WebRender of a new display list for the given pipeline. pub fn send_display_list( &self, - document: DocumentId, epoch: Epoch, size: LayoutSize, (pipeline, size2, list): (webrender_api::PipelineId, LayoutSize, BuiltDisplayList), ) { let (data, descriptor) = list.into_data(); if let Err(e) = self.0.send(WebrenderMsg::SendDisplayList( - document, webrender_api::Epoch(epoch.0), size, pipeline, @@ -1194,27 +1183,24 @@ impl WebrenderIpcSender { /// and a result is available. pub fn hit_test( &self, - document: DocumentId, pipeline: Option<webrender_api::PipelineId>, point: WorldPoint, flags: HitTestFlags, ) -> HitTestResult { let (sender, receiver) = ipc::channel().unwrap(); self.0 - .send(WebrenderMsg::HitTest( - document, pipeline, point, flags, sender, - )) + .send(WebrenderMsg::HitTest(pipeline, point, flags, sender)) .expect("error sending hit test"); receiver.recv().expect("error receiving hit test result") } /// Create a new image key. Blocks until the key is available. - pub fn generate_image_key(&self) -> ImageKey { + pub fn generate_image_key(&self) -> Result<ImageKey, ()> { let (sender, receiver) = ipc::channel().unwrap(); self.0 .send(WebrenderMsg::GenerateImageKey(sender)) - .expect("error sending image key generation"); - receiver.recv().expect("error receiving image key result") + .map_err(|_| ())?; + receiver.recv().map_err(|_| ()) } /// Perform a resource update operation. diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 1cb332e3da9..96b2ad36f68 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -38,6 +38,7 @@ webrender_debugger = ["webrender/debugger"] xr-profile = ["canvas/xr-profile", "canvas_traits/xr-profile", "script/xr-profile", "webxr/profile"] [dependencies] +app_units = "0.7" background_hang_monitor = { path = "../background_hang_monitor" } bluetooth = { path = "../bluetooth" } bluetooth_traits = { path = "../bluetooth_traits" } @@ -53,6 +54,7 @@ embedder_traits = { path = "../embedder_traits" } env_logger = "0.7" euclid = "0.20" gfx = { path = "../gfx" } +gfx_traits = { path = "../gfx_traits" } gleam = "0.11" gstreamer = { version = "0.15", optional = true } ipc-channel = "0.14" diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 9278fb5c0de..25fdd2261b4 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -64,10 +64,12 @@ fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) {} use bluetooth::BluetoothThreadFactory; use bluetooth_traits::BluetoothRequest; +use canvas::canvas_paint_thread::{self, CanvasPaintThread}; use canvas::{SurfaceProviders, WebGLComm, WebGlExecutor}; use canvas_traits::webgl::WebGLThreads; use compositing::compositor_thread::{ - CompositorProxy, CompositorReceiver, InitialCompositorState, Msg, + CompositorProxy, CompositorReceiver, InitialCompositorState, Msg, WebrenderCanvasMsg, + WebrenderFontMsg, WebrenderMsg, }; use compositing::windowing::{EmbedderMethods, WindowEvent, WindowMethods}; use compositing::{CompositingReason, ConstellationMsg, IOCompositor, ShutdownState}; @@ -115,7 +117,6 @@ use std::borrow::Cow; use std::cmp::max; use std::path::PathBuf; use std::rc::Rc; -use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex}; use surfman::GLApi; use webrender::ShaderPrecacheFlags; @@ -454,7 +455,7 @@ where webrender_surfman.clone(), webrender_gl.clone(), &mut webrender, - webrender_api_sender.clone(), + webrender_api.create_sender(), webrender_document, &mut webxr_main_thread, &mut external_image_handlers, @@ -500,8 +501,6 @@ where device_pixel_ratio: Scale::new(device_pixel_ratio), }; - let pending_wr_frame = Arc::new(AtomicBool::new(false)); - // Create the constellation, which maintains the engine // pipelines, including the script and layout threads, as well // as the navigation context. @@ -515,14 +514,12 @@ where debugger_chan, devtools_chan, webrender_document, - webrender_api_sender, webxr_main_thread.registry(), player_context, webgl_threads, glplayer_threads, event_loop_waker, window_size, - pending_wr_frame.clone(), ); if cfg!(feature = "webdriver") { @@ -547,7 +544,6 @@ where webrender_surfman, webrender_gl, webxr_main_thread, - pending_wr_frame, }, opts.output_file.clone(), opts.is_running_problem_test, @@ -855,14 +851,12 @@ fn create_constellation( debugger_chan: Option<debugger::Sender>, devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>, webrender_document: webrender_api::DocumentId, - webrender_api_sender: webrender_api::RenderApiSender, webxr_registry: webxr_api::Registry, player_context: WindowGLContext, webgl_threads: Option<WebGLThreads>, glplayer_threads: Option<GLPlayerThreads>, event_loop_waker: Option<Box<dyn EventLoopWaker>>, initial_window_size: WindowSizeData, - pending_wr_frame: Arc<AtomicBool>, ) -> Sender<ConstellationMsg> { // Global configuration options, parsed from the command line. let opts = opts::get(); @@ -879,14 +873,14 @@ fn create_constellation( config_dir, opts.certificate_path.clone(), ); + let font_cache_thread = FontCacheThread::new( public_resource_threads.sender(), - webrender_api_sender.create_api(), - webrender_document, + Box::new(FontCacheWR(compositor_proxy.clone())), ); let initial_state = InitialConstellationState { - compositor_proxy, + compositor_proxy: compositor_proxy.clone(), embedder_proxy, debugger_chan, devtools_chan, @@ -897,17 +891,16 @@ fn create_constellation( time_profiler_chan, mem_profiler_chan, webrender_document, - webrender_api_sender, webxr_registry, webgl_threads, glplayer_threads, player_context, event_loop_waker, - pending_wr_frame, user_agent, }; - let (canvas_chan, ipc_canvas_chan) = canvas::canvas_paint_thread::CanvasPaintThread::start(); + let (canvas_chan, ipc_canvas_chan) = + CanvasPaintThread::start(Box::new(CanvasWebrenderApi(compositor_proxy))); let constellation_chan = Constellation::< script_layout_interface::message::Msg, @@ -929,6 +922,50 @@ fn create_constellation( constellation_chan } +struct FontCacheWR(CompositorProxy); + +impl gfx_traits::WebrenderApi for FontCacheWR { + fn add_font_instance( + &self, + font_key: webrender_api::FontKey, + size: app_units::Au, + ) -> webrender_api::FontInstanceKey { + let (sender, receiver) = unbounded(); + let _ = self.0.send(Msg::Webrender(WebrenderMsg::Font( + WebrenderFontMsg::AddFontInstance(font_key, size, sender), + ))); + receiver.recv().unwrap() + } + fn add_font(&self, data: gfx_traits::FontData) -> webrender_api::FontKey { + let (sender, receiver) = unbounded(); + let _ = self.0.send(Msg::Webrender(WebrenderMsg::Font( + WebrenderFontMsg::AddFont(data, sender), + ))); + receiver.recv().unwrap() + } +} + +#[derive(Clone)] +struct CanvasWebrenderApi(CompositorProxy); + +impl canvas_paint_thread::WebrenderApi for CanvasWebrenderApi { + fn generate_key(&self) -> webrender_api::ImageKey { + let (sender, receiver) = unbounded(); + let _ = self.0.send(Msg::Webrender(WebrenderMsg::Canvas( + WebrenderCanvasMsg::GenerateKey(sender), + ))); + receiver.recv().unwrap() + } + fn update_images(&self, updates: Vec<canvas_paint_thread::ImageUpdate>) { + let _ = self.0.send(Msg::Webrender(WebrenderMsg::Canvas( + WebrenderCanvasMsg::UpdateImages(updates), + ))); + } + fn clone(&self) -> Box<dyn canvas_paint_thread::WebrenderApi> { + Box::new(<Self as Clone>::clone(self)) + } +} + // A logger that logs to two downstream loggers. // This should probably be in the log crate. struct BothLogger<Log1, Log2>(Log1, Log2); diff --git a/resources/badcert.html b/resources/badcert.html index 5a96eee377e..392bddc0572 100644 --- a/resources/badcert.html +++ b/resources/badcert.html @@ -3,6 +3,26 @@ <title>Certificate error</title> </head> <body> - <p>${reason}</p> + <p>${reason}</p> + <pre id="bytes">${bytes}</pre> + <button id="leave" onclick="history.back()">Go back (recommended)</button> + <button id="allow">Allow certificate temporarily</button> + <script> + let bytes = document.getElementById('bytes').textContent; + let button = document.getElementById('allow'); + let exitButton = document.getElementById('leave'); + if (bytes.length) { + button.onclick = function() { + let xhr = new XMLHttpRequest(); + xhr.open('POST', 'chrome:allowcert'); + xhr.onloadend = function() { + location.reload(true); + }; + xhr.send("${secret}&" + btoa(bytes)); + }; + } else { + button.style.display = "none"; + } + </script> </body> </html> diff --git a/resources/servo.css b/resources/servo.css index bc8d4f1223a..ed6bc3e93dd 100644 --- a/resources/servo.css +++ b/resources/servo.css @@ -1,3 +1,7 @@ +button { + cursor: default; +} + button, input { background: white; diff --git a/servo-tidy.toml b/servo-tidy.toml index 480b9fd9ddc..7fb6c99845f 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -37,7 +37,6 @@ packages = [ "wayland-sys", "parking_lot", "parking_lot_core", - "ron", # https://github.com/servo/servo/pull/23288#issuecomment-494687746 "gl_generator", diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index e57b659685e..616563a4e31 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -528572,7 +528572,7 @@ ] ], "send-data-es-object.any.js": [ - "c6fe5de260c212013052f66636b92fb07aa82373", + "92286bca6dd00b82b78de39fcf7988ba1c424d07", [ "xhr/send-data-es-object.any.html", { @@ -528621,42 +528621,6 @@ } ] ], - "send-data-readablestream.any.js": [ - "c53b1071828f95669d41a967c51bd352b389bebb", - [ - "xhr/send-data-readablestream.any.html", - { - "script_metadata": [ - [ - "global", - "window,dedicatedworker,sharedworker" - ] - ] - } - ], - [ - "xhr/send-data-readablestream.any.sharedworker.html", - { - "script_metadata": [ - [ - "global", - "window,dedicatedworker,sharedworker" - ] - ] - } - ], - [ - "xhr/send-data-readablestream.any.worker.html", - { - "script_metadata": [ - [ - "global", - "window,dedicatedworker,sharedworker" - ] - ] - } - ] - ], "send-data-sharedarraybuffer.any.js": [ "912f622697d538edbbc038f7ec76c2e63ee6ffa0", [ @@ -529008,7 +528972,7 @@ ] ], "setrequestheader-content-type.htm": [ - "8608c5967d6b29ba4f9d09ae7bf395a6b26876c2", + "07238391eb5cc8639edbe996208a18b6d9d26b04", [ null, { diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini new file mode 100644 index 00000000000..5496474410b --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-animation.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-animation.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-interposed.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-interposed.html.ini new file mode 100644 index 00000000000..f4ba42ba597 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-interposed.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-blended-element-interposed.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini new file mode 100644 index 00000000000..b88377b7471 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-blended-element-overflow-hidden-and-border-radius.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini new file mode 100644 index 00000000000..0cc8e7d5b89 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-overflow-scroll.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-blended-element-overflow-scroll.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-with-transparent-pixels.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-with-transparent-pixels.html.ini new file mode 100644 index 00000000000..e969ccfd9ae --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blended-element-with-transparent-pixels.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-blended-element-with-transparent-pixels.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blending-with-sibling.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blending-with-sibling.html.ini new file mode 100644 index 00000000000..51bd95228fb --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-blending-with-sibling.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-blending-with-sibling.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini index c66c3bf2773..db1a30234d6 100644 --- a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-both-parent-and-blended-with-3D-transform.html.ini @@ -1,3 +1,2 @@ [mix-blend-mode-both-parent-and-blended-with-3D-transform.html] - expected: - if os == "linux": FAIL + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-canvas-parent.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-canvas-parent.html.ini new file mode 100644 index 00000000000..3bca294ac5f --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-canvas-parent.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-canvas-parent.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-canvas-sibling.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-canvas-sibling.html.ini new file mode 100644 index 00000000000..2bc23c0b9b2 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-canvas-sibling.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-canvas-sibling.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-iframe-parent.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-iframe-parent.html.ini new file mode 100644 index 00000000000..85229ea8e3f --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-iframe-parent.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-iframe-parent.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-iframe-sibling.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-iframe-sibling.html.ini new file mode 100644 index 00000000000..17f22fdb1af --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-iframe-sibling.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-iframe-sibling.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-image.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-image.html.ini new file mode 100644 index 00000000000..7aa3a5aefe5 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-image.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-image.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html.ini index d8f5591b8fd..cfb2c1eebe7 100644 --- a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html.ini +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html.ini @@ -1,2 +1,3 @@ [mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html] fuzzy: /css/compositing/mix-blend-mode/reference/mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius-ref.html:9;8 + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-mask.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-mask.html.ini new file mode 100644 index 00000000000..1f039c2f7aa --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-mask.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-mask.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child-of-blended-element.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child-of-blended-element.html.ini new file mode 100644 index 00000000000..e628a53f56c --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child-of-blended-element.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-overflowing-child-of-blended-element.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child.html.ini new file mode 100644 index 00000000000..f50a0515ca4 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-overflowing-child.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-overflowing-child.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html.ini new file mode 100644 index 00000000000..f0050373a67 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-parent-element-overflow-scroll-blended-position-fixed.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll.html.ini new file mode 100644 index 00000000000..87eb5cbd4c6 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-element-overflow-scroll.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-parent-element-overflow-scroll.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini new file mode 100644 index 00000000000..3260cfddf6f --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-parent-with-3D-transform.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-border-radius.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-border-radius.html.ini new file mode 100644 index 00000000000..52a1cbb7a26 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-border-radius.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-parent-with-border-radius.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-text.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-text.html.ini index 89ffd68a401..8e6331ff659 100644 --- a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-text.html.ini +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-parent-with-text.html.ini @@ -1,3 +1,2 @@ [mix-blend-mode-parent-with-text.html] - expected: - if os == "linux": FAIL + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-script.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-script.html.ini new file mode 100644 index 00000000000..d9d62c6cff4 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-script.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-script.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform.html.ini new file mode 100644 index 00000000000..89b4eb5a86a --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-sibling-with-3D-transform.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-simple.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-simple.html.ini new file mode 100644 index 00000000000..b75b4a3d3e2 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-simple.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-simple.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-creates-isolation.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-creates-isolation.html.ini new file mode 100644 index 00000000000..8e3c2a518e1 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-creates-isolation.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-stacking-context-creates-isolation.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-with-transform-and-preserve-3D.html.ini b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-with-transform-and-preserve-3D.html.ini new file mode 100644 index 00000000000..5277e6aca56 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/mix-blend-mode/mix-blend-mode-with-transform-and-preserve-3D.html.ini @@ -0,0 +1,2 @@ +[mix-blend-mode-with-transform-and-preserve-3D.html] + expected: FAIL diff --git a/tests/wpt/metadata/css/compositing/root-element-blend-mode.html.ini b/tests/wpt/metadata/css/compositing/root-element-blend-mode.html.ini new file mode 100644 index 00000000000..448b96b4886 --- /dev/null +++ b/tests/wpt/metadata/css/compositing/root-element-blend-mode.html.ini @@ -0,0 +1,2 @@ +[root-element-blend-mode.html] + expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 5ce021feee6..47ba62031be 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -6080,6 +6080,19 @@ {} ] ], + "stacking-context-empty.html": [ + "952c73f1680805dc3a976446bb509cb924a6a702", + [ + null, + [ + [ + "/_mozilla/css/stacking-context-empty-ref.html", + "==" + ] + ], + {} + ] + ], "stacking_context_overflow_a.html": [ "dc379afb77977b0e99a0a8ce3321c9afff236a37", [ @@ -10311,6 +10324,10 @@ "0525bab6b11800d29f90efc7efef0f43165fba01", [] ], + "stacking-context-empty-ref.html": [ + "8006e2413694b0776f000d3b8138bed29812b7cd", + [] + ], "stacking_context_overflow_ref.html": [ "49991c449ab4f42afae6f512a7f184e70d77bc34", [] diff --git a/tests/wpt/mozilla/meta/css/inline_block_baseline_a.html.ini b/tests/wpt/mozilla/meta/css/inline_block_baseline_a.html.ini index 88c40a7a0ae..91cee3c0295 100644 --- a/tests/wpt/mozilla/meta/css/inline_block_baseline_a.html.ini +++ b/tests/wpt/mozilla/meta/css/inline_block_baseline_a.html.ini @@ -1,3 +1,4 @@ [inline_block_baseline_a.html] expected: - if os == "mac": FAIL + if os == "linux": FAIL + fuzzy: /_mozilla/css/inline_block_baseline_ref.html:49;2097 diff --git a/tests/wpt/mozilla/tests/css/stacking-context-empty-ref.html b/tests/wpt/mozilla/tests/css/stacking-context-empty-ref.html new file mode 100644 index 00000000000..8006e241369 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/stacking-context-empty-ref.html @@ -0,0 +1 @@ +<p><img src="100x100_green.png"> diff --git a/tests/wpt/mozilla/tests/css/stacking-context-empty.html b/tests/wpt/mozilla/tests/css/stacking-context-empty.html new file mode 100644 index 00000000000..952c73f1680 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/stacking-context-empty.html @@ -0,0 +1,14 @@ +<link rel="match" href="stacking-context-empty-ref.html"> +<style> + div { + border-radius: 2px; + background: #777; + border-bottom: 1px solid #f1f1f1; + } +.test { + transform: scaleX(0); +} +</style> +<p><img src="100x100_green.png"> +<div class="test">aaa</div> +<p><img class="test" src="100x100_green.png"> diff --git a/tests/wpt/web-platform-tests/xhr/send-data-es-object.any.js b/tests/wpt/web-platform-tests/xhr/send-data-es-object.any.js index c6fe5de260c..92286bca6dd 100644 --- a/tests/wpt/web-platform-tests/xhr/send-data-es-object.any.js +++ b/tests/wpt/web-platform-tests/xhr/send-data-es-object.any.js @@ -27,6 +27,7 @@ function do_test(obj, expected, name) { do_test({}, '[object Object]', 'sending a plain empty object') do_test(Math, '[object Math]', 'sending the ES Math object') do_test(new XMLHttpRequest, '[object XMLHttpRequest]', 'sending a new XHR instance') +do_test(new ReadableStream, '[object ReadableStream]', 'sending a new ReadableStream instance') do_test({toString:function(){}}, 'undefined', 'sending object that stringifies to undefined') do_test({toString:function(){return null}}, 'null', 'sending object that stringifies to null') var ancestor = {toString: function(){ diff --git a/tests/wpt/web-platform-tests/xhr/send-data-readablestream.any.js b/tests/wpt/web-platform-tests/xhr/send-data-readablestream.any.js deleted file mode 100644 index c53b1071828..00000000000 --- a/tests/wpt/web-platform-tests/xhr/send-data-readablestream.any.js +++ /dev/null @@ -1,27 +0,0 @@ -// META: global=window,dedicatedworker,sharedworker - -function assert_xhr(stream) { - const client = new XMLHttpRequest(); - client.open("POST", "..."); - assert_throws_js(TypeError, () => client.send(stream)); -} - -test(() => { - const stream = new ReadableStream(); - stream.getReader(); - assert_xhr(stream); -}, "XMLHttpRequest: send() with a stream on which getReader() is called"); - -test(() => { - const stream = new ReadableStream(); - stream.getReader().read(); - assert_xhr(stream); -}, "XMLHttpRequest: send() with a stream on which read() is called"); - -promise_test(async () => { - const stream = new ReadableStream({ pull: c => c.enqueue(new Uint8Array()) }), - reader = stream.getReader(); - await reader.read(); - reader.releaseLock(); - assert_xhr(stream); -}, "XMLHttpRequest: send() with a stream on which read() and releaseLock() are called"); diff --git a/tests/wpt/web-platform-tests/xhr/setrequestheader-content-type.htm b/tests/wpt/web-platform-tests/xhr/setrequestheader-content-type.htm index 8608c5967d6..07238391eb5 100644 --- a/tests/wpt/web-platform-tests/xhr/setrequestheader-content-type.htm +++ b/tests/wpt/web-platform-tests/xhr/setrequestheader-content-type.htm @@ -215,24 +215,6 @@ // https://fetch.spec.whatwg.org/#bodyinit, so the user's must be changed to match it // as per https://xhr.spec.whatwg.org/#the-send%28%29-method step 4. ) - request( - function _ReadableStream() { return new ReadableStream() }, - {"Content-Type": ""}, - "", - 'ReadableStream request respects setRequestHeader("")' - ) - request( - function _ReadableStream() { return new ReadableStream() }, - {}, - undefined, - "ReadableStream request with under type sends no Content-Type without setRequestHeader() call" - ) - request( - function _ReadableStream() { return new ReadableStream() }, - {"Content-Type": "application/xml;charset=ASCII"}, - "application/xml;charset=ASCII", - "ReadableStream request keeps setRequestHeader() Content-Type and charset" - ) </script> </body> </html> |