diff options
386 files changed, 11236 insertions, 5295 deletions
diff --git a/.travis.yml b/.travis.yml index 44bb3c52ccb..7796d98cd23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,9 @@ matrix: - xorg-dev - ccache - libdbus-glib-1-dev + - libavformat-dev + - libavcodec-dev + - libavutil-dev branches: only: diff --git a/README.md b/README.md index 00d8a650d71..5164f01c958 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ sudo apt-get install git curl freeglut3-dev autoconf \ libfreetype6-dev libgl1-mesa-dri libglib2.0-dev xorg-dev \ gperf g++ build-essential cmake virtualenv python-pip \ libssl-dev libbz2-dev libosmesa6-dev libxmu6 libxmu-dev \ - libglu1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev + libglu1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev \ + libavformat-dev ``` If you are on **Ubuntu 14.04** and encountered errors on installing these dependencies involving `libcheese`, see [#6158](https://github.com/servo/servo/issues/6158) for a workaround. @@ -56,7 +57,7 @@ sudo dnf install curl freeglut-devel libtool gcc-c++ libXi-devel \ freetype-devel mesa-libGL-devel mesa-libEGL-devel glib2-devel libX11-devel libXrandr-devel gperf \ fontconfig-devel cabextract ttmkfdir python python-virtualenv python-pip expat-devel \ rpm-build openssl-devel cmake bzip2-devel libXcursor-devel libXmu-devel mesa-libOSMesa-devel \ - dbus-devel + dbus-devel ffmpeg-devel ``` On Arch Linux: @@ -80,14 +81,21 @@ Download Python for Windows [here](https://www.python.org/downloads/release/pyth required for the SpiderMonkey build on Windows. Install MSYS2 from [here](https://msys2.github.io/). After you have done so, open an MSYS shell -window and update the core libraries and install new packages: +window and update the core libraries and install new packages. The extra step at the end is to +downgrate GCC to 5.4, as the GCC6 versions in mingw currently fail to compile some of our +dependencies. We are upgrading to a gcc-free build on Windows as soon as possible: ```sh pacman -Su pacman -Sy git mingw-w64-x86_64-toolchain mingw-w64-x86_64-freetype \ mingw-w64-x86_64-icu mingw-w64-x86_64-nspr mingw-w64-x86_64-ca-certificates \ mingw-w64-x86_64-expat mingw-w64-x86_64-cmake tar diffutils patch \ - patchutils make python2-setuptools + patchutils make python2-setuptools mingw-w64-x86_64-ffmpeg +export GCC_URL=http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc +export GCC_EXT=5.4.0-1-any.pkg.tar.xz +pacman -U --noconfirm $GCC_URL-$GCC_EXT $GCC_URL-ada-$GCC_EXT \ + $GCC_URL-fortran-$GCC_EXT $GCC_URL-libgfortran-$GCC_EXT $GCC_URL-libs-$GCC_EXT \ + $GCC_URL-objc-$GCC_EXT easy_install-2.7 pip virtualenv ``` diff --git a/appveyor.yml b/appveyor.yml index 3fd7b59c4e5..148ee4fb5bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,10 +19,14 @@ cache: install: - bash -lc "echo $MSYSTEM; pacman --needed --noconfirm -Sy pacman-mirrors" - bash -lc "pacman --noconfirm -Sy" - - bash -lc "pacman -Sy --needed --noconfirm git mingw-w64-x86_64-toolchain mingw-w64-x86_64-freetype mingw-w64-x86_64-icu mingw-w64-x86_64-nspr mingw-w64-x86_64-ca-certificates mingw-w64-x86_64-expat mingw-w64-x86_64-cmake tar diffutils patch patchutils make python2-setuptools" + - bash -lc "pacman -Sy --needed --noconfirm git mingw-w64-x86_64-toolchain mingw-w64-x86_64-freetype mingw-w64-x86_64-icu mingw-w64-x86_64-nspr mingw-w64-x86_64-ca-certificates mingw-w64-x86_64-expat mingw-w64-x86_64-cmake tar diffutils patch patchutils make python2-setuptools mingw-w64-x86_64-ffmpeg" - bash -lc "easy_install-2.7 pip virtualenv" - bash -lc "mv /mingw64/bin/python2.exe /mingw64/bin/python2-mingw64.exe" - bash -lc "mv /mingw64/bin/python2.7.exe /mingw64/bin/python2.7-mingw64.exe" + # Downgrade GCC to 5.4.0-1 - https://github.com/servo/servo/issues/12512 + - set GCC_URL=http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc + - set GCC_EXT=5.4.0-1-any.pkg.tar.xz + - bash -lc "pacman -U --noconfirm $GCC_URL-$GCC_EXT $GCC_URL-ada-$GCC_EXT $GCC_URL-fortran-$GCC_EXT $GCC_URL-libgfortran-$GCC_EXT $GCC_URL-libs-$GCC_EXT $GCC_URL-objc-$GCC_EXT" # Uncomment these lines to expose RDP access information to the build machine in the build log. #init: diff --git a/cargo-nightly-build b/cargo-nightly-build index d6dd780ab85..d5817d0f464 100644 --- a/cargo-nightly-build +++ b/cargo-nightly-build @@ -1 +1 @@ -2016-06-20 +2016-07-30 diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index e9803a764d5..d51f75fc12b 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -15,7 +15,7 @@ canvas_traits = {path = "../canvas_traits"} euclid = "0.7.1" gfx_traits = {path = "../gfx_traits"} gleam = "0.2.8" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" log = "0.3.5" num-traits = "0.1.32" offscreen_gl_context = "0.1.2" diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index 899e0eaf397..7016dc297a3 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -16,10 +16,10 @@ euclid = "0.7.1" gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" plugins = {path = "../plugins"} -serde = {version = "0.7.11", features = ["nightly"]} -serde_macros = "0.7.11" +serde = {version = "0.7.15", features = ["nightly"]} +serde_macros = "0.7.15" [dependencies.webrender_traits] git = "https://github.com/servo/webrender_traits" diff --git a/components/canvas_traits/lib.rs b/components/canvas_traits/lib.rs index db945750a0c..3682d252338 100644 --- a/components/canvas_traits/lib.rs +++ b/components/canvas_traits/lib.rs @@ -74,6 +74,7 @@ pub enum FromLayoutMsg { } #[derive(Clone, Deserialize, Serialize)] +#[serde(bound = "")] // Prevent serde from generating cyclic bounds. pub enum Canvas2dMsg { Arc(Point2D<f32>, f32, f32, f32, bool), ArcTo(Point2D<f32>, Point2D<f32>, f32), diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index 6ffc18fa6bf..ff5440b54d5 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -16,7 +16,7 @@ euclid = "0.7.1" gfx_traits = {path = "../gfx_traits"} gleam = "0.2.8" image = "0.10" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]} log = "0.3.5" msg = {path = "../msg"} @@ -24,8 +24,8 @@ net_traits = {path = "../net_traits"} plugins = {path = "../plugins"} profile_traits = {path = "../profile_traits"} script_traits = {path = "../script_traits"} -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" style_traits = {path = "../style_traits"} time = "0.1.17" url = {version = "1.0.0", features = ["heap_size"]} diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index da9272d08b9..60b64a03047 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -2114,7 +2114,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } // Check if there are any pending frames. If so, the image is not stable yet. - if self.pending_subpages.len() > 0 { + if !self.pending_subpages.is_empty() { return Err(NotReadyToPaint::PendingSubpages(self.pending_subpages.len())); } diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index 83d8aac997a..d3688a51e91 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -18,7 +18,7 @@ devtools_traits = {path = "../devtools_traits"} euclid = "0.7.1" gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]} layout_traits = {path = "../layout_traits"} log = "0.3.5" @@ -29,8 +29,8 @@ plugins = {path = "../plugins"} profile_traits = {path = "../profile_traits"} rand = "0.3" script_traits = {path = "../script_traits"} -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" style_traits = {path = "../style_traits"} url = {version = "1.0.0", features = ["heap_size"]} util = {path = "../util"} diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 7b1ae044921..dc28056e81b 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -30,7 +30,6 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection}; use msg::constellation_msg::{SubpageId, WindowSizeType}; use net_traits::bluetooth_thread::BluetoothMethodMsg; -use net_traits::filemanager_thread::FileManagerThreadMsg; use net_traits::image_cache_thread::ImageCacheThread; use net_traits::storage_thread::StorageThreadMsg; use net_traits::{self, ResourceThreads, IpcSend}; @@ -54,8 +53,8 @@ use std::iter::once; use std::marker::PhantomData; use std::mem::replace; use std::process; +use std::sync::Arc; use std::sync::mpsc::{Sender, channel, Receiver}; -use std::sync::{Arc, Mutex}; use std::thread; use std::time::Instant; use style_traits::PagePx; @@ -65,6 +64,7 @@ use timer_scheduler::TimerScheduler; use url::Url; use util::opts; use util::prefs::PREFS; +use util::remutex::ReentrantMutex; use util::thread::spawn_named; use webrender_traits; @@ -314,14 +314,14 @@ enum ExitPipelineMode { #[derive(Clone)] pub struct FromScriptLogger { /// A channel to the constellation - pub constellation_chan: Arc<Mutex<IpcSender<FromScriptMsg>>>, + pub constellation_chan: Arc<ReentrantMutex<IpcSender<FromScriptMsg>>>, } impl FromScriptLogger { /// Create a new constellation logger. pub fn new(constellation_chan: IpcSender<FromScriptMsg>) -> FromScriptLogger { FromScriptLogger { - constellation_chan: Arc::new(Mutex::new(constellation_chan)) + constellation_chan: Arc::new(ReentrantMutex::new(constellation_chan)) } } @@ -342,9 +342,8 @@ impl Log for FromScriptLogger { let pipeline_id = PipelineId::installed(); let thread_name = thread::current().name().map(ToOwned::to_owned); let msg = FromScriptMsg::LogEntry(pipeline_id, thread_name, entry); - if let Ok(chan) = self.constellation_chan.lock() { - let _ = chan.send(msg); - } + let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); + let _ = chan.send(msg); } } } @@ -353,14 +352,14 @@ impl Log for FromScriptLogger { #[derive(Clone)] pub struct FromCompositorLogger { /// A channel to the constellation - pub constellation_chan: Arc<Mutex<Sender<FromCompositorMsg>>>, + pub constellation_chan: Arc<ReentrantMutex<Sender<FromCompositorMsg>>>, } impl FromCompositorLogger { /// Create a new constellation logger. pub fn new(constellation_chan: Sender<FromCompositorMsg>) -> FromCompositorLogger { FromCompositorLogger { - constellation_chan: Arc::new(Mutex::new(constellation_chan)) + constellation_chan: Arc::new(ReentrantMutex::new(constellation_chan)) } } @@ -381,9 +380,8 @@ impl Log for FromCompositorLogger { let pipeline_id = PipelineId::installed(); let thread_name = thread::current().name().map(ToOwned::to_owned); let msg = FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry); - if let Ok(chan) = self.constellation_chan.lock() { - let _ = chan.send(msg); - } + let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); + let _ = chan.send(msg); } } } @@ -828,11 +826,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> debug!("constellation got load complete message"); self.handle_load_complete_msg(pipeline_id) } - // The DOM load event fired on a document - FromScriptMsg::DOMLoad(pipeline_id) => { - debug!("constellation got dom load message"); - self.handle_dom_load(pipeline_id) - } // Handle a forward or back request FromScriptMsg::TraverseHistory(pipeline_id, direction) => { debug!("constellation got traverse history message from script"); @@ -1048,11 +1041,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> warn!("Exit storage thread failed ({})", e); } - debug!("Exiting file manager resource threads."); - if let Err(e) = self.public_resource_threads.send(FileManagerThreadMsg::Exit) { - warn!("Exit storage thread failed ({})", e); - } - debug!("Exiting bluetooth thread."); if let Err(e) = self.bluetooth_thread.send(BluetoothMethodMsg::Exit) { warn!("Exit bluetooth thread failed ({})", e); @@ -1323,10 +1311,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn handle_alert(&mut self, pipeline_id: PipelineId, message: String, sender: IpcSender<bool>) { + fn handle_alert(&mut self, + pipeline_id: PipelineId, + message: String, + sender: IpcSender<bool>) { let display_alert_dialog = if PREFS.is_mozbrowser_enabled() { let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info); - if let Some(_) = parent_pipeline_info { + if parent_pipeline_info.is_some() { let root_pipeline_id = self.root_frame_id .and_then(|root_frame_id| self.frames.get(&root_frame_id)) .map(|root_frame| root_frame.current.0); @@ -1435,15 +1426,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_load_complete_msg(&mut self, pipeline_id: PipelineId) { - if let Some(frame_id) = self.get_top_level_frame_for_pipeline(Some(pipeline_id)) { - let forward = !self.joint_session_future(frame_id).is_empty(); - let back = !self.joint_session_past(frame_id).is_empty(); - let root = self.root_frame_id.is_none() || self.root_frame_id == Some(frame_id); - self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root)); - } - } - - fn handle_dom_load(&mut self, pipeline_id: PipelineId) { let mut webdriver_reset = false; if let Some((expected_pipeline_id, ref reply_chan)) = self.webdriver.load_channel { debug!("Sending load to WebDriver"); @@ -1455,7 +1437,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> if webdriver_reset { self.webdriver.load_channel = None; } - + if let Some(frame_id) = self.get_top_level_frame_for_pipeline(Some(pipeline_id)) { + let forward = !self.joint_session_future(frame_id).is_empty(); + let back = !self.joint_session_past(frame_id).is_empty(); + let root = self.root_frame_id.is_none() || self.root_frame_id == Some(frame_id); + self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root)); + } self.handle_subframe_loaded(pipeline_id); } @@ -1893,18 +1880,16 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Remove paint permissions for the pipeline being replaced. self.revoke_paint_permission(old_pipeline_id); - // Add new pipeline to navigation frame, and return frames evicted from history. - self.pipelines - .get(&old_pipeline_id) - .and_then(|pipeline| pipeline.frame) - .map(|frame_id| { - self.pipelines.get_mut(&frame_change.new_pipeline_id) - .map(|pipeline| pipeline.frame = Some(frame_id)); - self.frames.get_mut(&frame_id).map(|frame| frame.load(frame_change.new_pipeline_id)); - frame_id - }) + self.pipelines.get(&old_pipeline_id).and_then(|pipeline| pipeline.frame) }); + if let Some(frame_id) = frame_id { + // Add new pipeline to navigation frame, and return frames evicted from history. + self.pipelines.get_mut(&frame_change.new_pipeline_id) + .map(|pipeline| pipeline.frame = Some(frame_id)); + self.frames.get_mut(&frame_id).map(|frame| frame.load(frame_change.new_pipeline_id)); + } + if let None = frame_id { // The new pipeline is in a new frame with no history let frame_id = self.new_frame(frame_change.new_pipeline_id); @@ -2073,7 +2058,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } // If there are pending loads, wait for those to complete. - if self.pending_frames.len() > 0 { + if !self.pending_frames.is_empty() { return ReadyToSave::PendingFrames; } @@ -2089,7 +2074,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let pipeline_id = frame.current.0; let pipeline = match self.pipelines.get(&pipeline_id) { - None => { warn!("Pipeline {:?} screenshot while closing.", pipeline_id); continue; }, + None => { + warn!("Pipeline {:?} screenshot while closing.", pipeline_id); + continue; + }, Some(pipeline) => pipeline, }; diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index dd2a665f6ac..a75d083db64 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -28,6 +28,8 @@ use script_traits::{ConstellationControlMsg, InitialScriptState, MozBrowserEvent use script_traits::{LayoutControlMsg, LayoutMsg, NewLayoutInfo, ScriptMsg, SWManagerMsg, SWManagerSenders}; use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData}; use std::collections::HashMap; +use std::env; +use std::ffi::OsStr; use std::io::Error as IOError; use std::process; use std::sync::mpsc::{Sender, channel}; @@ -160,6 +162,7 @@ impl Pipeline { pipeline_port: pipeline_port, layout_to_constellation_chan: state.layout_to_constellation_chan.clone(), content_process_shutdown_chan: layout_content_process_shutdown_chan.clone(), + layout_threads: opts::get().layout_threads, }; if let Err(e) = script_chan.send(ConstellationControlMsg::AttachLayout(new_layout_info)) { @@ -470,7 +473,8 @@ impl UnprivilegedPipelineContent { self.time_profiler_chan, self.mem_profiler_chan, self.layout_content_process_shutdown_chan, - self.webrender_api_sender); + self.webrender_api_sender, + opts::get().layout_threads); if wait_for_completion { let _ = self.script_content_process_shutdown_port.recv(); @@ -483,7 +487,18 @@ impl UnprivilegedPipelineContent { use gaol::sandbox::{self, Sandbox, SandboxMethods}; use ipc_channel::ipc::IpcOneShotServer; use sandboxing::content_process_sandbox_profile; - use std::env; + + impl CommandMethods for sandbox::Command { + fn arg<T>(&mut self, arg: T) + where T: AsRef<OsStr> { + self.arg(arg); + } + + fn env<T, U>(&mut self, key: T, val: U) + where T: AsRef<OsStr>, U: AsRef<OsStr> { + self.env(key, val); + } + } // Note that this function can panic, due to process creation, // avoiding this panic would require a mechanism for dealing @@ -495,11 +510,7 @@ impl UnprivilegedPipelineContent { // If there is a sandbox, use the `gaol` API to create the child process. let child_process = if opts::get().sandbox { let mut command = sandbox::Command::me().expect("Failed to get current sandbox."); - command.arg("--content-process").arg(token); - - if let Ok(value) = env::var("RUST_BACKTRACE") { - command.env("RUST_BACKTRACE", value); - } + self.setup_common(&mut command, token); let profile = content_process_sandbox_profile(); ChildProcess::Sandboxed(Sandbox::new(profile).start(&mut command) @@ -508,12 +519,7 @@ impl UnprivilegedPipelineContent { let path_to_self = env::current_exe() .expect("Failed to get current executor."); let mut child_process = process::Command::new(path_to_self); - child_process.arg("--content-process"); - child_process.arg(token); - - if let Ok(value) = env::var("RUST_BACKTRACE") { - child_process.env("RUST_BACKTRACE", value); - } + self.setup_common(&mut child_process, token); ChildProcess::Unsandboxed(child_process.spawn() .expect("Failed to start unsandboxed child process!")) @@ -531,6 +537,19 @@ impl UnprivilegedPipelineContent { process::exit(1); } + fn setup_common<C: CommandMethods>(&self, command: &mut C, token: String) { + C::arg(command, "--content-process"); + C::arg(command, token); + + if let Ok(value) = env::var("RUST_BACKTRACE") { + C::env(command, "RUST_BACKTRACE", value); + } + + if let Ok(value) = env::var("RUST_LOG") { + C::env(command, "RUST_LOG", value); + } + } + pub fn constellation_chan(&self) -> IpcSender<ScriptMsg> { self.constellation_chan.clone() } @@ -550,3 +569,23 @@ impl UnprivilegedPipelineContent { } } } + +trait CommandMethods { + fn arg<T>(&mut self, arg: T) + where T: AsRef<OsStr>; + + fn env<T, U>(&mut self, key: T, val: U) + where T: AsRef<OsStr>, U: AsRef<OsStr>; +} + +impl CommandMethods for process::Command { + fn arg<T>(&mut self, arg: T) + where T: AsRef<OsStr> { + self.arg(arg); + } + + fn env<T, U>(&mut self, key: T, val: U) + where T: AsRef<OsStr>, U: AsRef<OsStr> { + self.env(key, val); + } +} diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml index 1a9b821d8ae..9bcf7f54a00 100644 --- a/components/devtools/Cargo.toml +++ b/components/devtools/Cargo.toml @@ -12,12 +12,12 @@ path = "lib.rs" [dependencies] devtools_traits = {path = "../devtools_traits"} hyper = { version = "0.9.9", features = [ "serde-serialization" ] } -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" log = "0.3.5" msg = {path = "../msg"} plugins = {path = "../plugins"} -serde = "0.7.11" +serde = "0.7.15" serde_json = "0.7" -serde_macros = "0.7.11" +serde_macros = "0.7.15" time = "0.1" util = {path = "../util"} diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs index a41c98c7bfc..0328c538e84 100644 --- a/components/devtools/actors/inspector.rs +++ b/components/devtools/actors/inspector.rs @@ -290,7 +290,7 @@ impl Actor for WalkerActor { "documentElement" => { let (tx, rx) = ipc::channel().unwrap(); self.script_chan.send(GetDocumentElement(self.pipeline, tx)).unwrap(); - let doc_elem_info = rx.recv().unwrap(); + let doc_elem_info = try!(rx.recv().unwrap().ok_or(())); let node = doc_elem_info.encode(registry, true, self.script_chan.clone(), self.pipeline); let msg = DocumentElementReply { @@ -316,7 +316,7 @@ impl Actor for WalkerActor { registry.actor_to_script(target.to_owned()), tx)) .unwrap(); - let children = rx.recv().unwrap(); + let children = try!(rx.recv().unwrap().ok_or(())); let msg = ChildrenReply { hasFirst: true, @@ -490,7 +490,7 @@ impl Actor for PageStyleActor { borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth, paddingTop, paddingRight, paddingBottom, paddingLeft, width, height, - } = rx.recv().unwrap(); + } = try!(rx.recv().unwrap().ok_or(())); let auto_margins = msg.get("autoMargins") .and_then(&Value::as_boolean).unwrap_or(false); @@ -564,7 +564,7 @@ impl Actor for InspectorActor { let (tx, rx) = ipc::channel().unwrap(); self.script_chan.send(GetRootNode(self.pipeline, tx)).unwrap(); - let root_info = rx.recv().unwrap(); + let root_info = try!(rx.recv().unwrap().ok_or(())); let node = root_info.encode(registry, false, self.script_chan.clone(), self.pipeline); diff --git a/components/devtools/actors/network_event.rs b/components/devtools/actors/network_event.rs index 38f7d5767df..ba2793af8b7 100644 --- a/components/devtools/actors/network_event.rs +++ b/components/devtools/actors/network_event.rs @@ -43,6 +43,7 @@ pub struct NetworkEventActor { pub name: String, request: HttpRequest, response: HttpResponse, + is_xhr: bool, } #[derive(Serialize)] @@ -340,7 +341,8 @@ impl NetworkEventActor { headers: None, status: None, body: None, - } + }, + is_xhr: false, } } @@ -353,6 +355,7 @@ impl NetworkEventActor { self.request.timeStamp = request.timeStamp; self.request.connect_time = request.connect_time; self.request.send_time = request.send_time; + self.is_xhr = request.is_xhr; } pub fn add_response(&mut self, response: DevtoolsHttpResponse) { @@ -369,7 +372,7 @@ impl NetworkEventActor { method: format!("{}", self.request.method), startedDateTime: format!("{}", self.request.startedDateTime.rfc3339()), timeStamp: self.request.timeStamp, - isXHR: false, + isXHR: self.is_xhr, private: false, } } diff --git a/components/devtools_traits/Cargo.toml b/components/devtools_traits/Cargo.toml index 20626fcab5c..22ba037a7b0 100644 --- a/components/devtools_traits/Cargo.toml +++ b/components/devtools_traits/Cargo.toml @@ -14,9 +14,9 @@ bitflags = "0.7" heapsize = "0.3.0" heapsize_plugin = "0.1.2" hyper = {version = "0.9.9", features = ["serde-serialization"]} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" msg = {path = "../msg"} -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" time = "0.1" url = {version = "1.0.0", features = ["heap_size"]} diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs index d64ac04b16f..2d8f5f0c197 100644 --- a/components/devtools_traits/lib.rs +++ b/components/devtools_traits/lib.rs @@ -194,13 +194,13 @@ pub enum DevtoolScriptControlMsg { /// Evaluate a JS snippet in the context of the global for the given pipeline. EvaluateJS(PipelineId, String, IpcSender<EvaluateJSReply>), /// Retrieve the details of the root node (ie. the document) for the given pipeline. - GetRootNode(PipelineId, IpcSender<NodeInfo>), + GetRootNode(PipelineId, IpcSender<Option<NodeInfo>>), /// Retrieve the details of the document element for the given pipeline. - GetDocumentElement(PipelineId, IpcSender<NodeInfo>), + GetDocumentElement(PipelineId, IpcSender<Option<NodeInfo>>), /// Retrieve the details of the child nodes of the given node in the given pipeline. - GetChildren(PipelineId, String, IpcSender<Vec<NodeInfo>>), + GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>), /// Retrieve the computed layout properties of the given node in the given pipeline. - GetLayout(PipelineId, String, IpcSender<ComputedNodeLayout>), + GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>), /// Retrieve all stored console messages for the given pipeline. GetCachedMessages(PipelineId, CachedConsoleMessageTypes, IpcSender<Vec<CachedConsoleMessage>>), /// Update a given node's attributes with a list of modifications. @@ -298,6 +298,7 @@ pub struct HttpRequest { pub timeStamp: i64, pub connect_time: u64, pub send_time: u64, + pub is_xhr: bool, } #[derive(Debug, PartialEq)] diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index ab66071626d..450c957886d 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -20,7 +20,7 @@ gfx_traits = {path = "../gfx_traits"} harfbuzz-sys = "0.1" heapsize = "0.3.0" heapsize_plugin = "0.1.2" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]} lazy_static = "0.2" libc = "0.2" @@ -33,8 +33,8 @@ profile_traits = {path = "../profile_traits"} rand = "0.3" range = {path = "../range"} rustc-serialize = "0.3" -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" smallvec = "0.1" string_cache = {version = "0.2.20", features = ["heap_size"]} style = {path = "../style"} diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 3eed504303b..0073b1b0a69 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -382,7 +382,11 @@ impl DisplayList { current_item_index: start, last_item_index: end, }; - self.draw_stacking_context(stacking_context, &mut traversal, paint_context, transform); + self.draw_stacking_context(stacking_context, + &mut traversal, + paint_context, + transform, + &Point2D::zero()); } fn draw_stacking_context_contents<'a>(&'a self, @@ -390,6 +394,7 @@ impl DisplayList { traversal: &mut DisplayListTraversal<'a>, paint_context: &mut PaintContext, transform: &Matrix4D<f32>, + subpixel_offset: &Point2D<Au>, tile_rect: Option<Rect<Au>>) { for child in stacking_context.children.iter() { while let Some(item) = traversal.advance(stacking_context) { @@ -399,7 +404,11 @@ impl DisplayList { } if child.intersects_rect_in_parent_context(tile_rect) { - self.draw_stacking_context(child, traversal, paint_context, &transform); + self.draw_stacking_context(child, + traversal, + paint_context, + &transform, + subpixel_offset); } else { traversal.skip_past_stacking_context(child); } @@ -417,12 +426,14 @@ impl DisplayList { stacking_context: &StackingContext, traversal: &mut DisplayListTraversal<'a>, paint_context: &mut PaintContext, - transform: &Matrix4D<f32>) { + transform: &Matrix4D<f32>, + subpixel_offset: &Point2D<Au>) { if stacking_context.context_type != StackingContextType::Real { self.draw_stacking_context_contents(stacking_context, traversal, paint_context, transform, + subpixel_offset, None); return; } @@ -431,18 +442,35 @@ impl DisplayList { &stacking_context.filters, stacking_context.blend_mode); - // If a layer is being used, the transform for this layer - // will be handled by the compositor. let old_transform = paint_context.draw_target.get_transform(); - let transform = match stacking_context.layer_info { - Some(..) => *transform, + let pixels_per_px = paint_context.screen_pixels_per_px(); + let (transform, subpixel_offset) = match stacking_context.layer_info { + // If this stacking context starts a layer, the offset and transformation are handled + // by layer position within the compositor. + Some(..) => (*transform, *subpixel_offset), None => { - let pixels_per_px = paint_context.screen_pixels_per_px(); - let origin = &stacking_context.bounds.origin; - transform.translate( - origin.x.to_nearest_pixel(pixels_per_px.get()) as AzFloat, - origin.y.to_nearest_pixel(pixels_per_px.get()) as AzFloat, - 0.0).mul(&stacking_context.transform) + let origin = stacking_context.bounds.origin + *subpixel_offset; + let pixel_snapped_origin = + Point2D::new(origin.x.to_nearest_pixel(pixels_per_px.get()), + origin.y.to_nearest_pixel(pixels_per_px.get())); + + let transform = transform.translate(pixel_snapped_origin.x as AzFloat, + pixel_snapped_origin.y as AzFloat, + 0.0).mul(&stacking_context.transform); + let inverse_transform = transform.invert(); + + // Here we are trying to accumulate any subpixel distances across transformed + // stacking contexts. This allows us transform stacking context with a + // pixel-snapped transform, but continue to propagate any subpixels from stacking + // context origins to children. + let subpixel_offset = Point2D::new(origin.x.to_f32_px() - pixel_snapped_origin.x, + origin.y.to_f32_px() - pixel_snapped_origin.y); + let subpixel_offset = inverse_transform.transform_point(&subpixel_offset) - + inverse_transform.transform_point(&Point2D::zero());; + let subpixel_offset = Point2D::new(Au::from_f32_px(subpixel_offset.x), + Au::from_f32_px(subpixel_offset.y)); + + (transform, subpixel_offset) } }; @@ -455,6 +483,7 @@ impl DisplayList { clip_rect: Some(stacking_context.overflow), transient_clip: None, layer_kind: paint_context.layer_kind, + subpixel_offset: subpixel_offset, }; // Set up our clip rect and transform. @@ -469,6 +498,7 @@ impl DisplayList { traversal, &mut paint_subcontext, &transform, + &subpixel_offset, Some(transformed_tile_rect(paint_context.screen_rect, &transform))); paint_subcontext.remove_transient_clip_if_applicable(); @@ -744,6 +774,7 @@ impl fmt::Debug for StackingContext { /// One drawing command in the list. #[derive(Clone, Deserialize, HeapSizeOf, Serialize)] +#[serde(bound = "")] // Prevent serde from generating cyclic bounds. pub enum DisplayItem { SolidColorClass(Box<SolidColorDisplayItem>), TextClass(Box<TextDisplayItem>), diff --git a/components/gfx/paint_context.rs b/components/gfx/paint_context.rs index 2614e77fc82..15c4b169ba4 100644 --- a/components/gfx/paint_context.rs +++ b/components/gfx/paint_context.rs @@ -53,6 +53,10 @@ pub struct PaintContext<'a> { pub transient_clip: Option<ClippingRegion>, /// A temporary hack to disable clipping optimizations on 3d layers. pub layer_kind: LayerKind, + /// The current subpixel offset, used to make pixel snapping aware of accumulated subpixels + /// from the StackingContext. + /// TODO: Eventually this should be added to all points handled by the PaintContext. + pub subpixel_offset: Point2D<Au>, } #[derive(Copy, Clone)] @@ -1338,24 +1342,26 @@ impl<'a> PaintContext<'a> { pub fn draw_text(&mut self, text: &TextDisplayItem) { let draw_target_transform = self.draw_target.get_transform(); + let origin = text.baseline_origin + self.subpixel_offset; + // Optimization: Don’t set a transform matrix for upright text, and pass a start point to // `draw_text_into_context`. // // For sideways text, it’s easier to do the rotation such that its center (the baseline’s // start point) is at (0, 0) coordinates. let baseline_origin = match text.orientation { - Upright => text.baseline_origin, + Upright => origin, SidewaysLeft => { - let x = text.baseline_origin.x.to_f32_px(); - let y = text.baseline_origin.y.to_f32_px(); + let x = origin.x.to_f32_px(); + let y = origin.y.to_f32_px(); self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., -1., 1., 0., x, y))); Point2D::zero() } SidewaysRight => { - let x = text.baseline_origin.x.to_f32_px(); - let y = text.baseline_origin.y.to_f32_px(); + let x = origin.x.to_f32_px(); + let y = origin.y.to_f32_px(); self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., 1., -1., 0., x, y))); @@ -1382,10 +1388,7 @@ impl<'a> PaintContext<'a> { // Blur, if necessary. self.blur_if_necessary(temporary_draw_target, text.blur_radius); - // Undo the transform, only when we did one. - if text.orientation != Upright { - self.draw_target.set_transform(&draw_target_transform) - } + self.draw_target.set_transform(&draw_target_transform) } /// Draws a linear gradient in the given boundaries from the given start point to the given end diff --git a/components/gfx/paint_thread.rs b/components/gfx/paint_thread.rs index b4ad2abd299..a06ef7ee7af 100644 --- a/components/gfx/paint_thread.rs +++ b/components/gfx/paint_thread.rs @@ -379,8 +379,7 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static { font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan) { - thread::spawn_named(format!("PaintThread {:?}", id), - move || { + thread::spawn_named(format!("PaintThread {:?}", id), move || { thread_state::initialize(thread_state::PAINT); PipelineId::install(id); @@ -425,9 +424,9 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static { let chrome_to_paint = &self.chrome_to_paint_port; select! { msg = layout_to_paint.recv() => - Msg::FromLayout(msg.unwrap()), + Msg::FromLayout(msg.expect("expected message from layout")), msg = chrome_to_paint.recv() => - Msg::FromChrome(msg.unwrap()) + Msg::FromChrome(msg.expect("expected message from chrome")) } }; @@ -685,11 +684,12 @@ impl WorkerThread { let mut paint_context = PaintContext { draw_target: draw_target.clone(), font_context: &mut self.font_context, - page_rect: Rect::from_untyped(&tile.page_rect), + page_rect: Rect::from_untyped(&tile.page_rect.translate(&paint_layer.display_list_origin)), screen_rect: Rect::from_untyped(&tile.screen_rect), clip_rect: None, transient_clip: None, layer_kind: layer_kind, + subpixel_offset: Point2D::zero(), }; // Apply the translation to paint the tile we want. diff --git a/components/gfx_traits/Cargo.toml b/components/gfx_traits/Cargo.toml index 37a7a592c72..1d303d85438 100644 --- a/components/gfx_traits/Cargo.toml +++ b/components/gfx_traits/Cargo.toml @@ -20,5 +20,5 @@ plugins = {path = "../plugins"} profile_traits = {path = "../profile_traits"} range = {path = "../range"} rustc-serialize = "0.3" -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index 9c83648128a..7471c12a5f7 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -21,7 +21,7 @@ gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" libc = "0.2" log = "0.3.5" msg = {path = "../msg"} @@ -33,7 +33,7 @@ rustc-serialize = "0.3" script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} selectors = {version = "0.7", features = ["heap_size"]} -serde_macros = "0.7.11" +serde_macros = "0.7.15" smallvec = "0.1" string_cache = {version = "0.2.20", features = ["heap_size"]} style = {path = "../style"} diff --git a/components/layout/block.rs b/components/layout/block.rs index 16a837d4dcc..62365478d2f 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -512,14 +512,6 @@ pub struct BlockFlow { /// The associated fragment. pub fragment: Fragment, - /// The sum of the inline-sizes of all logically left floats that precede this block. This is - /// used to speculatively lay out block formatting contexts. - inline_size_of_preceding_left_floats: Au, - - /// The sum of the inline-sizes of all logically right floats that precede this block. This is - /// used to speculatively lay out block formatting contexts. - inline_size_of_preceding_right_floats: Au, - /// Additional floating flow members. pub float: Option<Box<FloatedBlockInfo>>, @@ -551,8 +543,6 @@ impl BlockFlow { None => ForceNonfloatedFlag::ForceNonfloated, }), fragment: fragment, - inline_size_of_preceding_left_floats: Au(0), - inline_size_of_preceding_right_floats: Au(0), float: float_kind.map(|kind| box FloatedBlockInfo::new(kind)), flags: BlockFlowFlags::empty(), } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 5eb20156295..58ff6d23e44 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -29,7 +29,6 @@ use gfx::display_list::{LayeredItem, LayerInfo, LineDisplayItem, OpaqueNode}; use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType}; use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo}; use gfx::paint_thread::THREAD_TINT_COLORS; -use gfx::text::glyph::ByteIndex; use gfx_traits::{color, ScrollPolicy, StackingContextId}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; @@ -399,7 +398,7 @@ impl FragmentDisplayListBuilding for Fragment { gradient, style); } - Some(computed::Image::Url(ref image_url)) => { + Some(computed::Image::Url(ref image_url, ref _extra_data)) => { self.build_display_list_for_background_image(state, style, display_list_section, @@ -970,7 +969,8 @@ impl FragmentDisplayListBuilding for Fragment { Some(insertion_point_index) => insertion_point_index, None => return, }; - let range = Range::new(ByteIndex(0), insertion_point_index); + let range = Range::new(scanned_text_fragment_info.range.begin(), + insertion_point_index - scanned_text_fragment_info.range.begin()); let advance = scanned_text_fragment_info.run.advance_for_range(&range); let insertion_point_bounds; diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 6a6071aa3c7..0ddb083c1c0 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -882,16 +882,23 @@ impl Fragment { let size = LogicalSize::new(self.style.writing_mode, split.inline_size, self.border_box.size.block); - let flags = match self.specific { - SpecificFragmentInfo::ScannedText(ref info) => info.flags, - _ => ScannedTextFlags::empty() + // Preserve the insertion point if it is in this fragment's range or it is at line end. + let (flags, insertion_point) = match self.specific { + SpecificFragmentInfo::ScannedText(ref info) => { + match info.insertion_point { + Some(index) if split.range.contains(index) => (info.flags, info.insertion_point), + Some(index) if index == ByteIndex(text_run.text.chars().count() as isize - 1) && + index == split.range.end() => (info.flags, info.insertion_point), + _ => (info.flags, None) + } + }, + _ => (ScannedTextFlags::empty(), None) }; - // FIXME(pcwalton): This should modify the insertion point as necessary. let info = box ScannedTextFragmentInfo::new( text_run, split.range, size, - None, + insertion_point, flags); self.transform(size, SpecificFragmentInfo::ScannedText(info)) } @@ -2012,9 +2019,10 @@ impl Fragment { // See CSS 2.1 § 10.8.1. let flow = &info.flow_ref; let block_flow = flow.as_block(); + let is_auto = self.style.get_position().height == LengthOrPercentageOrAuto::Auto; let baseline_offset = match flow.baseline_offset_of_last_line_box_in_flow() { - Some(baseline_offset) => baseline_offset, - None => block_flow.fragment.border_box.size.block, + Some(baseline_offset) if is_auto => baseline_offset, + _ => block_flow.fragment.border_box.size.block, }; let start_margin = block_flow.fragment.margin.block_start; let end_margin = block_flow.fragment.margin.block_end; diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index a71b78b8ace..f012121f5ae 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -77,9 +77,10 @@ impl TableCellFlow { None, MarginsMayCollapseFlag::MarginsMayNotCollapse); debug_assert!(remaining.is_none()); - if !flow::base(self).restyle_damage.contains(REFLOW) { - return; - } + } + + /// Position this cell's children according to vertical-align. + pub fn valign_children(&mut self) { // Note to the reader: this code has been tested with negative margins. // We end up with a "end" that's before the "start," but the math still works out. let first_start = flow::base(self).children.front().map(|kid| { @@ -106,6 +107,9 @@ impl TableCellFlow { let self_size = flow::base(self).position.size.block - self.block_flow.fragment.border_padding.block_start_end(); let kids_self_gap = self_size - kids_size; + + // This offset should also account for vertical_align::T::baseline. + // Need max cell ascent from the first row of this cell. let offset = match self.block_flow.fragment.style().get_box().vertical_align { vertical_align::T::middle => kids_self_gap / 2, vertical_align::T::bottom => kids_self_gap, diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index 8fd0255f261..cb2f8f76c7c 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -162,6 +162,9 @@ impl TableRowFlow { // Assign the child's block size. child_table_cell.block_flow.base.position.size.block = block_size; + // Now we know the cell height, vertical align the cell's children. + child_table_cell.valign_children(); + // Write in the size of the relative containing block for children. (This information // is also needed to handle RTL.) child_table_cell.block_flow.base.early_absolute_position_info = diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 1362f1cb7b2..b1087e945d7 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -77,7 +77,9 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc> recalc_style_at(&self.context, self.root, node); } - fn process_postorder(&self, node: N) { construct_flows_at(&self.context, self.root, node); } + fn process_postorder(&self, node: N) { + construct_flows_at(&self.context, self.root, node); + } } /// A bottom-up, parallelizable traversal. @@ -96,7 +98,7 @@ fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: O // Always reconstruct if incremental layout is turned off. let nonincremental_layout = opts::get().nonincremental_layout; - if nonincremental_layout || node.has_dirty_descendants() { + if nonincremental_layout || node.is_dirty() || node.has_dirty_descendants() { let mut flow_constructor = FlowConstructor::new(context); if nonincremental_layout || !flow_constructor.repair_if_possible(&tnode) { flow_constructor.process(&tnode); diff --git a/components/layout_thread/Cargo.toml b/components/layout_thread/Cargo.toml index 4c5393f0223..a06cf20e28f 100644 --- a/components/layout_thread/Cargo.toml +++ b/components/layout_thread/Cargo.toml @@ -18,7 +18,7 @@ gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" layout = {path = "../layout"} layout_traits = {path = "../layout_traits"} log = "0.3.5" @@ -30,7 +30,7 @@ script = {path = "../script"} script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} serde_json = "0.7" -serde_macros = "0.7" +serde_macros = "0.7.15" style = {path = "../style"} url = {version = "1.0.0", features = ["heap_size"]} util = {path = "../util"} diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 9d576e3bd02..403f30a96f5 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -232,6 +232,10 @@ pub struct LayoutThread { /// The timer object to control the timing of the animations. This should /// only be a test-mode timer during testing for animations. timer: Timer, + + // Number of layout threads. This is copied from `util::opts`, but we'd + // rather limit the dependency on that module here. + layout_threads: usize, } impl LayoutThreadFactory for LayoutThread { @@ -251,7 +255,8 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, content_process_shutdown_chan: IpcSender<()>, - webrender_api_sender: Option<webrender_traits::RenderApiSender>) { + webrender_api_sender: Option<webrender_traits::RenderApiSender>, + layout_threads: usize) { thread::spawn_named(format!("LayoutThread {:?}", id), move || { thread_state::initialize(thread_state::LAYOUT); @@ -270,7 +275,8 @@ impl LayoutThreadFactory for LayoutThread { font_cache_thread, time_profiler_chan, mem_profiler_chan.clone(), - webrender_api_sender); + webrender_api_sender, + layout_threads); let reporter_name = format!("layout-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { @@ -381,14 +387,14 @@ impl LayoutThread { font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, - webrender_api_sender: Option<webrender_traits::RenderApiSender>) + webrender_api_sender: Option<webrender_traits::RenderApiSender>, + layout_threads: usize) -> LayoutThread { let device = Device::new( MediaType::Screen, opts::get().initial_window_size.as_f32() * ScaleFactor::new(1.0)); - let parallel_traversal = if opts::get().layout_threads != 1 { - Some(WorkQueue::new("LayoutWorker", thread_state::LAYOUT, - opts::get().layout_threads)) + let parallel_traversal = if layout_threads != 1 { + Some(WorkQueue::new("LayoutWorker", thread_state::LAYOUT, layout_threads)) } else { None }; @@ -479,6 +485,7 @@ impl LayoutThread { } else { Timer::new() }, + layout_threads: layout_threads, } } @@ -754,7 +761,8 @@ impl LayoutThread { self.time_profiler_chan.clone(), self.mem_profiler_chan.clone(), info.content_process_shutdown_chan, - self.webrender_api.as_ref().map(|wr| wr.clone_sender())); + self.webrender_api.as_ref().map(|wr| wr.clone_sender()), + info.layout_threads); } /// Enters a quiescent state in which no new messages will be processed until an `ExitNow` is @@ -961,7 +969,7 @@ impl LayoutThread { self.epoch.next(); - if opts::get().use_webrender { + if let Some(ref mut webrender_api) = self.webrender_api { // TODO: Avoid the temporary conversion and build webrender sc/dl directly! let Epoch(epoch_number) = self.epoch; let epoch = webrender_traits::Epoch(epoch_number); @@ -971,7 +979,7 @@ impl LayoutThread { let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id); let root_scroll_layer_id = frame_builder.next_scroll_layer_id(); let sc_id = rw_data.display_list.as_ref().unwrap().convert_to_webrender( - &mut self.webrender_api.as_mut().unwrap(), + webrender_api, pipeline_id, epoch, Some(root_scroll_layer_id), @@ -987,16 +995,15 @@ impl LayoutThread { let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(), self.viewport_size.height.to_f32_px()); - let api = self.webrender_api.as_ref().unwrap(); - api.set_root_stacking_context(sc_id, - root_background_color, - epoch, - pipeline_id, - viewport_size, - frame_builder.stacking_contexts, - frame_builder.display_lists, - frame_builder.auxiliary_lists_builder - .finalize()); + webrender_api.set_root_stacking_context( + sc_id, + root_background_color, + epoch, + pipeline_id, + viewport_size, + frame_builder.stacking_contexts, + frame_builder.display_lists, + frame_builder.auxiliary_lists_builder.finalize()); } else { self.paint_chan .send(LayoutToPaintMsg::PaintInit(self.epoch, display_list)) @@ -1097,12 +1104,16 @@ impl LayoutThread { .unwrap(); } if data.document_stylesheets.iter().any(|sheet| sheet.dirty_on_viewport_size_change) { - for node in node.traverse_preorder() { + let mut iter = node.traverse_preorder(); + + let mut next = iter.next(); + while let Some(node) = next { if node.needs_dirty_on_viewport_size_changed() { - node.dirty_self(); - node.dirty_descendants(); - // TODO(shinglyu): We can skip the traversal if the descendants were already - // dirtied + // NB: The dirty bit is propagated down the tree. + unsafe { node.set_dirty(true); } + next = iter.next_skipping_children(); + } else { + next = iter.next(); } } } @@ -1114,7 +1125,9 @@ impl LayoutThread { let needs_reflow = viewport_size_changed && !needs_dirtying; unsafe { if needs_dirtying { - LayoutThread::dirty_all_nodes(node); + // NB: The dirty flag is propagated down during the restyle + // process. + node.set_dirty(true); } } if needs_reflow { @@ -1158,7 +1171,7 @@ impl LayoutThread { // TODO(pcwalton): Measure energy usage of text shaping, perhaps? let text_shaping_time = (font::get_and_reset_text_shaping_performance_counter() as u64) / - (opts::get().layout_threads as u64); + (self.layout_threads as u64); time::send_profile_data(time::ProfilerCategory::LayoutTextShaping, self.profiler_metadata(), self.time_profiler_chan.clone(), @@ -1468,16 +1481,6 @@ impl LayoutThread { } } - unsafe fn dirty_all_nodes<N: LayoutNode>(node: N) { - for node in node.traverse_preorder() { - // TODO(cgaebel): mark nodes which are sensitive to media queries as - // "changed": - // > node.set_changed(true); - node.set_dirty(true); - node.set_dirty_descendants(true); - } - } - fn reflow_all_nodes(flow: &mut Flow) { debug!("reflowing all nodes!"); flow::mut_base(flow).restyle_damage.insert(REPAINT | STORE_OVERFLOW | REFLOW); diff --git a/components/layout_traits/Cargo.toml b/components/layout_traits/Cargo.toml index ff250314d49..653ae4102b7 100644 --- a/components/layout_traits/Cargo.toml +++ b/components/layout_traits/Cargo.toml @@ -16,7 +16,7 @@ msg = {path = "../msg"} net_traits = {path = "../net_traits"} profile_traits = {path = "../profile_traits"} util = {path = "../util"} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" url = {version = "1.0.0", features = ["heap_size"]} [dependencies.webrender_traits] diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index 1b6c621d755..5f9fc0d472b 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -48,5 +48,6 @@ pub trait LayoutThreadFactory { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, content_process_shutdown_chan: IpcSender<()>, - webrender_api_sender: Option<webrender_traits::RenderApiSender>); + webrender_api_sender: Option<webrender_traits::RenderApiSender>, + layout_threads: usize); } diff --git a/components/msg/Cargo.toml b/components/msg/Cargo.toml index 0b47f9a885c..06e60c24054 100644 --- a/components/msg/Cargo.toml +++ b/components/msg/Cargo.toml @@ -15,10 +15,10 @@ cssparser = {version = "0.5.4", features = ["heap_size", "serde-serialization"]} heapsize = "0.3.0" heapsize_plugin = "0.1.2" hyper = {version = "0.9.9", features = ["serde-serialization"]} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" plugins = {path = "../plugins"} -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" url = {version = "1.0.0", features = ["heap_size", "serde"]} [dependencies.webrender_traits] diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 9cb6ecfc5de..6ee9543b265 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -19,7 +19,7 @@ devtools_traits = {path = "../devtools_traits"} flate2 = "0.2.0" hyper = {version = "0.9.9", features = ["serde-serialization"]} immeta = "0.3.1" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" lazy_static = "0.2" log = "0.3.5" matches = "0.1" @@ -46,5 +46,5 @@ git = "https://github.com/servo/webrender_traits" default_features = false features = ["serde_macros"] -[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies] +[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies] tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"} diff --git a/components/net/blob_loader.rs b/components/net/blob_loader.rs index 0ded019553f..0783afd979a 100644 --- a/components/net/blob_loader.rs +++ b/components/net/blob_loader.rs @@ -2,15 +2,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use filemanager_thread::{FileManager, UIProvider}; use hyper::header::{DispositionType, ContentDisposition, DispositionParam}; use hyper::header::{Headers, ContentType, ContentLength, Charset}; use hyper::http::RawStatus; -use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::ipc; use mime::{Mime, Attr}; use mime_classifier::MimeClassifier; use net_traits::ProgressMsg::{Payload, Done}; use net_traits::blob_url_store::parse_blob_url; -use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId}; +use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, ReadFileProgress}; use net_traits::response::HttpsState; use net_traits::{LoadConsumer, LoadData, Metadata, NetworkError}; use resource_thread::CancellationListener; @@ -22,30 +23,30 @@ use util::thread::spawn_named; // TODO: Check on GET // https://w3c.github.io/FileAPI/#requestResponseModel -pub fn factory(filemanager_chan: IpcSender<FileManagerThreadMsg>) - -> Box<FnBox(LoadData, - LoadConsumer, - Arc<MimeClassifier>, - CancellationListener) + Send> { - box move |load_data: LoadData, start_chan, classifier, _cancel_listener| { +pub fn factory<UI: 'static + UIProvider>(filemanager: Arc<FileManager<UI>>) + -> Box<FnBox(LoadData, LoadConsumer, Arc<MimeClassifier>, CancellationListener) + Send> { + box move |load_data: LoadData, start_chan, classifier, cancel_listener| { spawn_named(format!("blob loader for {}", load_data.url), move || { - load_blob(load_data, start_chan, classifier, filemanager_chan); + load_blob(load_data, start_chan, classifier, filemanager, cancel_listener); }) } } -fn load_blob(load_data: LoadData, start_chan: LoadConsumer, +fn load_blob<UI: 'static + UIProvider> + (load_data: LoadData, start_chan: LoadConsumer, classifier: Arc<MimeClassifier>, - filemanager_chan: IpcSender<FileManagerThreadMsg>) { + filemanager: Arc<FileManager<UI>>, + cancel_listener: CancellationListener) { let (chan, recv) = ipc::channel().unwrap(); if let Ok((id, origin, _fragment)) = parse_blob_url(&load_data.url.clone()) { let id = SelectedFileId(id.simple().to_string()); let check_url_validity = true; let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin); - let _ = filemanager_chan.send(msg); + let _ = filemanager.handle(msg, Some(cancel_listener)); + // Receive first chunk match recv.recv().unwrap() { - Ok(blob_buf) => { + Ok(ReadFileProgress::Meta(blob_buf)) => { let content_type: Mime = blob_buf.type_string.parse().unwrap_or(mime!(Text / Plain)); let charset = content_type.get_param(Attr::Charset); @@ -80,9 +81,34 @@ fn load_blob(load_data: LoadData, start_chan: LoadConsumer, start_sending_sniffed_opt(start_chan, metadata, classifier, &blob_buf.bytes, load_data.context.clone()) { let _ = chan.send(Payload(blob_buf.bytes)); - let _ = chan.send(Done(Ok(()))); + + loop { + match recv.recv().unwrap() { + Ok(ReadFileProgress::Partial(bytes)) => { + let _ = chan.send(Payload(bytes)); + } + Ok(ReadFileProgress::EOF) => { + let _ = chan.send(Done(Ok(()))); + return; + } + Ok(_) => { + let err = NetworkError::Internal("Invalid filemanager reply".to_string()); + let _ = chan.send(Done(Err(err))); + return; + } + Err(e) => { + let err = NetworkError::Internal(format!("{:?}", e)); + let _ = chan.send(Done(Err(err))); + return; + } + } + } } } + Ok(_) => { + let err = NetworkError::Internal("Invalid filemanager reply".to_string()); + send_error(load_data.url, err, start_chan); + } Err(e) => { let err = NetworkError::Internal(format!("{:?}", e)); send_error(load_data.url, err, start_chan); diff --git a/components/net/bluetooth_thread.rs b/components/net/bluetooth_thread.rs index 1b882763911..3c2538b1f88 100644 --- a/components/net/bluetooth_thread.rs +++ b/components/net/bluetooth_thread.rs @@ -12,7 +12,7 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions}; use net_traits::bluetooth_thread::{BluetoothCharacteristicMsg, BluetoothCharacteristicsMsg}; use net_traits::bluetooth_thread::{BluetoothDescriptorMsg, BluetoothDescriptorsMsg}; -use net_traits::bluetooth_thread::{BluetoothDeviceMsg, BluetoothMethodMsg}; +use net_traits::bluetooth_thread::{BluetoothDeviceMsg, BluetoothError, BluetoothMethodMsg}; use net_traits::bluetooth_thread::{BluetoothResult, BluetoothServiceMsg, BluetoothServicesMsg}; use rand::{self, Rng}; use std::borrow::ToOwned; @@ -25,15 +25,7 @@ use tinyfiledialogs; use util::thread::spawn_named; const ADAPTER_ERROR: &'static str = "No adapter found"; -const DEVICE_ERROR: &'static str = "No device found"; -const DEVICE_MATCH_ERROR: &'static str = "No device found, that matches the given options"; -const PRIMARY_SERVICE_ERROR: &'static str = "No primary service found"; -const INCLUDED_SERVICE_ERROR: &'static str = "No included service found"; -const CHARACTERISTIC_ERROR: &'static str = "No characteristic found"; -const DESCRIPTOR_ERROR: &'static str = "No descriptor found"; -const VALUE_ERROR: &'static str = "No characteristic or descriptor found with that id"; -const SECURITY_ERROR: &'static str = "The operation is insecure"; -const NETWORK_ERROR: &'static str = "A network error occurred"; + // A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed. // https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 480) const MAXIMUM_TRANSACTION_TIME: u8 = 30; @@ -73,7 +65,7 @@ macro_rules! get_adapter_or_return_error( ($bl_manager:expr, $sender:expr) => ( match $bl_manager.get_or_create_adapter() { Some(adapter) => adapter, - None => return drop($sender.send(Err(String::from(ADAPTER_ERROR)))), + None => return drop($sender.send(Err(BluetoothError::Type(ADAPTER_ERROR.to_string())))), } ); ); @@ -453,7 +445,7 @@ impl BluetoothManager { if let Some(address) = self.select_device(matched_devices) { let device_id = match self.address_to_id.get(&address) { Some(id) => id.clone(), - None => return drop(sender.send(Err(String::from(DEVICE_MATCH_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::NotFound))), }; let mut services = options.get_services_set(); if let Some(services_set) = self.allowed_services.get(&device_id) { @@ -471,7 +463,7 @@ impl BluetoothManager { return drop(sender.send(message)); } } - return drop(sender.send(Err(String::from(DEVICE_MATCH_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } fn gatt_server_connect(&mut self, device_id: String, sender: IpcSender<BluetoothResult<bool>>) { @@ -489,9 +481,9 @@ impl BluetoothManager { false => thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS)), } } - return drop(sender.send(Err(String::from(NETWORK_ERROR)))); + return drop(sender.send(Err(BluetoothError::Network))); }, - None => return drop(sender.send(Err(String::from(DEVICE_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::NotFound))), } } @@ -510,9 +502,9 @@ impl BluetoothManager { false => return drop(sender.send(Ok(false))), } } - return drop(sender.send(Err(String::from(NETWORK_ERROR)))); + return drop(sender.send(Err(BluetoothError::Network))); }, - None => return drop(sender.send(Err(String::from(DEVICE_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::NotFound))), } } @@ -522,11 +514,11 @@ impl BluetoothManager { sender: IpcSender<BluetoothResult<BluetoothServiceMsg>>) { let mut adapter = get_adapter_or_return_error!(self, sender); if !self.allowed_services.get(&device_id).map_or(false, |s| s.contains(&uuid)) { - return drop(sender.send(Err(String::from(SECURITY_ERROR)))); + return drop(sender.send(Err(BluetoothError::Security))); } let services = self.get_gatt_services_by_uuid(&mut adapter, &device_id, &uuid); if services.is_empty() { - return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } for service in services { if service.is_primary().unwrap_or(false) { @@ -539,7 +531,7 @@ impl BluetoothManager { } } } - return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } fn get_primary_services(&mut self, @@ -550,14 +542,14 @@ impl BluetoothManager { let services = match uuid { Some(ref id) => { if !self.allowed_services.get(&device_id).map_or(false, |s| s.contains(id)) { - return drop(sender.send(Err(String::from(SECURITY_ERROR)))) + return drop(sender.send(Err(BluetoothError::Security))) } self.get_gatt_services_by_uuid(&mut adapter, &device_id, id) }, None => self.get_and_cache_gatt_services(&mut adapter, &device_id), }; if services.is_empty() { - return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let mut services_vec = vec!(); for service in services { @@ -572,7 +564,7 @@ impl BluetoothManager { } } if services_vec.is_empty() { - return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let _ = sender.send(Ok(services_vec)); @@ -584,11 +576,11 @@ impl BluetoothManager { sender: IpcSender<BluetoothResult<BluetoothServiceMsg>>) { let mut adapter = match self.get_or_create_adapter() { Some(a) => a, - None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::Type(ADAPTER_ERROR.to_string())))), }; let primary_service = match self.get_gatt_service(&mut adapter, &service_id) { Some(s) => s, - None => return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::NotFound))), }; let services = primary_service.get_includes().unwrap_or(vec!()); for service in services { @@ -602,7 +594,7 @@ impl BluetoothManager { } } } - return drop(sender.send(Err(String::from(INCLUDED_SERVICE_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } fn get_included_services(&mut self, @@ -611,11 +603,11 @@ impl BluetoothManager { sender: IpcSender<BluetoothResult<BluetoothServicesMsg>>) { let mut adapter = match self.get_or_create_adapter() { Some(a) => a, - None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::Type(ADAPTER_ERROR.to_string())))), }; let primary_service = match self.get_gatt_service(&mut adapter, &service_id) { Some(s) => s, - None => return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::NotFound))), }; let services = primary_service.get_includes().unwrap_or(vec!()); let mut services_vec = vec!(); @@ -632,7 +624,7 @@ impl BluetoothManager { services_vec.retain(|ref s| s.uuid == uuid); } if services_vec.is_empty() { - return drop(sender.send(Err(String::from(INCLUDED_SERVICE_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let _ = sender.send(Ok(services_vec)); @@ -645,7 +637,7 @@ impl BluetoothManager { let mut adapter = get_adapter_or_return_error!(self, sender); let characteristics = self.get_gatt_characteristics_by_uuid(&mut adapter, &service_id, &uuid); if characteristics.is_empty() { - return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } for characteristic in characteristics { if let Ok(uuid) = characteristic.get_uuid() { @@ -666,7 +658,7 @@ impl BluetoothManager { return drop(sender.send(message)); } } - return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } fn get_characteristics(&mut self, @@ -679,7 +671,7 @@ impl BluetoothManager { None => self.get_and_cache_gatt_characteristics(&mut adapter, &service_id), }; if characteristics.is_empty() { - return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let mut characteristics_vec = vec!(); for characteristic in characteristics { @@ -702,7 +694,7 @@ impl BluetoothManager { } } if characteristics_vec.is_empty() { - return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let _ = sender.send(Ok(characteristics_vec)); @@ -715,7 +707,7 @@ impl BluetoothManager { let mut adapter = get_adapter_or_return_error!(self, sender); let descriptors = self.get_gatt_descriptors_by_uuid(&mut adapter, &characteristic_id, &uuid); if descriptors.is_empty() { - return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } for descriptor in descriptors { if let Ok(uuid) = descriptor.get_uuid() { @@ -725,7 +717,7 @@ impl BluetoothManager { }))); } } - return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } fn get_descriptors(&mut self, @@ -738,7 +730,7 @@ impl BluetoothManager { None => self.get_and_cache_gatt_descriptors(&mut adapter, &characteristic_id), }; if descriptors.is_empty() { - return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let mut descriptors_vec = vec!(); for descriptor in descriptors { @@ -750,7 +742,7 @@ impl BluetoothManager { } } if descriptors_vec.is_empty() { - return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR)))); + return drop(sender.send(Err(BluetoothError::NotFound))); } let _ = sender.send(Ok(descriptors_vec)); } @@ -763,7 +755,7 @@ impl BluetoothManager { value = self.get_gatt_descriptor(&mut adapter, &id) .map(|d| d.read_value().unwrap_or(vec![])); } - let _ = sender.send(value.ok_or(String::from(VALUE_ERROR))); + let _ = sender.send(value.ok_or(BluetoothError::NotSupported)); } fn write_value(&mut self, id: String, value: Vec<u8>, sender: IpcSender<BluetoothResult<bool>>) { @@ -777,9 +769,9 @@ impl BluetoothManager { let message = match result { Some(v) => match v { Ok(_) => Ok(true), - Err(e) => return drop(sender.send(Err(e.to_string()))), + Err(_) => return drop(sender.send(Err(BluetoothError::NotSupported))), }, - None => return drop(sender.send(Err(String::from(VALUE_ERROR)))), + None => return drop(sender.send(Err(BluetoothError::NotSupported))), }; let _ = sender.send(message); } diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs index bef25ef9ba0..15aa3d28c00 100644 --- a/components/net/fetch/methods.rs +++ b/components/net/fetch/methods.rs @@ -4,10 +4,12 @@ use connector::create_http_connector; use data_loader::decode; +use devtools_traits::DevtoolsControlMsg; use fetch::cors_cache::CORSCache; use http_loader::{HttpState, set_default_accept_encoding, set_request_cookies}; use http_loader::{NetworkHttpRequestFactory, ReadResult, StreamedResponse, obtain_response, read_block}; use http_loader::{auth_from_cache, determine_request_referrer}; +use http_loader::{send_response_to_devtools, send_request_to_devtools}; use hyper::header::{Accept, AcceptLanguage, Authorization, AccessControlAllowCredentials}; use hyper::header::{AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlAllowMethods}; use hyper::header::{AccessControlRequestHeaders, AccessControlMaxAge, AccessControlRequestMethod, Basic}; @@ -20,7 +22,7 @@ use hyper::status::StatusCode; use mime_guess::guess_mime_type; use msg::constellation_msg::ReferrerPolicy; use net_traits::FetchTaskTarget; -use net_traits::request::{CacheMode, CredentialsMode}; +use net_traits::request::{CacheMode, CredentialsMode, Destination}; use net_traits::request::{RedirectMode, Referer, Request, RequestMode, ResponseTainting}; use net_traits::request::{Type, Origin, Window}; use net_traits::response::{HttpsState, TerminationReason}; @@ -36,6 +38,7 @@ use std::sync::mpsc::{channel, Sender, Receiver}; use unicase::UniCase; use url::{Origin as UrlOrigin, Url}; use util::thread::spawn_named; +use uuid; pub type Target = Option<Box<FetchTaskTarget + Send>>; @@ -47,6 +50,7 @@ enum Data { pub struct FetchContext { pub state: HttpState, pub user_agent: String, + pub devtools_chan: Option<Sender<DevtoolsControlMsg>>, } type DoneChannel = Option<(Sender<Data>, Receiver<Data>)>; @@ -210,7 +214,8 @@ fn main_fetch(request: Rc<Request>, cache: &mut CORSCache, cors_flag: bool, request.headers.borrow().iter().any(|h| !is_simple_header(&h)))) { request.response_tainting.set(ResponseTainting::CORSTainting); request.redirect_mode.set(RedirectMode::Error); - let response = http_fetch(request.clone(), cache, true, true, false, target, done_chan, context); + let response = http_fetch(request.clone(), cache, true, true, false, + target, done_chan, context); if response.is_network_error() { // TODO clear cache entries using request } @@ -888,7 +893,8 @@ fn http_network_or_cache_fetch(request: Rc<Request>, // Step 18 if response.is_none() { - response = Some(http_network_fetch(http_request.clone(), credentials_flag, done_chan)); + response = Some(http_network_fetch(http_request.clone(), credentials_flag, + done_chan, context.devtools_chan.clone())); } let response = response.unwrap(); @@ -924,7 +930,8 @@ fn http_network_or_cache_fetch(request: Rc<Request>, /// [HTTP network fetch](https://fetch.spec.whatwg.org/#http-network-fetch) fn http_network_fetch(request: Rc<Request>, _credentials_flag: bool, - done_chan: &mut DoneChannel) -> Response { + done_chan: &mut DoneChannel, + devtools_chan: Option<Sender<DevtoolsControlMsg>>) -> Response { // TODO: Implement HTTP network fetch spec // Step 1 @@ -944,14 +951,22 @@ fn http_network_fetch(request: Rc<Request>, let url = request.current_url(); let cancellation_listener = CancellationListener::new(None); + let request_id = uuid::Uuid::new_v4().simple().to_string(); + + // XHR uses the default destination; other kinds of fetches (which haven't been implemented yet) + // do not. Once we support other kinds of fetches we'll need to be more fine grained here + // since things like image fetches are classified differently by devtools + let is_xhr = request.destination == Destination::None; let wrapped_response = obtain_response(&factory, &url, &request.method.borrow(), &request.headers.borrow(), &cancellation_listener, &request.body.borrow(), &request.method.borrow(), - &None, request.redirect_count.get() + 1, &None, ""); + &request.pipeline_id.get(), request.redirect_count.get() + 1, + &devtools_chan, &request_id, is_xhr); + let pipeline_id = request.pipeline_id.get(); let mut response = Response::new(); match wrapped_response { - Ok((res, _)) => { + Ok((res, msg)) => { response.url = Some(url.clone()); response.status = Some(res.response.status); response.raw_status = Some(res.response.status_raw().clone()); @@ -963,10 +978,29 @@ fn http_network_fetch(request: Rc<Request>, *done_chan = Some(channel()); let meta = response.metadata().expect("Response metadata should exist at this stage"); let done_sender = done_chan.as_ref().map(|ch| ch.0.clone()); + let devtools_sender = devtools_chan.clone(); + let meta_status = meta.status.clone(); + let meta_headers = meta.headers.clone(); spawn_named(format!("fetch worker thread"), move || { match StreamedResponse::from_http_response(box res, meta) { Ok(mut res) => { *res_body.lock().unwrap() = ResponseBody::Receiving(vec![]); + + if let Some(ref sender) = devtools_sender { + if let Some(m) = msg { + send_request_to_devtools(m, &sender); + } + + // --- Tell devtools that we got a response + // Send an HttpResponse message to devtools with the corresponding request_id + if let Some(pipeline_id) = pipeline_id { + send_response_to_devtools( + &sender, request_id.into(), + meta_headers, meta_status, + pipeline_id); + } + } + loop { match read_block(&mut res) { Ok(ReadResult::Payload(chunk)) => { @@ -994,7 +1028,6 @@ fn http_network_fetch(request: Rc<Request>, break; } } - } } Err(_) => { @@ -1064,9 +1097,11 @@ fn http_network_fetch(request: Rc<Request>, } /// [CORS preflight fetch](https://fetch.spec.whatwg.org#cors-preflight-fetch) -fn cors_preflight_fetch(request: Rc<Request>, cache: &mut CORSCache, context: &FetchContext) -> Response { +fn cors_preflight_fetch(request: Rc<Request>, cache: &mut CORSCache, + context: &FetchContext) -> Response { // Step 1 - let mut preflight = Request::new(request.current_url(), Some(request.origin.borrow().clone()), false); + let mut preflight = Request::new(request.current_url(), Some(request.origin.borrow().clone()), + false, request.pipeline_id.get()); *preflight.method.borrow_mut() = Method::Options; preflight.initiator = request.initiator.clone(); preflight.type_ = request.type_.clone(); diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 175d1ca3fe1..5f9e6654bed 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.rs @@ -2,11 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use ipc_channel::ipc::IpcSender; use mime_guess::guess_mime_type_opt; use net_traits::blob_url_store::{BlobBuf, BlobURLStoreError}; use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerResult, FilterPattern, FileOrigin}; -use net_traits::filemanager_thread::{SelectedFile, RelativePos, FileManagerThreadError, SelectedFileId}; +use net_traits::filemanager_thread::{SelectedFile, RelativePos, FileManagerThreadError}; +use net_traits::filemanager_thread::{SelectedFileId, ReadFileProgress}; +use resource_thread::CancellationListener; use std::collections::HashMap; use std::fs::File; use std::io::{Read, Seek, SeekFrom}; @@ -14,17 +16,13 @@ use std::ops::Index; use std::path::{Path, PathBuf}; use std::sync::atomic::{self, AtomicUsize, AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use tinyfiledialogs; use url::Url; use util::prefs::PREFS; use util::thread::spawn_named; use uuid::Uuid; -pub trait FileManagerThreadFactory<UI: 'static + UIProvider> { - fn new(&'static UI) -> Self; -} - /// Trait that provider of file-dialog UI should implement. /// It will be used to initialize a generic FileManager. /// For example, we can choose a dummy UI for testing purpose. @@ -37,7 +35,7 @@ pub trait UIProvider where Self: Sync { pub struct TFDProvider; impl UIProvider for TFDProvider { - #[cfg(any(target_os = "macos", target_os = "linux"))] + #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn open_file_dialog(&self, path: &str, patterns: Vec<FilterPattern>) -> Option<String> { let mut filter = vec![]; for p in patterns { @@ -52,7 +50,7 @@ impl UIProvider for TFDProvider { tinyfiledialogs::open_file_dialog("Pick a file", path, filter_opt) } - #[cfg(any(target_os = "macos", target_os = "linux"))] + #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn open_file_dialog_multi(&self, path: &str, patterns: Vec<FilterPattern>) -> Option<Vec<String>> { let mut filter = vec![]; for p in patterns { @@ -67,30 +65,17 @@ impl UIProvider for TFDProvider { tinyfiledialogs::open_file_dialog_multi("Pick files", path, filter_opt) } - #[cfg(not(any(target_os = "macos", target_os = "linux")))] - fn open_file_dialog(&self, path: &str, patterns: Vec<FilterPattern>) -> Option<String> { + #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] + fn open_file_dialog(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<String> { None } - #[cfg(not(any(target_os = "macos", target_os = "linux")))] - fn open_file_dialog_multi(&self, path: &str, patterns: Vec<FilterPattern>) -> Option<Vec<String>> { + #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] + fn open_file_dialog_multi(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<Vec<String>> { None } } -impl<UI: 'static + UIProvider> FileManagerThreadFactory<UI> for IpcSender<FileManagerThreadMsg> { - /// Create a FileManagerThread - fn new(ui: &'static UI) -> IpcSender<FileManagerThreadMsg> { - let (chan, recv) = ipc::channel().unwrap(); - - spawn_named("FileManager".to_owned(), move || { - FileManager::new(recv, ui).start(); - }); - - chan - } -} - /// FileManagerStore's entry struct FileStoreEntry { /// Origin of the entry's "creator" @@ -126,93 +111,79 @@ enum FileImpl { Sliced(Uuid, RelativePos), } -struct FileManager<UI: 'static + UIProvider> { - receiver: IpcReceiver<FileManagerThreadMsg>, +pub struct FileManager<UI: 'static + UIProvider> { store: Arc<FileManagerStore<UI>>, } impl<UI: 'static + UIProvider> FileManager<UI> { - fn new(recv: IpcReceiver<FileManagerThreadMsg>, ui: &'static UI) -> FileManager<UI> { + pub fn new(ui: &'static UI) -> FileManager<UI> { FileManager { - receiver: recv, store: Arc::new(FileManagerStore::new(ui)), } } - /// Start the file manager event loop - fn start(&mut self) { - loop { - let store = self.store.clone(); - match self.receiver.recv().unwrap() { - FileManagerThreadMsg::SelectFile(filter, sender, origin, opt_test_path) => { - spawn_named("select file".to_owned(), move || { - store.select_file(filter, sender, origin, opt_test_path); - }); - } - FileManagerThreadMsg::SelectFiles(filter, sender, origin, opt_test_paths) => { - spawn_named("select files".to_owned(), move || { - store.select_files(filter, sender, origin, opt_test_paths); - }) - } - FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin) => { - spawn_named("read file".to_owned(), move || { - match store.try_read_file(id, check_url_validity, origin) { - Ok(buffer) => { let _ = sender.send(Ok(buffer)); } - Err(e) => { - let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e))); - } - } - }) - } - FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, sender, origin) => { - spawn_named("transfer memory".to_owned(), move || { - store.promote_memory(blob_buf, set_valid, sender, origin); + /// Message handler + pub fn handle(&self, msg: FileManagerThreadMsg, cancel_listener: Option<CancellationListener>) { + let store = self.store.clone(); + match msg { + FileManagerThreadMsg::SelectFile(filter, sender, origin, opt_test_path) => { + spawn_named("select file".to_owned(), move || { + store.select_file(filter, sender, origin, opt_test_path); + }); + } + FileManagerThreadMsg::SelectFiles(filter, sender, origin, opt_test_paths) => { + spawn_named("select files".to_owned(), move || { + store.select_files(filter, sender, origin, opt_test_paths); + }) + } + FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin) => { + spawn_named("read file".to_owned(), move || { + if let Err(e) = store.try_read_file(sender.clone(), id, check_url_validity, + origin, cancel_listener) { + let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e))); + } + }) + } + FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, sender, origin) => { + spawn_named("transfer memory".to_owned(), move || { + store.promote_memory(blob_buf, set_valid, sender, origin); + }) + } + FileManagerThreadMsg::AddSlicedURLEntry(id, rel_pos, sender, origin) =>{ + spawn_named("add sliced URL entry".to_owned(), move || { + store.add_sliced_url_entry(id, rel_pos, sender, origin); + }) + } + FileManagerThreadMsg::DecRef(id, origin, sender) => { + if let Ok(id) = Uuid::parse_str(&id.0) { + spawn_named("dec ref".to_owned(), move || { + // Since it is simple DecRef (possibly caused by close/drop), + // unset_url_validity is false + let _ = sender.send(store.dec_ref(&id, &origin)); }) + } else { + let _ = sender.send(Err(BlobURLStoreError::InvalidFileID)); } - FileManagerThreadMsg::AddSlicedURLEntry(id, rel_pos, sender, origin) =>{ - spawn_named("add sliced URL entry".to_owned(), move || { - store.add_sliced_url_entry(id, rel_pos, sender, origin); + } + FileManagerThreadMsg::RevokeBlobURL(id, origin, sender) => { + if let Ok(id) = Uuid::parse_str(&id.0) { + spawn_named("revoke blob url".to_owned(), move || { + // Since it is revocation, unset_url_validity is true + let _ = sender.send(store.set_blob_url_validity(false, &id, &origin)); }) + } else { + let _ = sender.send(Err(BlobURLStoreError::InvalidFileID)); } - FileManagerThreadMsg::RevokeBlobURL(id, origin, sender) => { - if let Ok(id) = Uuid::parse_str(&id.0) { - spawn_named("revoke blob url".to_owned(), move || { - // Since it is revocation, unset_url_validity is true - let _ = sender.send(store.dec_ref(&id, &origin, true)); - }) - } else { - let _ = sender.send(Err(BlobURLStoreError::InvalidFileID)); - } - } - FileManagerThreadMsg::DecRef(id, origin, sender) => { - if let Ok(id) = Uuid::parse_str(&id.0) { - spawn_named("dec ref".to_owned(), move || { - // Since it is simple DecRef (possibly caused by close/drop), - // unset_url_validity is false - let _ = sender.send(store.dec_ref(&id, &origin, false)); - }) - } else { - let _ = sender.send(Err(BlobURLStoreError::InvalidFileID)); - } - } - FileManagerThreadMsg::IncRef(id, origin) => { - if let Ok(id) = Uuid::parse_str(&id.0) { - spawn_named("inc ref".to_owned(), move || { - let _ = store.inc_ref(&id, &origin); - }) - } - } - FileManagerThreadMsg::ActivateBlobURL(id, sender, origin) => { - if let Ok(id) = Uuid::parse_str(&id.0) { - spawn_named("activate blob url".to_owned(), move || { - let _ = sender.send(store.activate_blob_url(&id, &origin)); - }); - } else { - let _ = sender.send(Err(BlobURLStoreError::InvalidFileID)); - } + } + FileManagerThreadMsg::ActivateBlobURL(id, sender, origin) => { + if let Ok(id) = Uuid::parse_str(&id.0) { + spawn_named("activate blob url".to_owned(), move || { + let _ = sender.send(store.set_blob_url_validity(true, &id, &origin)); + }); + } else { + let _ = sender.send(Err(BlobURLStoreError::InvalidFileID)); } - FileManagerThreadMsg::Exit => break, - }; + } } } } @@ -287,9 +258,11 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { file_impl: FileImpl::Sliced(parent_id, rel_pos), refs: AtomicUsize::new(1), // Valid here since AddSlicedURLEntry implies URL creation + // from a BlobImpl::Sliced is_valid_url: AtomicBool::new(true), }); + // We assume that the returned id will be held by BlobImpl::File let _ = sender.send(Ok(SelectedFileId(new_id.simple().to_string()))); } Err(e) => { @@ -370,8 +343,8 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { fn create_entry(&self, file_path: &Path, origin: &str) -> Result<SelectedFile, FileManagerThreadError> { use net_traits::filemanager_thread::FileManagerThreadError::FileSystemError; - let handler = try!(File::open(file_path).map_err(|e| FileSystemError(e.to_string()))); - let metadata = try!(handler.metadata().map_err(|e| FileSystemError(e.to_string()))); + let file = try!(File::open(file_path).map_err(|e| FileSystemError(e.to_string()))); + let metadata = try!(file.metadata().map_err(|e| FileSystemError(e.to_string()))); let modified = try!(metadata.modified().map_err(|e| FileSystemError(e.to_string()))); let elapsed = try!(modified.elapsed().map_err(|e| FileSystemError(e.to_string()))); // Unix Epoch: https://doc.servo.org/std/time/constant.UNIX_EPOCH.html @@ -410,22 +383,29 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { }) } - fn get_blob_buf(&self, id: &Uuid, origin_in: &FileOrigin, rel_pos: RelativePos, - check_url_validity: bool) -> Result<BlobBuf, BlobURLStoreError> { + fn get_blob_buf(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>, + id: &Uuid, origin_in: &FileOrigin, rel_pos: RelativePos, + check_url_validity: bool, + cancel_listener: Option<CancellationListener>) -> Result<(), BlobURLStoreError> { let file_impl = try!(self.get_impl(id, origin_in, check_url_validity)); match file_impl { FileImpl::Memory(buf) => { let range = rel_pos.to_abs_range(buf.size as usize); - Ok(BlobBuf { + let buf = BlobBuf { filename: None, type_string: buf.type_string, size: range.len() as u64, bytes: buf.bytes.index(range).to_vec(), - }) + }; + + let _ = sender.send(Ok(ReadFileProgress::Meta(buf))); + let _ = sender.send(Ok(ReadFileProgress::EOF)); + + Ok(()) } FileImpl::MetaDataOnly(metadata) => { /* XXX: Snapshot state check (optional) https://w3c.github.io/FileAPI/#snapshot-state. - Concretely, here we create another handler, and this handler might not + Concretely, here we create another file, and this file might not has the same underlying file state (meta-info plus content) as the time create_entry is called. */ @@ -437,25 +417,20 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { let mime = guess_mime_type_opt(metadata.path.clone()); let range = rel_pos.to_abs_range(metadata.size as usize); - let mut handler = try!(File::open(&metadata.path) - .map_err(|e| BlobURLStoreError::External(e.to_string()))); - let seeked_start = try!(handler.seek(SeekFrom::Start(range.start as u64)) + let mut file = try!(File::open(&metadata.path) + .map_err(|e| BlobURLStoreError::External(e.to_string()))); + let seeked_start = try!(file.seek(SeekFrom::Start(range.start as u64)) .map_err(|e| BlobURLStoreError::External(e.to_string()))); if seeked_start == (range.start as u64) { - let mut bytes = vec![0; range.len()]; - try!(handler.read_exact(&mut bytes) - .map_err(|e| BlobURLStoreError::External(e.to_string()))); - - Ok(BlobBuf { - filename: opt_filename, - type_string: match mime { - Some(x) => format!("{}", x), - None => "".to_string(), - }, - size: range.len() as u64, - bytes: bytes, - }) + let type_string = match mime { + Some(x) => format!("{}", x), + None => "".to_string(), + }; + + chunked_read(sender, &mut file, range.len(), opt_filename, + type_string, cancel_listener); + Ok(()) } else { Err(BlobURLStoreError::InvalidEntry) } @@ -463,29 +438,28 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { FileImpl::Sliced(parent_id, inner_rel_pos) => { // Next time we don't need to check validity since // we have already done that for requesting URL if necessary - self.get_blob_buf(&parent_id, origin_in, rel_pos.slice_inner(&inner_rel_pos), false) + self.get_blob_buf(sender, &parent_id, origin_in, + rel_pos.slice_inner(&inner_rel_pos), false, + cancel_listener) } } } // Convenient wrapper over get_blob_buf - fn try_read_file(&self, id: SelectedFileId, check_url_validity: bool, - origin_in: FileOrigin) -> Result<BlobBuf, BlobURLStoreError> { + fn try_read_file(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>, + id: SelectedFileId, check_url_validity: bool, origin_in: FileOrigin, + cancel_listener: Option<CancellationListener>) -> Result<(), BlobURLStoreError> { let id = try!(Uuid::parse_str(&id.0).map_err(|_| BlobURLStoreError::InvalidFileID)); - self.get_blob_buf(&id, &origin_in, RelativePos::full_range(), check_url_validity) + self.get_blob_buf(sender, &id, &origin_in, RelativePos::full_range(), + check_url_validity, cancel_listener) } - fn dec_ref(&self, id: &Uuid, origin_in: &FileOrigin, - unset_url_validity: bool) -> Result<(), BlobURLStoreError> { + fn dec_ref(&self, id: &Uuid, origin_in: &FileOrigin) -> Result<(), BlobURLStoreError> { let (do_remove, opt_parent_id) = match self.entries.read().unwrap().get(id) { Some(entry) => { if *entry.origin == *origin_in { let old_refs = entry.refs.fetch_sub(1, Ordering::Release); - if unset_url_validity { - entry.is_valid_url.store(false, Ordering::Release); - } - if old_refs > 1 { // not the last reference, no need to touch parent (false, None) @@ -515,7 +489,7 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { if let Some(parent_id) = opt_parent_id { // unset_url_validity for parent is false since we only need // to unset the initial requesting URL - return self.dec_ref(&parent_id, origin_in, false); + return self.dec_ref(&parent_id, origin_in); } } @@ -543,23 +517,97 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> { } } - fn activate_blob_url(&self, id: &Uuid, origin_in: &FileOrigin) -> Result<(), BlobURLStoreError> { - match self.entries.read().unwrap().get(id) { + fn set_blob_url_validity(&self, validity: bool, id: &Uuid, + origin_in: &FileOrigin) -> Result<(), BlobURLStoreError> { + let (do_remove, opt_parent_id, res) = match self.entries.read().unwrap().get(id) { Some(entry) => { if *entry.origin == *origin_in { - entry.is_valid_url.store(true, Ordering::Release); - Ok(()) + entry.is_valid_url.store(validity, Ordering::Release); + + if !validity { + // Check if it is the last possible reference + // since refs only accounts for blob id holders + // and store entry id holders + let zero_refs = entry.refs.load(Ordering::Acquire) == 0; + + if let FileImpl::Sliced(ref parent_id, _) = entry.file_impl { + (zero_refs, Some(parent_id.clone()), Ok(())) + } else { + (zero_refs, None, Ok(())) + } + } else { + (false, None, Ok(())) + } } else { - Err(BlobURLStoreError::InvalidOrigin) + (false, None, Err(BlobURLStoreError::InvalidOrigin)) } } - None => Err(BlobURLStoreError::InvalidFileID) + None => (false, None, Err(BlobURLStoreError::InvalidFileID)) + }; + + if do_remove { + atomic::fence(Ordering::Acquire); + self.remove(id); + + if let Some(parent_id) = opt_parent_id { + return self.dec_ref(&parent_id, origin_in); + } } + res } } - fn select_files_pref_enabled() -> bool { PREFS.get("dom.testing.htmlinputelement.select_files.enabled") .as_boolean().unwrap_or(false) } + +const CHUNK_SIZE: usize = 8192; + +fn chunked_read(sender: IpcSender<FileManagerResult<ReadFileProgress>>, + file: &mut File, size: usize, opt_filename: Option<String>, + type_string: String, cancel_listener: Option<CancellationListener>) { + // First chunk + let mut buf = vec![0; CHUNK_SIZE]; + match file.read(&mut buf) { + Ok(n) => { + buf.truncate(n); + let blob_buf = BlobBuf { + filename: opt_filename, + type_string: type_string, + size: size as u64, + bytes: buf, + }; + let _ = sender.send(Ok(ReadFileProgress::Meta(blob_buf))); + } + Err(e) => { + let _ = sender.send(Err(FileManagerThreadError::FileSystemError(e.to_string()))); + return; + } + } + + // Send the remaining chunks + loop { + if let Some(ref listener) = cancel_listener.as_ref() { + if listener.is_cancelled() { + break; + } + } + + let mut buf = vec![0; CHUNK_SIZE]; + match file.read(&mut buf) { + Ok(0) => { + let _ = sender.send(Ok(ReadFileProgress::EOF)); + return; + } + Ok(n) => { + buf.truncate(n); + let _ = sender.send(Ok(ReadFileProgress::Partial(buf))); + } + Err(e) => { + let _ = sender.send(Err(FileManagerThreadError::FileSystemError(e.to_string()))); + return; + } + } + } +} diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index a39d284a486..2f328917352 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -48,7 +48,7 @@ use std::sync::mpsc::Sender; use std::sync::{Arc, RwLock}; use time; use time::Tm; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use tinyfiledialogs; use url::{Url, Position}; use util::prefs::PREFS; @@ -600,7 +600,8 @@ fn prepare_devtools_request(request_id: String, pipeline_id: PipelineId, now: Tm, connect_time: u64, - send_time: u64) -> ChromeToDevtoolsControlMsg { + send_time: u64, + is_xhr: bool) -> ChromeToDevtoolsControlMsg { let request = DevtoolsHttpRequest { url: url, method: method, @@ -611,29 +612,28 @@ fn prepare_devtools_request(request_id: String, timeStamp: now.to_timespec().sec, connect_time: connect_time, send_time: send_time, + is_xhr: is_xhr, }; let net_event = NetworkEvent::HttpRequest(request); ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event) } -fn send_request_to_devtools(msg: ChromeToDevtoolsControlMsg, +pub fn send_request_to_devtools(msg: ChromeToDevtoolsControlMsg, devtools_chan: &Sender<DevtoolsControlMsg>) { devtools_chan.send(DevtoolsControlMsg::FromChrome(msg)).unwrap(); } -fn send_response_to_devtools(devtools_chan: Option<Sender<DevtoolsControlMsg>>, +pub fn send_response_to_devtools(devtools_chan: &Sender<DevtoolsControlMsg>, request_id: String, headers: Option<Headers>, status: Option<RawStatus>, pipeline_id: PipelineId) { - if let Some(ref chan) = devtools_chan { - let response = DevtoolsHttpResponse { headers: headers, status: status, body: None, pipeline_id: pipeline_id }; - let net_event_response = NetworkEvent::HttpResponse(response); + let response = DevtoolsHttpResponse { headers: headers, status: status, body: None, pipeline_id: pipeline_id }; + let net_event_response = NetworkEvent::HttpResponse(response); - let msg = ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event_response); - chan.send(DevtoolsControlMsg::FromChrome(msg)).unwrap(); - } + let msg = ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event_response); + let _ = devtools_chan.send(DevtoolsControlMsg::FromChrome(msg)); } fn request_must_be_secured(url: &Url, hsts_list: &Arc<RwLock<HstsList>>) -> bool { @@ -744,7 +744,8 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>, pipeline_id: &Option<PipelineId>, iters: u32, devtools_chan: &Option<Sender<DevtoolsControlMsg>>, - request_id: &str) + request_id: &str, + is_xhr: bool) -> Result<(A::R, Option<ChromeToDevtoolsControlMsg>), LoadError> where A: HttpRequest + 'static { let null_data = None; @@ -752,6 +753,7 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>, let connection_url = replace_hosts(&url); let mut msg; + // loop trying connections in connection pool // they may have grown stale (disconnected), in which case we'll get // a ConnectionAborted error. this loop tries again with a new @@ -811,7 +813,7 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>, request_id.clone().into(), url.clone(), method.clone(), headers, request_body.clone(), pipeline_id, time::now(), - connect_end - connect_start, send_end - send_start)) + connect_end - connect_start, send_end - send_start, is_xhr)) } else { None } @@ -843,13 +845,13 @@ pub trait UIProvider { } impl UIProvider for TFDProvider { - #[cfg(any(target_os = "macos", target_os = "linux"))] + #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn input_username_and_password(&self, prompt: &str) -> (Option<String>, Option<String>) { (tinyfiledialogs::input_box(prompt, "Username:", ""), tinyfiledialogs::input_box(prompt, "Password:", "")) } - #[cfg(not(any(target_os = "macos", target_os = "linux")))] + #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] fn input_username_and_password(&self, _prompt: &str) -> (Option<String>, Option<String>) { (None, None) } @@ -989,7 +991,7 @@ pub fn load<A, B>(load_data: &LoadData, let (response, msg) = try!(obtain_response(request_factory, &doc_url, &method, &request_headers, &cancel_listener, &load_data.data, &load_data.method, - &load_data.pipeline_id, iters, &devtools_chan, &request_id)); + &load_data.pipeline_id, iters, &devtools_chan, &request_id, false)); process_response_headers(&response, &doc_url, &http_state.cookie_jar, &http_state.hsts_list, &load_data); @@ -1056,10 +1058,13 @@ pub fn load<A, B>(load_data: &LoadData, doc_url = new_doc_url; redirected_to.insert(doc_url.clone()); - continue; } } + // Only notify the devtools about the final request that received a response. + if let Some(m) = msg { + send_request_to_devtools(m, devtools_chan.as_ref().unwrap()); + } let mut adjusted_headers = response.headers().clone(); if viewing_source { @@ -1078,23 +1083,24 @@ pub fn load<A, B>(load_data: &LoadData, } else { HttpsState::None }; - metadata.referrer = referrer_url; - - // Only notify the devtools about the final request that received a response. - if let Some(msg) = msg { - send_request_to_devtools(msg, devtools_chan.as_ref().unwrap()); - } + metadata.referrer = referrer_url.clone(); // --- Tell devtools that we got a response // Send an HttpResponse message to devtools with the corresponding request_id // TODO: Send this message even when the load fails? if let Some(pipeline_id) = load_data.pipeline_id { + if let Some(ref chan) = devtools_chan { send_response_to_devtools( - devtools_chan, request_id, + &chan, request_id, metadata.headers.clone(), metadata.status.clone(), pipeline_id); - } - return StreamedResponse::from_http_response(box response, metadata) + } + } + if response.status().class() == StatusClass::Redirection { + continue; + } else { + return StreamedResponse::from_http_response(box response, metadata); + } } } diff --git a/components/net/lib.rs b/components/net/lib.rs index 80c6294c277..53efb84f6c2 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -38,7 +38,7 @@ extern crate rand; extern crate rustc_serialize; extern crate threadpool; extern crate time; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] extern crate tinyfiledialogs; extern crate unicase; extern crate url; diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index 9ee16b911ad..411b0d22373 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -15,7 +15,7 @@ use data_loader; use devtools_traits::DevtoolsControlMsg; use fetch::methods::{fetch, FetchContext}; use file_loader; -use filemanager_thread::{FileManagerThreadFactory, TFDProvider}; +use filemanager_thread::{FileManager, TFDProvider}; use hsts::HstsList; use http_loader::{self, HttpState}; use hyper::client::pool::Pool; @@ -25,7 +25,6 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcReceiverSet}; use mime_classifier::{ApacheBugFlag, MimeClassifier, NoSniffFlag}; use net_traits::LoadContext; use net_traits::ProgressMsg::Done; -use net_traits::filemanager_thread::FileManagerThreadMsg; use net_traits::request::{Request, RequestInit}; use net_traits::storage_thread::StorageThreadMsg; use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResponseAction, CoreResourceThread}; @@ -42,13 +41,13 @@ use std::collections::HashMap; use std::error::Error; use std::fs::File; use std::io::prelude::*; -use std::path::Path; +use std::ops::Deref; +use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::mpsc::{Receiver, Sender, channel}; use std::sync::{Arc, RwLock}; use storage_thread::StorageThreadFactory; use url::Url; -use util::opts; use util::prefs::PREFS; use util::thread::spawn_named; use websocket_loader; @@ -165,13 +164,17 @@ fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata, /// Returns a tuple of (public, private) senders to the new threads. pub fn new_resource_threads(user_agent: String, devtools_chan: Option<Sender<DevtoolsControlMsg>>, - profiler_chan: ProfilerChan) -> (ResourceThreads, ResourceThreads) { - let filemanager_chan: IpcSender<FileManagerThreadMsg> = FileManagerThreadFactory::new(TFD_PROVIDER); - let (public_core, private_core) = new_core_resource_thread(user_agent, devtools_chan, - profiler_chan, filemanager_chan.clone()); - let storage: IpcSender<StorageThreadMsg> = StorageThreadFactory::new(); - (ResourceThreads::new(public_core, storage.clone(), filemanager_chan.clone()), - ResourceThreads::new(private_core, storage, filemanager_chan)) + profiler_chan: ProfilerChan, + config_dir: Option<PathBuf>) + -> (ResourceThreads, ResourceThreads) { + let (public_core, private_core) = new_core_resource_thread( + user_agent, + devtools_chan, + profiler_chan, + config_dir.clone()); + let storage: IpcSender<StorageThreadMsg> = StorageThreadFactory::new(config_dir); + (ResourceThreads::new(public_core, storage.clone()), + ResourceThreads::new(private_core, storage)) } @@ -179,7 +182,7 @@ pub fn new_resource_threads(user_agent: String, pub fn new_core_resource_thread(user_agent: String, devtools_chan: Option<Sender<DevtoolsControlMsg>>, profiler_chan: ProfilerChan, - filemanager_chan: IpcSender<FileManagerThreadMsg>) + config_dir: Option<PathBuf>) -> (CoreResourceThread, CoreResourceThread) { let (public_setup_chan, public_setup_port) = ipc::channel().unwrap(); let (private_setup_chan, private_setup_port) = ipc::channel().unwrap(); @@ -187,11 +190,12 @@ pub fn new_core_resource_thread(user_agent: String, let private_setup_chan_clone = private_setup_chan.clone(); spawn_named("ResourceManager".to_owned(), move || { let resource_manager = CoreResourceManager::new( - user_agent, devtools_chan, profiler_chan, filemanager_chan + user_agent, devtools_chan, profiler_chan ); let mut channel_manager = ResourceChannelManager { resource_manager: resource_manager, + config_dir: config_dir, }; channel_manager.start(public_setup_chan_clone, private_setup_chan_clone, @@ -202,14 +206,16 @@ pub fn new_core_resource_thread(user_agent: String, } struct ResourceChannelManager { - resource_manager: CoreResourceManager + resource_manager: CoreResourceManager, + config_dir: Option<PathBuf>, } -fn create_resource_groups() -> (ResourceGroup, ResourceGroup) { +fn create_resource_groups(config_dir: Option<&Path>) + -> (ResourceGroup, ResourceGroup) { let mut hsts_list = HstsList::from_servo_preload(); let mut auth_cache = AuthCache::new(); let mut cookie_jar = CookieStorage::new(); - if let Some(ref config_dir) = opts::get().config_dir { + if let Some(config_dir) = config_dir { read_json_from_file(&mut auth_cache, config_dir, "auth_cache.json"); read_json_from_file(&mut hsts_list, config_dir, "hsts_list.json"); read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json"); @@ -236,7 +242,8 @@ impl ResourceChannelManager { private_control_sender: CoreResourceThread, public_receiver: IpcReceiver<CoreResourceMsg>, private_receiver: IpcReceiver<CoreResourceMsg>) { - let (public_resource_group, private_resource_group) = create_resource_groups(); + let (public_resource_group, private_resource_group) = + create_resource_groups(self.config_dir.as_ref().map(Deref::deref)); let mut rx_set = IpcReceiverSet::new().unwrap(); let private_id = rx_set.add(private_receiver).unwrap(); @@ -296,8 +303,9 @@ impl ResourceChannelManager { CoreResourceMsg::Synchronize(sender) => { let _ = sender.send(()); } + CoreResourceMsg::ToFileManager(msg) => self.resource_manager.filemanager.handle(msg, None), CoreResourceMsg::Exit(sender) => { - if let Some(ref config_dir) = opts::get().config_dir { + if let Some(ref config_dir) = self.config_dir { match group.auth_cache.read() { Ok(auth_cache) => write_json_to_file(&*auth_cache, config_dir, "auth_cache.json"), Err(_) => warn!("Error writing auth cache to disk"), @@ -319,8 +327,10 @@ impl ResourceChannelManager { } } -pub fn read_json_from_file<T: Decodable>(data: &mut T, config_dir: &str, filename: &str) { - let path = Path::new(config_dir).join(filename); +pub fn read_json_from_file<T>(data: &mut T, config_dir: &Path, filename: &str) + where T: Decodable +{ + let path = config_dir.join(filename); let display = path.display(); let mut file = match File::open(&path) { @@ -346,13 +356,15 @@ pub fn read_json_from_file<T: Decodable>(data: &mut T, config_dir: &str, filenam } } -pub fn write_json_to_file<T: Encodable>(data: &T, config_dir: &str, filename: &str) { +pub fn write_json_to_file<T>(data: &T, config_dir: &Path, filename: &str) + where T: Encodable +{ let json_encoded: String; match json::encode(&data) { Ok(d) => json_encoded = d, Err(_) => return, } - let path = Path::new(config_dir).join(filename); + let path = config_dir.join(filename); let display = path.display(); let mut file = match File::create(&path) { @@ -461,7 +473,7 @@ pub struct CoreResourceManager { devtools_chan: Option<Sender<DevtoolsControlMsg>>, swmanager_chan: Option<IpcSender<CustomResponseMediator>>, profiler_chan: ProfilerChan, - filemanager_chan: IpcSender<FileManagerThreadMsg>, + filemanager: Arc<FileManager<TFDProvider>>, cancel_load_map: HashMap<ResourceId, Sender<()>>, next_resource_id: ResourceId, } @@ -469,15 +481,14 @@ pub struct CoreResourceManager { impl CoreResourceManager { pub fn new(user_agent: String, devtools_channel: Option<Sender<DevtoolsControlMsg>>, - profiler_chan: ProfilerChan, - filemanager_chan: IpcSender<FileManagerThreadMsg>) -> CoreResourceManager { + profiler_chan: ProfilerChan) -> CoreResourceManager { CoreResourceManager { user_agent: user_agent, mime_classifier: Arc::new(MimeClassifier::new()), devtools_chan: devtools_channel, swmanager_chan: None, profiler_chan: profiler_chan, - filemanager_chan: filemanager_chan, + filemanager: Arc::new(FileManager::new(TFD_PROVIDER)), cancel_load_map: HashMap::new(), next_resource_id: ResourceId(0), } @@ -552,14 +563,14 @@ impl CoreResourceManager { }, "data" => from_factory(data_loader::factory), "about" => from_factory(about_loader::factory), - "blob" => blob_loader::factory(self.filemanager_chan.clone()), + "blob" => blob_loader::factory(self.filemanager.clone()), _ => { debug!("resource_thread: no loader for scheme {}", load_data.url.scheme()); send_error(load_data.url, NetworkError::Internal("no loader for scheme".to_owned()), consumer); return } }; - debug!("resource_thread: loading url: {}", load_data.url); + debug!("loading url: {}", load_data.url); loader.call_box((load_data, consumer, @@ -578,6 +589,7 @@ impl CoreResourceManager { blocked_content: BLOCKED_CONTENT_RULES.clone(), }; let ua = self.user_agent.clone(); + let dc = self.devtools_chan.clone(); spawn_named(format!("fetch thread for {}", init.url), move || { let request = Request::from_init(init); // XXXManishearth: Check origin against pipeline id (also ensure that the mode is allowed) @@ -585,7 +597,7 @@ impl CoreResourceManager { // todo referrer policy? // todo service worker stuff let mut target = Some(Box::new(sender) as Box<FetchTaskTarget + Send + 'static>); - let context = FetchContext { state: http_state, user_agent: ua }; + let context = FetchContext { state: http_state, user_agent: ua, devtools_chan: dc }; fetch(Rc::new(request), &mut target, context); }) } diff --git a/components/net/storage_thread.rs b/components/net/storage_thread.rs index cc329f08922..0e7c7647420 100644 --- a/components/net/storage_thread.rs +++ b/components/net/storage_thread.rs @@ -8,22 +8,22 @@ use resource_thread; use std::borrow::ToOwned; use std::collections::BTreeMap; use std::collections::HashMap; +use std::path::PathBuf; use url::Url; -use util::opts; use util::thread::spawn_named; const QUOTA_SIZE_LIMIT: usize = 5 * 1024 * 1024; pub trait StorageThreadFactory { - fn new() -> Self; + fn new(config_dir: Option<PathBuf>) -> Self; } impl StorageThreadFactory for IpcSender<StorageThreadMsg> { /// Create a storage thread - fn new() -> IpcSender<StorageThreadMsg> { + fn new(config_dir: Option<PathBuf>) -> IpcSender<StorageThreadMsg> { let (chan, port) = ipc::channel().unwrap(); spawn_named("StorageManager".to_owned(), move || { - StorageManager::new(port).start(); + StorageManager::new(port, config_dir).start(); }); chan } @@ -33,18 +33,22 @@ struct StorageManager { port: IpcReceiver<StorageThreadMsg>, session_data: HashMap<String, (usize, BTreeMap<String, String>)>, local_data: HashMap<String, (usize, BTreeMap<String, String>)>, + config_dir: Option<PathBuf>, } impl StorageManager { - fn new(port: IpcReceiver<StorageThreadMsg>) -> StorageManager { + fn new(port: IpcReceiver<StorageThreadMsg>, + config_dir: Option<PathBuf>) + -> StorageManager { let mut local_data = HashMap::new(); - if let Some(ref config_dir) = opts::get().config_dir { + if let Some(ref config_dir) = config_dir { resource_thread::read_json_from_file(&mut local_data, config_dir, "local_data.json"); } StorageManager { port: port, session_data: HashMap::new(), local_data: local_data, + config_dir: config_dir, } } } @@ -75,7 +79,7 @@ impl StorageManager { self.clear(sender, url, storage_type) } StorageThreadMsg::Exit(sender) => { - if let Some(ref config_dir) = opts::get().config_dir { + if let Some(ref config_dir) = self.config_dir { resource_thread::write_json_to_file(&self.local_data, config_dir, "local_data.json"); } let _ = sender.send(()); diff --git a/components/net_traits/Cargo.toml b/components/net_traits/Cargo.toml index 3ce61c9d303..52877605b15 100644 --- a/components/net_traits/Cargo.toml +++ b/components/net_traits/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" [dependencies] util = {path = "../util"} msg = {path = "../msg"} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" heapsize = "0.3.0" heapsize_plugin = "0.1.2" hyper = { version = "0.9.9", features = [ "serde-serialization" ] } @@ -20,8 +20,8 @@ image = "0.10" lazy_static = "0.2" log = "0.3.5" num-traits = "0.1.32" -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" url = {version = "1.0.0", features = ["heap_size"]} websocket = "0.17" uuid = { version = "0.2.2", features = ["v4", "serde"] } diff --git a/components/net_traits/bluetooth_thread.rs b/components/net_traits/bluetooth_thread.rs index caeadabd6d4..48f64ff7474 100644 --- a/components/net_traits/bluetooth_thread.rs +++ b/components/net_traits/bluetooth_thread.rs @@ -1,10 +1,20 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + use bluetooth_scanfilter::RequestDeviceoptions; use ipc_channel::ipc::IpcSender; #[derive(Deserialize, Serialize)] +pub enum BluetoothError { + Type(String), + Network, + NotFound, + NotSupported, + Security, +} + +#[derive(Deserialize, Serialize)] pub struct BluetoothDeviceMsg { // Bluetooth Device properties pub id: String, @@ -51,7 +61,7 @@ pub type BluetoothCharacteristicsMsg = Vec<BluetoothCharacteristicMsg>; pub type BluetoothDescriptorsMsg = Vec<BluetoothDescriptorMsg>; -pub type BluetoothResult<T> = Result<T, String>; +pub type BluetoothResult<T> = Result<T, BluetoothError>; #[derive(Deserialize, Serialize)] pub enum BluetoothMethodMsg { diff --git a/components/net_traits/filemanager_thread.rs b/components/net_traits/filemanager_thread.rs index 957205fcc11..8ea607f191f 100644 --- a/components/net_traits/filemanager_thread.rs +++ b/components/net_traits/filemanager_thread.rs @@ -127,9 +127,8 @@ pub enum FileManagerThreadMsg { /// Select multiple files, return a vector of triples SelectFiles(Vec<FilterPattern>, IpcSender<FileManagerResult<Vec<SelectedFile>>>, FileOrigin, Option<Vec<String>>), - /// Read file by FileID, optionally check URL validity based on - /// third flag, return the blob buffer object - ReadFile(IpcSender<FileManagerResult<BlobBuf>>, SelectedFileId, bool, FileOrigin), + /// Read file in chunks by FileID, optionally check URL validity based on fourth flag + ReadFile(IpcSender<FileManagerResult<ReadFileProgress>>, SelectedFileId, bool, FileOrigin), /// Add an entry as promoted memory-based blob and send back the associated FileID /// as part of a valid/invalid Blob URL depending on the second bool flag @@ -139,20 +138,21 @@ pub enum FileManagerThreadMsg { /// as part of a valid Blob URL AddSlicedURLEntry(SelectedFileId, RelativePos, IpcSender<Result<SelectedFileId, BlobURLStoreError>>, FileOrigin), - /// Revoke Blob URL and send back the acknowledgement - RevokeBlobURL(SelectedFileId, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>), - /// Decrease reference count and send back the acknowledgement DecRef(SelectedFileId, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>), - /// Increase reference count - IncRef(SelectedFileId, FileOrigin), - /// Activate an internal FileID so it becomes valid as part of a Blob URL ActivateBlobURL(SelectedFileId, IpcSender<Result<(), BlobURLStoreError>>, FileOrigin), - /// Shut down this thread - Exit, + /// Revoke Blob URL and send back the acknowledgement + RevokeBlobURL(SelectedFileId, FileOrigin, IpcSender<Result<(), BlobURLStoreError>>), +} + +#[derive(Debug, Deserialize, Serialize)] +pub enum ReadFileProgress { + Meta(BlobBuf), + Partial(Vec<u8>), + EOF } pub type FileManagerResult<T> = Result<T, FileManagerThreadError>; diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 8e7bb996697..fd2973033eb 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -321,17 +321,14 @@ pub trait IpcSend<T> where T: serde::Serialize + serde::Deserialize { pub struct ResourceThreads { core_thread: CoreResourceThread, storage_thread: IpcSender<StorageThreadMsg>, - filemanager_thread: IpcSender<FileManagerThreadMsg>, } impl ResourceThreads { pub fn new(c: CoreResourceThread, - s: IpcSender<StorageThreadMsg>, - f: IpcSender<FileManagerThreadMsg>) -> ResourceThreads { + s: IpcSender<StorageThreadMsg>) -> ResourceThreads { ResourceThreads { core_thread: c, storage_thread: s, - filemanager_thread: f, } } } @@ -356,16 +353,6 @@ impl IpcSend<StorageThreadMsg> for ResourceThreads { } } -impl IpcSend<FileManagerThreadMsg> for ResourceThreads { - fn send(&self, msg: FileManagerThreadMsg) -> IpcSendResult { - self.filemanager_thread.send(msg) - } - - fn sender(&self) -> IpcSender<FileManagerThreadMsg> { - self.filemanager_thread.clone() - } -} - // Ignore the sub-fields impl HeapSizeOf for ResourceThreads { fn heap_size_of_children(&self) -> usize { 0 } @@ -431,6 +418,8 @@ pub enum CoreResourceMsg { Synchronize(IpcSender<()>), /// Send the network sender in constellation to CoreResourceThread NetworkMediator(IpcSender<CustomResponseMediator>), + /// Message forwarded to file manager's handler + ToFileManager(FileManagerThreadMsg), /// Break the load handler loop, send a reply when done cleaning up local resources // and exit Exit(IpcSender<()>), diff --git a/components/net_traits/request.rs b/components/net_traits/request.rs index 1fbcdabe868..bf7e22d2d0b 100644 --- a/components/net_traits/request.rs +++ b/components/net_traits/request.rs @@ -4,7 +4,7 @@ use hyper::header::Headers; use hyper::method::Method; -use msg::constellation_msg::ReferrerPolicy; +use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use std::cell::{Cell, RefCell}; use std::mem::swap; use url::{Origin as UrlOrigin, Url}; @@ -130,6 +130,7 @@ pub struct RequestInit { // XXXManishearth these should be part of the client object pub referer_url: Option<Url>, pub referrer_policy: Option<ReferrerPolicy>, + pub pipeline_id: Option<PipelineId>, } /// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec @@ -159,6 +160,7 @@ pub struct Request { /// https://fetch.spec.whatwg.org/#concept-request-referrer pub referer: RefCell<Referer>, pub referrer_policy: Cell<Option<ReferrerPolicy>>, + pub pipeline_id: Cell<Option<PipelineId>>, pub synchronous: bool, pub mode: RequestMode, pub use_cors_preflight: bool, @@ -178,7 +180,8 @@ pub struct Request { impl Request { pub fn new(url: Url, origin: Option<Origin>, - is_service_worker_global_scope: bool) -> Request { + is_service_worker_global_scope: bool, + pipeline_id: Option<PipelineId>) -> Request { Request { method: RefCell::new(Method::Get), local_urls_only: false, @@ -198,6 +201,7 @@ impl Request { same_origin_data: Cell::new(false), referer: RefCell::new(Referer::Client), referrer_policy: Cell::new(None), + pipeline_id: Cell::new(pipeline_id), synchronous: false, mode: RequestMode::NoCORS, use_cors_preflight: false, @@ -216,7 +220,7 @@ impl Request { pub fn from_init(init: RequestInit) -> Request { let mut req = Request::new(init.url, Some(Origin::Origin(init.origin.origin())), - false); + false, init.pipeline_id); *req.method.borrow_mut() = init.method; *req.headers.borrow_mut() = init.headers; req.unsafe_request = init.unsafe_request; @@ -234,6 +238,7 @@ impl Request { Referer::NoReferer }; req.referrer_policy.set(init.referrer_policy); + req.pipeline_id.set(init.pipeline_id); req } @@ -241,7 +246,8 @@ impl Request { pub fn potential_cors_request(url: Url, cors_attribute_state: Option<CORSSettings>, is_service_worker_global_scope: bool, - same_origin_fallback: bool) -> Request { + same_origin_fallback: bool, + pipeline_id: Option<PipelineId>) -> Request { Request { method: RefCell::new(Method::Get), local_urls_only: false, @@ -281,6 +287,7 @@ impl Request { url_list: RefCell::new(vec![url]), redirect_count: Cell::new(0), response_tainting: Cell::new(ResponseTainting::Basic), + pipeline_id: Cell::new(pipeline_id), done: Cell::new(false) } } diff --git a/components/plugins/jstraceable.rs b/components/plugins/jstraceable.rs index a1a9d81e94f..8dcd93f2d4c 100644 --- a/components/plugins/jstraceable.rs +++ b/components/plugins/jstraceable.rs @@ -86,5 +86,5 @@ fn jstraceable_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substru stmts.push(call_trace(span, self_.clone())); } - cx.expr_block(cx.block(trait_span, stmts, None)) + cx.expr_block(cx.block(trait_span, stmts)) } diff --git a/components/profile/Cargo.toml b/components/profile/Cargo.toml index 7532de19136..e430982d57f 100644 --- a/components/profile/Cargo.toml +++ b/components/profile/Cargo.toml @@ -13,12 +13,12 @@ path = "lib.rs" profile_traits = {path = "../profile_traits"} plugins = {path = "../plugins"} util = {path = "../util", features = ["servo"]} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" heartbeats-simple = "0.3" log = "0.3.5" -serde = "0.7.11" +serde = "0.7.15" serde_json = "0.7" -serde_macros = "0.7.11" +serde_macros = "0.7.15" time = "0.1.12" [target.'cfg(target_os = "macos")'.dependencies] diff --git a/components/profile_traits/Cargo.toml b/components/profile_traits/Cargo.toml index 5e6d0890b64..0c8f966af28 100644 --- a/components/profile_traits/Cargo.toml +++ b/components/profile_traits/Cargo.toml @@ -13,10 +13,10 @@ path = "lib.rs" energy-profiling = ["energymon", "energy-monitor"] [dependencies] -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" energymon = {git = "https://github.com/energymon/energymon-rust.git", optional = true} energy-monitor = {version = "0.2.0", optional = true} plugins = {path = "../plugins"} -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" time = "0.1.12" diff --git a/components/range/Cargo.toml b/components/range/Cargo.toml index c3573de6515..c9cbf2e9b50 100644 --- a/components/range/Cargo.toml +++ b/components/range/Cargo.toml @@ -15,5 +15,5 @@ heapsize = "0.3.0" heapsize_plugin = "0.1.2" num-traits = "0.1.32" rustc-serialize = "0.3" -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 0640fb17f60..891b48f3dd9 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -14,9 +14,12 @@ path = "lib.rs" [features] debugmozjs = ['js/debugmozjs'] -[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies] +[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies] tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"} +[target.'cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))'.dependencies] +video-metadata = {git = "https://github.com/GuillaumeGomez/video-metadata-rs"} + [dependencies] angle = {git = "https://github.com/servo/angle", branch = "servo"} app_units = "0.2.5" @@ -35,7 +38,7 @@ heapsize_plugin = "0.1.2" html5ever = {version = "0.5.1", features = ["heap_size", "unstable"]} hyper = {version = "0.9.9", features = ["serde-serialization"]} image = "0.10" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" js = {git = "https://github.com/servo/rust-mozjs"} libc = "0.2" log = "0.3.5" @@ -46,8 +49,8 @@ net_traits = {path = "../net_traits"} num-traits = "0.1.32" offscreen_gl_context = "0.1.2" open = "1.1.1" -phf = "0.7.13" -phf_macros = "0.7.13" +phf = "0.7.16" +phf_macros = "0.7.16" plugins = {path = "../plugins"} profile_traits = {path = "../profile_traits"} rand = "0.3" @@ -59,7 +62,7 @@ rustc-serialize = "0.3" script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} selectors = {version = "0.7", features = ["heap_size"]} -serde = "0.7.11" +serde = "0.7.15" smallvec = "0.1" string_cache = {version = "0.2.20", features = ["heap_size", "unstable"]} style = {path = "../style"} diff --git a/components/script/build.rs b/components/script/build.rs index 88b1e22b953..a0d693d152f 100644 --- a/components/script/build.rs +++ b/components/script/build.rs @@ -2,12 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::env; use std::process::Command; +use std::time::Instant; fn main() { + let start = Instant::now(); + let num_jobs = env::var("NUM_JOBS").unwrap(); assert!(Command::new("make") - .args(&["-f", "makefile.cargo"]) + .args(&["-f", "makefile.cargo", "-j", &num_jobs]) .status() .unwrap() .success()); + println!("Binding generation completed in {}s", start.elapsed().as_secs()); } diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 20394bf367a..024307bc696 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -25,7 +25,6 @@ use ipc_channel::ipc::IpcSender; use js::jsapi::{JSAutoCompartment, ObjectClassName}; use js::jsval::UndefinedValue; use msg::constellation_msg::PipelineId; -use script_thread::get_browsing_context; use std::ffi::CStr; use std::str; use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left}; @@ -68,58 +67,72 @@ pub fn handle_evaluate_js(global: &GlobalRef, eval: String, reply: IpcSender<Eva reply.send(result).unwrap(); } -pub fn handle_get_root_node(context: &BrowsingContext, pipeline: PipelineId, reply: IpcSender<NodeInfo>) { - let context = get_browsing_context(context, pipeline); +pub fn handle_get_root_node(context: &BrowsingContext, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) { + let context = match context.find(pipeline) { + Some(found_context) => found_context, + None => return reply.send(None).unwrap() + }; + let document = context.active_document(); let node = document.upcast::<Node>(); - reply.send(node.summarize()).unwrap(); + reply.send(Some(node.summarize())).unwrap(); } pub fn handle_get_document_element(context: &BrowsingContext, pipeline: PipelineId, - reply: IpcSender<NodeInfo>) { - let context = get_browsing_context(context, pipeline); + reply: IpcSender<Option<NodeInfo>>) { + let context = match context.find(pipeline) { + Some(found_context) => found_context, + None => return reply.send(None).unwrap() + }; + let document = context.active_document(); let document_element = document.GetDocumentElement().unwrap(); let node = document_element.upcast::<Node>(); - reply.send(node.summarize()).unwrap(); + reply.send(Some(node.summarize())).unwrap(); } fn find_node_by_unique_id(context: &BrowsingContext, pipeline: PipelineId, - node_id: String) - -> Root<Node> { - let context = get_browsing_context(context, pipeline); + node_id: &str) + -> Option<Root<Node>> { + let context = match context.find(pipeline) { + Some(found_context) => found_context, + None => return None + }; + let document = context.active_document(); let node = document.upcast::<Node>(); - for candidate in node.traverse_preorder() { - if candidate.unique_id() == node_id { - return candidate; - } - } - - panic!("couldn't find node with unique id {}", node_id) + node.traverse_preorder().find(|candidate| candidate.unique_id() == node_id) } pub fn handle_get_children(context: &BrowsingContext, pipeline: PipelineId, node_id: String, - reply: IpcSender<Vec<NodeInfo>>) { - let parent = find_node_by_unique_id(context, pipeline, node_id); - let children = parent.children() - .map(|child| child.summarize()) - .collect(); - reply.send(children).unwrap(); + reply: IpcSender<Option<Vec<NodeInfo>>>) { + match find_node_by_unique_id(context, pipeline, &*node_id) { + None => return reply.send(None).unwrap(), + Some(parent) => { + let children = parent.children() + .map(|child| child.summarize()) + .collect(); + + reply.send(Some(children)).unwrap(); + } + }; } pub fn handle_get_layout(context: &BrowsingContext, pipeline: PipelineId, node_id: String, - reply: IpcSender<ComputedNodeLayout>) { - let node = find_node_by_unique_id(context, pipeline, node_id); + reply: IpcSender<Option<ComputedNodeLayout>>) { + let node = match find_node_by_unique_id(context, pipeline, &*node_id) { + None => return reply.send(None).unwrap(), + Some(found_node) => found_node + }; let elem = node.downcast::<Element>().expect("should be getting layout of element"); let rect = elem.GetBoundingClientRect(); @@ -130,7 +143,7 @@ pub fn handle_get_layout(context: &BrowsingContext, let elem = node.downcast::<Element>().expect("should be getting layout of element"); let computed_style = window.r().GetComputedStyle(elem, None); - reply.send(ComputedNodeLayout { + reply.send(Some(ComputedNodeLayout { display: String::from(computed_style.Display()), position: String::from(computed_style.Position()), zIndex: String::from(computed_style.ZIndex()), @@ -150,7 +163,7 @@ pub fn handle_get_layout(context: &BrowsingContext, paddingLeft: String::from(computed_style.PaddingLeft()), width: width, height: height, - }).unwrap(); + })).unwrap(); } fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins { @@ -209,7 +222,11 @@ pub fn handle_modify_attribute(context: &BrowsingContext, pipeline: PipelineId, node_id: String, modifications: Vec<Modification>) { - let node = find_node_by_unique_id(context, pipeline, node_id); + let node = match find_node_by_unique_id(context, pipeline, &*node_id) { + None => return warn!("node id {} for pipeline id {} is not found", &node_id, &pipeline), + Some(found_node) => found_node + }; + let elem = node.downcast::<Element>().expect("should be getting layout of element"); for modification in modifications { @@ -243,7 +260,11 @@ pub fn handle_drop_timeline_markers(context: &BrowsingContext, pub fn handle_request_animation_frame(context: &BrowsingContext, id: PipelineId, actor_name: String) { - let context = context.find(id).expect("There is no such context"); + let context = match context.find(id) { + None => return warn!("context for pipeline id {} is not found", id), + Some(found_node) => found_node + }; + let doc = context.active_document(); let devtools_sender = context.active_window().devtools_chan().unwrap(); doc.request_animation_frame(box move |time| { @@ -254,7 +275,11 @@ pub fn handle_request_animation_frame(context: &BrowsingContext, pub fn handle_reload(context: &BrowsingContext, id: PipelineId) { - let context = context.find(id).expect("There is no such context"); + let context = match context.find(id) { + None => return warn!("context for pipeline id {} is not found", id), + Some(found_node) => found_node + }; + let win = context.active_window(); let location = win.Location(); location.Reload(); diff --git a/components/script/dom/abstractworker.rs b/components/script/dom/abstractworker.rs index 4f2f029800b..28c755d4f03 100644 --- a/components/script/dom/abstractworker.rs +++ b/components/script/dom/abstractworker.rs @@ -15,7 +15,7 @@ pub enum WorkerScriptMsg { /// Common variants associated with the script messages Common(CommonScriptMsg), /// Message sent through Worker.postMessage - DOMMessage(StructuredCloneData), + DOMMessage(StructuredCloneData) } pub struct SimpleWorkerErrorHandler<T: Reflectable> { diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8360dfc322a..2e0dc2415dd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1872,56 +1872,31 @@ class CGDOMJSClass(CGThing): elif self.descriptor.weakReferenceable: args["slots"] = "2" return """\ +static CLASS_OPS: js::jsapi::ClassOps = js::jsapi::ClassOps { + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: %(enumerateHook)s, + resolve: %(resolveHook)s, + mayResolve: None, + finalize: Some(%(finalizeHook)s), + call: None, + hasInstance: None, + construct: None, + trace: Some(%(traceHook)s), +}; + static Class: DOMJSClass = DOMJSClass { base: js::jsapi::Class { name: %(name)s as *const u8 as *const libc::c_char, flags: JSCLASS_IS_DOMJSCLASS | %(flags)s | (((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) /* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: %(enumerateHook)s, - resolve: %(resolveHook)s, - mayResolve: None, - finalize: Some(%(finalizeHook)s), - call: None, - hasInstance: None, - construct: None, - trace: Some(%(traceHook)s), - - spec: js::jsapi::ClassSpec { - createConstructor_: None, - createPrototype_: None, - constructorFunctions_: 0 as *const js::jsapi::JSFunctionSpec, - constructorProperties_: 0 as *const js::jsapi::JSPropertySpec, - prototypeFunctions_: 0 as *const js::jsapi::JSFunctionSpec, - prototypeProperties_: 0 as *const js::jsapi::JSPropertySpec, - finishInit_: None, - flags: 0, - }, - - ext: js::jsapi::ClassExtension { - isWrappedNative: false, - weakmapKeyDelegateOp: None, - objectMovedOp: None, - }, - - ops: js::jsapi::ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - watch: None, - unwatch: None, - getElements: None, - enumerate: None, - funToString: None, - }, + cOps: &CLASS_OPS, + spec: ptr::null(), + ext: ptr::null(), + oOps: ptr::null(), }, dom_class: %(domClass)s };""" % args @@ -1947,19 +1922,8 @@ static PrototypeClass: JSClass = JSClass { flags: // JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s) (%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: None, - hasInstance: None, - construct: None, - trace: None, - reserved: [0 as *mut os::raw::c_void; 23] + cOps: 0 as *const _, + reserved: [0 as *mut os::raw::c_void; 3] }; """ % {'name': name, 'slotCount': slotCount} @@ -1983,9 +1947,12 @@ class CGInterfaceObjectJSClass(CGThing): "depth": self.descriptor.prototypeDepth } return """\ +static INTERFACE_OBJECT_OPS: js::jsapi::ClassOps = + NonCallbackInterfaceObjectClass::ops(%(constructorBehavior)s); + static InterfaceObjectClass: NonCallbackInterfaceObjectClass = NonCallbackInterfaceObjectClass::new( - %(constructorBehavior)s, + &INTERFACE_OBJECT_OPS, %(representation)s, PrototypeList::ID::%(id)s, %(depth)s); @@ -2772,6 +2739,7 @@ let traps = ProxyTraps { ownPropertyKeys: Some(own_property_keys), delete_: Some(%(delete)s), enumerate: None, + getPrototypeIfOrdinary: Some(proxyhandler::get_prototype_if_ordinary), preventExtensions: Some(proxyhandler::prevent_extensions), isExtensible: Some(proxyhandler::is_extensible), has: None, diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index d0074335c23..c4bda97e521 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -4,15 +4,26 @@ //! Utilities to throw exceptions from Rust bindings. +use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; -use dom::bindings::conversions::ToJSValConvertible; +use dom::bindings::conversions::root_from_object; +use dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}; use dom::bindings::global::GlobalRef; +use dom::bindings::str::USVString; use dom::domexception::{DOMErrorName, DOMException}; use js::error::{throw_range_error, throw_type_error}; +use js::jsapi::HandleObject; use js::jsapi::JSAutoCompartment; -use js::jsapi::{JSContext, JSObject}; -use js::jsapi::{JS_IsExceptionPending, JS_ReportPendingException, JS_SetPendingException}; +use js::jsapi::JSContext; +use js::jsapi::JSObject; +use js::jsapi::JS_ClearPendingException; +use js::jsapi::JS_ErrorFromException; +use js::jsapi::JS_GetPendingException; +use js::jsapi::JS_IsExceptionPending; +use js::jsapi::JS_SetPendingException; use js::jsval::UndefinedValue; +use libc::c_uint; +use std::slice::from_raw_parts; /// DOM exceptions that can be thrown by a native DOM method. #[derive(Debug, Clone, HeapSizeOf)] @@ -123,11 +134,101 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, result: JS_SetPendingException(cx, thrown.handle()); } +struct ErrorInfo { + filename: String, + message: String, + lineno: c_uint, + column: c_uint, +} + +impl ErrorInfo { + unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) + -> Option<ErrorInfo> { + let report = JS_ErrorFromException(cx, object); + if report.is_null() { + return None; + } + + let filename = { + let filename = (*report).filename as *const u8; + if !filename.is_null() { + let length = (0..).find(|idx| *filename.offset(*idx) == 0).unwrap(); + let filename = from_raw_parts(filename, length as usize); + String::from_utf8_lossy(filename).into_owned() + } else { + "none".to_string() + } + }; + + let lineno = (*report).lineno; + let column = (*report).column; + + let message = { + let message = (*report).ucmessage; + let length = (0..).find(|idx| *message.offset(*idx) == 0).unwrap(); + let message = from_raw_parts(message, length as usize); + String::from_utf16_lossy(message) + }; + + Some(ErrorInfo { + filename: filename, + message: message, + lineno: lineno, + column: column, + }) + } + + fn from_dom_exception(object: HandleObject) -> Option<ErrorInfo> { + let exception = match root_from_object::<DOMException>(object.get()) { + Ok(exception) => exception, + Err(_) => return None, + }; + + Some(ErrorInfo { + filename: "".to_string(), + message: exception.Stringifier().into(), + lineno: 0, + column: 0, + }) + } +} + /// Report a pending exception, thereby clearing it. pub unsafe fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { if JS_IsExceptionPending(cx) { let _ac = JSAutoCompartment::new(cx, obj); - JS_ReportPendingException(cx); + rooted!(in(cx) let mut value = UndefinedValue()); + if !JS_GetPendingException(cx, value.handle_mut()) { + JS_ClearPendingException(cx); + error!("Uncaught exception: JS_GetPendingException failed"); + return; + } + + JS_ClearPendingException(cx); + if !value.is_object() { + match USVString::from_jsval(cx, value.handle(), ()) { + Ok(USVString(string)) => error!("Uncaught exception: {}", string), + Err(_) => error!("Uncaught exception: failed to stringify primitive"), + } + return; + } + + rooted!(in(cx) let object = value.to_object()); + let error_info = ErrorInfo::from_native_error(cx, object.handle()) + .or_else(|| ErrorInfo::from_dom_exception(object.handle())); + let error_info = match error_info { + Some(error_info) => error_info, + None => { + error!("Uncaught exception: failed to extract information"); + return; + } + }; + + error!("Error at {}:{}:{} {}", + error_info.filename, + error_info.lineno, + error_info.column, + error_info.message); } } diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index fe81b8a14de..bfc3212a9c4 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -19,7 +19,6 @@ use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment}; use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue}; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; use msg::constellation_msg::PipelineId; -use net_traits::filemanager_thread::FileManagerThreadMsg; use net_traits::{ResourceThreads, CoreResourceThread, IpcSend}; use profile_traits::{mem, time}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; @@ -133,11 +132,6 @@ impl<'a> GlobalRef<'a> { self.resource_threads().sender() } - /// Get the port to file manager for this global scope - pub fn filemanager_thread(&self) -> IpcSender<FileManagerThreadMsg> { - self.resource_threads().sender() - } - /// Get the worker's id. pub fn get_worker_id(&self) -> Option<WorkerId> { match *self { diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 4e2c630a453..3b2b5dbde36 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -11,7 +11,7 @@ use dom::bindings::guard::Guard; use dom::bindings::utils::get_proto_or_iface_array; use js::error::throw_type_error; use js::glue::{RUST_SYMBOL_TO_JSID, UncheckedUnwrapObject}; -use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment}; +use js::jsapi::{Class, ClassOps, GetGlobalForObjectCrossCompartment}; use js::jsapi::{GetWellKnownSymbol, HandleObject, HandleValue, JSClass, JSContext}; use js::jsapi::{JSFunctionSpec, JSNative, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE}; use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING, JSPropertySpec}; @@ -101,6 +101,21 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext, ret } +const OBJECT_OPS: ObjectOps = ObjectOps { + lookupProperty: None, + defineProperty: None, + hasProperty: None, + getProperty: None, + setProperty: None, + getOwnPropertyDescriptor: None, + deleteProperty: None, + watch: None, + unwatch: None, + getElements: None, + enumerate: None, + funToString: Some(fun_to_string_hook), +}; + /// The class of a non-callback interface object. #[derive(Copy, Clone)] pub struct NonCallbackInterfaceObjectClass { @@ -117,58 +132,39 @@ pub struct NonCallbackInterfaceObjectClass { unsafe impl Sync for NonCallbackInterfaceObjectClass {} impl NonCallbackInterfaceObjectClass { + /// Create `ClassOps` for a `NonCallbackInterfaceObjectClass`. + pub const fn ops(constructor_behavior: InterfaceConstructorBehavior) + -> ClassOps { + ClassOps { + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: None, + resolve: None, + mayResolve: None, + finalize: None, + call: constructor_behavior.call, + construct: constructor_behavior.construct, + hasInstance: Some(has_instance_hook), + trace: None, + } + } + /// Create a new `NonCallbackInterfaceObjectClass` structure. - pub const fn new( - constructor_behavior: InterfaceConstructorBehavior, - string_rep: &'static [u8], - proto_id: PrototypeList::ID, - proto_depth: u16) - -> NonCallbackInterfaceObjectClass { + pub const fn new(ops: &'static ClassOps, + string_rep: &'static [u8], + proto_id: PrototypeList::ID, + proto_depth: u16) + -> NonCallbackInterfaceObjectClass { NonCallbackInterfaceObjectClass { class: Class { name: b"Function\0" as *const _ as *const libc::c_char, flags: 0, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: constructor_behavior.call, - construct: constructor_behavior.construct, - hasInstance: Some(has_instance_hook), - trace: None, - spec: ClassSpec { - createConstructor_: None, - createPrototype_: None, - constructorFunctions_: ptr::null(), - constructorProperties_: ptr::null(), - prototypeFunctions_: ptr::null(), - prototypeProperties_: ptr::null(), - finishInit_: None, - flags: 0, - }, - ext: ClassExtension { - isWrappedNative: false, - weakmapKeyDelegateOp: None, - objectMovedOp: None, - }, - ops: ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - watch: None, - unwatch: None, - getElements: None, - enumerate: None, - funToString: Some(fun_to_string_hook), - } + cOps: ops, + spec: ptr::null(), + ext: ptr::null(), + oOps: &OBJECT_OPS, }, proto_id: proto_id, proto_depth: proto_depth, diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 9db30d8835c..c863cc31994 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -12,7 +12,9 @@ use js::glue::GetProxyExtra; use js::glue::InvokeGetOwnPropertyDescriptor; use js::glue::{GetProxyHandler, SetProxyExtra}; use js::jsapi::GetObjectProto; +use js::jsapi::GetStaticPrototype; use js::jsapi::JS_GetPropertyDescriptorById; +use js::jsapi::MutableHandleObject; use js::jsapi::{Handle, HandleId, HandleObject, MutableHandle, ObjectOpResult}; use js::jsapi::{JSContext, JSObject, JSPROP_GETTER, PropertyDescriptor}; use js::jsapi::{JSErrNum, JS_StrictPropertyStub}; @@ -103,6 +105,25 @@ pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext, true } +/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as +/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior +/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s +/// prototype in `proto`. Otherwise set `*isOrdinary` to false. In case of +/// error, both outparams have unspecified value. +/// +/// This implementation always handles the case of the ordinary +/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be +/// necessary for the Location object. +pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, + proxy: HandleObject, + is_ordinary: *mut bool, + proto: MutableHandleObject) + -> bool { + *is_ordinary = true; + proto.set(GetStaticPrototype(proxy.get())); + true +} + /// Get the expando object, or null if there is none. pub fn get_expando_object(obj: HandleObject) -> *mut JSObject { unsafe { diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 3c13572bf37..618061fe769 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -91,6 +91,7 @@ use style::element_state::*; use style::properties::PropertyDeclarationBlock; use style::selector_impl::{PseudoElement, ElementSnapshot}; use style::values::specified::Length; +use time::Duration; use url::Origin as UrlOrigin; use url::Url; use uuid::Uuid; @@ -109,6 +110,8 @@ no_jsmanaged_fields!(EncodingRef); no_jsmanaged_fields!(Reflector); +no_jsmanaged_fields!(Duration); + /// Trace a `JSVal`. pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) { unsafe { diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index f63e66e3b7b..4711da80010 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -14,18 +14,20 @@ use dom::bindings::str::DOMString; use encoding::all::UTF_8; use encoding::types::{EncoderTrap, Encoding}; use ipc_channel::ipc; -use net_traits::IpcSend; use net_traits::blob_url_store::{BlobBuf, get_blob_origin}; -use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos}; +use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos, ReadFileProgress}; +use net_traits::{CoreResourceMsg, IpcSend}; use std::cell::Cell; +use std::mem; use std::ops::Index; use std::path::PathBuf; +use uuid::Uuid; /// File-based blob #[derive(JSTraceable)] pub struct FileBlob { id: SelectedFileId, - name: PathBuf, + name: Option<PathBuf>, cache: DOMRefCell<Option<Vec<u8>>>, size: u64, } @@ -56,7 +58,7 @@ impl BlobImpl { pub fn new_from_file(file_id: SelectedFileId, name: PathBuf, size: u64) -> BlobImpl { BlobImpl::File(FileBlob { id: file_id, - name: name, + name: Some(name), cache: DOMRefCell::new(None), size: size, }) @@ -97,9 +99,7 @@ impl Blob { relativeContentType: DOMString) -> Root<Blob> { let global = parent.global(); let blob_impl = match *parent.blob_impl.borrow() { - BlobImpl::File(ref f) => { - inc_ref_id(global.r(), f.id.clone()); - + BlobImpl::File(_) => { // Create new parent node BlobImpl::Sliced(JS::from_ref(parent), rel_pos) } @@ -109,13 +109,7 @@ impl Blob { } BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => { // Adjust the slicing position, using same parent - let new_rel_pos = old_rel_pos.slice_inner(&rel_pos); - - if let BlobImpl::File(ref f) = *grandparent.blob_impl.borrow() { - inc_ref_id(global.r(), f.id.clone()); - } - - BlobImpl::Sliced(grandparent.clone(), new_rel_pos) + BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos)) } }; @@ -172,85 +166,116 @@ impl Blob { /// Get a FileID representing the Blob content, /// used by URL.createObjectURL pub fn get_blob_url_id(&self) -> SelectedFileId { - match *self.blob_impl.borrow() { - BlobImpl::File(ref f) => { - let global = self.global(); - let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); - let (tx, rx) = ipc::channel().unwrap(); - - let _ = filemanager.send(FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone())); - - match rx.recv().unwrap() { - Ok(_) => f.id.clone(), - Err(_) => SelectedFileId("".to_string()) // Return a dummy id on error - } - } - BlobImpl::Memory(ref slice) => { - self.promote(slice, true) - } + let opt_sliced_parent = match *self.blob_impl.borrow() { BlobImpl::Sliced(ref parent, ref rel_pos) => { - match *parent.blob_impl.borrow() { - BlobImpl::Sliced(_, _) => { - debug!("Sliced can't have a sliced parent"); - // Return dummy id - SelectedFileId("".to_string()) - } - BlobImpl::File(ref f) => - self.create_sliced_url_id(&f.id, rel_pos), - BlobImpl::Memory(ref bytes) => { - let parent_id = parent.promote(bytes, false); - *self.blob_impl.borrow_mut() = BlobImpl::Sliced(parent.clone(), rel_pos.clone()); - self.create_sliced_url_id(&parent_id, rel_pos) - } - } + Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size())) } + _ => None + }; + + match opt_sliced_parent { + Some((parent_id, rel_pos, size)) => self.create_sliced_url_id(&parent_id, &rel_pos, size), + None => self.promote(/* set_valid is */ true), } } - /// Promite memory-based Blob to file-based, - /// The bytes in data slice will be transferred to file manager thread. + /// Promote non-Slice blob: + /// 1. Memory-based: The bytes in data slice will be transferred to file manager thread. + /// 2. File-based: Activation /// Depending on set_valid, the returned FileID can be part of /// valid or invalid Blob URL. - fn promote(&self, bytes: &[u8], set_valid: bool) -> SelectedFileId { + fn promote(&self, set_valid: bool) -> SelectedFileId { + let mut bytes = vec![]; + + match *self.blob_impl.borrow_mut() { + BlobImpl::Sliced(_, _) => { + debug!("Sliced can't have a sliced parent"); + // Return dummy id + return SelectedFileId(Uuid::new_v4().simple().to_string()); + } + BlobImpl::File(ref f) => { + if set_valid { + let global = self.global(); + let origin = get_blob_origin(&global.r().get_url()); + let (tx, rx) = ipc::channel().unwrap(); + + let msg = FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone()); + self.send_to_file_manager(msg); + + match rx.recv().unwrap() { + Ok(_) => return f.id.clone(), + // Return a dummy id on error + Err(_) => return SelectedFileId(Uuid::new_v4().simple().to_string()) + } + } else { + // no need to activate + return f.id.clone(); + } + } + BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes), + }; + let global = self.global(); let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); let blob_buf = BlobBuf { filename: None, type_string: self.typeString.clone(), - size: self.Size(), + size: bytes.len() as u64, bytes: bytes.to_vec(), }; let (tx, rx) = ipc::channel().unwrap(); - let _ = filemanager.send(FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone())); + let msg = FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone()); + self.send_to_file_manager(msg); match rx.recv().unwrap() { - Ok(new_id) => SelectedFileId(new_id.0), + Ok(id) => { + let id = SelectedFileId(id.0); + *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob { + id: id.clone(), + name: None, + cache: DOMRefCell::new(Some(bytes.to_vec())), + size: bytes.len() as u64, + }); + id + } // Dummy id - Err(_) => SelectedFileId("".to_string()), + Err(_) => SelectedFileId(Uuid::new_v4().simple().to_string()), } } /// Get a FileID representing sliced parent-blob content fn create_sliced_url_id(&self, parent_id: &SelectedFileId, - rel_pos: &RelativePos) -> SelectedFileId { + rel_pos: &RelativePos, parent_len: u64) -> SelectedFileId { let global = self.global(); let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); let msg = FileManagerThreadMsg::AddSlicedURLEntry(parent_id.clone(), rel_pos.clone(), tx, origin.clone()); - let _ = filemanager.send(msg); - let new_id = rx.recv().unwrap().unwrap(); - - // Return the indirect id reference - SelectedFileId(new_id.0) + self.send_to_file_manager(msg); + match rx.recv().expect("File manager thread is down") { + Ok(new_id) => { + let new_id = SelectedFileId(new_id.0); + + *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob { + id: new_id.clone(), + name: None, + cache: DOMRefCell::new(None), + size: rel_pos.to_abs_range(parent_len as usize).len() as u64, + }); + + // Return the indirect id reference + new_id + } + Err(_) => { + // Return dummy id + SelectedFileId(Uuid::new_v4().simple().to_string()) + } + } } /// Cleanups at the time of destruction/closing @@ -259,14 +284,19 @@ impl Blob { let global = self.global(); let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); let msg = FileManagerThreadMsg::DecRef(f.id.clone(), origin, tx); - let _ = filemanager.send(msg); + self.send_to_file_manager(msg); let _ = rx.recv().unwrap(); } } + + fn send_to_file_manager(&self, msg: FileManagerThreadMsg) { + let global = self.global(); + let resource_threads = global.r().resource_threads(); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)); + } } impl Drop for Blob { @@ -278,16 +308,28 @@ impl Drop for Blob { } fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<Vec<u8>, ()> { - let file_manager = global.filemanager_thread(); + let resource_threads = global.resource_threads(); let (chan, recv) = ipc::channel().map_err(|_|())?; let origin = get_blob_origin(&global.get_url()); let check_url_validity = false; let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin); - let _ = file_manager.send(msg); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)); + + let mut bytes = vec![]; - match recv.recv().unwrap() { - Ok(blob_buf) => Ok(blob_buf.bytes), - Err(_) => Err(()), + loop { + match recv.recv().unwrap() { + Ok(ReadFileProgress::Meta(mut blob_buf)) => { + bytes.append(&mut blob_buf.bytes); + } + Ok(ReadFileProgress::Partial(mut bytes_in)) => { + bytes.append(&mut bytes_in); + } + Ok(ReadFileProgress::EOF) => { + return Ok(bytes); + } + Err(_) => return Err(()), + } } } @@ -379,11 +421,3 @@ fn is_ascii_printable(string: &str) -> bool { // https://w3c.github.io/FileAPI/#constructorBlob string.chars().all(|c| c >= '\x20' && c <= '\x7E') } - -/// Bump the reference counter in file manager thread -fn inc_ref_id(global: GlobalRef, id: SelectedFileId) { - let file_manager = global.filemanager_thread(); - let origin = get_blob_origin(&global.get_url()); - let msg = FileManagerThreadMsg::IncRef(id, origin); - let _ = file_manager.send(msg); -} diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 7deca26c9d3..c86fa0150a3 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -7,7 +7,7 @@ use core::clone::Clone; use dom::bindings::codegen::Bindings::BluetoothBinding; use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions; use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothScanFilter, BluetoothMethods}; -use dom::bindings::error::Error::{Security, Type}; +use dom::bindings::error::Error::{self, Security, Type}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; @@ -19,7 +19,7 @@ use dom::bluetoothuuid::BluetoothUUID; use ipc_channel::ipc::{self, IpcSender}; use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence}; use net_traits::bluetooth_scanfilter::{RequestDeviceoptions, ServiceUUIDSequence}; -use net_traits::bluetooth_thread::BluetoothMethodMsg; +use net_traits::bluetooth_thread::{BluetoothError, BluetoothMethodMsg}; const FILTER_EMPTY_ERROR: &'static str = "'filters' member must be non - empty to find any devices."; const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way."; @@ -135,6 +135,18 @@ fn convert_request_device_options(options: &RequestDeviceOptions, ServiceUUIDSequence::new(optional_services))) } +impl From<BluetoothError> for Error { + fn from(error: BluetoothError) -> Self { + match error { + BluetoothError::Type(message) => Error::Type(message), + BluetoothError::Network => Error::Network, + BluetoothError::NotFound => Error::NotFound, + BluetoothError::NotSupported => Error::NotSupported, + BluetoothError::Security => Error::Security, + } + } +} + impl BluetoothMethods for Bluetooth { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> { @@ -154,7 +166,7 @@ impl BluetoothMethods for Bluetooth { &ad_data)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs index e3e17b4a0f9..0c27097625c 100644 --- a/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding:: BluetoothRemoteGATTCharacteristicMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; -use dom::bindings::error::Error::{InvalidModification, Network, NotSupported, Security, Type}; +use dom::bindings::error::Error::{self, InvalidModification, Network, NotSupported, Security}; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -115,7 +115,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris descriptor.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -147,7 +147,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris .collect()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -177,7 +177,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris ByteString::new(val) }, Err(error) => { - return Err(Type(error)) + return Err(Error::from(error)) }, }; *self.value.borrow_mut() = Some(value.clone()); @@ -195,6 +195,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris if !self.Service().Device().Gatt().Connected() { return Err(Network) } + + if !(self.Properties().Write() || + self.Properties().WriteWithoutResponse() || + self.Properties().AuthenticatedSignedWrites()) { + return Err(NotSupported) + } let (sender, receiver) = ipc::channel().unwrap(); self.get_bluetooth_thread().send( BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap(); @@ -202,7 +208,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris match result { Ok(_) => Ok(()), Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetoothremotegattdescriptor.rs index f821d4aca2d..0ba52181b48 100644 --- a/components/script/dom/bluetoothremotegattdescriptor.rs +++ b/components/script/dom/bluetoothremotegattdescriptor.rs @@ -11,7 +11,7 @@ use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; -use dom::bindings::error::Error::{InvalidModification, Network, Security, Type}; +use dom::bindings::error::Error::{self, InvalidModification, Network, Security}; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -101,7 +101,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { ByteString::new(val) }, Err(error) => { - return Err(Type(error)) + return Err(Error::from(error)) }, }; *self.value.borrow_mut() = Some(value.clone()); @@ -126,7 +126,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { match result { Ok(_) => Ok(()), Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs index 56aad1b8bf6..f4b1e532f10 100644 --- a/components/script/dom/bluetoothremotegattserver.rs +++ b/components/script/dom/bluetoothremotegattserver.rs @@ -6,7 +6,7 @@ use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted}; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; -use dom::bindings::error::Error::{Security, Type}; +use dom::bindings::error::Error::{self, Security}; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -72,7 +72,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { Ok(Root::from_ref(self)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -89,7 +89,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { Ok(()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -113,7 +113,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { service.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -146,7 +146,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { .collect()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs index f0954a1c76f..5b80bc6afc0 100644 --- a/components/script/dom/bluetoothremotegattservice.rs +++ b/components/script/dom/bluetoothremotegattservice.rs @@ -5,7 +5,7 @@ use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted}; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; -use dom::bindings::error::Error::{Security, Type}; +use dom::bindings::error::Error::{self, Security}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -115,7 +115,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { characteristic.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -160,7 +160,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { Ok(characteristics) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -188,7 +188,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { service.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -223,7 +223,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { .collect()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs index 4c0914ddf3c..878d376ca66 100644 --- a/components/script/dom/browsingcontext.rs +++ b/components/script/dom/browsingcontext.rs @@ -22,7 +22,7 @@ use js::jsapi::{Handle, HandleId, HandleObject, HandleValue, JSAutoCompartment}; use js::jsapi::{JSContext, JSPROP_READONLY, JSErrNum, JSObject, PropertyDescriptor, JS_DefinePropertyById}; use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass, JSTracer, FreeOp}; use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle}; -use js::jsapi::{MutableHandleValue, ObjectOpResult}; +use js::jsapi::{MutableHandleObject, MutableHandleValue, ObjectOpResult}; use js::jsval::{UndefinedValue, PrivateValue}; use msg::constellation_msg::{PipelineId, SubpageId}; use std::cell::Cell; @@ -354,6 +354,28 @@ unsafe extern "C" fn set(cx: *mut JSContext, res) } +#[allow(unsafe_code)] +unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, + _: HandleObject, + is_ordinary: *mut bool, + _: MutableHandleObject) + -> bool { + // Window's [[GetPrototypeOf]] trap isn't the ordinary definition: + // + // https://html.spec.whatwg.org/multipage/#windowproxy-getprototypeof + // + // We nonetheless can implement it with a static [[Prototype]], because + // wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply + // all non-ordinary behavior. + // + // But from a spec point of view, it's the exact same object in both cases -- + // only the observer's changed. So this getPrototypeIfOrdinary trap on the + // non-wrapper object *must* report non-ordinary, even if static [[Prototype]] + // usually means ordinary. + *is_ordinary = false; + return true; +} + static PROXY_HANDLER: ProxyTraps = ProxyTraps { enter: None, getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor), @@ -361,6 +383,7 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps { ownPropertyKeys: None, delete_: None, enumerate: None, + getPrototypeIfOrdinary: Some(get_prototype_if_ordinary), preventExtensions: None, isExtensible: None, has: Some(has), diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index b65fd72ab62..dfe385f0696 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -218,7 +218,7 @@ impl DedicatedWorkerGlobalScope { scope.execute_script(DOMString::from(source)); } - let reporter_name = format!("worker-reporter-{}", random::<u64>()); + let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>()); scope.mem_profiler_chan().run_with_memory_reporting(|| { while let Ok(event) = global.receive_event() { if scope.is_closing() { @@ -307,7 +307,7 @@ impl DedicatedWorkerGlobalScope { let path_seg = format!("url({})", scope.get_url()); let reports = get_reports(cx, path_seg); reports_chan.send(reports); - }, + } } } @@ -370,6 +370,12 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope { Ok(()) } + // https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-close + fn Close(&self) { + // Step 2 + self.upcast::<WorkerGlobalScope>().close(); + } + // https://html.spec.whatwg.org/multipage/#handler-dedicatedworkerglobalscope-onmessage event_handler!(message, GetOnmessage, SetOnmessage); } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 28edce553ad..78ccbbdf1f5 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -376,6 +376,7 @@ impl Document { // that workable. match self.GetDocumentElement() { Some(root) => { + root.upcast::<Node>().is_dirty() || root.upcast::<Node>().has_dirty_descendants() || !self.modified_elements.borrow().is_empty() } @@ -1371,6 +1372,7 @@ impl Document { } pub fn finish_load(&self, load: LoadType) { + debug!("Document got finish_load: {:?}", load); // The parser might need the loader, so restrict the lifetime of the borrow. { let mut loader = self.loader.borrow_mut(); @@ -1396,9 +1398,9 @@ impl Document { // If we don't have a parser, and the reflow timer has been reset, explicitly // trigger a reflow. if let LoadType::Stylesheet(_) = load { - self.window().reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::StylesheetLoaded); + self.window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::StylesheetLoaded); } } @@ -1487,24 +1489,25 @@ impl Document { return; } self.domcontentloaded_dispatched.set(true); + assert!(self.ReadyState() != DocumentReadyState::Complete, + "Complete before DOMContentLoaded?"); update_with_current_time_ms(&self.dom_content_loaded_event_start); let window = self.window(); window.dom_manipulation_task_source().queue_event(self.upcast(), atom!("DOMContentLoaded"), EventBubbles::Bubbles, EventCancelable::NotCancelable, window); + window.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DOMContentLoaded); - update_with_current_time_ms(&self.dom_content_loaded_event_end); } pub fn notify_constellation_load(&self) { let pipeline_id = self.window.pipeline(); - let event = ConstellationMsg::DOMLoad(pipeline_id); - self.window.constellation_chan().send(event).unwrap(); - + let load_event = ConstellationMsg::LoadComplete(pipeline_id); + self.window.constellation_chan().send(load_event).unwrap(); } pub fn set_current_parser(&self, script: Option<ParserRef>) { @@ -2908,16 +2911,18 @@ impl DocumentProgressHandler { // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart update_with_current_time_ms(&document.load_event_start); + debug!("About to dispatch load for {:?}", document.url()); let _ = wintarget.dispatch_event_with_target(document.upcast(), &event); // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd update_with_current_time_ms(&document.load_event_end); - document.notify_constellation_load(); window.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DocumentLoaded); + + document.notify_constellation_load(); } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index a4c1ed28583..ae3c31d151c 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -347,7 +347,8 @@ impl LayoutElementHelpers for LayoutJS<Element> { if let Some(url) = background { hints.push(from_declaration( PropertyDeclaration::BackgroundImage(DeclaredValue::Value( - background_image::SpecifiedValue(Some(specified::Image::Url(url))))))); + background_image::SpecifiedValue(Some( + specified::Image::Url(url, specified::UrlExtraData { }))))))); } let color = if let Some(this) = self.downcast::<HTMLFontElement>() { diff --git a/components/script/dom/file.rs b/components/script/dom/file.rs index 4528a116e45..f9b181dbf1a 100644 --- a/components/script/dom/file.rs +++ b/components/script/dom/file.rs @@ -73,7 +73,10 @@ impl File { let ref typeString = blobPropertyBag.type_; let modified = filePropertyBag.lastModified; - Ok(File::new(global, BlobImpl::new_from_bytes(bytes), filename, modified, typeString)) + // NOTE: Following behaviour might be removed in future, + // see https://github.com/w3c/FileAPI/issues/41 + let replaced_filename = DOMString::from_string(filename.replace("/", ":")); + Ok(File::new(global, BlobImpl::new_from_bytes(bytes), replaced_filename, modified, typeString)) } pub fn name(&self) -> &DOMString { diff --git a/components/script/dom/filelist.rs b/components/script/dom/filelist.rs index 96bfc4ce0d3..4f8e976f5f7 100644 --- a/components/script/dom/filelist.rs +++ b/components/script/dom/filelist.rs @@ -9,6 +9,7 @@ use dom::bindings::js::{JS, Root}; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::file::File; use dom::window::Window; +use std::slice::Iter; // https://w3c.github.io/FileAPI/#dfn-filelist #[dom_struct] @@ -32,6 +33,10 @@ impl FileList { GlobalRef::Window(window), FileListBinding::Wrap) } + + pub fn iter_files(&self) -> Iter<JS<File>> { + self.list.iter() + } } impl FileListMethods for FileList { diff --git a/components/script/dom/filereadersync.rs b/components/script/dom/filereadersync.rs new file mode 100644 index 00000000000..b248848edad --- /dev/null +++ b/components/script/dom/filereadersync.rs @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::FileReaderSyncBinding; +use dom::bindings::error::Fallible; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::Root; +use dom::bindings::reflector::reflect_dom_object; +use dom::eventtarget::EventTarget; + + + +#[dom_struct] +pub struct FileReaderSync { + eventtarget: EventTarget +} + +impl FileReaderSync { + pub fn new_inherited() -> FileReaderSync { + FileReaderSync { + eventtarget: EventTarget::new_inherited(), + } + } + + pub fn new(global: GlobalRef) -> Root<FileReaderSync> { + reflect_dom_object(box FileReaderSync::new_inherited(), + global, FileReaderSyncBinding::Wrap) + } + + pub fn Constructor(global: GlobalRef) -> Fallible<Root<FileReaderSync>> { + Ok(FileReaderSync::new(global)) + } +} diff --git a/components/script/dom/headers.rs b/components/script/dom/headers.rs index e97edc00572..4ae212aee78 100644 --- a/components/script/dom/headers.rs +++ b/components/script/dom/headers.rs @@ -5,12 +5,13 @@ use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HeadersBinding; use dom::bindings::codegen::Bindings::HeadersBinding::HeadersMethods; -use dom::bindings::error::Error; +use dom::bindings::codegen::UnionTypes::HeadersOrByteStringSequenceSequence; +use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, is_token}; -use hyper; +use hyper::header::Headers as HyperHeaders; use std::result::Result; #[dom_struct] @@ -18,7 +19,7 @@ pub struct Headers { reflector_: Reflector, guard: Guard, #[ignore_heap_size_of = "Defined in hyper"] - header_list: DOMRefCell<hyper::header::Headers> + header_list: DOMRefCell<HyperHeaders> } // https://fetch.spec.whatwg.org/#concept-headers-guard @@ -36,12 +37,50 @@ impl Headers { Headers { reflector_: Reflector::new(), guard: Guard::None, - header_list: DOMRefCell::new(hyper::header::Headers::new()), + header_list: DOMRefCell::new(HyperHeaders::new()), } } - pub fn new(global: GlobalRef) -> Root<Headers> { - reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap) + // https://fetch.spec.whatwg.org/#concept-headers-fill + pub fn new(global: GlobalRef, init: Option<HeadersBinding::HeadersInit>) + -> Fallible<Root<Headers>> { + let dom_headers_new = reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap); + match init { + // Step 1 + Some(HeadersOrByteStringSequenceSequence::Headers(h)) => { + // header_list_copy has type hyper::header::Headers + let header_list_copy = h.header_list.clone(); + for header in header_list_copy.borrow().iter() { + try!(dom_headers_new.Append( + ByteString::new(Vec::from(header.name())), + ByteString::new(Vec::from(header.value_string().into_bytes())) + )); + } + Ok(dom_headers_new) + }, + // Step 2 + Some(HeadersOrByteStringSequenceSequence::ByteStringSequenceSequence(v)) => { + for mut seq in v { + if seq.len() == 2 { + let val = seq.pop().unwrap(); + let name = seq.pop().unwrap(); + try!(dom_headers_new.Append(name, val)); + } else { + return Err(Error::Type( + format!("Each header object must be a sequence of length 2 - found one with length {}", + seq.len()))); + } + } + Ok(dom_headers_new) + }, + // Step 3 TODO constructor for when init is an open-ended dictionary + None => Ok(dom_headers_new), + } + } + + pub fn Constructor(global: GlobalRef, init: Option<HeadersBinding::HeadersInit>) + -> Fallible<Root<Headers>> { + Headers::new(global, init) } } @@ -50,32 +89,102 @@ impl HeadersMethods for Headers { fn Append(&self, name: ByteString, value: ByteString) -> Result<(), Error> { // Step 1 let value = normalize_value(value); - // Step 2 - let (valid_name, valid_value) = try!(validate_name_and_value(name, value)); + let (mut valid_name, valid_value) = try!(validate_name_and_value(name, value)); + valid_name = valid_name.to_lowercase(); // Step 3 if self.guard == Guard::Immutable { return Err(Error::Type("Guard is immutable".to_string())); } - // Step 4 if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { return Ok(()); } - // Step 5 if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { return Ok(()); } - // Step 6 if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { return Ok(()); } + // Step 7 + let mut combined_value = self.header_list.borrow_mut().get_raw(&valid_name).unwrap()[0].clone(); + combined_value.push(b","[0]); + combined_value.extend(valid_value.iter().cloned()); + self.header_list.borrow_mut().set_raw(valid_name, vec![combined_value]); + Ok(()) + } + + // https://fetch.spec.whatwg.org/#dom-headers-delete + fn Delete(&self, name: ByteString) -> ErrorResult { + // Step 1 + let valid_name = try!(validate_name(name)); + // Step 2 + if self.guard == Guard::Immutable { + return Err(Error::Type("Guard is immutable".to_string())); + } + // Step 3 + if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { + return Ok(()); + } + // Step 4 + if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { + return Ok(()); + } + // Step 5 + if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { + return Ok(()); + } + // Step 6 + self.header_list.borrow_mut().remove_raw(&valid_name); + Ok(()) + } + + // https://fetch.spec.whatwg.org/#dom-headers-get + fn Get(&self, name: ByteString) -> Fallible<Option<ByteString>> { + // Step 1 + let valid_name = &try!(validate_name(name)); + Ok(self.header_list.borrow().get_raw(&valid_name).map(|v| { + ByteString::new(v[0].clone()) + })) + } + // https://fetch.spec.whatwg.org/#dom-headers-has + fn Has(&self, name: ByteString) -> Fallible<bool> { + // Step 1 + let valid_name = try!(validate_name(name)); + // Step 2 + Ok(self.header_list.borrow_mut().get_raw(&valid_name).is_some()) + } + + // https://fetch.spec.whatwg.org/#dom-headers-set + fn Set(&self, name: ByteString, value: ByteString) -> Fallible<()> { + // Step 1 + let value = normalize_value(value); + // Step 2 + let (mut valid_name, valid_value) = try!(validate_name_and_value(name, value)); + valid_name = valid_name.to_lowercase(); + // Step 3 + if self.guard == Guard::Immutable { + return Err(Error::Type("Guard is immutable".to_string())); + } + // Step 4 + if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { + return Ok(()); + } + // Step 5 + if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { + return Ok(()); + } + // Step 6 + if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { + return Ok(()); + } // Step 7 + // https://fetch.spec.whatwg.org/#concept-header-list-set self.header_list.borrow_mut().set_raw(valid_name, vec![valid_value]); - return Ok(()); + Ok(()) } } @@ -130,7 +239,7 @@ pub fn is_forbidden_header_name(name: &str) -> bool { // ISSUE 1: // It defines a value as "a byte sequence that matches the field-content token production." // To note, there is a difference between field-content and -// field-value (which is made up of fied-content and obs-fold). The +// field-value (which is made up of field-content and obs-fold). The // current definition does not allow for obs-fold (which are white // space and newlines) in values. So perhaps a value should be defined // as "a byte sequence that matches the field-value token production." @@ -147,14 +256,19 @@ pub fn is_forbidden_header_name(name: &str) -> bool { // [4] https://www.rfc-editor.org/errata_search.php?rfc=7230 fn validate_name_and_value(name: ByteString, value: ByteString) -> Result<(String, Vec<u8>), Error> { - if !is_field_name(&name) { - return Err(Error::Type("Name is not valid".to_string())); - } + let valid_name = try!(validate_name(name)); if !is_field_content(&value) { return Err(Error::Type("Value is not valid".to_string())); } + Ok((valid_name, value.into())) +} + +fn validate_name(name: ByteString) -> Result<String, Error> { + if !is_field_name(&name) { + return Err(Error::Type("Name is not valid".to_string())); + } match String::from_utf8(name.into()) { - Ok(ns) => Ok((ns, value.into())), + Ok(ns) => Ok(ns), _ => Err(Error::Type("Non-UTF8 header name found".to_string())), } } diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs new file mode 100644 index 00000000000..061d7616f4a --- /dev/null +++ b/components/script/dom/history.rs @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::HistoryBinding; +use dom::bindings::codegen::Bindings::HistoryBinding::HistoryMethods; +use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{JS, Root}; +use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::window::Window; +use msg::constellation_msg::TraversalDirection; +use script_traits::ScriptMsg as ConstellationMsg; + +// https://html.spec.whatwg.org/multipage/#the-history-interface +#[dom_struct] +pub struct History { + reflector_: Reflector, + window: JS<Window>, +} + +impl History { + pub fn new_inherited(window: &Window) -> History { + History { + reflector_: Reflector::new(), + window: JS::from_ref(&window), + } + } + + pub fn new(window: &Window) -> Root<History> { + reflect_dom_object(box History::new_inherited(window), + GlobalRef::Window(window), + HistoryBinding::Wrap) + } +} + +impl History { + fn traverse_history(&self, direction: TraversalDirection) { + let pipeline = self.window.pipeline(); + let msg = ConstellationMsg::TraverseHistory(Some(pipeline), direction); + let _ = self.window.constellation_chan().send(msg); + } +} + +impl HistoryMethods for History { + // https://html.spec.whatwg.org/multipage/#dom-history-go + fn Go(&self, delta: i32) { + let direction = if delta > 0 { + TraversalDirection::Forward(delta as usize) + } else if delta < 0 { + TraversalDirection::Back(-delta as usize) + } else { + self.window.Location().Reload(); + return; + }; + + self.traverse_history(direction); + } + + // https://html.spec.whatwg.org/multipage/#dom-history-back + fn Back(&self) { + self.traverse_history(TraversalDirection::Back(1)); + } + + // https://html.spec.whatwg.org/multipage/#dom-history-forward + fn Forward(&self) { + self.traverse_history(TraversalDirection::Forward(1)); + } +} diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index 798d0731b2c..95134556bc0 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -248,7 +248,7 @@ impl<'a> Iterator for HTMLCollectionElementsIter<'a> { .filter_map(Root::downcast) .filter(|element| filter.filter(&element, root)) .next() - } + } } impl HTMLCollectionMethods for HTMLCollection { diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 9d7ce208ee2..72b8cc19c16 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -37,11 +37,9 @@ use dom::htmlselectelement::HTMLSelectElement; use dom::htmltextareaelement::HTMLTextAreaElement; use dom::node::{Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; -use dom::window::Window; use encoding::EncodingRef; use encoding::all::UTF_8; use encoding::label::encoding_from_whatwg_label; -use encoding::types::DecoderTrap; use hyper::header::{Charset, ContentDisposition, ContentType, DispositionParam, DispositionType}; use hyper::method::Method; use msg::constellation_msg::{LoadData, PipelineId}; @@ -54,7 +52,6 @@ use string_cache::Atom; use style::attr::AttrValue; use style::str::split_html_space_chars; use task_source::TaskSource; -use url::form_urlencoded; #[derive(JSTraceable, PartialEq, Clone, Copy, HeapSizeOf)] pub struct GenerationId(u32); @@ -280,39 +277,38 @@ impl HTMLFormElement { // https://html.spec.whatwg.org/multipage/#multipart/form-data-encoding-algorithm fn encode_multipart_form_data(&self, form_data: &mut Vec<FormDatum>, - encoding: Option<EncodingRef>, - boundary: String) -> String { + boundary: String, encoding: EncodingRef) -> Vec<u8> { // Step 1 - let mut result = "".to_owned(); + let mut result = vec![]; // Step 2 - // (maybe take encoding as input) - let encoding = encoding.unwrap_or(self.pick_encoding()); - - // Step 3 let charset = &*encoding.whatwg_name().unwrap_or("UTF-8"); - // Step 4 + // Step 3 for entry in form_data.iter_mut() { - // Substep 1 + // 3.1 if entry.name == "_charset_" && entry.ty == "hidden" { entry.value = FormDatumValue::String(DOMString::from(charset.clone())); } - // TODO: Substep 2 + // TODO: 3.2 - // Step 5 + // Step 4 // https://tools.ietf.org/html/rfc7578#section-4 - result.push_str(&*format!("\r\n--{}\r\n", boundary)); + // NOTE(izgzhen): The encoding here expected by most servers seems different from + // what spec says (that it should start with a '\r\n'). + let mut boundary_bytes = format!("--{}\r\n", boundary).into_bytes(); + result.append(&mut boundary_bytes); let mut content_disposition = ContentDisposition { disposition: DispositionType::Ext("form-data".to_owned()), parameters: vec![DispositionParam::Ext("name".to_owned(), String::from(entry.name.clone()))] }; match entry.value { - FormDatumValue::String(ref s) => - result.push_str(&*format!("Content-Disposition: {}\r\n\r\n{}", - content_disposition, - s)), + FormDatumValue::String(ref s) => { + let mut bytes = format!("Content-Disposition: {}\r\n\r\n{}", + content_disposition, s).into_bytes(); + result.append(&mut bytes); + } FormDatumValue::File(ref f) => { content_disposition.parameters.push( DispositionParam::Filename(Charset::Ext(String::from(charset.clone())), @@ -321,20 +317,20 @@ impl HTMLFormElement { // https://tools.ietf.org/html/rfc7578#section-4.4 let content_type = ContentType(f.upcast::<Blob>().Type() .parse().unwrap_or(mime!(Text / Plain))); - result.push_str(&*format!("Content-Disposition: {}\r\n{}\r\n\r\n", - content_disposition, - content_type)); + let mut type_bytes = format!("Content-Disposition: {}\r\n{}\r\n\r\n", + content_disposition, + content_type).into_bytes(); + result.append(&mut type_bytes); - let bytes = &f.upcast::<Blob>().get_bytes().unwrap_or(vec![])[..]; + let mut bytes = f.upcast::<Blob>().get_bytes().unwrap_or(vec![]); - let decoded = encoding.decode(bytes, DecoderTrap::Replace) - .expect("Invalid encoding in file"); - result.push_str(&decoded); + result.append(&mut bytes); } } } - result.push_str(&*format!("\r\n--{}--", boundary)); + let mut boundary_bytes = format!("\r\n--{}--", boundary).into_bytes(); + result.append(&mut boundary_bytes); result } @@ -351,18 +347,11 @@ impl HTMLFormElement { let charset = &*encoding.whatwg_name().unwrap(); for entry in form_data.iter_mut() { - // Step 4 - if entry.name == "_charset_" && entry.ty == "hidden" { - entry.value = FormDatumValue::String(DOMString::from(charset.clone())); - } - - // Step 5 - if entry.ty == "file" { - entry.value = FormDatumValue::String(DOMString::from(entry.value_str())); - } + // Step 4, 5 + let value = entry.replace_value(charset); // Step 6 - result.push_str(&*format!("{}={}\r\n", entry.name, entry.value_str())); + result.push_str(&*format!("{}={}\r\n", entry.name, value)); } // Step 7 @@ -374,7 +363,7 @@ impl HTMLFormElement { // Step 1 let doc = document_from_node(self); let base = doc.url(); - // TODO: Handle browsing contexts + // TODO: Handle browsing contexts (Step 2, 3) // Step 4 if submit_method_flag == SubmittedFrom::NotFromForm && !submitter.no_validate(self) @@ -397,13 +386,18 @@ impl HTMLFormElement { } // Step 6 let mut form_data = self.get_form_dataset(Some(submitter)); + // Step 7 - let mut action = submitter.action(); + let encoding = self.pick_encoding(); + // Step 8 + let mut action = submitter.action(); + + // Step 9 if action.is_empty() { action = DOMString::from(base.as_str()); } - // Step 9-11 + // Step 10-11 let action_components = match base.join(&action) { Ok(url) => url, Err(_) => return @@ -417,57 +411,87 @@ impl HTMLFormElement { let mut load_data = LoadData::new(action_components, doc.get_referrer_policy(), Some(doc.url().clone())); - let parsed_data = match enctype { + // Step 18 + match (&*scheme, method) { + (_, FormMethod::FormDialog) => { + // TODO: Submit dialog + // https://html.spec.whatwg.org/multipage/#submit-dialog + } + // https://html.spec.whatwg.org/multipage/#submit-mutate-action + ("http", FormMethod::FormGet) | ("https", FormMethod::FormGet) | ("data", FormMethod::FormGet) => { + load_data.headers.set(ContentType::form_url_encoded()); + self.mutate_action_url(&mut form_data, load_data, encoding); + } + // https://html.spec.whatwg.org/multipage/#submit-body + ("http", FormMethod::FormPost) | ("https", FormMethod::FormPost) => { + load_data.method = Method::Post; + self.submit_entity_body(&mut form_data, load_data, enctype, encoding); + } + // https://html.spec.whatwg.org/multipage/#submit-get-action + ("file", _) | ("about", _) | ("data", FormMethod::FormPost) | + ("ftp", _) | ("javascript", _) => { + self.plan_to_navigate(load_data); + } + ("mailto", FormMethod::FormPost) => { + // TODO: Mail as body + // https://html.spec.whatwg.org/multipage/#submit-mailto-body + } + ("mailto", FormMethod::FormGet) => { + // TODO: Mail with headers + // https://html.spec.whatwg.org/multipage/#submit-mailto-headers + } + _ => return, + } + } + + // https://html.spec.whatwg.org/multipage/#submit-mutate-action + fn mutate_action_url(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, encoding: EncodingRef) { + let charset = &*encoding.whatwg_name().unwrap(); + + load_data.url.query_pairs_mut().clear() + .encoding_override(Some(self.pick_encoding())) + .extend_pairs(form_data.into_iter() + .map(|field| (field.name.clone(), field.replace_value(charset)))); + + self.plan_to_navigate(load_data); + } + + // https://html.spec.whatwg.org/multipage/#submit-body + fn submit_entity_body(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, + enctype: FormEncType, encoding: EncodingRef) { + let boundary = self.generate_boundary(); + let bytes = match enctype { FormEncType::UrlEncoded => { + let mut url = load_data.url.clone(); + let charset = &*encoding.whatwg_name().unwrap(); load_data.headers.set(ContentType::form_url_encoded()); - form_urlencoded::Serializer::new(String::new()) - .encoding_override(Some(self.pick_encoding())) - .extend_pairs(form_data.into_iter().map(|field| (field.name.clone(), field.value_str()))) - .finish() + url.query_pairs_mut().clear() + .encoding_override(Some(self.pick_encoding())) + .extend_pairs(form_data.into_iter() + .map(|field| (field.name.clone(), field.replace_value(charset)))); + + url.query().unwrap_or("").to_string().into_bytes() } FormEncType::FormDataEncoded => { - let boundary = self.generate_boundary(); let mime = mime!(Multipart / FormData; Boundary =(&boundary)); load_data.headers.set(ContentType(mime)); - - self.encode_multipart_form_data(&mut form_data, None, boundary) + self.encode_multipart_form_data(form_data, boundary, encoding) } FormEncType::TextPlainEncoded => { load_data.headers.set(ContentType(mime!(Text / Plain))); - - self.encode_plaintext(&mut form_data) + self.encode_plaintext(form_data).into_bytes() } }; - // Step 18 - let win = window_from_node(self); - match (&*scheme, method) { - // https://html.spec.whatwg.org/multipage/#submit-dialog - (_, FormMethod::FormDialog) => return, // Unimplemented - // https://html.spec.whatwg.org/multipage/#submit-mutate-action - ("http", FormMethod::FormGet) | ("https", FormMethod::FormGet) => { - // FIXME(SimonSapin): use url.query_pairs_mut() here. - load_data.url.set_query(Some(&*parsed_data)); - self.plan_to_navigate(load_data, &win); - } - // https://html.spec.whatwg.org/multipage/#submit-body - ("http", FormMethod::FormPost) | ("https", FormMethod::FormPost) => { - load_data.method = Method::Post; - load_data.data = Some(parsed_data.into_bytes()); - self.plan_to_navigate(load_data, &win); - } - // https://html.spec.whatwg.org/multipage/#submit-get-action - ("file", _) | ("about", _) | ("data", FormMethod::FormGet) | - ("ftp", _) | ("javascript", _) => { - self.plan_to_navigate(load_data, &win); - } - _ => return // Unimplemented (data and mailto) - } + load_data.data = Some(bytes); + self.plan_to_navigate(load_data); } /// [Planned navigation](https://html.spec.whatwg.org/multipage/#planned-navigation) - fn plan_to_navigate(&self, load_data: LoadData, window: &Window) { + fn plan_to_navigate(&self, load_data: LoadData) { + let window = window_from_node(self); + // Step 1 // Each planned navigation runnable is tagged with a generation ID, and // before the runnable is handled, it first checks whether the HTMLFormElement's @@ -485,7 +509,7 @@ impl HTMLFormElement { }; // Step 3 - window.dom_manipulation_task_source().queue(nav, GlobalRef::Window(window)).unwrap(); + window.dom_manipulation_task_source().queue(nav, GlobalRef::Window(&window)).unwrap(); } /// Interactively validate the constraints of form elements @@ -558,10 +582,8 @@ impl HTMLFormElement { match element { HTMLElementTypeId::HTMLInputElement => { let input = child.downcast::<HTMLInputElement>().unwrap(); - // Step 3.2-3.7 - if let Some(datum) = input.form_datum(submitter) { - data_set.push(datum); - } + + data_set.append(&mut input.form_datums(submitter)); } HTMLElementTypeId::HTMLButtonElement => { let button = child.downcast::<HTMLButtonElement>().unwrap(); @@ -709,10 +731,14 @@ pub struct FormDatum { } impl FormDatum { - pub fn value_str(&self) -> String { + pub fn replace_value(&self, charset: &str) -> String { + if self.name == "_charset_" && self.ty == "hidden" { + return charset.to_string(); + } + match self.value { + FormDatumValue::File(ref f) => String::from(f.name().clone()), FormDatumValue::String(ref s) => String::from(s.clone()), - FormDatumValue::File(ref f) => String::from(f.name().clone()) } } } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 7f524cac29d..a98fcbcfb4e 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -34,9 +34,9 @@ use dom::virtualmethods::VirtualMethods; use ipc_channel::ipc::{self, IpcSender}; use mime_guess; use msg::constellation_msg::Key; -use net_traits::IpcSend; use net_traits::blob_url_store::get_blob_origin; use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; +use net_traits::{IpcSend, CoreResourceMsg}; use script_traits::ScriptMsg as ConstellationMsg; use std::borrow::ToOwned; use std::cell::Cell; @@ -648,7 +648,7 @@ impl HTMLInputElement { /// https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set /// Steps range from 3.1 to 3.7 (specific to HTMLInputElement) - pub fn form_datum(&self, submitter: Option<FormSubmitter>) -> Option<FormDatum> { + pub fn form_datums(&self, submitter: Option<FormSubmitter>) -> Vec<FormDatum> { // 3.1: disabled state check is in get_unclean_dataset // Step 3.2 @@ -664,26 +664,55 @@ impl HTMLInputElement { match ty { // Step 3.1: it's a button but it is not submitter. - atom!("submit") | atom!("button") | atom!("reset") if !is_submitter => return None, + atom!("submit") | atom!("button") | atom!("reset") if !is_submitter => return vec![], // Step 3.1: it's the "Checkbox" or "Radio Button" and whose checkedness is false. atom!("radio") | atom!("checkbox") => if !self.Checked() || name.is_empty() { - return None; + return vec![]; }, + atom!("file") => { + let mut datums = vec![]; + + // Step 3.2-3.7 + let name = self.Name(); + let type_ = self.Type(); + + match self.GetFiles() { + Some(fl) => { + for f in fl.iter_files() { + datums.push(FormDatum { + ty: type_.clone(), + name: name.clone(), + value: FormDatumValue::File(Root::from_ref(&f)), + }); + } + } + None => { + datums.push(FormDatum { + // XXX(izgzhen): Spec says 'application/octet-stream' as the type, + // but this is _type_ of element rather than content right? + ty: type_.clone(), + name: name.clone(), + value: FormDatumValue::String(DOMString::from("")), + }) + } + } - atom!("image") | atom!("file") => return None, // Unimplemented + return datums; + } + atom!("image") => return vec![], // Unimplemented // Step 3.1: it's not the "Image Button" and doesn't have a name attribute. _ => if name.is_empty() { - return None; + return vec![]; } } // Step 3.9 - Some(FormDatum { + vec![FormDatum { ty: DOMString::from(&*ty), // FIXME(ajeffrey): Convert directly from Atoms to DOMStrings name: name, value: FormDatumValue::String(self.Value()) - }) + }] } // https://html.spec.whatwg.org/multipage/#radio-button-group @@ -751,7 +780,7 @@ impl HTMLInputElement { fn select_files(&self, opt_test_paths: Option<Vec<DOMString>>) { let window = window_from_node(self); let origin = get_blob_origin(&window.get_url()); - let filemanager = window.resource_threads().sender(); + let resource_threads = window.resource_threads(); let mut files: Vec<Root<File>> = vec![]; let mut error = None; @@ -764,7 +793,7 @@ impl HTMLInputElement { let (chan, recv) = ipc::channel().expect("Error initializing channel"); let msg = FileManagerThreadMsg::SelectFiles(filter, chan, origin, opt_test_paths); - let _ = filemanager.send(msg).unwrap(); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)).unwrap(); match recv.recv().expect("IpcSender side error") { Ok(selected_files) => { @@ -788,7 +817,7 @@ impl HTMLInputElement { let (chan, recv) = ipc::channel().expect("Error initializing channel"); let msg = FileManagerThreadMsg::SelectFile(filter, chan, origin, opt_test_path); - let _ = filemanager.send(msg).unwrap(); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)).unwrap(); match recv.recv().expect("IpcSender side error") { Ok(selected) => { diff --git a/components/script/dom/htmllielement.rs b/components/script/dom/htmllielement.rs index 444fc37827c..32915a5c351 100644 --- a/components/script/dom/htmllielement.rs +++ b/components/script/dom/htmllielement.rs @@ -3,12 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::HTMLLIElementBinding; +use dom::bindings::codegen::Bindings::HTMLLIElementBinding::HTMLLIElementMethods; +use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::str::DOMString; use dom::document::Document; use dom::htmlelement::HTMLElement; use dom::node::Node; +use dom::virtualmethods::VirtualMethods; use string_cache::Atom; +use style::attr::AttrValue; #[dom_struct] pub struct HTMLLIElement { @@ -31,3 +35,24 @@ impl HTMLLIElement { HTMLLIElementBinding::Wrap) } } + +impl HTMLLIElementMethods for HTMLLIElement { + // https://html.spec.whatwg.org/multipage/#dom-li-value + make_int_getter!(Value, "value"); + + // https://html.spec.whatwg.org/multipage/#dom-li-value + make_int_setter!(SetValue, "value"); +} + +impl VirtualMethods for HTMLLIElement { + fn super_type(&self) -> Option<&VirtualMethods> { + Some(self.upcast::<HTMLElement>() as &VirtualMethods) + } + + fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue { + match name { + &atom!("value") => AttrValue::from_i32(value.into(), 0), + _ => self.super_type().unwrap().parse_plain_attribute(name, value), + } + } +} diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 7a94768c13a..119139ae6d8 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -35,6 +35,8 @@ use string_cache::Atom; use task_source::TaskSource; use time::{self, Timespec, Duration}; use url::Url; +#[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))] +use video_metadata; struct HTMLMediaElementContext { /// The element that initiated the request. @@ -75,12 +77,11 @@ impl AsyncResponseListener for HTMLMediaElementContext { } } - fn data_available(&mut self, payload: Vec<u8>) { + fn data_available(&mut self, mut payload: Vec<u8>) { if self.ignore_response { return; } - let mut payload = payload; self.data.append(&mut payload); let elem = self.elem.root(); @@ -88,11 +89,7 @@ impl AsyncResponseListener for HTMLMediaElementContext { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "Once enough of the media data has been fetched to determine the duration..." if !self.have_metadata { - //TODO: actually check if the payload contains the full metadata - - // Step 6 - elem.change_ready_state(HAVE_METADATA); - self.have_metadata = true; + self.check_metadata(&elem); } else { elem.change_ready_state(HAVE_CURRENT_DATA); } @@ -162,6 +159,46 @@ impl HTMLMediaElementContext { ignore_response: false, } } + + #[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))] + fn check_metadata(&mut self, elem: &HTMLMediaElement) { + match video_metadata::get_format_from_slice(&self.data) { + Ok(meta) => { + let dur = meta.duration.unwrap_or(::std::time::Duration::new(0, 0)); + *elem.video.borrow_mut() = Some(VideoMedia { + format: format!("{:?}", meta.format), + duration: Duration::seconds(dur.as_secs() as i64) + + Duration::nanoseconds(dur.subsec_nanos() as i64), + width: meta.size.width, + height: meta.size.height, + video: meta.video, + audio: meta.audio, + }); + // Step 6 + elem.change_ready_state(HAVE_METADATA); + self.have_metadata = true; + } + _ => {} + } + } + + #[cfg(any(target_os = "android", target_arch = "arm", target_arch = "aarch64"))] + fn check_metadata(&mut self, elem: &HTMLMediaElement) { + // Step 6. + elem.change_ready_state(HAVE_METADATA); + self.have_metadata = true; + } +} + +#[derive(JSTraceable, HeapSizeOf)] +pub struct VideoMedia { + format: String, + #[ignore_heap_size_of = "defined in time"] + duration: Duration, + width: u32, + height: u32, + video: String, + audio: Option<String>, } #[dom_struct] @@ -175,6 +212,7 @@ pub struct HTMLMediaElement { error: MutNullableHeap<JS<MediaError>>, paused: Cell<bool>, autoplaying: Cell<bool>, + video: DOMRefCell<Option<VideoMedia>>, } impl HTMLMediaElement { @@ -192,6 +230,7 @@ impl HTMLMediaElement { error: Default::default(), paused: Cell::new(true), autoplaying: Cell::new(true), + video: DOMRefCell::new(None), } } diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index 4cff33b78a1..1d189f4a21f 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -34,6 +34,20 @@ pub struct HTMLTableElement { tbodies: MutNullableHeap<JS<HTMLCollection>>, } +#[allow(unrooted_must_root)] +#[derive(JSTraceable, HeapSizeOf)] +struct TableRowFilter { + sections: Vec<JS<Node>>, +} + +impl CollectionFilter for TableRowFilter { + fn filter(&self, elem: &Element, root: &Node) -> bool { + elem.is::<HTMLTableRowElement>() && + (root.is_parent_of(elem.upcast()) + || self.sections.iter().any(|ref section| section.is_parent_of(elem.upcast()))) + } +} + impl HTMLTableElement { fn new_inherited(localName: Atom, prefix: Option<DOMString>, document: &Document) -> HTMLTableElement { @@ -120,32 +134,22 @@ impl HTMLTableElement { thead.upcast::<Node>().remove_self(); } } -} - -impl HTMLTableElementMethods for HTMLTableElement { - // https://html.spec.whatwg.org/multipage/#dom-table-rows - fn Rows(&self) -> Root<HTMLCollection> { - #[allow(unrooted_must_root)] - #[derive(JSTraceable, HeapSizeOf)] - struct TableRowFilter { - sections: Vec<JS<Node>> - } - - impl CollectionFilter for TableRowFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - elem.is::<HTMLTableRowElement>() && - (root.is_parent_of(elem.upcast()) - || self.sections.iter().any(|ref section| section.is_parent_of(elem.upcast()))) - } - } - let filter = TableRowFilter { + fn get_rows(&self) -> TableRowFilter { + TableRowFilter { sections: self.upcast::<Node>() .children() .filter_map(|ref node| node.downcast::<HTMLTableSectionElement>().map(|_| JS::from_ref(&**node))) .collect() - }; + } + } +} + +impl HTMLTableElementMethods for HTMLTableElement { + // https://html.spec.whatwg.org/multipage/#dom-table-rows + fn Rows(&self) -> Root<HTMLCollection> { + let filter = self.get_rows(); HTMLCollection::new(window_from_node(self).r(), self.upcast(), box filter) } @@ -338,6 +342,22 @@ impl HTMLTableElementMethods for HTMLTableElement { Ok(new_row) } + // https://html.spec.whatwg.org/multipage/#dom-table-deleterow + fn DeleteRow(&self, mut index: i32) -> Fallible<()> { + let rows = self.Rows(); + // Step 1. + if index == -1 { + index = rows.Length() as i32 - 1; + } + // Step 2. + if index < 0 || index as u32 >= rows.Length() { + return Err(Error::IndexSize); + } + // Step 3. + Root::upcast::<Node>(rows.Item(index as u32).unwrap()).remove_self(); + Ok(()) + } + // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor make_getter!(BgColor, "bgcolor"); diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 58af2b28ac6..2b29ec8014c 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -47,6 +47,22 @@ macro_rules! make_limited_int_setter( ); #[macro_export] +macro_rules! make_int_setter( + ($attr:ident, $htmlname:tt, $default:expr) => ( + fn $attr(&self, value: i32) { + use dom::bindings::inheritance::Castable; + use dom::element::Element; + + let element = self.upcast::<Element>(); + element.set_int_attribute(&atom!($htmlname), value) + } + ); + ($attr:ident, $htmlname:tt) => { + make_int_setter!($attr, $htmlname, 0); + }; +); + +#[macro_export] macro_rules! make_int_getter( ($attr:ident, $htmlname:tt, $default:expr) => ( fn $attr(&self) -> i32 { diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 172026c4d8e..a2112526228 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -265,11 +265,13 @@ pub mod eventtarget; pub mod file; pub mod filelist; pub mod filereader; +pub mod filereadersync; pub mod focusevent; pub mod forcetouchevent; pub mod formdata; pub mod hashchangeevent; pub mod headers; +pub mod history; pub mod htmlanchorelement; pub mod htmlappletelement; pub mod htmlareaelement; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 37495be3ba3..2769b7503bc 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -479,19 +479,7 @@ impl Node { return } - // 2. Dirty descendants. - fn dirty_subtree(node: &Node) { - // Stop if this subtree is already dirty. - if node.is_dirty() { return } - - node.set_flag(IS_DIRTY | HAS_DIRTY_DESCENDANTS, true); - - for kid in node.children() { - dirty_subtree(kid.r()); - } - } - - dirty_subtree(self); + self.set_flag(IS_DIRTY, true); // 4. Dirty ancestors. for ancestor in self.ancestors() { @@ -1299,22 +1287,17 @@ impl TreeIterator { depth: 0, } } -} -impl Iterator for TreeIterator { - type Item = Root<Node>; - - // https://dom.spec.whatwg.org/#concept-tree-order - fn next(&mut self) -> Option<Root<Node>> { + pub fn next_skipping_children(&mut self) -> Option<Root<Node>> { let current = match self.current.take() { None => return None, Some(current) => current, }; - if let Some(first_child) = current.GetFirstChild() { - self.current = Some(first_child); - self.depth += 1; - return Some(current); - }; + + self.next_skipping_children_impl(current) + } + + fn next_skipping_children_impl(&mut self, current: Root<Node>) -> Option<Root<Node>> { for ancestor in current.inclusive_ancestors() { if self.depth == 0 { break; @@ -1331,6 +1314,25 @@ impl Iterator for TreeIterator { } } +impl Iterator for TreeIterator { + type Item = Root<Node>; + + // https://dom.spec.whatwg.org/#concept-tree-order + fn next(&mut self) -> Option<Root<Node>> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }; + if let Some(first_child) = current.GetFirstChild() { + self.current = Some(first_child); + self.depth += 1; + return Some(current); + }; + + self.next_skipping_children_impl(current) + } +} + /// Specifies whether children must be recursively cloned or not. #[derive(Copy, Clone, PartialEq, HeapSizeOf)] pub enum CloneChildrenFlag { diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 4841e0ff08a..c6a238ac10f 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -24,7 +24,8 @@ use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext}; use js::jsval::UndefinedValue; use js::rust::Runtime; use msg::constellation_msg::PipelineId; -use net_traits::{LoadContext, load_whole_resource, IpcSend}; +use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator}; +use rand::random; use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx}; use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg}; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; @@ -36,8 +37,16 @@ use util::thread::spawn_named; use util::thread_state; use util::thread_state::{IN_WORKER, SCRIPT}; +/// Messages used to control service worker event loop +pub enum ServiceWorkerScriptMsg { + /// Message common to all workers + CommonWorker(WorkerScriptMsg), + // Message to request a custom response by the service worker + Response(CustomResponseMediator) +} + pub enum MixedMessage { - FromServiceWorker((TrustedServiceWorkerAddress, WorkerScriptMsg)), + FromServiceWorker(ServiceWorkerScriptMsg), FromDevtools(DevtoolScriptControlMsg), FromTimeoutThread(()), } @@ -47,9 +56,9 @@ pub struct ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, id: PipelineId, #[ignore_heap_size_of = "Defined in std"] - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + receiver: Receiver<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] timer_event_port: Receiver<()>, #[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"] @@ -66,8 +75,8 @@ impl ServiceWorkerGlobalScope { id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, timer_event_chan: IpcSender<TimerEvent>, timer_event_port: Receiver<()>, swmanager_sender: IpcSender<ServiceWorkerMsg>, @@ -95,8 +104,8 @@ impl ServiceWorkerGlobalScope { id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, timer_event_chan: IpcSender<TimerEvent>, timer_event_port: Receiver<()>, swmanager_sender: IpcSender<ServiceWorkerMsg>, @@ -119,8 +128,8 @@ impl ServiceWorkerGlobalScope { #[allow(unsafe_code)] pub fn run_serviceworker_scope(scope_things: ScopeThings, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, swmanager_sender: IpcSender<ServiceWorkerMsg>, scope_url: Url) { @@ -177,12 +186,14 @@ impl ServiceWorkerGlobalScope { let _ = timer_chan.send(()); }); - // TODO XXXcreativcoder bring back run_with_memory_reporting when things are more concrete here. - while let Ok(event) = global.receive_event() { - if !global.handle_event(event) { - break; + let reporter_name = format!("service-worker-reporter-{}", random::<u64>()); + scope.mem_profiler_chan().run_with_memory_reporting(|| { + while let Ok(event) = global.receive_event() { + if !global.handle_event(event) { + break; + } } - } + }, reporter_name, scope.script_chan(), CommonScriptMsg::CollectReports); }); } @@ -201,7 +212,7 @@ impl ServiceWorkerGlobalScope { } true } - MixedMessage::FromServiceWorker((_, msg)) => { + MixedMessage::FromServiceWorker(msg) => { self.handle_script_event(msg); true } @@ -212,9 +223,11 @@ impl ServiceWorkerGlobalScope { } } - fn handle_script_event(&self, msg: WorkerScriptMsg) { + fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) { + use self::ServiceWorkerScriptMsg::*; + match msg { - WorkerScriptMsg::DOMMessage(data) => { + CommonWorker(WorkerScriptMsg::DOMMessage(data)) => { let scope = self.upcast::<WorkerGlobalScope>(); let target = self.upcast(); let _ac = JSAutoCompartment::new(scope.get_cx(), @@ -223,19 +236,22 @@ impl ServiceWorkerGlobalScope { data.read(GlobalRef::Worker(scope), message.handle_mut()); MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle()); }, - WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable))) => { runnable.handler() }, - WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr))) => { LiveDOMReferences::cleanup(addr); }, - WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan))) => { let scope = self.upcast::<WorkerGlobalScope>(); let cx = scope.get_cx(); let path_seg = format!("url({})", scope.get_url()); let reports = get_reports(cx, path_seg); reports_chan.send(reports); }, + Response(mediator) => { + let _ = mediator.response_chan.send(None); + } } } @@ -275,7 +291,7 @@ impl ServiceWorkerGlobalScope { } pub fn process_event(&self, msg: CommonScriptMsg) { - self.handle_script_event(WorkerScriptMsg::Common(msg)); + self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg))); } } diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index a28612416fc..09ee38a1232 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -7,13 +7,18 @@ use document_loader::LoadType; use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; +use dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods; +use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::ServoHTMLParserBinding; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, Root}; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::str::DOMString; use dom::bindings::trace::JSTraceable; use dom::document::Document; +use dom::htmlimageelement::HTMLImageElement; use dom::node::Node; use dom::window::Window; use encoding::all::UTF_8; @@ -112,13 +117,20 @@ impl AsyncResponseListener for ParserContext { match content_type { Some(ContentType(Mime(TopLevel::Image, _, _))) => { self.is_synthesized_document = true; - let page = format!("<html><body><img src='{}' /></body></html>", self.url); + let page = "<html><body></body></html>".into(); parser.pending_input().borrow_mut().push(page); parser.parse_sync(); + + let doc = parser.document(); + let doc_body = Root::upcast::<Node>(doc.GetBody().unwrap()); + let img = HTMLImageElement::new(atom!("img"), None, doc); + img.SetSrc(DOMString::from(self.url.to_string())); + doc_body.AppendChild(&Root::upcast::<Node>(img)).expect("Appending failed"); + }, Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => { // https://html.spec.whatwg.org/multipage/#read-text - let page = format!("<pre>\n"); + let page = "<pre>\n".into(); parser.pending_input().borrow_mut().push(page); parser.parse_sync(); parser.set_plaintext_state(); diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs index 81c806de806..768dabf1475 100644 --- a/components/script/dom/url.rs +++ b/components/script/dom/url.rs @@ -14,9 +14,9 @@ use dom::blob::Blob; use dom::urlhelper::UrlHelper; use dom::urlsearchparams::URLSearchParams; use ipc_channel::ipc; -use net_traits::IpcSend; use net_traits::blob_url_store::{get_blob_origin, parse_blob_url}; use net_traits::filemanager_thread::{SelectedFileId, FileManagerThreadMsg}; +use net_traits::{IpcSend, CoreResourceMsg}; use std::borrow::ToOwned; use std::default::Default; use url::quirks::domain_to_unicode; @@ -145,11 +145,11 @@ impl URL { if let Ok(url) = Url::parse(&url) { if let Ok((id, _, _)) = parse_blob_url(&url) { - let filemanager = global.resource_threads().sender(); + let resource_threads = global.resource_threads(); let id = SelectedFileId(id.simple().to_string()); let (tx, rx) = ipc::channel().unwrap(); let msg = FileManagerThreadMsg::RevokeBlobURL(id, origin, tx); - let _ = filemanager.send(msg); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)); let _ = rx.recv().unwrap(); } diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index b42e8b676c3..d4cf1609568 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -29,6 +29,7 @@ use dom::htmliframeelement::HTMLIFrameElement; use dom::htmlimageelement::HTMLImageElement; use dom::htmlinputelement::HTMLInputElement; use dom::htmllabelelement::HTMLLabelElement; +use dom::htmllielement::HTMLLIElement; use dom::htmllinkelement::HTMLLinkElement; use dom::htmlmediaelement::HTMLMediaElement; use dom::htmlmetaelement::HTMLMetaElement; @@ -179,6 +180,9 @@ pub fn vtable_for(node: &Node) -> &VirtualMethods { NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => { node.downcast::<HTMLLabelElement>().unwrap() as &VirtualMethods } + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLIElement)) => { + node.downcast::<HTMLLIElement>().unwrap() as &VirtualMethods + } NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => { node.downcast::<HTMLLinkElement>().unwrap() as &VirtualMethods } diff --git a/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl b/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl index cd0d393e22e..53996ee3965 100644 --- a/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl +++ b/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl @@ -8,4 +8,6 @@ [Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/); attribute EventHandler onmessage; + + void close(); }; diff --git a/components/script/dom/webidls/FileReaderSync.webidl b/components/script/dom/webidls/FileReaderSync.webidl new file mode 100644 index 00000000000..cbc18a47921 --- /dev/null +++ b/components/script/dom/webidls/FileReaderSync.webidl @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://w3c.github.io/FileAPI/#FileReaderSync + +[Constructor, Exposed=Worker] +interface FileReaderSync { + // Synchronously return strings + + // ArrayBuffer readAsArrayBuffer(Blob blob); + // DOMString readAsBinaryString(Blob blob); + // DOMString readAsText(Blob blob, optional DOMString label); + // DOMString readAsDataURL(Blob blob); +}; diff --git a/components/script/dom/webidls/HTMLAnchorElement.webidl b/components/script/dom/webidls/HTMLAnchorElement.webidl index c728744e495..f78d1dae6dd 100644 --- a/components/script/dom/webidls/HTMLAnchorElement.webidl +++ b/components/script/dom/webidls/HTMLAnchorElement.webidl @@ -11,7 +11,6 @@ */ // https://html.spec.whatwg.org/multipage/#htmlanchorelement -[Exposed=(Window,Worker)] interface HTMLAnchorElement : HTMLElement { attribute DOMString target; // attribute DOMString download; diff --git a/components/script/dom/webidls/HTMLAppletElement.webidl b/components/script/dom/webidls/HTMLAppletElement.webidl index efb3d24b2e7..9cfeb4183df 100644 --- a/components/script/dom/webidls/HTMLAppletElement.webidl +++ b/components/script/dom/webidls/HTMLAppletElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlappletelement -[Exposed=(Window,Worker)] interface HTMLAppletElement : HTMLElement { // attribute DOMString align; // attribute DOMString alt; diff --git a/components/script/dom/webidls/HTMLAreaElement.webidl b/components/script/dom/webidls/HTMLAreaElement.webidl index f39db4fa4d2..14883df3613 100644 --- a/components/script/dom/webidls/HTMLAreaElement.webidl +++ b/components/script/dom/webidls/HTMLAreaElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlareaelement -[Exposed=(Window,Worker)] interface HTMLAreaElement : HTMLElement { // attribute DOMString alt; // attribute DOMString coords; diff --git a/components/script/dom/webidls/HTMLAudioElement.webidl b/components/script/dom/webidls/HTMLAudioElement.webidl index df0710b1856..09ad8a7cdb3 100644 --- a/components/script/dom/webidls/HTMLAudioElement.webidl +++ b/components/script/dom/webidls/HTMLAudioElement.webidl @@ -4,5 +4,4 @@ // https://html.spec.whatwg.org/multipage/#htmlaudioelement //[NamedConstructor=Audio(optional DOMString src)] -[Exposed=(Window,Worker)] interface HTMLAudioElement : HTMLMediaElement {}; diff --git a/components/script/dom/webidls/HTMLBRElement.webidl b/components/script/dom/webidls/HTMLBRElement.webidl index 4d811f3e285..ab277396bdd 100644 --- a/components/script/dom/webidls/HTMLBRElement.webidl +++ b/components/script/dom/webidls/HTMLBRElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbrelement -[Exposed=(Window,Worker)] interface HTMLBRElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLBaseElement.webidl b/components/script/dom/webidls/HTMLBaseElement.webidl index dee9895c8ef..a13be544cb9 100644 --- a/components/script/dom/webidls/HTMLBaseElement.webidl +++ b/components/script/dom/webidls/HTMLBaseElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbaseelement -[Exposed=(Window,Worker)] interface HTMLBaseElement : HTMLElement { attribute DOMString href; // attribute DOMString target; diff --git a/components/script/dom/webidls/HTMLBodyElement.webidl b/components/script/dom/webidls/HTMLBodyElement.webidl index 31097e75614..36c6f4d64e3 100644 --- a/components/script/dom/webidls/HTMLBodyElement.webidl +++ b/components/script/dom/webidls/HTMLBodyElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#the-body-element -[Exposed=(Window,Worker)] interface HTMLBodyElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLButtonElement.webidl b/components/script/dom/webidls/HTMLButtonElement.webidl index a5c689cbc46..7f663fd305f 100644 --- a/components/script/dom/webidls/HTMLButtonElement.webidl +++ b/components/script/dom/webidls/HTMLButtonElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbuttonelement -[Exposed=(Window,Worker)] interface HTMLButtonElement : HTMLElement { // attribute boolean autofocus; attribute boolean disabled; diff --git a/components/script/dom/webidls/HTMLDListElement.webidl b/components/script/dom/webidls/HTMLDListElement.webidl index e0420cf8418..b6275107db5 100644 --- a/components/script/dom/webidls/HTMLDListElement.webidl +++ b/components/script/dom/webidls/HTMLDListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldlistelement -[Exposed=(Window,Worker)] interface HTMLDListElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLDataElement.webidl b/components/script/dom/webidls/HTMLDataElement.webidl index e0b2aa2cafa..be932250678 100644 --- a/components/script/dom/webidls/HTMLDataElement.webidl +++ b/components/script/dom/webidls/HTMLDataElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldataelement -[Exposed=(Window,Worker)] interface HTMLDataElement : HTMLElement { // attribute DOMString value; }; diff --git a/components/script/dom/webidls/HTMLDataListElement.webidl b/components/script/dom/webidls/HTMLDataListElement.webidl index c970ae495fb..b8673b21c77 100644 --- a/components/script/dom/webidls/HTMLDataListElement.webidl +++ b/components/script/dom/webidls/HTMLDataListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldatalistelement -[Exposed=(Window,Worker)] interface HTMLDataListElement : HTMLElement { readonly attribute HTMLCollection options; }; diff --git a/components/script/dom/webidls/HTMLDetailsElement.webidl b/components/script/dom/webidls/HTMLDetailsElement.webidl index 8dbffdea064..811465c1c02 100644 --- a/components/script/dom/webidls/HTMLDetailsElement.webidl +++ b/components/script/dom/webidls/HTMLDetailsElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldetailselement -[Exposed=(Window,Worker)] interface HTMLDetailsElement : HTMLElement { attribute boolean open; }; diff --git a/components/script/dom/webidls/HTMLDialogElement.webidl b/components/script/dom/webidls/HTMLDialogElement.webidl index 82d11ea2cae..78a14e1e2a0 100644 --- a/components/script/dom/webidls/HTMLDialogElement.webidl +++ b/components/script/dom/webidls/HTMLDialogElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldialogelement -[Exposed=(Window,Worker)] interface HTMLDialogElement : HTMLElement { attribute boolean open; attribute DOMString returnValue; diff --git a/components/script/dom/webidls/HTMLDirectoryElement.webidl b/components/script/dom/webidls/HTMLDirectoryElement.webidl index 4a1d8af74ab..5df65cd90c2 100644 --- a/components/script/dom/webidls/HTMLDirectoryElement.webidl +++ b/components/script/dom/webidls/HTMLDirectoryElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldirectoryelement -[Exposed=(Window,Worker)] interface HTMLDirectoryElement : HTMLElement { // attribute boolean compact; }; diff --git a/components/script/dom/webidls/HTMLDivElement.webidl b/components/script/dom/webidls/HTMLDivElement.webidl index 827dfe7ab49..46ee67ee0e5 100644 --- a/components/script/dom/webidls/HTMLDivElement.webidl +++ b/components/script/dom/webidls/HTMLDivElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldivelement -[Exposed=(Window,Worker)] interface HTMLDivElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLEmbedElement.webidl b/components/script/dom/webidls/HTMLEmbedElement.webidl index 3e4063c9377..26fa4c3ea5a 100644 --- a/components/script/dom/webidls/HTMLEmbedElement.webidl +++ b/components/script/dom/webidls/HTMLEmbedElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlembedelement -[Exposed=(Window,Worker)] interface HTMLEmbedElement : HTMLElement { // attribute DOMString src; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLFieldSetElement.webidl b/components/script/dom/webidls/HTMLFieldSetElement.webidl index 6c05b23f9ae..d041cdd612f 100644 --- a/components/script/dom/webidls/HTMLFieldSetElement.webidl +++ b/components/script/dom/webidls/HTMLFieldSetElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlfieldsetelement -[Exposed=(Window,Worker)] interface HTMLFieldSetElement : HTMLElement { attribute boolean disabled; readonly attribute HTMLFormElement? form; diff --git a/components/script/dom/webidls/HTMLFontElement.webidl b/components/script/dom/webidls/HTMLFontElement.webidl index 7c524eb0a4d..74db3f45057 100644 --- a/components/script/dom/webidls/HTMLFontElement.webidl +++ b/components/script/dom/webidls/HTMLFontElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlfontelement -[Exposed=(Window,Worker)] interface HTMLFontElement : HTMLElement { [TreatNullAs=EmptyString] attribute DOMString color; attribute DOMString face; diff --git a/components/script/dom/webidls/HTMLFrameElement.webidl b/components/script/dom/webidls/HTMLFrameElement.webidl index 0de80f7df1e..ecac61f6860 100644 --- a/components/script/dom/webidls/HTMLFrameElement.webidl +++ b/components/script/dom/webidls/HTMLFrameElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlframeelement -[Exposed=(Window,Worker)] interface HTMLFrameElement : HTMLElement { // attribute DOMString name; // attribute DOMString scrolling; diff --git a/components/script/dom/webidls/HTMLFrameSetElement.webidl b/components/script/dom/webidls/HTMLFrameSetElement.webidl index 34ab7a42289..5addd41d253 100644 --- a/components/script/dom/webidls/HTMLFrameSetElement.webidl +++ b/components/script/dom/webidls/HTMLFrameSetElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlframesetelement -[Exposed=(Window,Worker)] interface HTMLFrameSetElement : HTMLElement { // attribute DOMString cols; // attribute DOMString rows; diff --git a/components/script/dom/webidls/HTMLHRElement.webidl b/components/script/dom/webidls/HTMLHRElement.webidl index 84ab2a423c6..56e2f6ae19b 100644 --- a/components/script/dom/webidls/HTMLHRElement.webidl +++ b/components/script/dom/webidls/HTMLHRElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlhrelement -[Exposed=(Window,Worker)] interface HTMLHRElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLHeadingElement.webidl b/components/script/dom/webidls/HTMLHeadingElement.webidl index 8185fcb961e..2c47d6fa10f 100644 --- a/components/script/dom/webidls/HTMLHeadingElement.webidl +++ b/components/script/dom/webidls/HTMLHeadingElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlheadingelement -[Exposed=(Window,Worker)] interface HTMLHeadingElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLHtmlElement.webidl b/components/script/dom/webidls/HTMLHtmlElement.webidl index d25b22702b3..ed409b1b84c 100644 --- a/components/script/dom/webidls/HTMLHtmlElement.webidl +++ b/components/script/dom/webidls/HTMLHtmlElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlhtmlelement -[Exposed=(Window,Worker)] interface HTMLHtmlElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl b/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl index 46336743a53..3ff0418b13f 100644 --- a/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl +++ b/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlhyperlinkelementutils -[NoInterfaceObject, Exposed=(Window,Worker)] +[NoInterfaceObject] interface HTMLHyperlinkElementUtils { // stringifier attribute USVString href; attribute USVString href; diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl index 58a9af38d9c..ced089391d2 100644 --- a/components/script/dom/webidls/HTMLIFrameElement.webidl +++ b/components/script/dom/webidls/HTMLIFrameElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmliframeelement -[Exposed=(Window,Worker)] interface HTMLIFrameElement : HTMLElement { attribute DOMString src; // attribute DOMString srcdoc; diff --git a/components/script/dom/webidls/HTMLImageElement.webidl b/components/script/dom/webidls/HTMLImageElement.webidl index d3e2a419132..88e0dae8d3b 100644 --- a/components/script/dom/webidls/HTMLImageElement.webidl +++ b/components/script/dom/webidls/HTMLImageElement.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlimageelement -[NamedConstructor=Image(optional unsigned long width, optional unsigned long height), Exposed=(Window,Worker)] +[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)] interface HTMLImageElement : HTMLElement { attribute DOMString alt; attribute DOMString src; diff --git a/components/script/dom/webidls/HTMLInputElement.webidl b/components/script/dom/webidls/HTMLInputElement.webidl index d5b3a3985ed..1d6160b14cd 100644 --- a/components/script/dom/webidls/HTMLInputElement.webidl +++ b/components/script/dom/webidls/HTMLInputElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlinputelement -[Exposed=(Window,Worker)] interface HTMLInputElement : HTMLElement { attribute DOMString accept; attribute DOMString alt; diff --git a/components/script/dom/webidls/HTMLLIElement.webidl b/components/script/dom/webidls/HTMLLIElement.webidl index 944029bfb04..ea7d574eba4 100644 --- a/components/script/dom/webidls/HTMLLIElement.webidl +++ b/components/script/dom/webidls/HTMLLIElement.webidl @@ -3,9 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmllielement -[Exposed=(Window,Worker)] interface HTMLLIElement : HTMLElement { - // attribute long value; + attribute long value; // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLLabelElement.webidl b/components/script/dom/webidls/HTMLLabelElement.webidl index 5a194998747..8acb1f312c8 100644 --- a/components/script/dom/webidls/HTMLLabelElement.webidl +++ b/components/script/dom/webidls/HTMLLabelElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmllabelelement -[Exposed=(Window,Worker)] interface HTMLLabelElement : HTMLElement { readonly attribute HTMLFormElement? form; attribute DOMString htmlFor; diff --git a/components/script/dom/webidls/HTMLLegendElement.webidl b/components/script/dom/webidls/HTMLLegendElement.webidl index 4c79ce2ecc6..c137d6db66a 100644 --- a/components/script/dom/webidls/HTMLLegendElement.webidl +++ b/components/script/dom/webidls/HTMLLegendElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmllegendelement -[Exposed=(Window,Worker)] interface HTMLLegendElement : HTMLElement { readonly attribute HTMLFormElement? form; diff --git a/components/script/dom/webidls/HTMLParagraphElement.webidl b/components/script/dom/webidls/HTMLParagraphElement.webidl index ff2facc455d..a96c6dc6f81 100644 --- a/components/script/dom/webidls/HTMLParagraphElement.webidl +++ b/components/script/dom/webidls/HTMLParagraphElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlparagraphelement -[Exposed=(Window,Worker)] interface HTMLParagraphElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLParamElement.webidl b/components/script/dom/webidls/HTMLParamElement.webidl index 1b0805480a6..9648c9f87ce 100644 --- a/components/script/dom/webidls/HTMLParamElement.webidl +++ b/components/script/dom/webidls/HTMLParamElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlparamelement -[Exposed=(Window,Worker)] interface HTMLParamElement : HTMLElement { // attribute DOMString name; // attribute DOMString value; diff --git a/components/script/dom/webidls/HTMLPreElement.webidl b/components/script/dom/webidls/HTMLPreElement.webidl index 7d65e225d4f..ea0df151020 100644 --- a/components/script/dom/webidls/HTMLPreElement.webidl +++ b/components/script/dom/webidls/HTMLPreElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlpreelement -[Exposed=(Window,Worker)] interface HTMLPreElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLProgressElement.webidl b/components/script/dom/webidls/HTMLProgressElement.webidl index 852e683b1f7..cf69566ecdd 100644 --- a/components/script/dom/webidls/HTMLProgressElement.webidl +++ b/components/script/dom/webidls/HTMLProgressElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlprogresselement -[Exposed=(Window,Worker)] interface HTMLProgressElement : HTMLElement { // attribute double value; // attribute double max; diff --git a/components/script/dom/webidls/HTMLQuoteElement.webidl b/components/script/dom/webidls/HTMLQuoteElement.webidl index 6741d7b4041..e546f151d49 100644 --- a/components/script/dom/webidls/HTMLQuoteElement.webidl +++ b/components/script/dom/webidls/HTMLQuoteElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlquoteelement -[Exposed=(Window,Worker)] interface HTMLQuoteElement : HTMLElement { // attribute DOMString cite; }; diff --git a/components/script/dom/webidls/HTMLSelectElement.webidl b/components/script/dom/webidls/HTMLSelectElement.webidl index 2bcbbf098e4..ba84d183a72 100644 --- a/components/script/dom/webidls/HTMLSelectElement.webidl +++ b/components/script/dom/webidls/HTMLSelectElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlselectelement -[Exposed=(Window,Worker)] interface HTMLSelectElement : HTMLElement { // attribute boolean autofocus; attribute boolean disabled; diff --git a/components/script/dom/webidls/HTMLSourceElement.webidl b/components/script/dom/webidls/HTMLSourceElement.webidl index a631876b42e..738a545713a 100644 --- a/components/script/dom/webidls/HTMLSourceElement.webidl +++ b/components/script/dom/webidls/HTMLSourceElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlsourceelement -[Exposed=(Window,Worker)] interface HTMLSourceElement : HTMLElement { // attribute DOMString src; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLSpanElement.webidl b/components/script/dom/webidls/HTMLSpanElement.webidl index 082ba45cf8b..a74967536a1 100644 --- a/components/script/dom/webidls/HTMLSpanElement.webidl +++ b/components/script/dom/webidls/HTMLSpanElement.webidl @@ -3,5 +3,4 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlspanelement -[Exposed=(Window,Worker)] interface HTMLSpanElement : HTMLElement {}; diff --git a/components/script/dom/webidls/HTMLStyleElement.webidl b/components/script/dom/webidls/HTMLStyleElement.webidl index 4bc4430a38c..dd766f41d22 100644 --- a/components/script/dom/webidls/HTMLStyleElement.webidl +++ b/components/script/dom/webidls/HTMLStyleElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlstyleelement -[Exposed=(Window,Worker)] interface HTMLStyleElement : HTMLElement { // attribute DOMString media; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLTableCaptionElement.webidl b/components/script/dom/webidls/HTMLTableCaptionElement.webidl index 0860aa7e796..b405d23ed40 100644 --- a/components/script/dom/webidls/HTMLTableCaptionElement.webidl +++ b/components/script/dom/webidls/HTMLTableCaptionElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecaptionelement -[Exposed=(Window,Worker)] interface HTMLTableCaptionElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableCellElement.webidl b/components/script/dom/webidls/HTMLTableCellElement.webidl index 2264d56b5e2..33863b3dc20 100644 --- a/components/script/dom/webidls/HTMLTableCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableCellElement.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecellelement -[Abstract, Exposed=(Window,Worker)] +[Abstract] interface HTMLTableCellElement : HTMLElement { attribute unsigned long colSpan; // attribute unsigned long rowSpan; diff --git a/components/script/dom/webidls/HTMLTableColElement.webidl b/components/script/dom/webidls/HTMLTableColElement.webidl index 3868de31272..69188251443 100644 --- a/components/script/dom/webidls/HTMLTableColElement.webidl +++ b/components/script/dom/webidls/HTMLTableColElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecolelement -[Exposed=(Window,Worker)] interface HTMLTableColElement : HTMLElement { // attribute unsigned long span; diff --git a/components/script/dom/webidls/HTMLTableDataCellElement.webidl b/components/script/dom/webidls/HTMLTableDataCellElement.webidl index 7c286df77e4..208ed76d692 100644 --- a/components/script/dom/webidls/HTMLTableDataCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableDataCellElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltabledatacellelement -[Exposed=(Window,Worker)] interface HTMLTableDataCellElement : HTMLTableCellElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableElement.webidl b/components/script/dom/webidls/HTMLTableElement.webidl index c97d24fd57b..f0d8e19d0eb 100644 --- a/components/script/dom/webidls/HTMLTableElement.webidl +++ b/components/script/dom/webidls/HTMLTableElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltableelement -[Exposed=(Window,Worker)] interface HTMLTableElement : HTMLElement { attribute HTMLTableCaptionElement? caption; HTMLTableCaptionElement createCaption(); @@ -20,7 +19,7 @@ interface HTMLTableElement : HTMLElement { HTMLTableSectionElement createTBody(); readonly attribute HTMLCollection rows; [Throws] HTMLTableRowElement insertRow(optional long index = -1); - //void deleteRow(long index); + [Throws] void deleteRow(long index); // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl b/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl index fb3e7126672..9bf8f1fc950 100644 --- a/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltableheadercellelement -[Exposed=(Window,Worker)] interface HTMLTableHeaderCellElement : HTMLTableCellElement { // attribute DOMString scope; // attribute DOMString abbr; diff --git a/components/script/dom/webidls/HTMLTableRowElement.webidl b/components/script/dom/webidls/HTMLTableRowElement.webidl index 75898c577e1..9d4b0655cad 100644 --- a/components/script/dom/webidls/HTMLTableRowElement.webidl +++ b/components/script/dom/webidls/HTMLTableRowElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablerowelement -[Exposed=(Window,Worker)] interface HTMLTableRowElement : HTMLElement { readonly attribute long rowIndex; readonly attribute long sectionRowIndex; diff --git a/components/script/dom/webidls/HTMLTableSectionElement.webidl b/components/script/dom/webidls/HTMLTableSectionElement.webidl index dd9d1c654f1..979d8030ffd 100644 --- a/components/script/dom/webidls/HTMLTableSectionElement.webidl +++ b/components/script/dom/webidls/HTMLTableSectionElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablesectionelement -[Exposed=(Window,Worker)] interface HTMLTableSectionElement : HTMLElement { readonly attribute HTMLCollection rows; [Throws] diff --git a/components/script/dom/webidls/HTMLTemplateElement.webidl b/components/script/dom/webidls/HTMLTemplateElement.webidl index 7506f9a28e0..b3383de69d2 100644 --- a/components/script/dom/webidls/HTMLTemplateElement.webidl +++ b/components/script/dom/webidls/HTMLTemplateElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltemplateelement -[Exposed=(Window,Worker)] interface HTMLTemplateElement : HTMLElement { readonly attribute DocumentFragment content; }; diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 32a2ba43ccf..f92e662c354 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltextareaelement -[Exposed=(Window,Worker)] interface HTMLTextAreaElement : HTMLElement { // attribute DOMString autocomplete; // attribute boolean autofocus; diff --git a/components/script/dom/webidls/HTMLTimeElement.webidl b/components/script/dom/webidls/HTMLTimeElement.webidl index dbd80686b0c..21f9dcf090e 100644 --- a/components/script/dom/webidls/HTMLTimeElement.webidl +++ b/components/script/dom/webidls/HTMLTimeElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltimeelement -[Exposed=(Window,Worker)] interface HTMLTimeElement : HTMLElement { // attribute DOMString dateTime; }; diff --git a/components/script/dom/webidls/HTMLTitleElement.webidl b/components/script/dom/webidls/HTMLTitleElement.webidl index 9332cae40a7..10373be7e4b 100644 --- a/components/script/dom/webidls/HTMLTitleElement.webidl +++ b/components/script/dom/webidls/HTMLTitleElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltitleelement -[Exposed=(Window,Worker)] interface HTMLTitleElement : HTMLElement { [Pure] attribute DOMString text; diff --git a/components/script/dom/webidls/HTMLTrackElement.webidl b/components/script/dom/webidls/HTMLTrackElement.webidl index 9828139bee2..55733235321 100644 --- a/components/script/dom/webidls/HTMLTrackElement.webidl +++ b/components/script/dom/webidls/HTMLTrackElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltrackelement -[Exposed=(Window,Worker)] interface HTMLTrackElement : HTMLElement { // attribute DOMString kind; // attribute DOMString src; diff --git a/components/script/dom/webidls/HTMLUListElement.webidl b/components/script/dom/webidls/HTMLUListElement.webidl index 6abaf544b7f..91a79c7f925 100644 --- a/components/script/dom/webidls/HTMLUListElement.webidl +++ b/components/script/dom/webidls/HTMLUListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlulistelement -[Exposed=(Window,Worker)] interface HTMLUListElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLUnknownElement.webidl b/components/script/dom/webidls/HTMLUnknownElement.webidl index 624d7d8541d..acf5a47a996 100644 --- a/components/script/dom/webidls/HTMLUnknownElement.webidl +++ b/components/script/dom/webidls/HTMLUnknownElement.webidl @@ -11,6 +11,5 @@ * and create derivative works of this document. */ -[Exposed=(Window,Worker)] interface HTMLUnknownElement : HTMLElement { }; diff --git a/components/script/dom/webidls/HTMLVideoElement.webidl b/components/script/dom/webidls/HTMLVideoElement.webidl index 3af425cc06b..5e7c9cb9fce 100644 --- a/components/script/dom/webidls/HTMLVideoElement.webidl +++ b/components/script/dom/webidls/HTMLVideoElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlvideoelement -[Exposed=(Window,Worker)] interface HTMLVideoElement : HTMLMediaElement { // attribute unsigned long width; // attribute unsigned long height; diff --git a/components/script/dom/webidls/Headers.webidl b/components/script/dom/webidls/Headers.webidl index 038dbe46f74..6696bf64731 100644 --- a/components/script/dom/webidls/Headers.webidl +++ b/components/script/dom/webidls/Headers.webidl @@ -4,19 +4,21 @@ // https://fetch.spec.whatwg.org/#headers-class -/* typedef (Headers or sequence<sequence<ByteString>>) HeadersInit; */ - -/* [Constructor(optional HeadersInit init),*/ - [Exposed=(Window,Worker)] +// TODO support OpenEndedDictionary<ByteString> +typedef (Headers or sequence<sequence<ByteString>>) HeadersInit; +[Constructor(optional HeadersInit init), + Exposed=(Window,Worker)] interface Headers { [Throws] void append(ByteString name, ByteString value); + [Throws] + void delete(ByteString name); + [Throws] + ByteString? get(ByteString name); + [Throws] + boolean has(ByteString name); + [Throws] + void set(ByteString name, ByteString value); + // iterable<ByteString, ByteString>; // TODO see issue #12628 }; - -/* void delete(ByteString name); - * ByteString? get(ByteString name); - * boolean has(ByteString name); - * void set(ByteString name, ByteString value); - * iterable<ByteString, ByteString>; - * }; */ diff --git a/components/script/dom/webidls/History.webidl b/components/script/dom/webidls/History.webidl new file mode 100644 index 00000000000..04742d52601 --- /dev/null +++ b/components/script/dom/webidls/History.webidl @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// enum ScrollRestoration { "auto", "manual" }; + +// https://html.spec.whatwg.org/multipage/#the-history-interface +[Exposed=(Window,Worker)] +interface History { + // readonly attribute unsigned long length; + // attribute ScrollRestoration scrollRestoration; + // readonly attribute any state; + void go(optional long delta = 0); + void back(); + void forward(); + // void pushState(any data, DOMString title, optional USVString? url = null); + // void replaceState(any data, DOMString title, optional USVString? url = null); +}; diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index bda73c9479a..651c7081305 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -11,7 +11,7 @@ [Unforgeable] readonly attribute Document document; // attribute DOMString name; [/*PutForwards=href, */Unforgeable] readonly attribute Location location; - //readonly attribute History history; + readonly attribute History history; //[Replaceable] readonly attribute BarProp locationbar; //[Replaceable] readonly attribute BarProp menubar; //[Replaceable] readonly attribute BarProp personalbar; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 1a34096f26b..3b3652040e9 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -461,6 +461,8 @@ struct ConnectionEstablishedTask { } impl Runnable for ConnectionEstablishedTask { + fn name(&self) -> &'static str { "ConnectionEstablishedTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); let global = ws.r().global(); @@ -510,6 +512,8 @@ impl Runnable for BufferedAmountTask { // To be compliant with standards, we need to reset bufferedAmount only when the event loop // reaches step 1. In our implementation, the bytes will already have been sent on a background // thread. + fn name(&self) -> &'static str { "BufferedAmountTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); @@ -526,6 +530,8 @@ struct CloseTask { } impl Runnable for CloseTask { + fn name(&self) -> &'static str { "CloseTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); let ws = ws.r(); @@ -568,6 +574,8 @@ struct MessageReceivedTask { } impl Runnable for MessageReceivedTask { + fn name(&self) -> &'static str { "MessageReceivedTask" } + #[allow(unsafe_code)] fn handler(self: Box<Self>) { let ws = self.address.root(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index b4984bb2a4a..ebd9550d117 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -30,6 +30,7 @@ use dom::document::Document; use dom::element::Element; use dom::event::Event; use dom::eventtarget::EventTarget; +use dom::history::History; use dom::htmliframeelement::build_mozbrowser_custom_event; use dom::location::Location; use dom::navigator::Navigator; @@ -94,7 +95,7 @@ use task_source::networking::NetworkingTaskSource; use task_source::user_interaction::UserInteractionTaskSource; use time; use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback}; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use tinyfiledialogs::{self, MessageBoxIcon}; use url::Url; use util::geometry::{self, MAX_RECT}; @@ -158,6 +159,7 @@ pub struct Window { #[ignore_heap_size_of = "channels are hard"] image_cache_chan: ImageCacheChan, browsing_context: MutNullableHeap<JS<BrowsingContext>>, + history: MutNullableHeap<JS<History>>, performance: MutNullableHeap<JS<Performance>>, navigation_start: u64, navigation_start_precise: f64, @@ -359,14 +361,14 @@ impl Window { } } -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn display_alert_dialog(message: &str) { tinyfiledialogs::message_box_ok("Alert!", message, MessageBoxIcon::Warning); } -#[cfg(not(any(target_os = "macos", target_os = "linux")))] +#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] fn display_alert_dialog(_message: &str) { - // tinyfiledialogs not supported on Windows + // tinyfiledialogs not supported on Android } // https://html.spec.whatwg.org/multipage/#atob @@ -448,13 +450,15 @@ impl WindowMethods for Window { // Right now, just print to the console // Ensure that stderr doesn't trample through the alert() we use to // communicate test results (see executorservo.py in wptrunner). - let stderr = stderr(); - let mut stderr = stderr.lock(); - let stdout = stdout(); - let mut stdout = stdout.lock(); - writeln!(&mut stdout, "ALERT: {}", s).unwrap(); - stdout.flush().unwrap(); - stderr.flush().unwrap(); + { + let stderr = stderr(); + let mut stderr = stderr.lock(); + let stdout = stdout(); + let mut stdout = stdout.lock(); + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); + stdout.flush().unwrap(); + stderr.flush().unwrap(); + } let (sender, receiver) = ipc::channel().unwrap(); self.constellation_chan().send(ConstellationMsg::Alert(self.pipeline(), s.to_string(), sender)).unwrap(); @@ -475,6 +479,11 @@ impl WindowMethods for Window { self.browsing_context().active_document() } + // https://html.spec.whatwg.org/multipage/#dom-history + fn History(&self) -> Root<History> { + self.history.or_init(|| History::new(self)) + } + // https://html.spec.whatwg.org/multipage/#dom-location fn Location(&self) -> Root<Location> { self.Document().GetLocation().unwrap() @@ -1648,6 +1657,7 @@ impl Window { mem_profiler_chan: mem_profiler_chan, time_profiler_chan: time_profiler_chan, devtools_chan: devtools_chan, + history: Default::default(), browsing_context: Default::default(), performance: Default::default(), navigation_start: (current_time.sec * 1000 + current_time.nsec as i64 / 1000000) as u64, diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index c318672fb7a..c1ad7cf5a96 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -27,6 +27,7 @@ use js::jsapi::{HandleValue, JSContext, JSAutoCompartment}; use js::jsval::UndefinedValue; use script_thread::Runnable; use script_traits::WorkerScriptLoadOrigin; +use std::cell::Cell; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Sender, channel}; use std::sync::{Arc, Mutex}; @@ -43,7 +44,8 @@ pub struct Worker { sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, closing: Arc<AtomicBool>, #[ignore_heap_size_of = "Defined in rust-mozjs"] - runtime: Arc<Mutex<Option<SharedRt>>> + runtime: Arc<Mutex<Option<SharedRt>>>, + terminated: Cell<bool>, } impl Worker { @@ -53,7 +55,8 @@ impl Worker { eventtarget: EventTarget::new_inherited(), sender: sender, closing: closing, - runtime: Arc::new(Mutex::new(None)) + runtime: Arc::new(Mutex::new(None)), + terminated: Cell::new(false), } } @@ -112,11 +115,15 @@ impl Worker { self.closing.load(Ordering::SeqCst) } + pub fn is_terminated(&self) -> bool { + self.terminated.get() + } + pub fn handle_message(address: TrustedWorkerAddress, data: StructuredCloneData) { let worker = address.root(); - if worker.is_closing() { + if worker.is_terminated() { return; } @@ -137,7 +144,7 @@ impl Worker { filename: DOMString, lineno: u32, colno: u32) { let worker = address.root(); - if worker.is_closing() { + if worker.is_terminated() { return; } @@ -169,7 +176,10 @@ impl WorkerMethods for Worker { return; } - // Step 4 + // Step 2 + self.terminated.set(true); + + // Step 3 if let Some(runtime) = *self.runtime.lock().unwrap() { runtime.request_interrupt(); } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 154705fe145..16388d54d73 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -444,4 +444,10 @@ impl WorkerGlobalScope { pub fn set_devtools_wants_updates(&self, value: bool) { self.devtools_wants_updates.set(value); } + + pub fn close(&self) { + if let Some(ref closing) = self.closing { + closing.store(true, Ordering::SeqCst); + } + } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 5cef702c01a..b35ffef73c5 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -594,6 +594,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { origin: self.global().r().get_url(), referer_url: self.referrer_url.clone(), referrer_policy: self.referrer_policy.clone(), + pipeline_id: self.pipeline_id(), }; if bypass_cross_origin_check { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index df44774dd5a..bfd7a8273d9 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -199,15 +199,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { self.node.set_flag(DIRTY_ON_VIEWPORT_SIZE_CHANGE, true); } - fn set_descendants_dirty_on_viewport_size_changed(&self) { - for ref child in self.children() { - unsafe { - child.set_dirty_on_viewport_size_changed(); - } - child.set_descendants_dirty_on_viewport_size_changed(); - } - } - fn can_be_fragmented(&self) -> bool { unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) } } diff --git a/components/script/lib.rs b/components/script/lib.rs index 78a84f83586..2eecac4d1b5 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -10,7 +10,6 @@ #![feature(custom_attribute)] #![feature(custom_derive)] #![feature(fnbox)] -#![feature(iter_arith)] #![feature(mpsc_select)] #![feature(nonzero)] #![feature(on_unimplemented)] @@ -82,12 +81,14 @@ extern crate smallvec; #[macro_use] extern crate style; extern crate time; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] extern crate tinyfiledialogs; extern crate url; #[macro_use] extern crate util; extern crate uuid; +#[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))] +extern crate video_metadata; extern crate webrender_traits; extern crate websocket; extern crate xml5ever; @@ -186,4 +187,3 @@ pub fn init(sw_senders: SWManagerSenders) { pub unsafe fn script_can_initiate_scroll(_: *mut JSContext, _: Handle<*mut JSObject>) -> bool { !opts::get().use_webrender } - diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index d07491d8ce8..dfbb5ba5203 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -120,7 +120,7 @@ pub unsafe fn new_rt_and_cx() -> Runtime { // Pre barriers aren't working correctly at the moment DisableIncrementalGC(runtime.rt()); - set_gc_zeal_options(runtime.cx()); + set_gc_zeal_options(runtime.rt()); // Enable or disable the JITs. let rt_opts = &mut *RuntimeOptionsRef(runtime.rt()); @@ -400,7 +400,7 @@ unsafe extern fn trace_rust_roots(tr: *mut JSTracer, _data: *mut os::raw::c_void #[allow(unsafe_code)] #[cfg(feature = "debugmozjs")] -unsafe fn set_gc_zeal_options(cx: *mut JSContext) { +unsafe fn set_gc_zeal_options(rt: *mut JSRuntime) { use js::jsapi::{JS_DEFAULT_ZEAL_FREQ, JS_SetGCZeal}; let level = match PREFS.get("js.mem.gc.zeal.level").as_i64() { @@ -411,9 +411,9 @@ unsafe fn set_gc_zeal_options(cx: *mut JSContext) { Some(frequency) if frequency >= 0 => frequency as u32, _ => JS_DEFAULT_ZEAL_FREQ, }; - JS_SetGCZeal(cx, level, frequency); + JS_SetGCZeal(rt, level, frequency); } #[allow(unsafe_code)] #[cfg(not(feature = "debugmozjs"))] -unsafe fn set_gc_zeal_options(_: *mut JSContext) {} +unsafe fn set_gc_zeal_options(_: *mut JSRuntime) {} diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index cf0cebf5a65..e3d2766c84c 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -1073,7 +1073,10 @@ impl ScriptThread { fn handle_resize(&self, id: PipelineId, size: WindowSizeData, size_type: WindowSizeType) { if let Some(ref context) = self.find_child_context(id) { - let window = context.active_window(); + let window = match context.find(id) { + Some(browsing_context) => browsing_context.active_window(), + None => return warn!("Message sent to closed pipeline {}.", id), + }; window.set_resize_event(size, size_type); return; } @@ -1142,6 +1145,7 @@ impl ScriptThread { pipeline_port, layout_to_constellation_chan, content_process_shutdown_chan, + layout_threads, } = new_layout_info; let layout_pair = channel(); @@ -1158,6 +1162,7 @@ impl ScriptThread { script_chan: self.control_chan.clone(), image_cache_thread: self.image_cache_thread.clone(), content_process_shutdown_chan: content_process_shutdown_chan, + layout_threads: layout_threads, }; let context = self.root_browsing_context(); @@ -1193,8 +1198,6 @@ impl ScriptThread { // https://html.spec.whatwg.org/multipage/#the-end step 7 let handler = box DocumentProgressHandler::new(Trusted::new(doc)); self.dom_manipulation_task_source.queue(handler, GlobalRef::Window(doc.window())).unwrap(); - - self.constellation_chan.send(ConstellationMsg::LoadComplete(pipeline)).unwrap(); } fn collect_reports(&self, reports_chan: ReportsChan) { @@ -2209,15 +2212,6 @@ fn shut_down_layout(context_tree: &BrowsingContext) { } } -// TODO: remove this function, as it's a source of panic. -pub fn get_browsing_context(context: &BrowsingContext, - pipeline_id: PipelineId) - -> Root<BrowsingContext> { - context.find(pipeline_id).expect("ScriptThread: received an event \ - message for a layout channel that is not associated with this script thread.\ - This is a bug.") -} - fn dom_last_modified(tm: &Tm) -> String { tm.to_local().strftime("%m/%d/%Y %H:%M:%S").unwrap().to_string() } diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index 85f76faadd1..1c24c6fef3f 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -8,15 +8,16 @@ //! active_workers map use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg}; -use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope; +use dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg}; use dom::serviceworkerregistration::longest_prefix_match; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use net_traits::{CustomResponseMediator, CoreResourceMsg}; use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders}; use std::collections::HashMap; -use std::sync::mpsc::{channel, Receiver, RecvError}; +use std::sync::mpsc::{channel, Sender, Receiver, RecvError}; use url::Url; +use util::prefs::PREFS; use util::thread::spawn_named; enum Message { @@ -62,7 +63,7 @@ impl ServiceWorkerManager { }); } - pub fn prepare_activation(&mut self, load_url: &Url) { + pub fn prepare_activation(&mut self, load_url: &Url) -> Option<Sender<ServiceWorkerScriptMsg>> { let mut scope_url = None; for scope in self.registered_workers.keys() { if longest_prefix_match(&scope, load_url) { @@ -75,7 +76,7 @@ impl ServiceWorkerManager { if self.active_workers.contains_key(&scope_url) { // do not run the same worker if already active. warn!("Service worker for {:?} already active", scope_url); - return; + return None; } let scope_things = self.registered_workers.get(&scope_url); if let Some(scope_things) = scope_things { @@ -93,17 +94,19 @@ impl ServiceWorkerManager { page_info)); }; ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(), - sender, + sender.clone(), receiver, devtools_receiver, self.own_sender.clone(), scope_url.clone()); // We store the activated worker self.active_workers.insert(scope_url.clone(), scope_things.clone()); + return Some(sender); } else { warn!("Unable to activate service worker"); } } + None } fn handle_message(&mut self) { @@ -146,11 +149,14 @@ impl ServiceWorkerManager { #[inline] fn handle_message_from_resource(&mut self, mediator: CustomResponseMediator) -> bool { - self.prepare_activation(&mediator.load_url); - // TODO XXXcreativcoder This mediator will need to be send to the appropriate service worker - // so that it may do the sending of custom responses. - // For now we just send a None from here itself - let _ = mediator.response_chan.send(None); + if serviceworker_enabled() { + let worker_sender = self.prepare_activation(&mediator.load_url); + if let Some(ref sender) = worker_sender { + let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator)); + } + } else { + let _ = mediator.response_chan.send(None); + } true } @@ -164,3 +170,7 @@ impl ServiceWorkerManager { } } } + +pub fn serviceworker_enabled() -> bool { + PREFS.get("dom.serviceworker.enabled").as_boolean().unwrap_or(false) +} diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 2711cfb1225..74a754c36ce 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -34,7 +34,6 @@ use msg::constellation_msg::PipelineId; use net_traits::CookieSource::{HTTP, NonHTTP}; use net_traits::CoreResourceMsg::{GetCookiesDataForUrl, SetCookiesForUrlWithData}; use net_traits::IpcSend; -use script_thread::get_browsing_context; use script_traits::webdriver_msg::WebDriverCookieError; use script_traits::webdriver_msg::{WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue}; use url::Url; @@ -43,7 +42,11 @@ fn find_node_by_unique_id(context: &BrowsingContext, pipeline: PipelineId, node_id: String) -> Option<Root<Node>> { - let context = get_browsing_context(&context, pipeline); + let context = match context.find(pipeline) { + Some(context) => context, + None => return None + }; + let document = context.active_document(); document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id) } @@ -72,7 +75,11 @@ pub fn handle_execute_script(context: &BrowsingContext, pipeline: PipelineId, eval: String, reply: IpcSender<WebDriverJSResult>) { - let context = get_browsing_context(&context, pipeline); + let context = match context.find(pipeline) { + Some(context) => context, + None => return reply.send(Err(WebDriverJSError::BrowsingContextNotFound)).unwrap() + }; + let window = context.active_window(); let result = unsafe { let cx = window.get_cx(); @@ -87,7 +94,11 @@ pub fn handle_execute_async_script(context: &BrowsingContext, pipeline: PipelineId, eval: String, reply: IpcSender<WebDriverJSResult>) { - let context = get_browsing_context(&context, pipeline); + let context = match context.find(pipeline) { + Some(context) => context, + None => return reply.send(Err(WebDriverJSError::BrowsingContextNotFound)).unwrap() + }; + let window = context.active_window(); let cx = window.get_cx(); window.set_webdriver_script_chan(Some(reply)); diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index d4a71804900..cbd8d65b72e 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -18,7 +18,7 @@ euclid = "0.7.1" gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" libc = "0.2" log = "0.3.5" msg = {path = "../msg"} diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 4fbed81429d..b46703e778e 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -149,4 +149,5 @@ pub struct NewLayoutThreadInfo { pub image_cache_thread: ImageCacheThread, pub paint_chan: OptionalOpaqueIpcSender, pub content_process_shutdown_chan: IpcSender<()>, + pub layout_threads: usize, } diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 67a229cbb80..47fc10b95c7 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -18,7 +18,7 @@ euclid = "0.7.1" gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]} libc = "0.2" msg = {path = "../msg"} @@ -27,8 +27,8 @@ offscreen_gl_context = "0.1.2" plugins = {path = "../plugins"} profile_traits = {path = "../profile_traits"} rustc-serialize = "0.3.4" -serde = "0.7.11" -serde_macros = "0.7.11" +serde = "0.7.15" +serde_macros = "0.7.15" style_traits = {path = "../style_traits", features = ["servo"]} time = "0.1.12" url = {version = "1.0.0", features = ["heap_size"]} diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 7731e16743d..8269ca318ed 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -146,6 +146,8 @@ pub struct NewLayoutInfo { pub layout_to_constellation_chan: IpcSender<LayoutMsg>, /// A shutdown channel so that layout can tell the content process to shut down when it's done. pub content_process_shutdown_chan: IpcSender<()>, + /// Number of threads to use for layout. + pub layout_threads: usize, } /// Messages sent from the constellation or layout to the script thread. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 3ba4494432b..58a49165448 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -59,6 +59,7 @@ pub enum LogEntry { /// Messages from the script to the constellation. #[derive(Deserialize, Serialize)] +#[serde(bound = "")] // Prevent serde from generating cyclic bounds. pub enum ScriptMsg { /// Indicates whether this pipeline is currently running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), @@ -70,10 +71,6 @@ pub enum ScriptMsg { CreateWebGLPaintThread(Size2D<i32>, GLContextAttributes, IpcSender<Result<(IpcSender<CanvasMsg>, GLLimits), String>>), - /// Dispatched after the DOM load event has fired on a document - /// Causes a `load` event to be dispatched to any enclosing frame context element - /// for the given pipeline. - DOMLoad(PipelineId), /// Notifies the constellation that this frame has received focus. Focus(PipelineId), /// Re-send a mouse button event that was sent to the parent window. @@ -84,7 +81,8 @@ pub enum ScriptMsg { GetClipboardContents(IpcSender<String>), /// <head> tag finished parsing HeadParsed, - /// All pending loads are complete. + /// All pending loads are complete, and the `load` event for this pipeline + /// has been dispatched. LoadComplete(PipelineId), /// A new load has been requested. LoadUrl(PipelineId, LoadData), diff --git a/components/script_traits/webdriver_msg.rs b/components/script_traits/webdriver_msg.rs index 0694c97f29d..09d3c9e9e1c 100644 --- a/components/script_traits/webdriver_msg.rs +++ b/components/script_traits/webdriver_msg.rs @@ -53,7 +53,10 @@ pub enum WebDriverJSValue { #[derive(Deserialize, Serialize)] pub enum WebDriverJSError { Timeout, - UnknownType + UnknownType, + /// Occurs when handler received an event message for a layout channel that is not + /// associated with the current script thread + BrowsingContextNotFound } pub type WebDriverJSResult = Result<WebDriverJSValue, WebDriverJSError>; diff --git a/components/servo/.cargo/config b/components/servo/.cargo/config index dffe440072c..1cea095353f 100644 --- a/components/servo/.cargo/config +++ b/components/servo/.cargo/config @@ -9,3 +9,6 @@ ar = "arm-linux-gnueabihf-ar" [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" ar = "aarch64-linux-gnu-ar" + +[target.'cfg(target_os=windows)'] +linker = "./fake-ld.cmd"
\ No newline at end of file diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index b881a7c3ac4..55e2ebc8d87 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -19,7 +19,7 @@ dependencies = [ "gfx_tests 0.0.1", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "glutin_app 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layout 0.0.1", "layout_tests 0.0.1", "layout_thread 0.0.1", @@ -83,7 +83,7 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -97,7 +97,7 @@ dependencies = [ [[package]] name = "aster" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -113,8 +113,8 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "servo-skia 0.20130412.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -152,7 +152,7 @@ dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -209,7 +209,7 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -228,10 +228,10 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)", ] @@ -307,7 +307,7 @@ dependencies = [ "gfx_traits 0.0.1", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -315,8 +315,8 @@ dependencies = [ "plugins 0.0.1", "profile_traits 0.0.1", "script_traits 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -338,7 +338,7 @@ dependencies = [ "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", "gfx_traits 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "layout_traits 0.0.1", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -349,8 +349,8 @@ dependencies = [ "profile_traits 0.0.1", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", @@ -374,7 +374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -403,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -430,8 +430,8 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -482,13 +482,13 @@ version = "0.0.1" dependencies = [ "devtools_traits 0.0.1", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] @@ -501,10 +501,10 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -658,7 +658,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -758,7 +758,7 @@ dependencies = [ "harfbuzz-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -771,8 +771,8 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "range 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "simd 0.1.0 (git+https://github.com/huonw/simd)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -792,7 +792,7 @@ name = "gfx_tests" version = "0.0.1" dependencies = [ "gfx 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", ] @@ -810,8 +810,8 @@ dependencies = [ "profile_traits 0.0.1", "range 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -938,8 +938,8 @@ dependencies = [ "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -965,7 +965,7 @@ dependencies = [ "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -997,7 +997,7 @@ dependencies = [ "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1031,13 +1031,13 @@ dependencies = [ [[package]] name = "ipc-channel" version = "0.4.0" -source = "git+https://github.com/servo/ipc-channel#346456b792f0a8e86b4ed077997408a697a06a0f" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bincode 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1053,7 +1053,7 @@ dependencies = [ [[package]] name = "js" version = "0.1.3" -source = "git+https://github.com/servo/rust-mozjs#bc9add648b3174120d70d0bef3935912bd6f1313" +source = "git+https://github.com/servo/rust-mozjs#14e4556d7cd3dc4fd5eaf5e19e725a1325be14e6" dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1119,7 +1119,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -1131,7 +1131,7 @@ dependencies = [ "script_layout_interface 0.0.1", "script_traits 0.0.1", "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -1162,7 +1162,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layout 0.0.1", "layout_traits 0.0.1", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1174,7 +1174,7 @@ dependencies = [ "script_layout_interface 0.0.1", "script_traits 0.0.1", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", @@ -1186,7 +1186,7 @@ name = "layout_traits" version = "0.0.1" dependencies = [ "gfx 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "net_traits 0.0.1", "profile_traits 0.0.1", @@ -1310,7 +1310,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1319,8 +1319,8 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1336,7 +1336,7 @@ dependencies = [ [[package]] name = "mozjs_sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#2af5849a97a9f18acd482940ba3fa0c6797ed7eb" +source = "git+https://github.com/servo/mozjs#94eabc218780b696933122184e524bd35544c378" dependencies = [ "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1351,10 +1351,10 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)", ] @@ -1372,7 +1372,7 @@ dependencies = [ "flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "immeta 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1418,7 +1418,7 @@ dependencies = [ "devtools_traits 0.0.1", "flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "net 0.0.1", "net_traits 0.0.1", @@ -1439,13 +1439,13 @@ dependencies = [ "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1554,7 +1554,7 @@ dependencies = [ "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1617,42 +1617,42 @@ dependencies = [ [[package]] name = "phf" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_codegen" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_generator" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_macros" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_shared" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1689,13 +1689,12 @@ dependencies = [ [[package]] name = "png" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1704,15 +1703,15 @@ name = "profile" version = "0.0.1" dependencies = [ "heartbeats-simple 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "profile_traits 0.0.1", "regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "task_info 0.0.1", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", @@ -1722,7 +1721,7 @@ dependencies = [ name = "profile_tests" version = "0.0.1" dependencies = [ - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "profile 0.0.1", "profile_traits 0.0.1", ] @@ -1733,32 +1732,32 @@ version = "0.0.1" dependencies = [ "energy-monitor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "energymon 0.2.0 (git+https://github.com/energymon/energymon-rust.git)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quasi_codegen" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi_macros" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quasi_codegen 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1786,8 +1785,8 @@ dependencies = [ "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1871,7 +1870,7 @@ dependencies = [ "html5ever 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "js 0.1.3 (git+https://github.com/servo/rust-mozjs)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1882,8 +1881,8 @@ dependencies = [ "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_macros 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "profile_traits 0.0.1", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1895,7 +1894,7 @@ dependencies = [ "script_layout_interface 0.0.1", "script_traits 0.0.1", "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -1904,6 +1903,7 @@ dependencies = [ "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "video-metadata 0.1.3 (git+https://github.com/GuillaumeGomez/video-metadata-rs)", "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)", "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1921,7 +1921,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -1959,7 +1959,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -1968,8 +1968,8 @@ dependencies = [ "plugins 0.0.1", "profile_traits 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1999,23 +1999,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_codegen" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_macros 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_item 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen_internals 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "serde_item" -version = "0.2.0" +name = "serde_codegen_internals" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2024,15 +2024,15 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_macros" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_codegen 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2169,9 +2169,9 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_generator 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2197,8 +2197,8 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", @@ -2233,8 +2233,8 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2316,8 +2316,9 @@ dependencies = [ [[package]] name = "tinyfiledialogs" version = "0.1.0" -source = "git+https://github.com/jdm/tinyfiledialogs#3a30f8f95686195cb3bcecfc77ff77277a624a53" +source = "git+https://github.com/jdm/tinyfiledialogs#54f6aa4f579edbc726b8a764fd759a6d6ed0dd84" dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2379,7 +2380,7 @@ dependencies = [ "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2413,14 +2414,14 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2438,7 +2439,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "video-metadata" +version = "0.1.3" +source = "git+https://github.com/GuillaumeGomez/video-metadata-rs#44c8d547f9212be5d368a38d9f1238d85bc6728e" +dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2526,7 +2538,7 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "plugins 0.0.1", @@ -2542,7 +2554,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.1.0" -source = "git+https://github.com/servo/webrender#fd38ab8994be39ba194f56182af8c467b4f9f929" +source = "git+https://github.com/servo/webrender#79b807160ea3c3cf558072813c51a59bbaccb8dd" dependencies = [ "app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2553,7 +2565,7 @@ dependencies = [ "fnv 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2566,7 +2578,7 @@ dependencies = [ [[package]] name = "webrender_traits" version = "0.2.0" -source = "git+https://github.com/servo/webrender_traits#d86e51ace4fd1b43123e0490dc80f631be0726d0" +source = "git+https://github.com/servo/webrender_traits#a26ebe4da490cc1fb60d830c73cbefb135b768b1" dependencies = [ "app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2574,10 +2586,10 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2658,8 +2670,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index ba9279d35fc..9a809f5148b 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -56,7 +56,7 @@ euclid = "0.7.1" gfx = {path = "../gfx"} gleam = "0.2" glutin_app = {path = "../../ports/glutin"} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" layout = {path = "../layout"} layout_thread = {path = "../layout_thread"} libc = "0.2" diff --git a/components/servo/fake-ld.cmd b/components/servo/fake-ld.cmd new file mode 100644 index 00000000000..b13c7e818ab --- /dev/null +++ b/components/servo/fake-ld.cmd @@ -0,0 +1,2 @@ +@echo off +gcc -mwindows %* diff --git a/components/servo/lib.rs b/components/servo/lib.rs index d96da810889..515f4d898a7 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -150,6 +150,7 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static { enable_aa: opts.enable_text_antialiasing, enable_msaa: opts.use_msaa, enable_profiler: opts.webrender_stats, + debug: opts.webrender_debug, }); (Some(webrender), Some(webrender_sender)) } else { @@ -239,7 +240,8 @@ fn create_constellation(opts: opts::Opts, let (public_resource_threads, private_resource_threads) = new_resource_threads(opts.user_agent.clone(), devtools_chan.clone(), - time_profiler_chan.clone()); + time_profiler_chan.clone(), + opts.config_dir.map(Into::into)); let image_cache_thread = new_image_cache_thread(public_resource_threads.sender(), webrender_api_sender.as_ref().map(|wr| wr.create_api())); let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(), diff --git a/components/servo/main.rs b/components/servo/main.rs index a13c2ca8b5d..64112fde54b 100644 --- a/components/servo/main.rs +++ b/components/servo/main.rs @@ -70,7 +70,10 @@ fn install_crash_handler() { } } - signal!(Sig::SEGV, handler); + signal!(Sig::SEGV, handler); // handle segfaults + signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs + signal!(Sig::IOT, handler); // handle double panics + signal!(Sig::BUS, handler); // handle invalid memory access } #[cfg(target_os = "android")] diff --git a/components/servo/servo.exe.manifest b/components/servo/servo.exe.manifest index 3748cdaca40..198d8d51709 100644 --- a/components/servo/servo.exe.manifest +++ b/components/servo/servo.exe.manifest @@ -6,7 +6,7 @@ name="servo.Servo" version="0.1.0.0"/> - <compatibility> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!-- Windows 7 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!-- Windows 8 --> diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index c9a1da6fccf..71898ea32e0 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -38,8 +38,8 @@ num-traits = "0.1.32" rand = "0.3" rustc-serialize = "0.3" selectors = "0.7" -serde = {version = "0.7.11", optional = true} -serde_macros = {version = "0.7.11", optional = true} +serde = {version = "0.7.15", optional = true} +serde_macros = {version = "0.7.15", optional = true} smallvec = "0.1" string_cache = "0.2.20" style_traits = {path = "../style_traits"} diff --git a/components/style/animation.rs b/components/style/animation.rs index c36cde3caea..a4600418023 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -668,3 +668,29 @@ where Damage: TRestyleDamage { } } } + +/// Update the style in the node when it finishes. +pub fn complete_expired_transitions(node: OpaqueNode, style: &mut Arc<ComputedValues>, + context: &SharedStyleContext) -> bool { + let had_animations_to_expire; + { + let all_expired_animations = context.expired_animations.read().unwrap(); + let animations_to_expire = all_expired_animations.get(&node); + had_animations_to_expire = animations_to_expire.is_some(); + if let Some(ref animations) = animations_to_expire { + for animation in *animations { + // TODO: support animation-fill-mode + if let Animation::Transition(_, _, ref frame, _) = *animation { + frame.property_animation.update(Arc::make_mut(style), 1.0); + } + } + } + } + + if had_animations_to_expire { + context.expired_animations.write().unwrap().remove(&node); + } + + had_animations_to_expire +} + diff --git a/components/style/attr.rs b/components/style/attr.rs index af7cfa015f6..fc741d61575 100644 --- a/components/style/attr.rs +++ b/components/style/attr.rs @@ -92,17 +92,17 @@ pub fn parse_double(string: &str) -> Result<f64, ()> { let trimmed = string.trim_matches(HTML_SPACE_CHARACTERS); let mut input = trimmed.chars().peekable(); - let (value, divisor) = match input.peek() { + let (value, divisor, chars_skipped) = match input.peek() { None => return Err(()), Some(&'-') => { input.next(); - (-1f64, -1f64) + (-1f64, -1f64, 1) } Some(&'+') => { input.next(); - (1f64, 1f64) + (1f64, 1f64, 1) } - _ => (1f64, 1f64) + _ => (1f64, 1f64, 0) }; let (value, value_digits) = if let Some(&'.') = input.peek() { @@ -112,11 +112,11 @@ pub fn parse_double(string: &str) -> Result<f64, ()> { (value * read_val.and_then(|result| result.to_f64()).unwrap_or(1f64), read_digits) }; - let input = trimmed.chars().skip(value_digits).peekable(); + let input = trimmed.chars().skip(value_digits + chars_skipped).peekable(); let (mut value, fraction_digits) = read_fraction(input, divisor, value); - let input = trimmed.chars().skip(value_digits + fraction_digits).peekable(); + let input = trimmed.chars().skip(value_digits + chars_skipped + fraction_digits).peekable(); if let Some(exp) = read_exponent(input) { value *= 10f64.powi(exp) diff --git a/components/style/data.rs b/components/style/data.rs index 906848998fb..44920c72c98 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -37,13 +37,13 @@ impl PrivateStyleData { #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct DomParallelInfo { /// The number of children that still need work done. - pub children_count: AtomicIsize, + pub children_to_process: AtomicIsize, } impl DomParallelInfo { pub fn new() -> DomParallelInfo { DomParallelInfo { - children_count: AtomicIsize::new(0), + children_to_process: AtomicIsize::new(0), } } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 5c5f3905d8d..c694ca75732 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -111,33 +111,10 @@ pub trait TNode : Sized + Copy + Clone { unsafe fn set_dirty_descendants(&self, value: bool); - fn dirty_self(&self) { - unsafe { - self.set_dirty(true); - self.set_dirty_descendants(true); - } - } - - fn dirty_descendants(&self) { - for ref child in self.children() { - child.dirty_self(); - child.dirty_descendants(); - } - } - fn needs_dirty_on_viewport_size_changed(&self) -> bool; unsafe fn set_dirty_on_viewport_size_changed(&self); - fn set_descendants_dirty_on_viewport_size_changed(&self) { - for ref child in self.children() { - unsafe { - child.set_dirty_on_viewport_size_changed(); - } - child.set_descendants_dirty_on_viewport_size_changed(); - } - } - fn can_be_fragmented(&self) -> bool; unsafe fn set_can_be_fragmented(&self, value: bool); @@ -215,7 +192,7 @@ pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynt fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool; /// Properly marks nodes as dirty in response to restyle hints. - fn note_restyle_hint(&self, mut hint: RestyleHint) { + fn note_restyle_hint(&self, hint: RestyleHint) { // Bail early if there's no restyling to do. if hint.is_empty() { return; @@ -233,23 +210,21 @@ pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynt // Process hints. if hint.contains(RESTYLE_SELF) { - node.dirty_self(); - - // FIXME(bholley, #8438): We currently need to RESTYLE_DESCENDANTS in the - // RESTYLE_SELF case in order to make sure "inherit" style structs propagate - // properly. See the explanation in the github issue. - hint.insert(RESTYLE_DESCENDANTS); - } - if hint.contains(RESTYLE_DESCENDANTS) { - unsafe { node.set_dirty_descendants(true); } - node.dirty_descendants(); + unsafe { node.set_dirty(true); } + // XXX(emilio): For now, dirty implies dirty descendants if found. + } else if hint.contains(RESTYLE_DESCENDANTS) { + let mut current = node.first_child(); + while let Some(node) = current { + unsafe { node.set_dirty(true); } + current = node.next_sibling(); + } } + if hint.contains(RESTYLE_LATER_SIBLINGS) { let mut next = ::selectors::Element::next_sibling_element(self); while let Some(sib) = next { let sib_node = sib.as_node(); - sib_node.dirty_self(); - sib_node.dirty_descendants(); + unsafe { sib_node.set_dirty(true) }; next = ::selectors::Element::next_sibling_element(&sib); } } @@ -262,12 +237,16 @@ pub struct TreeIterator<ConcreteNode> where ConcreteNode: TNode { impl<ConcreteNode> TreeIterator<ConcreteNode> where ConcreteNode: TNode { fn new(root: ConcreteNode) -> TreeIterator<ConcreteNode> { - let mut stack = vec!(); + let mut stack = vec![]; stack.push(root); TreeIterator { stack: stack, } } + + pub fn next_skipping_children(&mut self) -> Option<ConcreteNode> { + self.stack.pop() + } } impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode> diff --git a/components/style/gecko_conversions.rs b/components/style/gecko_conversions.rs index 95ab9eb8b00..56e2e3bbc5f 100644 --- a/components/style/gecko_conversions.rs +++ b/components/style/gecko_conversions.rs @@ -8,7 +8,7 @@ use app_units::Au; use gecko_bindings::structs::nsStyleCoord_CalcValue; -use values::computed::CalcLengthOrPercentage; +use values::computed::{CalcLengthOrPercentage, LengthOrPercentage}; impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue { fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue { @@ -34,3 +34,35 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage { } } } + +impl From<LengthOrPercentage> for nsStyleCoord_CalcValue { + fn from(other: LengthOrPercentage) -> nsStyleCoord_CalcValue { + match other { + LengthOrPercentage::Length(au) => { + nsStyleCoord_CalcValue { + mLength: au.0, + mPercent: 0.0, + mHasPercent: false, + } + }, + LengthOrPercentage::Percentage(pc) => { + nsStyleCoord_CalcValue { + mLength: 0, + mPercent: pc, + mHasPercent: true, + } + }, + LengthOrPercentage::Calc(calc) => calc.into(), + } + } +} + +impl From<nsStyleCoord_CalcValue> for LengthOrPercentage { + fn from(other: nsStyleCoord_CalcValue) -> LengthOrPercentage { + match (other.mHasPercent, other.mLength) { + (false, _) => LengthOrPercentage::Length(Au(other.mLength)), + (true, 0) => LengthOrPercentage::Percentage(other.mPercent), + _ => LengthOrPercentage::Calc(other.into()), + } + } +} diff --git a/components/style/gecko_selector_impl.rs b/components/style/gecko_selector_impl.rs index ed99fd39758..5798222cb07 100644 --- a/components/style/gecko_selector_impl.rs +++ b/components/style/gecko_selector_impl.rs @@ -44,7 +44,8 @@ pub enum PseudoElement { // https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum AnonBoxPseudoElement { - MozNonElement, + MozText, + MozOtherNonElement, MozAnonymousBlock, MozAnonymousPositionedBlock, MozMathMLAnonymousBlock, @@ -67,7 +68,7 @@ pub enum AnonBoxPseudoElement { MozTableCell, MozTableColumnGroup, MozTableColumn, - MozTableOuter, + MozTableWrapper, MozTableRowGroup, MozTableRow, @@ -214,7 +215,8 @@ impl SelectorImpl for GeckoSelectorImpl { } Ok(AnonBox(match_ignore_ascii_case! { name, - "-moz-non-element" => MozNonElement, + "-moz-text" => MozText, + "-moz-other-non-element" => MozOtherNonElement, "-moz-anonymous-block" => MozAnonymousBlock, "-moz-anonymous-positioned-block" => MozAnonymousPositionedBlock, @@ -240,7 +242,7 @@ impl SelectorImpl for GeckoSelectorImpl { "-moz-table-cell" => MozTableCell, "-moz-table-column-group" => MozTableColumnGroup, "-moz-table-column" => MozTableColumn, - "-moz-table-outer" => MozTableOuter, + "-moz-table-wrapper" => MozTableWrapper, "-moz-table-row-group" => MozTableRowGroup, "-moz-table-row" => MozTableRow, @@ -305,7 +307,8 @@ impl SelectorImplExt for GeckoSelectorImpl { fun(After); fun(FirstLine); - fun(AnonBox(MozNonElement)); + fun(AnonBox(MozText)); + fun(AnonBox(MozOtherNonElement)); fun(AnonBox(MozAnonymousBlock)); fun(AnonBox(MozAnonymousPositionedBlock)); fun(AnonBox(MozMathMLAnonymousBlock)); @@ -328,7 +331,7 @@ impl SelectorImplExt for GeckoSelectorImpl { fun(AnonBox(MozTableCell)); fun(AnonBox(MozTableColumnGroup)); fun(AnonBox(MozTableColumn)); - fun(AnonBox(MozTableOuter)); + fun(AnonBox(MozTableWrapper)); fun(AnonBox(MozTableRowGroup)); fun(AnonBox(MozTableRow)); diff --git a/components/style/matching.rs b/components/style/matching.rs index 2c4dfc990cd..2cd51352355 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -466,25 +466,8 @@ trait PrivateMatchMethods: TNode // Finish any expired transitions. let this_opaque = self.opaque(); - let had_animations_to_expire; - { - let all_expired_animations = context.expired_animations.read().unwrap(); - let animations_to_expire = all_expired_animations.get(&this_opaque); - had_animations_to_expire = animations_to_expire.is_some(); - if let Some(ref animations) = animations_to_expire { - for animation in *animations { - // NB: Expiring a keyframes animation is the same as not - // applying the keyframes style to it, so we're safe. - if let Animation::Transition(_, _, ref frame, _) = *animation { - frame.property_animation.update(Arc::make_mut(style), 1.0); - } - } - } - } - - if had_animations_to_expire { - context.expired_animations.write().unwrap().remove(&this_opaque); - } + let had_animations_to_expire = + animation::complete_expired_transitions(this_opaque, style, context); // Merge any running transitions into the current style, and cancel them. let had_running_animations = context.running_animations diff --git a/components/style/parallel.rs b/components/style/parallel.rs index 0bc840f7492..b82727657c3 100644 --- a/components/style/parallel.rs +++ b/components/style/parallel.rs @@ -63,25 +63,40 @@ fn top_down_dom<N, C>(unsafe_nodes: UnsafeNodeList, // Get a real layout node. let node = unsafe { N::from_unsafe(&unsafe_node) }; + if !context.should_process(node) { + continue; + } + // Perform the appropriate traversal. context.process_preorder(node); - let child_count = node.children_count(); + // Possibly enqueue the children. + let mut children_to_process = 0isize; + for kid in node.children() { + // Trigger the hook pre-adding the kid to the list. This can (and in + // fact uses to) change the result of the should_process operation. + // + // As of right now, this hook takes care of propagating the restyle + // flag down the tree. In the future, more accurate behavior is + // probably going to be needed. + context.pre_process_child_hook(node, kid); + if context.should_process(kid) { + children_to_process += 1; + discovered_child_nodes.push(kid.to_unsafe()) + } + } // Reset the count of children. { let data = node.mutate_data().unwrap(); - data.parallel.children_count.store(child_count as isize, - Ordering::Relaxed); + data.parallel.children_to_process + .store(children_to_process, + Ordering::Relaxed); } - // Possibly enqueue the children. - if child_count != 0 { - for kid in node.children() { - discovered_child_nodes.push(kid.to_unsafe()) - } - } else { - // If there were no more children, start walking back up. + + // If there were no more children, start walking back up. + if children_to_process == 0 { bottom_up_dom::<N, C>(unsafe_nodes.1, unsafe_node, proxy) } } @@ -128,7 +143,7 @@ fn bottom_up_dom<N, C>(root: OpaqueNode, if parent_data .parallel - .children_count + .children_to_process .fetch_sub(1, Ordering::Relaxed) != 1 { // Get out of here and find another node to work on. break @@ -138,4 +153,3 @@ fn bottom_up_dom<N, C>(root: OpaqueNode, node = parent; } } - diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 1386d6486dd..7c63356ca22 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -18,11 +18,15 @@ def to_camel_case(ident): class Keyword(object): def __init__(self, name, values, gecko_constant_prefix=None, + gecko_enum_prefix=None, extra_gecko_values=None, extra_servo_values=None): self.name = name self.values = values.split() + if gecko_constant_prefix and gecko_enum_prefix: + raise TypeError("Only one of gecko_constant_prefix and gecko_enum_prefix can be specified") self.gecko_constant_prefix = gecko_constant_prefix or \ "NS_STYLE_" + self.name.upper().replace("-", "_") + self.gecko_enum_prefix = gecko_enum_prefix self.extra_gecko_values = (extra_gecko_values or "").split() self.extra_servo_values = (extra_servo_values or "").split() @@ -41,7 +45,18 @@ class Keyword(object): raise Exception("Bad product: " + product) def gecko_constant(self, value): - return self.gecko_constant_prefix + "_" + value.replace("-moz-", "").replace("-", "_").upper() + if self.gecko_enum_prefix: + if value == "none": + return self.gecko_enum_prefix + "::None_" + else: + parts = value.replace("-moz-", "").split("-") + parts = [p.title() for p in parts] + return self.gecko_enum_prefix + "::" + "".join(parts) + else: + return self.gecko_constant_prefix + "_" + value.replace("-moz-", "").replace("-", "_").upper() + + def needs_cast(self): + return self.gecko_enum_prefix is None class Longhand(object): diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 2209651b18b..24893da9f7b 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -194,7 +194,11 @@ def set_gecko_property(ffi_name, expr): // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts let result = match v { % for value in keyword.values_for('gecko'): - Keyword::${to_rust_ident(value)} => structs::${keyword.gecko_constant(value)} as u8, + % if keyword.needs_cast(): + Keyword::${to_rust_ident(value)} => structs::${keyword.gecko_constant(value)} as u8, + % else: + Keyword::${to_rust_ident(value)} => structs::${keyword.gecko_constant(value)}, + % endif % endfor }; ${set_gecko_property(gecko_ffi_name, "result")} @@ -657,9 +661,10 @@ fn static_assert() { use gecko_bindings::structs::nsStyleUnit; // z-index is never a calc(). If it were, we'd be leaking here, so // assert that it isn't. - debug_assert!(self.gecko.mZIndex.mUnit != nsStyleUnit::eStyleUnit_Calc); - self.gecko.mZIndex.mUnit = other.gecko.mZIndex.mUnit; - self.gecko.mZIndex.mValue = other.gecko.mZIndex.mValue; + debug_assert!(self.gecko.mZIndex.unit() != nsStyleUnit::eStyleUnit_Calc); + unsafe { + self.gecko.mZIndex.copy_from_unchecked(&other.gecko.mZIndex); + } } pub fn clone_z_index(&self) -> longhands::z_index::computed_value::T { @@ -917,7 +922,8 @@ fn static_assert() { // add support for parsing these lists in servo and pushing to nsTArray's. <% skip_background_longhands = """background-color background-repeat background-image background-clip - background-origin background-attachment""" %> + background-origin background-attachment + background-position""" %> <%self:impl_trait style_struct_name="Background" skip_longhands="${skip_background_longhands}" skip_additionals="*"> @@ -1005,6 +1011,29 @@ fn static_assert() { }; } + pub fn copy_background_position_from(&mut self, other: &Self) { + self.gecko.mImage.mPositionXCount = cmp::min(1, other.gecko.mImage.mPositionXCount); + self.gecko.mImage.mPositionYCount = cmp::min(1, other.gecko.mImage.mPositionYCount); + self.gecko.mImage.mLayers.mFirstElement.mPosition = + other.gecko.mImage.mLayers.mFirstElement.mPosition; + } + + pub fn clone_background_position(&self) -> longhands::background_position::computed_value::T { + let position = &self.gecko.mImage.mLayers.mFirstElement.mPosition; + longhands::background_position::computed_value::T { + horizontal: position.mXPosition.into(), + vertical: position.mYPosition.into(), + } + } + + pub fn set_background_position(&mut self, v: longhands::background_position::computed_value::T) { + let position = &mut self.gecko.mImage.mLayers.mFirstElement.mPosition; + position.mXPosition = v.horizontal.into(); + position.mYPosition = v.vertical.into(); + self.gecko.mImage.mPositionXCount = 1; + self.gecko.mImage.mPositionYCount = 1; + } + pub fn copy_background_image_from(&mut self, other: &Self) { unsafe { Gecko_CopyImageValueFrom(&mut self.gecko.mImage.mLayers.mFirstElement.mImage, @@ -1093,7 +1122,7 @@ fn static_assert() { Gecko_SetGradientImageValue(&mut geckoimage.mImage, gecko_gradient); } }, - Image::Url(_) => { + Image::Url(..) => { // let utf8_bytes = url.as_bytes(); // Gecko_SetUrlImageValue(&mut self.gecko.mImage.mLayers.mFirstElement, // utf8_bytes.as_ptr() as *const _, diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 40bef518de9..fc6caa1cda3 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -289,7 +289,8 @@ <%def name="single_keyword_computed(name, values, **kwargs)"> <% keyword_kwargs = {a: kwargs.pop(a, None) for a in [ - 'gecko_constant_prefix', 'extra_gecko_values', 'extra_servo_values' + 'gecko_constant_prefix', 'gecko_enum_prefix', + 'extra_gecko_values', 'extra_servo_values', ]} %> <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> @@ -317,7 +318,8 @@ <%def name="keyword_list(name, values, **kwargs)"> <% keyword_kwargs = {a: kwargs.pop(a, None) for a in [ - 'gecko_constant_prefix', 'extra_gecko_values', 'extra_servo_values' + 'gecko_constant_prefix', 'gecko_enum_prefix', + 'extra_gecko_values', 'extra_servo_values', ]} %> <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index f5708c5ede8..501a98fd7fa 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -28,7 +28,7 @@ ${helpers.predefined_type("background-color", "CSSColor", fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match self.0 { None => dest.write_str("none"), - Some(computed::Image::Url(ref url)) => url.to_css(dest), + Some(computed::Image::Url(ref url, ref _extra_data)) => url.to_css(dest), Some(computed::Image::LinearGradient(ref gradient)) => gradient.to_css(dest) } diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index cbf97ecc0be..da34a5f8425 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -82,6 +82,6 @@ ${helpers.single_keyword("box-decoration-break", "slice clone", ${helpers.single_keyword("-moz-float-edge", "content-box margin-box", gecko_ffi_name="mFloatEdge", - gecko_constant_prefix="NS_STYLE_FLOAT_EDGE", + gecko_enum_prefix="StyleFloatEdge", products="gecko", animatable=False)} diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 87af34df33e..a00f0c01393 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -914,19 +914,12 @@ ${helpers.single_keyword("-moz-appearance", use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI}; use std::fmt::{self, Write}; use url::Url; + use values::specified::UrlExtraData; use values::computed::ComputedValueAsSpecified; use values::NoViewportPercentage; #[derive(PartialEq, Clone, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct UrlExtraData { - pub base: GeckoArcURI, - pub referrer: GeckoArcURI, - pub principal: GeckoArcPrincipal, - } - - #[derive(PartialEq, Clone, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum SpecifiedValue { Url(Url, UrlExtraData), None, diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/pointing.mako.rs index 3bdb71d2392..859a71527ba 100644 --- a/components/style/properties/longhand/pointing.mako.rs +++ b/components/style/properties/longhand/pointing.mako.rs @@ -71,5 +71,5 @@ ${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only", ${helpers.single_keyword("-moz-user-focus", "ignore normal select-after select-before select-menu select-same select-all none", products="gecko", gecko_ffi_name="mUserFocus", - gecko_constant_prefix="NS_STYLE_USER_FOCUS", + gecko_enum_prefix="StyleUserFocus", animatable=False)} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index cb9ef5152df..83ad6b73d82 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2146,10 +2146,6 @@ pub fn modify_style_for_input_text(style: &mut Arc<ComputedValues>) { margin_style.margin_right = computed::LengthOrPercentageOrAuto::Length(Au(0)); margin_style.margin_bottom = computed::LengthOrPercentageOrAuto::Length(Au(0)); margin_style.margin_left = computed::LengthOrPercentageOrAuto::Length(Au(0)); - - // whitespace inside text input should not be collapsed - let inherited_text = Arc::make_mut(&mut style.inheritedtext); - inherited_text.white_space = longhands::white_space::computed_value::T::pre; } /// Adjusts the `clip` property so that an inline absolute hypothetical fragment doesn't clip its diff --git a/components/style/sequential.rs b/components/style/sequential.rs index a5a9b519e57..56b8a563d27 100644 --- a/components/style/sequential.rs +++ b/components/style/sequential.rs @@ -9,20 +9,29 @@ use traversal::DomTraversalContext; pub fn traverse_dom<N, C>(root: N, shared: &C::SharedContext) - where N: TNode, - C: DomTraversalContext<N> { + where N: TNode, + C: DomTraversalContext<N> +{ fn doit<'a, N, C>(context: &'a C, node: N) - where N: TNode, C: DomTraversalContext<N> { + where N: TNode, + C: DomTraversalContext<N> + { + debug_assert!(context.should_process(node)); context.process_preorder(node); for kid in node.children() { - doit::<N, C>(context, kid); + context.pre_process_child_hook(node, kid); + if context.should_process(node) { + doit::<N, C>(context, kid); + } } context.process_postorder(node); } let context = C::new(shared, root.opaque()); - doit::<N, C>(&context, root); + if context.should_process(root) { + doit::<N, C>(&context, root); + } } diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 76f8539c72f..d1cf9eb833b 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -4,6 +4,7 @@ //! Traversing the DOM tree; the bloom filter. +use animation; use context::{SharedStyleContext, StyleContext}; use dom::{OpaqueNode, TElement, TNode, TRestyleDamage, UnsafeNode}; use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult}; @@ -11,6 +12,7 @@ use selector_impl::SelectorImplExt; use selectors::Element; use selectors::bloom::BloomFilter; use std::cell::RefCell; +use std::sync::Arc; use tid::tid; use util::opts; use values::HasViewportPercentage; @@ -147,6 +149,30 @@ pub trait DomTraversalContext<N: TNode> { fn process_preorder(&self, node: N); /// Process `node` on the way up, after its children have been processed. fn process_postorder(&self, node: N); + + /// Returns if the node should be processed by the preorder traversal (and + /// then by the post-order one). + /// + /// Note that this is true unconditionally for servo, since it requires to + /// bubble the widths bottom-up for all the DOM. + fn should_process(&self, node: N) -> bool { + node.is_dirty() || node.has_dirty_descendants() + } + + /// Do an action over the child before pushing him to the work queue. + /// + /// By default, propagate the IS_DIRTY flag down the tree. + #[allow(unsafe_code)] + fn pre_process_child_hook(&self, parent: N, kid: N) { + // NOTE: At this point is completely safe to modify either the parent or + // the child, since we have exclusive access to both of them. + if parent.is_dirty() { + unsafe { + kid.set_dirty(true); + parent.set_dirty_descendants(true); + } + } + } } /// Calculates the style for a single node. @@ -232,6 +258,13 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C, node.set_restyle_damage(damage); } } + } else { + // Finish any expired transitions. + animation::complete_expired_transitions( + node.opaque(), + node.mutate_data().unwrap().style.as_mut().unwrap(), + context.shared_context() + ); } let unsafe_layout_node = node.to_unsafe(); @@ -244,22 +277,17 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C, // NB: flow construction updates the bloom filter on the way up. put_thread_local_bloom_filter(bf, &unsafe_layout_node, context.shared_context()); - // Mark the node as DIRTY_ON_VIEWPORT_SIZE_CHANGE is it uses viewport percentage units. - match node.as_element() { - Some(element) => { - match *element.style_attribute() { - Some(ref property_declaration_block) => { - if property_declaration_block.declarations().any(|d| d.0.has_viewport_percentage()) { - unsafe { - node.set_dirty_on_viewport_size_changed(); - } - node.set_descendants_dirty_on_viewport_size_changed(); + // Mark the node as DIRTY_ON_VIEWPORT_SIZE_CHANGE is it uses viewport + // percentage units. + if !node.needs_dirty_on_viewport_size_changed() { + if let Some(element) = node.as_element() { + if let Some(ref property_declaration_block) = *element.style_attribute() { + if property_declaration_block.declarations().any(|d| d.0.has_viewport_percentage()) { + unsafe { + node.set_dirty_on_viewport_size_changed(); } - }, - None => {} + } } - }, - None => {} + } } } - diff --git a/components/style/values.rs b/components/style/values.rs deleted file mode 100644 index 35063977aa6..00000000000 --- a/components/style/values.rs +++ /dev/null @@ -1,2286 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! Common [values][values] used in CSS. -//! -//! [values]: https://drafts.csswg.org/css-values/ - -pub use cssparser::RGBA; - -use app_units::Au; -use cssparser::CssStringWriter; -use std::fmt::{self, Write}; -use url::Url; - - -/// The real ToCss trait can't be implemented for types in crates that don't -/// depend on each other. -pub trait LocalToCss { - /// Serialize `self` in CSS syntax, writing to `dest`. - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write; - - /// Serialize `self` in CSS syntax and return a string. - /// - /// (This is a convenience wrapper for `to_css` and probably should not be overridden.) - #[inline] - fn to_css_string(&self) -> String { - let mut s = String::new(); - self.to_css(&mut s).unwrap(); - s - } -} - -impl LocalToCss for Au { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - write!(dest, "{}px", self.to_f64_px()) - } -} - -impl LocalToCss for Url { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(dest.write_str("url(\"")); - try!(write!(CssStringWriter::new(dest), "{}", self)); - try!(dest.write_str("\")")); - Ok(()) - } -} - -macro_rules! define_numbered_css_keyword_enum { - ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => { - define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+); - }; - ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => { - #[allow(non_camel_case_types)] - #[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Copy, RustcEncodable, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] - pub enum $name { - $( $variant = $value ),+ - } - - impl $name { - pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> { - match_ignore_ascii_case! { try!(input.expect_ident()), - $( $css => Ok($name::$variant), )+ - _ => Err(()) - } - } - } - - impl ::cssparser::ToCss for $name { - fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result - where W: ::std::fmt::Write { - match *self { - $( $name::$variant => dest.write_str($css) ),+ - } - } - } - } -} - -pub type CSSFloat = f32; - -pub const FONT_MEDIUM_PX: i32 = 16; - -pub trait HasViewportPercentage { - fn has_viewport_percentage(&self) -> bool; -} - -pub trait NoViewportPercentage {} - -impl<T> HasViewportPercentage for T where T: NoViewportPercentage { - fn has_viewport_percentage(&self) -> bool { - false - } -} - -pub mod specified { - use app_units::Au; - use cssparser::{self, Parser, ToCss, Token}; - use euclid::size::Size2D; - use parser::ParserContext; - use std::ascii::AsciiExt; - use std::cmp; - use std::f32::consts::PI; - use std::fmt; - use std::ops::Mul; - use style_traits::values::specified::AllowedNumericType; - use super::computed::{Context, ToComputedValue}; - use super::{CSSFloat, FONT_MEDIUM_PX, HasViewportPercentage, LocalToCss, NoViewportPercentage}; - use url::Url; - - impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order - - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct CSSColor { - pub parsed: cssparser::Color, - pub authored: Option<String>, - } - impl CSSColor { - pub fn parse(input: &mut Parser) -> Result<CSSColor, ()> { - let start_position = input.position(); - let authored = match input.next() { - Ok(Token::Ident(s)) => Some(s.into_owned()), - _ => None, - }; - input.reset(start_position); - Ok(CSSColor { - parsed: try!(cssparser::Color::parse(input)), - authored: authored, - }) - } - } - - impl NoViewportPercentage for CSSColor {} - - impl ToCss for CSSColor { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.authored { - Some(ref s) => dest.write_str(s), - None => self.parsed.to_css(dest), - } - } - } - - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct CSSRGBA { - pub parsed: cssparser::RGBA, - pub authored: Option<String>, - } - - impl NoViewportPercentage for CSSRGBA {} - - impl ToCss for CSSRGBA { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.authored { - Some(ref s) => dest.write_str(s), - None => self.parsed.to_css(dest), - } - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum FontRelativeLength { - Em(CSSFloat), - Ex(CSSFloat), - Ch(CSSFloat), - Rem(CSSFloat) - } - - impl ToCss for FontRelativeLength { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - FontRelativeLength::Em(length) => write!(dest, "{}em", length), - FontRelativeLength::Ex(length) => write!(dest, "{}ex", length), - FontRelativeLength::Ch(length) => write!(dest, "{}ch", length), - FontRelativeLength::Rem(length) => write!(dest, "{}rem", length) - } - } - } - - impl FontRelativeLength { - pub fn to_computed_value(&self, - reference_font_size: Au, - root_font_size: Au) - -> Au - { - match *self { - FontRelativeLength::Em(length) => reference_font_size.scale_by(length), - FontRelativeLength::Ex(length) | FontRelativeLength::Ch(length) => { - // https://github.com/servo/servo/issues/7462 - let em_factor = 0.5; - reference_font_size.scale_by(length * em_factor) - }, - FontRelativeLength::Rem(length) => root_font_size.scale_by(length) - } - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum ViewportPercentageLength { - Vw(CSSFloat), - Vh(CSSFloat), - Vmin(CSSFloat), - Vmax(CSSFloat) - } - - impl HasViewportPercentage for ViewportPercentageLength { - fn has_viewport_percentage(&self) -> bool { - true - } - } - - impl ToCss for ViewportPercentageLength { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - ViewportPercentageLength::Vw(length) => write!(dest, "{}vw", length), - ViewportPercentageLength::Vh(length) => write!(dest, "{}vh", length), - ViewportPercentageLength::Vmin(length) => write!(dest, "{}vmin", length), - ViewportPercentageLength::Vmax(length) => write!(dest, "{}vmax", length) - } - } - } - - impl ViewportPercentageLength { - pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au { - macro_rules! to_unit { - ($viewport_dimension:expr) => { - $viewport_dimension.to_f32_px() / 100.0 - } - } - - let value = match *self { - ViewportPercentageLength::Vw(length) => - length * to_unit!(viewport_size.width), - ViewportPercentageLength::Vh(length) => - length * to_unit!(viewport_size.height), - ViewportPercentageLength::Vmin(length) => - length * to_unit!(cmp::min(viewport_size.width, viewport_size.height)), - ViewportPercentageLength::Vmax(length) => - length * to_unit!(cmp::max(viewport_size.width, viewport_size.height)), - }; - Au::from_f32_px(value) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct CharacterWidth(pub i32); - - impl CharacterWidth { - pub fn to_computed_value(&self, reference_font_size: Au) -> Au { - // This applies the *converting a character width to pixels* algorithm as specified - // in HTML5 § 14.5.4. - // - // TODO(pcwalton): Find these from the font. - let average_advance = reference_font_size.scale_by(0.5); - let max_advance = reference_font_size; - average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum Length { - Absolute(Au), // application units - FontRelative(FontRelativeLength), - ViewportPercentage(ViewportPercentageLength), - - /// HTML5 "character width", as defined in HTML5 § 14.5.4. - /// - /// This cannot be specified by the user directly and is only generated by - /// `Stylist::synthesize_rules_for_legacy_attributes()`. - ServoCharacterWidth(CharacterWidth), - - Calc(CalcLengthOrPercentage), - } - - impl HasViewportPercentage for Length { - fn has_viewport_percentage(&self) -> bool { - match *self { - Length::ViewportPercentage(_) => true, - _ => false - } - } - } - - impl ToCss for Length { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()), - Length::FontRelative(length) => length.to_css(dest), - Length::ViewportPercentage(length) => length.to_css(dest), - Length::Calc(calc) => calc.to_css(dest), - Length::ServoCharacterWidth(_) - => panic!("internal CSS values should never be serialized"), - } - } - } - - impl Mul<CSSFloat> for Length { - type Output = Length; - - #[inline] - fn mul(self, scalar: CSSFloat) -> Length { - match self { - Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)), - Length::FontRelative(v) => Length::FontRelative(v * scalar), - Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar), - Length::Calc(_) => panic!("Can't multiply Calc!"), - Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"), - } - } - } - - impl Mul<CSSFloat> for FontRelativeLength { - type Output = FontRelativeLength; - - #[inline] - fn mul(self, scalar: CSSFloat) -> FontRelativeLength { - match self { - FontRelativeLength::Em(v) => FontRelativeLength::Em(v * scalar), - FontRelativeLength::Ex(v) => FontRelativeLength::Ex(v * scalar), - FontRelativeLength::Ch(v) => FontRelativeLength::Ch(v * scalar), - FontRelativeLength::Rem(v) => FontRelativeLength::Rem(v * scalar), - } - } - } - - impl Mul<CSSFloat> for ViewportPercentageLength { - type Output = ViewportPercentageLength; - - #[inline] - fn mul(self, scalar: CSSFloat) -> ViewportPercentageLength { - match self { - ViewportPercentageLength::Vw(v) => ViewportPercentageLength::Vw(v * scalar), - ViewportPercentageLength::Vh(v) => ViewportPercentageLength::Vh(v * scalar), - ViewportPercentageLength::Vmin(v) => ViewportPercentageLength::Vmin(v * scalar), - ViewportPercentageLength::Vmax(v) => ViewportPercentageLength::Vmax(v * scalar), - } - } - } - - const AU_PER_PX: CSSFloat = 60.; - const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; - const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; - const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4; - const AU_PER_Q: CSSFloat = AU_PER_MM / 4.; - const AU_PER_PT: CSSFloat = AU_PER_IN / 72.; - const AU_PER_PC: CSSFloat = AU_PER_PT * 12.; - impl Length { - // https://drafts.csswg.org/css-fonts-3/#font-size-prop - pub fn from_str(s: &str) -> Option<Length> { - Some(match_ignore_ascii_case! { s, - "xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5), - "x-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4), - "small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9), - "medium" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX)), - "large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5), - "x-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2), - "xx-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2), - - // https://github.com/servo/servo/issues/3423#issuecomment-56321664 - "smaller" => Length::FontRelative(FontRelativeLength::Em(0.85)), - "larger" => Length::FontRelative(FontRelativeLength::Em(1.2)), - _ => return None - }) - } - - #[inline] - fn parse_internal(input: &mut Parser, context: &AllowedNumericType) -> Result<Length, ()> { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => - Length::parse_dimension(value.value, unit), - Token::Number(ref value) if value.value == 0. => - Ok(Length::Absolute(Au(0))), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => - input.parse_nested_block(CalcLengthOrPercentage::parse_length), - _ => Err(()) - } - } - pub fn parse(input: &mut Parser) -> Result<Length, ()> { - Length::parse_internal(input, &AllowedNumericType::All) - } - pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> { - Length::parse_internal(input, &AllowedNumericType::NonNegative) - } - pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> { - match_ignore_ascii_case! { unit, - "px" => Ok(Length::from_px(value)), - "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))), - "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))), - "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))), - "q" => Ok(Length::Absolute(Au((value * AU_PER_Q) as i32))), - "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))), - "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))), - // font-relative - "em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))), - "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))), - "ch" => Ok(Length::FontRelative(FontRelativeLength::Ch(value))), - "rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))), - // viewport percentages - "vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))), - "vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))), - "vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))), - "vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value))), - _ => Err(()) - } - } - #[inline] - pub fn from_px(px_value: CSSFloat) -> Length { - Length::Absolute(Au((px_value * AU_PER_PX) as i32)) - } - } - - #[derive(Clone, Debug)] - struct CalcSumNode { - products: Vec<CalcProductNode>, - } - - #[derive(Clone, Debug)] - struct CalcProductNode { - values: Vec<CalcValueNode> - } - - #[derive(Clone, Debug)] - enum CalcValueNode { - Length(Length), - Angle(Angle), - Time(Time), - Percentage(CSSFloat), - Number(CSSFloat), - Sum(Box<CalcSumNode>), - } - - #[derive(Clone, Debug)] - struct SimplifiedSumNode { - values: Vec<SimplifiedValueNode>, - } - impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode { - type Output = SimplifiedSumNode; - - #[inline] - fn mul(self, scalar: CSSFloat) -> SimplifiedSumNode { - SimplifiedSumNode { - values: self.values.iter().map(|p| p * scalar).collect() - } - } - } - - #[derive(Clone, Debug)] - enum SimplifiedValueNode { - Length(Length), - Angle(Angle), - Time(Time), - Percentage(CSSFloat), - Number(CSSFloat), - Sum(Box<SimplifiedSumNode>), - } - impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode { - type Output = SimplifiedValueNode; - - #[inline] - fn mul(self, scalar: CSSFloat) -> SimplifiedValueNode { - match *self { - SimplifiedValueNode::Length(l) => SimplifiedValueNode::Length(l * scalar), - SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p * scalar), - SimplifiedValueNode::Angle(Angle(a)) => SimplifiedValueNode::Angle(Angle(a * scalar)), - SimplifiedValueNode::Time(Time(t)) => SimplifiedValueNode::Time(Time(t * scalar)), - SimplifiedValueNode::Number(n) => SimplifiedValueNode::Number(n * scalar), - SimplifiedValueNode::Sum(ref s) => { - let sum = &**s * scalar; - SimplifiedValueNode::Sum(Box::new(sum)) - } - } - } - } - - pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> { - match try!(input.next()) { - Token::Number(ref value) => value.int_value.ok_or(()), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer))); - - let mut result = None; - - for ref node in ast.products { - match try!(CalcLengthOrPercentage::simplify_product(node)) { - SimplifiedValueNode::Number(val) => - result = Some(result.unwrap_or(0) + val as i32), - _ => unreachable!() - } - } - - match result { - Some(result) => Ok(result), - _ => Err(()) - } - } - _ => Err(()) - } - } - - pub fn parse_number(input: &mut Parser) -> Result<f32, ()> { - match try!(input.next()) { - Token::Number(ref value) => Ok(value.value), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Number))); - - let mut result = None; - - for ref node in ast.products { - match try!(CalcLengthOrPercentage::simplify_product(node)) { - SimplifiedValueNode::Number(val) => - result = Some(result.unwrap_or(0.) + val), - _ => unreachable!() - } - } - - match result { - Some(result) => Ok(result), - _ => Err(()) - } - } - _ => Err(()) - } - } - - #[derive(Clone, Copy, PartialEq)] - enum CalcUnit { - Number, - Integer, - Length, - LengthOrPercentage, - Angle, - Time, - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct CalcLengthOrPercentage { - pub absolute: Option<Au>, - pub vw: Option<ViewportPercentageLength>, - pub vh: Option<ViewportPercentageLength>, - pub vmin: Option<ViewportPercentageLength>, - pub vmax: Option<ViewportPercentageLength>, - pub em: Option<FontRelativeLength>, - pub ex: Option<FontRelativeLength>, - pub ch: Option<FontRelativeLength>, - pub rem: Option<FontRelativeLength>, - pub percentage: Option<Percentage>, - } - impl CalcLengthOrPercentage { - fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> { - let mut products = Vec::new(); - products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); - - while let Ok(token) = input.next() { - match token { - Token::Delim('+') => { - products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); - } - Token::Delim('-') => { - let mut right = try!(CalcLengthOrPercentage::parse_product(input, expected_unit)); - right.values.push(CalcValueNode::Number(-1.)); - products.push(right); - } - _ => return Err(()) - } - } - - Ok(CalcSumNode { products: products }) - } - - fn parse_product(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcProductNode, ()> { - let mut values = Vec::new(); - values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit))); - - loop { - let position = input.position(); - match input.next() { - Ok(Token::Delim('*')) => { - values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit))); - } - Ok(Token::Delim('/')) if expected_unit != CalcUnit::Integer => { - if let Ok(Token::Number(ref value)) = input.next() { - if value.value == 0. { - return Err(()); - } - values.push(CalcValueNode::Number(1. / value.value)); - } else { - return Err(()); - } - } - _ => { - input.reset(position); - break - } - } - } - - Ok(CalcProductNode { values: values }) - } - - fn parse_value(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcValueNode, ()> { - match (try!(input.next()), expected_unit) { - (Token::Number(ref value), _) => Ok(CalcValueNode::Number(value.value)), - (Token::Dimension(ref value, ref unit), CalcUnit::Length) | - (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => { - Length::parse_dimension(value.value, unit).map(CalcValueNode::Length) - } - (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => { - Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle) - } - (Token::Dimension(ref value, ref unit), CalcUnit::Time) => { - Time::parse_dimension(value.value, unit).map(CalcValueNode::Time) - } - (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) => - Ok(CalcValueNode::Percentage(value.unit_value)), - (Token::ParenthesisBlock, _) => { - input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, expected_unit)) - .map(|result| CalcValueNode::Sum(Box::new(result))) - }, - _ => Err(()) - } - } - - fn simplify_value_to_number(node: &CalcValueNode) -> Option<CSSFloat> { - match *node { - CalcValueNode::Number(number) => Some(number), - CalcValueNode::Sum(ref sum) => CalcLengthOrPercentage::simplify_sum_to_number(sum), - _ => None - } - } - - fn simplify_sum_to_number(node: &CalcSumNode) -> Option<CSSFloat> { - let mut sum = 0.; - for ref product in &node.products { - match CalcLengthOrPercentage::simplify_product_to_number(product) { - Some(number) => sum += number, - _ => return None - } - } - Some(sum) - } - - fn simplify_product_to_number(node: &CalcProductNode) -> Option<CSSFloat> { - let mut product = 1.; - for ref value in &node.values { - match CalcLengthOrPercentage::simplify_value_to_number(value) { - Some(number) => product *= number, - _ => return None - } - } - Some(product) - } - - fn simplify_products_in_sum(node: &CalcSumNode) -> Result<SimplifiedValueNode, ()> { - let mut simplified = Vec::new(); - for product in &node.products { - match try!(CalcLengthOrPercentage::simplify_product(product)) { - SimplifiedValueNode::Sum(ref sum) => simplified.extend_from_slice(&sum.values), - val => simplified.push(val), - } - } - - if simplified.len() == 1 { - Ok(simplified[0].clone()) - } else { - Ok(SimplifiedValueNode::Sum(Box::new(SimplifiedSumNode { values: simplified }))) - } - } - - fn simplify_product(node: &CalcProductNode) -> Result<SimplifiedValueNode, ()> { - let mut multiplier = 1.; - let mut node_with_unit = None; - for node in &node.values { - match CalcLengthOrPercentage::simplify_value_to_number(&node) { - Some(number) => multiplier *= number, - _ if node_with_unit.is_none() => { - node_with_unit = Some(match *node { - CalcValueNode::Sum(ref sum) => - try!(CalcLengthOrPercentage::simplify_products_in_sum(sum)), - CalcValueNode::Length(l) => SimplifiedValueNode::Length(l), - CalcValueNode::Angle(a) => SimplifiedValueNode::Angle(a), - CalcValueNode::Time(t) => SimplifiedValueNode::Time(t), - CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p), - _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer") - }) - }, - _ => return Err(()), - } - } - - match node_with_unit { - None => Ok(SimplifiedValueNode::Number(multiplier)), - Some(ref value) => Ok(value * multiplier) - } - } - - fn parse_length(input: &mut Parser) -> Result<Length, ()> { - CalcLengthOrPercentage::parse(input, CalcUnit::Length).map(Length::Calc) - } - - fn parse_length_or_percentage(input: &mut Parser) -> Result<CalcLengthOrPercentage, ()> { - CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage) - } - - fn parse(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> { - let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit)); - - let mut simplified = Vec::new(); - for ref node in ast.products { - match try!(CalcLengthOrPercentage::simplify_product(node)) { - SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values), - value => simplified.push(value), - } - } - - let mut absolute = None; - let mut vw = None; - let mut vh = None; - let mut vmax = None; - let mut vmin = None; - let mut em = None; - let mut ex = None; - let mut ch = None; - let mut rem = None; - let mut percentage = None; - let mut number = None; - - for value in simplified { - match value { - SimplifiedValueNode::Percentage(p) => - percentage = Some(percentage.unwrap_or(0.) + p), - SimplifiedValueNode::Length(Length::Absolute(Au(au))) => - absolute = Some(absolute.unwrap_or(0) + au), - SimplifiedValueNode::Length(Length::ViewportPercentage(v)) => - match v { - ViewportPercentageLength::Vw(val) => - vw = Some(vw.unwrap_or(0.) + val), - ViewportPercentageLength::Vh(val) => - vh = Some(vh.unwrap_or(0.) + val), - ViewportPercentageLength::Vmin(val) => - vmin = Some(vmin.unwrap_or(0.) + val), - ViewportPercentageLength::Vmax(val) => - vmax = Some(vmax.unwrap_or(0.) + val), - }, - SimplifiedValueNode::Length(Length::FontRelative(f)) => - match f { - FontRelativeLength::Em(val) => - em = Some(em.unwrap_or(0.) + val), - FontRelativeLength::Ex(val) => - ex = Some(ex.unwrap_or(0.) + val), - FontRelativeLength::Ch(val) => - ch = Some(ch.unwrap_or(0.) + val), - FontRelativeLength::Rem(val) => - rem = Some(rem.unwrap_or(0.) + val), - }, - SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), - _ => return Err(()), - } - } - - Ok(CalcLengthOrPercentage { - absolute: absolute.map(Au), - vw: vw.map(ViewportPercentageLength::Vw), - vh: vh.map(ViewportPercentageLength::Vh), - vmax: vmax.map(ViewportPercentageLength::Vmax), - vmin: vmin.map(ViewportPercentageLength::Vmin), - em: em.map(FontRelativeLength::Em), - ex: ex.map(FontRelativeLength::Ex), - ch: ch.map(FontRelativeLength::Ch), - rem: rem.map(FontRelativeLength::Rem), - percentage: percentage.map(Percentage), - }) - } - - pub fn parse_time(input: &mut Parser) -> Result<Time, ()> { - let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time)); - - let mut simplified = Vec::new(); - for ref node in ast.products { - match try!(CalcLengthOrPercentage::simplify_product(node)) { - SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values), - value => simplified.push(value), - } - } - - let mut time = None; - - for value in simplified { - match value { - SimplifiedValueNode::Time(Time(val)) => - time = Some(time.unwrap_or(0.) + val), - _ => return Err(()), - } - } - - match time { - Some(time) => Ok(Time(time)), - _ => Err(()) - } - } - - pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> { - let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle)); - - let mut simplified = Vec::new(); - for ref node in ast.products { - match try!(CalcLengthOrPercentage::simplify_product(node)) { - SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values), - value => simplified.push(value), - } - } - - let mut angle = None; - let mut number = None; - - for value in simplified { - match value { - SimplifiedValueNode::Angle(Angle(val)) => - angle = Some(angle.unwrap_or(0.) + val), - SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), - _ => unreachable!() - } - } - - match (angle, number) { - (Some(angle), None) => Ok(Angle(angle)), - (None, Some(value)) if value == 0. => Ok(Angle(0.)), - _ => Err(()) - } - } - } - - impl ToCss for CalcLengthOrPercentage { - #[allow(unused_assignments)] - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - macro_rules! count { - ( $( $val:ident ),* ) => { - { - let mut count = 0; - $( - if let Some(_) = self.$val { - count += 1; - } - )* - count - } - }; - } - - macro_rules! serialize { - ( $( $val:ident ),* ) => { - { - let mut first_value = true; - $( - if let Some(val) = self.$val { - if !first_value { - try!(write!(dest, " + ")); - } else { - first_value = false; - } - try!(val.to_css(dest)); - } - )* - } - }; - } - - let count = count!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); - assert!(count > 0); - - if count > 1 { - try!(write!(dest, "calc(")); - } - - serialize!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); - - if count > 1 { - try!(write!(dest, ")")); - } - Ok(()) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct Percentage(pub CSSFloat); // [0 .. 100%] maps to [0.0 .. 1.0] - - impl ToCss for Percentage { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - write!(dest, "{}%", self.0 * 100.) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentage { - Length(Length), - Percentage(Percentage), - Calc(CalcLengthOrPercentage), - } - - impl HasViewportPercentage for LengthOrPercentage { - fn has_viewport_percentage(&self) -> bool { - match *self { - LengthOrPercentage::Length(length) => length.has_viewport_percentage(), - _ => false - } - } - } - - impl ToCss for LengthOrPercentage { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentage::Length(length) => length.to_css(dest), - LengthOrPercentage::Percentage(percentage) => percentage.to_css(dest), - LengthOrPercentage::Calc(calc) => calc.to_css(dest), - } - } - } - impl LengthOrPercentage { - pub fn zero() -> LengthOrPercentage { - LengthOrPercentage::Length(Length::Absolute(Au(0))) - } - - fn parse_internal(input: &mut Parser, context: &AllowedNumericType) - -> Result<LengthOrPercentage, ()> - { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => - Length::parse_dimension(value.value, unit).map(LengthOrPercentage::Length), - Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) if value.value == 0. => - Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); - Ok(LengthOrPercentage::Calc(calc)) - }, - _ => Err(()) - } - } - #[inline] - pub fn parse(input: &mut Parser) -> Result<LengthOrPercentage, ()> { - LengthOrPercentage::parse_internal(input, &AllowedNumericType::All) - } - #[inline] - pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> { - LengthOrPercentage::parse_internal(input, &AllowedNumericType::NonNegative) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentageOrAuto { - Length(Length), - Percentage(Percentage), - Auto, - Calc(CalcLengthOrPercentage), - } - - impl HasViewportPercentage for LengthOrPercentageOrAuto { - fn has_viewport_percentage(&self) -> bool { - match *self { - LengthOrPercentageOrAuto::Length(length) => length.has_viewport_percentage(), - _ => false - } - } - } - - impl ToCss for LengthOrPercentageOrAuto { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrAuto::Length(length) => length.to_css(dest), - LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest), - LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), - LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), - } - } - } - - impl LengthOrPercentageOrAuto { - fn parse_internal(input: &mut Parser, context: &AllowedNumericType) - -> Result<LengthOrPercentageOrAuto, ()> - { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => - Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAuto::Length), - Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) if value.value == 0. => - Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))), - Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => - Ok(LengthOrPercentageOrAuto::Auto), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); - Ok(LengthOrPercentageOrAuto::Calc(calc)) - }, - _ => Err(()) - } - } - #[inline] - pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { - LengthOrPercentageOrAuto::parse_internal(input, &AllowedNumericType::All) - } - #[inline] - pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { - LengthOrPercentageOrAuto::parse_internal(input, &AllowedNumericType::NonNegative) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentageOrNone { - Length(Length), - Percentage(Percentage), - Calc(CalcLengthOrPercentage), - None, - } - - impl HasViewportPercentage for LengthOrPercentageOrNone { - fn has_viewport_percentage(&self) -> bool { - match *self { - LengthOrPercentageOrNone::Length(length) => length.has_viewport_percentage(), - _ => false - } - } - } - - impl ToCss for LengthOrPercentageOrNone { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrNone::Length(length) => length.to_css(dest), - LengthOrPercentageOrNone::Percentage(percentage) => percentage.to_css(dest), - LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest), - LengthOrPercentageOrNone::None => dest.write_str("none"), - } - } - } - impl LengthOrPercentageOrNone { - fn parse_internal(input: &mut Parser, context: &AllowedNumericType) - -> Result<LengthOrPercentageOrNone, ()> - { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => - Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrNone::Length), - Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) if value.value == 0. => - Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); - Ok(LengthOrPercentageOrNone::Calc(calc)) - }, - Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => - Ok(LengthOrPercentageOrNone::None), - _ => Err(()) - } - } - #[inline] - pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> { - LengthOrPercentageOrNone::parse_internal(input, &AllowedNumericType::All) - } - #[inline] - pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> { - LengthOrPercentageOrNone::parse_internal(input, &AllowedNumericType::NonNegative) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrNone { - Length(Length), - None, - } - - impl HasViewportPercentage for LengthOrNone { - fn has_viewport_percentage(&self) -> bool { - match *self { - LengthOrNone::Length(length) => length.has_viewport_percentage(), - _ => false - } - } - } - - impl ToCss for LengthOrNone { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrNone::Length(length) => length.to_css(dest), - LengthOrNone::None => dest.write_str("none"), - } - } - } - impl LengthOrNone { - fn parse_internal(input: &mut Parser, context: &AllowedNumericType) - -> Result<LengthOrNone, ()> - { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => - Length::parse_dimension(value.value, unit).map(LengthOrNone::Length), - Token::Number(ref value) if value.value == 0. => - Ok(LengthOrNone::Length(Length::Absolute(Au(0)))), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => - input.parse_nested_block(CalcLengthOrPercentage::parse_length).map(LengthOrNone::Length), - Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => - Ok(LengthOrNone::None), - _ => Err(()) - } - } - #[inline] - pub fn parse(input: &mut Parser) -> Result<LengthOrNone, ()> { - LengthOrNone::parse_internal(input, &AllowedNumericType::All) - } - #[inline] - pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrNone, ()> { - LengthOrNone::parse_internal(input, &AllowedNumericType::NonNegative) - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentageOrAutoOrContent { - Length(Length), - Percentage(Percentage), - Calc(CalcLengthOrPercentage), - Auto, - Content - } - - impl HasViewportPercentage for LengthOrPercentageOrAutoOrContent { - fn has_viewport_percentage(&self) -> bool { - match *self { - LengthOrPercentageOrAutoOrContent::Length(length) => length.has_viewport_percentage(), - _ => false - } - } - } - - impl ToCss for LengthOrPercentageOrAutoOrContent { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrAutoOrContent::Length(len) => len.to_css(dest), - LengthOrPercentageOrAutoOrContent::Percentage(perc) => perc.to_css(dest), - LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"), - LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content"), - LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest), - } - } - } - - impl LengthOrPercentageOrAutoOrContent { - pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAutoOrContent, ()> { - let context = AllowedNumericType::NonNegative; - match try!(input.next()) { - Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => - Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAutoOrContent::Length), - Token::Percentage(ref value) if context.is_ok(value.unit_value) => - Ok(LengthOrPercentageOrAutoOrContent::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) if value.value == 0. => - Ok(LengthOrPercentageOrAutoOrContent::Length(Length::Absolute(Au(0)))), - Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => - Ok(LengthOrPercentageOrAutoOrContent::Auto), - Token::Ident(ref value) if value.eq_ignore_ascii_case("content") => - Ok(LengthOrPercentageOrAutoOrContent::Content), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); - Ok(LengthOrPercentageOrAutoOrContent::Calc(calc)) - }, - _ => Err(()) - } - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>); - - impl NoViewportPercentage for BorderRadiusSize {} - - impl BorderRadiusSize { - pub fn zero() -> BorderRadiusSize { - let zero = LengthOrPercentage::Length(Length::Absolute(Au(0))); - BorderRadiusSize(Size2D::new(zero, zero)) - } - - pub fn new(width: LengthOrPercentage, height: LengthOrPercentage) -> BorderRadiusSize { - BorderRadiusSize(Size2D::new(width, height)) - } - - pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize { - BorderRadiusSize(Size2D::new(radius, radius)) - } - - #[inline] - pub fn parse(input: &mut Parser) -> Result<BorderRadiusSize, ()> { - let first = try!(LengthOrPercentage::parse_non_negative(input)); - let second = input.try(LengthOrPercentage::parse_non_negative).unwrap_or(first); - Ok(BorderRadiusSize(Size2D::new(first, second))) - } - } - - impl ToCss for BorderRadiusSize { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.0.width.to_css(dest)); - try!(dest.write_str(" ")); - self.0.height.to_css(dest) - } - } - - // http://dev.w3.org/csswg/css2/colors.html#propdef-background-position - #[derive(Clone, PartialEq, Copy)] - pub enum PositionComponent { - LengthOrPercentage(LengthOrPercentage), - Center, - Left, - Right, - Top, - Bottom, - } - - impl HasViewportPercentage for PositionComponent { - fn has_viewport_percentage(&self) -> bool { - match *self { - PositionComponent::LengthOrPercentage(length) => length.has_viewport_percentage(), - _ => false - } - } - } - - impl PositionComponent { - pub fn parse(input: &mut Parser) -> Result<PositionComponent, ()> { - input.try(LengthOrPercentage::parse) - .map(PositionComponent::LengthOrPercentage) - .or_else(|()| { - match try!(input.next()) { - Token::Ident(value) => { - match_ignore_ascii_case! { value, - "center" => Ok(PositionComponent::Center), - "left" => Ok(PositionComponent::Left), - "right" => Ok(PositionComponent::Right), - "top" => Ok(PositionComponent::Top), - "bottom" => Ok(PositionComponent::Bottom), - _ => Err(()) - } - }, - _ => Err(()) - } - }) - } - #[inline] - pub fn to_length_or_percentage(self) -> LengthOrPercentage { - match self { - PositionComponent::LengthOrPercentage(value) => value, - PositionComponent::Center => LengthOrPercentage::Percentage(Percentage(0.5)), - PositionComponent::Left | - PositionComponent::Top => LengthOrPercentage::Percentage(Percentage(0.0)), - PositionComponent::Right | - PositionComponent::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), - } - } - } - - #[derive(Clone, PartialEq, PartialOrd, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] - /// An angle, normalized to radians. - pub struct Angle(pub CSSFloat); - - impl ToCss for Angle { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - write!(dest, "{}rad", self.0) - } - } - - impl Angle { - #[inline] - pub fn radians(self) -> f32 { - self.0 - } - - #[inline] - pub fn from_radians(r: f32) -> Self { - Angle(r) - } - } - - const RAD_PER_DEG: CSSFloat = PI / 180.0; - const RAD_PER_GRAD: CSSFloat = PI / 200.0; - const RAD_PER_TURN: CSSFloat = PI * 2.0; - - impl Angle { - /// Parses an angle according to CSS-VALUES § 6.1. - pub fn parse(input: &mut Parser) -> Result<Angle, ()> { - match try!(input.next()) { - Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit), - Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)), - Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { - input.parse_nested_block(CalcLengthOrPercentage::parse_angle) - }, - _ => Err(()) - } - } - - pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> { - match_ignore_ascii_case! { unit, - "deg" => Ok(Angle(value * RAD_PER_DEG)), - "grad" => Ok(Angle(value * RAD_PER_GRAD)), - "turn" => Ok(Angle(value * RAD_PER_TURN)), - "rad" => Ok(Angle(value)), - _ => Err(()) - } - } - } - - /// Specified values for an image according to CSS-IMAGES. - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum Image { - Url(Url), - LinearGradient(LinearGradient), - } - - impl ToCss for Image { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - use values::LocalToCss; - match *self { - Image::Url(ref url) => { - url.to_css(dest) - } - Image::LinearGradient(ref gradient) => gradient.to_css(dest) - } - } - } - - impl Image { - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> { - if let Ok(url) = input.try(|input| input.expect_url()) { - Ok(Image::Url(context.parse_url(&url))) - } else { - match_ignore_ascii_case! { try!(input.expect_function()), - "linear-gradient" => { - Ok(Image::LinearGradient(try!( - input.parse_nested_block(LinearGradient::parse_function)))) - }, - _ => Err(()) - } - } - } - } - - /// Specified values for a CSS linear gradient. - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct LinearGradient { - /// The angle or corner of the gradient. - pub angle_or_corner: AngleOrCorner, - - /// The color stops. - pub stops: Vec<ColorStop>, - } - - impl ToCss for LinearGradient { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(dest.write_str("linear-gradient(")); - try!(self.angle_or_corner.to_css(dest)); - for stop in &self.stops { - try!(dest.write_str(", ")); - try!(stop.to_css(dest)); - } - try!(dest.write_str(")")); - Ok(()) - } - } - - /// Specified values for an angle or a corner in a linear gradient. - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum AngleOrCorner { - Angle(Angle), - Corner(HorizontalDirection, VerticalDirection), - } - - impl ToCss for AngleOrCorner { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - AngleOrCorner::Angle(angle) => angle.to_css(dest), - AngleOrCorner::Corner(horizontal, vertical) => { - try!(dest.write_str("to ")); - try!(horizontal.to_css(dest)); - try!(dest.write_str(" ")); - try!(vertical.to_css(dest)); - Ok(()) - } - } - } - } - - /// Specified values for one color stop in a linear gradient. - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct ColorStop { - /// The color of this stop. - pub color: CSSColor, - - /// The position of this stop. If not specified, this stop is placed halfway between the - /// point that precedes it and the point that follows it. - pub position: Option<LengthOrPercentage>, - } - - impl ToCss for ColorStop { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.color.to_css(dest)); - if let Some(position) = self.position { - try!(dest.write_str(" ")); - try!(position.to_css(dest)); - } - Ok(()) - } - } - - define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right); - define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom); - - fn parse_one_color_stop(input: &mut Parser) -> Result<ColorStop, ()> { - Ok(ColorStop { - color: try!(CSSColor::parse(input)), - position: input.try(LengthOrPercentage::parse).ok(), - }) - } - - impl LinearGradient { - /// Parses a linear gradient from the given arguments. - pub fn parse_function(input: &mut Parser) -> Result<LinearGradient, ()> { - let angle_or_corner = if input.try(|input| input.expect_ident_matching("to")).is_ok() { - let (horizontal, vertical) = - if let Ok(value) = input.try(HorizontalDirection::parse) { - (Some(value), input.try(VerticalDirection::parse).ok()) - } else { - let value = try!(VerticalDirection::parse(input)); - (input.try(HorizontalDirection::parse).ok(), Some(value)) - }; - try!(input.expect_comma()); - match (horizontal, vertical) { - (None, Some(VerticalDirection::Top)) => { - AngleOrCorner::Angle(Angle(0.0)) - }, - (Some(HorizontalDirection::Right), None) => { - AngleOrCorner::Angle(Angle(PI * 0.5)) - }, - (None, Some(VerticalDirection::Bottom)) => { - AngleOrCorner::Angle(Angle(PI)) - }, - (Some(HorizontalDirection::Left), None) => { - AngleOrCorner::Angle(Angle(PI * 1.5)) - }, - (Some(horizontal), Some(vertical)) => { - AngleOrCorner::Corner(horizontal, vertical) - } - (None, None) => unreachable!(), - } - } else if let Ok(angle) = input.try(Angle::parse) { - try!(input.expect_comma()); - AngleOrCorner::Angle(angle) - } else { - AngleOrCorner::Angle(Angle(PI)) - }; - // Parse the color stops. - let stops = try!(input.parse_comma_separated(parse_one_color_stop)); - if stops.len() < 2 { - return Err(()) - } - Ok(LinearGradient { - angle_or_corner: angle_or_corner, - stops: stops, - }) - } - } - - pub fn parse_border_radius(input: &mut Parser) -> Result<BorderRadiusSize, ()> { - input.try(BorderRadiusSize::parse).or_else(|()| { - match_ignore_ascii_case! { try!(input.expect_ident()), - "thin" => Ok(BorderRadiusSize::circle( - LengthOrPercentage::Length(Length::from_px(1.)))), - "medium" => Ok(BorderRadiusSize::circle( - LengthOrPercentage::Length(Length::from_px(3.)))), - "thick" => Ok(BorderRadiusSize::circle( - LengthOrPercentage::Length(Length::from_px(5.)))), - _ => Err(()) - } - }) - } - - pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> { - input.try(Length::parse_non_negative).or_else(|()| { - match_ignore_ascii_case! { try!(input.expect_ident()), - "thin" => Ok(Length::from_px(1.)), - "medium" => Ok(Length::from_px(3.)), - "thick" => Ok(Length::from_px(5.)), - _ => Err(()) - } - }) - } - - // The integer values here correspond to the border conflict resolution rules in CSS 2.1 § - // 17.6.2.1. Higher values override lower values. - define_numbered_css_keyword_enum! { BorderStyle: - "none" => none = -1, - "solid" => solid = 6, - "double" => double = 7, - "dotted" => dotted = 4, - "dashed" => dashed = 5, - "hidden" => hidden = -2, - "groove" => groove = 1, - "ridge" => ridge = 3, - "inset" => inset = 0, - "outset" => outset = 2, - } - - impl NoViewportPercentage for BorderStyle {} - - impl BorderStyle { - pub fn none_or_hidden(&self) -> bool { - matches!(*self, BorderStyle::none | BorderStyle::hidden) - } - } - - /// A time in seconds according to CSS-VALUES § 6.2. - #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct Time(pub CSSFloat); - - impl Time { - /// Returns the time in fractional seconds. - pub fn seconds(self) -> f32 { - let Time(seconds) = self; - seconds - } - - /// Parses a time according to CSS-VALUES § 6.2. - fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Time, ()> { - if unit.eq_ignore_ascii_case("s") { - Ok(Time(value)) - } else if unit.eq_ignore_ascii_case("ms") { - Ok(Time(value / 1000.0)) - } else { - Err(()) - } - } - - pub fn parse(input: &mut Parser) -> Result<Time, ()> { - match input.next() { - Ok(Token::Dimension(ref value, ref unit)) => { - Time::parse_dimension(value.value, &unit) - } - Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => { - input.parse_nested_block(CalcLengthOrPercentage::parse_time) - } - _ => Err(()) - } - } - } - - impl ToComputedValue for Time { - type ComputedValue = Time; - - #[inline] - fn to_computed_value(&self, _: &Context) -> Time { - *self - } - } - - impl ToCss for Time { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - write!(dest, "{}s", self.0) - } - } - - #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct Number(pub CSSFloat); - - impl NoViewportPercentage for Number {} - - impl Number { - pub fn parse(input: &mut Parser) -> Result<Number, ()> { - parse_number(input).map(Number) - } - - fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> { - match parse_number(input) { - Ok(value) if value < min => Err(()), - value => value.map(Number), - } - } - - pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> { - Number::parse_with_minimum(input, 0.0) - } - - pub fn parse_at_least_one(input: &mut Parser) -> Result<Number, ()> { - Number::parse_with_minimum(input, 1.0) - } - } - - impl ToComputedValue for Number { - type ComputedValue = CSSFloat; - - #[inline] - fn to_computed_value(&self, _: &Context) -> CSSFloat { self.0 } - } - - impl ToCss for Number { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } - } - - #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct Opacity(pub CSSFloat); - - impl NoViewportPercentage for Opacity {} - - impl Opacity { - pub fn parse(input: &mut Parser) -> Result<Opacity, ()> { - parse_number(input).map(Opacity) - } - } - - impl ToComputedValue for Opacity { - type ComputedValue = CSSFloat; - - #[inline] - fn to_computed_value(&self, _: &Context) -> CSSFloat { - if self.0 < 0.0 { - 0.0 - } else if self.0 > 1.0 { - 1.0 - } else { - self.0 - } - } - } - - impl ToCss for Opacity { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } - } -} - -pub mod computed { - use app_units::Au; - use euclid::size::Size2D; - use properties::ComputedValues; - use std::fmt; - use super::LocalToCss; - use super::specified::AngleOrCorner; - use super::{CSSFloat, specified}; - use url::Url; - pub use cssparser::Color as CSSColor; - pub use super::specified::{Angle, BorderStyle, Time}; - - pub struct Context<'a> { - pub is_root_element: bool, - pub viewport_size: Size2D<Au>, - pub inherited_style: &'a ComputedValues, - - /// Values access through this need to be in the properties "computed early": - /// color, text-decoration, font-size, display, position, float, border-*-style, outline-style - pub style: ComputedValues, - } - - impl<'a> Context<'a> { - pub fn is_root_element(&self) -> bool { self.is_root_element } - pub fn viewport_size(&self) -> Size2D<Au> { self.viewport_size } - pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style } - pub fn style(&self) -> &ComputedValues { &self.style } - pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style } - } - - pub trait ToComputedValue { - type ComputedValue; - - #[inline] - fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue; - } - - pub trait ComputedValueAsSpecified {} - - impl<T> ToComputedValue for T where T: ComputedValueAsSpecified + Clone { - type ComputedValue = T; - - #[inline] - fn to_computed_value(&self, _context: &Context) -> T { - self.clone() - } - } - - impl ToComputedValue for specified::CSSColor { - type ComputedValue = CSSColor; - - #[inline] - fn to_computed_value(&self, _context: &Context) -> CSSColor { - self.parsed - } - } - - impl ComputedValueAsSpecified for specified::BorderStyle {} - - impl ToComputedValue for specified::Length { - type ComputedValue = Au; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Au { - match *self { - specified::Length::Absolute(length) => length, - specified::Length::Calc(calc) => calc.to_computed_value(context).length(), - specified::Length::FontRelative(length) => - length.to_computed_value(context.style().get_font().clone_font_size(), - context.style().root_font_size()), - specified::Length::ViewportPercentage(length) => - length.to_computed_value(context.viewport_size()), - specified::Length::ServoCharacterWidth(length) => - length.to_computed_value(context.style().get_font().clone_font_size()) - } - } - } - - #[derive(Clone, PartialEq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct CalcLengthOrPercentage { - pub length: Option<Au>, - pub percentage: Option<CSSFloat>, - } - - impl CalcLengthOrPercentage { - #[inline] - pub fn length(&self) -> Au { - self.length.unwrap_or(Au(0)) - } - - #[inline] - pub fn percentage(&self) -> CSSFloat { - self.percentage.unwrap_or(0.) - } - } - - impl From<LengthOrPercentage> for CalcLengthOrPercentage { - fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage { - match len { - LengthOrPercentage::Percentage(this) => { - CalcLengthOrPercentage { - length: None, - percentage: Some(this), - } - } - LengthOrPercentage::Length(this) => { - CalcLengthOrPercentage { - length: Some(this), - percentage: None, - } - } - LengthOrPercentage::Calc(this) => { - this - } - } - } - } - - impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> { - fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> { - match len { - LengthOrPercentageOrAuto::Percentage(this) => { - Some(CalcLengthOrPercentage { - length: None, - percentage: Some(this), - }) - } - LengthOrPercentageOrAuto::Length(this) => { - Some(CalcLengthOrPercentage { - length: Some(this), - percentage: None, - }) - } - LengthOrPercentageOrAuto::Calc(this) => { - Some(this) - } - LengthOrPercentageOrAuto::Auto => { - None - } - } - } - } - - impl ::cssparser::ToCss for CalcLengthOrPercentage { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match (self.length, self.percentage) { - (None, Some(p)) => write!(dest, "{}%", p * 100.), - (Some(l), None) => write!(dest, "{}px", Au::to_px(l)), - (Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.), - _ => unreachable!() - } - } - } - - impl ToComputedValue for specified::CalcLengthOrPercentage { - type ComputedValue = CalcLengthOrPercentage; - - fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage { - let mut length = None; - - if let Some(absolute) = self.absolute { - length = Some(length.unwrap_or(Au(0)) + absolute); - } - - for val in &[self.vw, self.vh, self.vmin, self.vmax] { - if let Some(val) = *val { - length = Some(length.unwrap_or(Au(0)) + - val.to_computed_value(context.viewport_size())); - } - } - for val in &[self.ch, self.em, self.ex, self.rem] { - if let Some(val) = *val { - length = Some(length.unwrap_or(Au(0)) + val.to_computed_value( - context.style().get_font().clone_font_size(), context.style().root_font_size())); - } - } - - CalcLengthOrPercentage { length: length, percentage: self.percentage.map(|p| p.0) } - } - } - - - #[derive(Debug, PartialEq, Clone, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>); - - impl BorderRadiusSize { - pub fn zero() -> BorderRadiusSize { - BorderRadiusSize(Size2D::new(LengthOrPercentage::Length(Au(0)), LengthOrPercentage::Length(Au(0)))) - } - } - - impl ToComputedValue for specified::BorderRadiusSize { - type ComputedValue = BorderRadiusSize; - - #[inline] - fn to_computed_value(&self, context: &Context) -> BorderRadiusSize { - let w = self.0.width.to_computed_value(context); - let h = self.0.height.to_computed_value(context); - BorderRadiusSize(Size2D::new(w, h)) - } - } - - impl ::cssparser::ToCss for BorderRadiusSize { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.0.width.to_css(dest)); - try!(dest.write_str("/")); - self.0.height.to_css(dest) - } - } - - #[derive(PartialEq, Clone, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentage { - Length(Au), - Percentage(CSSFloat), - Calc(CalcLengthOrPercentage), - } - - impl LengthOrPercentage { - #[inline] - pub fn zero() -> LengthOrPercentage { - LengthOrPercentage::Length(Au(0)) - } - - /// Returns true if the computed value is absolute 0 or 0%. - /// - /// (Returns false for calc() values, even if ones that may resolve to zero.) - #[inline] - pub fn is_definitely_zero(&self) -> bool { - use self::LengthOrPercentage::*; - match *self { - Length(Au(0)) | Percentage(0.0) => true, - Length(_) | Percentage(_) | Calc(_) => false - } - } - } - - impl fmt::Debug for LengthOrPercentage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentage::Length(length) => write!(f, "{:?}", length), - LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc), - } - } - } - - impl ToComputedValue for specified::LengthOrPercentage { - type ComputedValue = LengthOrPercentage; - - fn to_computed_value(&self, context: &Context) -> LengthOrPercentage { - match *self { - specified::LengthOrPercentage::Length(value) => { - LengthOrPercentage::Length(value.to_computed_value(context)) - } - specified::LengthOrPercentage::Percentage(value) => { - LengthOrPercentage::Percentage(value.0) - } - specified::LengthOrPercentage::Calc(calc) => { - LengthOrPercentage::Calc(calc.to_computed_value(context)) - } - } - } - } - - impl ::cssparser::ToCss for LengthOrPercentage { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentage::Length(length) => length.to_css(dest), - LengthOrPercentage::Percentage(percentage) - => write!(dest, "{}%", percentage * 100.), - LengthOrPercentage::Calc(calc) => calc.to_css(dest), - } - } - } - - #[derive(PartialEq, Clone, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentageOrAuto { - Length(Au), - Percentage(CSSFloat), - Auto, - Calc(CalcLengthOrPercentage), - } - - impl LengthOrPercentageOrAuto { - /// Returns true if the computed value is absolute 0 or 0%. - /// - /// (Returns false for calc() values, even if ones that may resolve to zero.) - #[inline] - pub fn is_definitely_zero(&self) -> bool { - use self::LengthOrPercentageOrAuto::*; - match *self { - Length(Au(0)) | Percentage(0.0) => true, - Length(_) | Percentage(_) | Calc(_) | Auto => false - } - } - } - - impl fmt::Debug for LengthOrPercentageOrAuto { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length), - LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - LengthOrPercentageOrAuto::Auto => write!(f, "auto"), - LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc), - } - } - } - - impl ToComputedValue for specified::LengthOrPercentageOrAuto { - type ComputedValue = LengthOrPercentageOrAuto; - - #[inline] - fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAuto { - match *self { - specified::LengthOrPercentageOrAuto::Length(value) => { - LengthOrPercentageOrAuto::Length(value.to_computed_value(context)) - } - specified::LengthOrPercentageOrAuto::Percentage(value) => { - LengthOrPercentageOrAuto::Percentage(value.0) - } - specified::LengthOrPercentageOrAuto::Auto => { - LengthOrPercentageOrAuto::Auto - } - specified::LengthOrPercentageOrAuto::Calc(calc) => { - LengthOrPercentageOrAuto::Calc(calc.to_computed_value(context)) - } - } - } - } - - impl ::cssparser::ToCss for LengthOrPercentageOrAuto { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrAuto::Length(length) => length.to_css(dest), - LengthOrPercentageOrAuto::Percentage(percentage) - => write!(dest, "{}%", percentage * 100.), - LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), - LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), - } - } - } - - #[derive(PartialEq, Clone, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentageOrAutoOrContent { - Length(Au), - Percentage(CSSFloat), - Calc(CalcLengthOrPercentage), - Auto, - Content - } - - impl fmt::Debug for LengthOrPercentageOrAutoOrContent { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentageOrAutoOrContent::Length(length) => write!(f, "{:?}", length), - LengthOrPercentageOrAutoOrContent::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - LengthOrPercentageOrAutoOrContent::Calc(calc) => write!(f, "{:?}", calc), - LengthOrPercentageOrAutoOrContent::Auto => write!(f, "auto"), - LengthOrPercentageOrAutoOrContent::Content => write!(f, "content") - } - } - } - - impl ToComputedValue for specified::LengthOrPercentageOrAutoOrContent { - type ComputedValue = LengthOrPercentageOrAutoOrContent; - - #[inline] - fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAutoOrContent { - match *self { - specified::LengthOrPercentageOrAutoOrContent::Length(value) => { - LengthOrPercentageOrAutoOrContent::Length(value.to_computed_value(context)) - }, - specified::LengthOrPercentageOrAutoOrContent::Percentage(value) => { - LengthOrPercentageOrAutoOrContent::Percentage(value.0) - }, - specified::LengthOrPercentageOrAutoOrContent::Calc(calc) => { - LengthOrPercentageOrAutoOrContent::Calc(calc.to_computed_value(context)) - }, - specified::LengthOrPercentageOrAutoOrContent::Auto => { - LengthOrPercentageOrAutoOrContent::Auto - }, - specified::LengthOrPercentageOrAutoOrContent::Content => { - LengthOrPercentageOrAutoOrContent::Content - } - } - } - } - - impl ::cssparser::ToCss for LengthOrPercentageOrAutoOrContent { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrAutoOrContent::Length(length) => length.to_css(dest), - LengthOrPercentageOrAutoOrContent::Percentage(percentage) - => write!(dest, "{}%", percentage * 100.), - LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest), - LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"), - LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content") - } - } - } - - #[derive(PartialEq, Clone, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrPercentageOrNone { - Length(Au), - Percentage(CSSFloat), - Calc(CalcLengthOrPercentage), - None, - } - - impl fmt::Debug for LengthOrPercentageOrNone { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length), - LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.), - LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc), - LengthOrPercentageOrNone::None => write!(f, "none"), - } - } - } - - impl ToComputedValue for specified::LengthOrPercentageOrNone { - type ComputedValue = LengthOrPercentageOrNone; - - #[inline] - fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrNone { - match *self { - specified::LengthOrPercentageOrNone::Length(value) => { - LengthOrPercentageOrNone::Length(value.to_computed_value(context)) - } - specified::LengthOrPercentageOrNone::Percentage(value) => { - LengthOrPercentageOrNone::Percentage(value.0) - } - specified::LengthOrPercentageOrNone::Calc(calc) => { - LengthOrPercentageOrNone::Calc(calc.to_computed_value(context)) - } - specified::LengthOrPercentageOrNone::None => { - LengthOrPercentageOrNone::None - } - } - } - } - - impl ::cssparser::ToCss for LengthOrPercentageOrNone { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrNone::Length(length) => length.to_css(dest), - LengthOrPercentageOrNone::Percentage(percentage) => - write!(dest, "{}%", percentage * 100.), - LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest), - LengthOrPercentageOrNone::None => dest.write_str("none"), - } - } - } - - #[derive(PartialEq, Clone, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum LengthOrNone { - Length(Au), - None, - } - - impl fmt::Debug for LengthOrNone { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrNone::Length(length) => write!(f, "{:?}", length), - LengthOrNone::None => write!(f, "none"), - } - } - } - - impl ToComputedValue for specified::LengthOrNone { - type ComputedValue = LengthOrNone; - - #[inline] - fn to_computed_value(&self, context: &Context) -> LengthOrNone { - match *self { - specified::LengthOrNone::Length(specified::Length::Calc(calc)) => { - LengthOrNone::Length(calc.to_computed_value(context).length()) - } - specified::LengthOrNone::Length(value) => { - LengthOrNone::Length(value.to_computed_value(context)) - } - specified::LengthOrNone::None => { - LengthOrNone::None - } - } - } - } - - impl ::cssparser::ToCss for LengthOrNone { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrNone::Length(length) => length.to_css(dest), - LengthOrNone::None => dest.write_str("none"), - } - } - } - - impl ToComputedValue for specified::Image { - type ComputedValue = Image; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Image { - match *self { - specified::Image::Url(ref url) => Image::Url(url.clone()), - specified::Image::LinearGradient(ref linear_gradient) => { - Image::LinearGradient(linear_gradient.to_computed_value(context)) - } - } - } - } - - - /// Computed values for an image according to CSS-IMAGES. - #[derive(Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum Image { - Url(Url), - LinearGradient(LinearGradient), - } - - impl fmt::Debug for Image { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Image::Url(ref url) => write!(f, "url(\"{}\")", url), - Image::LinearGradient(ref grad) => write!(f, "linear-gradient({:?})", grad), - } - } - } - - /// Computed values for a CSS linear gradient. - #[derive(Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct LinearGradient { - /// The angle or corner of the gradient. - pub angle_or_corner: AngleOrCorner, - - /// The color stops. - pub stops: Vec<ColorStop>, - } - - impl ::cssparser::ToCss for LinearGradient { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(dest.write_str("linear-gradient(")); - try!(self.angle_or_corner.to_css(dest)); - for stop in &self.stops { - try!(dest.write_str(", ")); - try!(stop.to_css(dest)); - } - try!(dest.write_str(")")); - Ok(()) - } - } - - impl fmt::Debug for LinearGradient { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let _ = write!(f, "{:?}", self.angle_or_corner); - for stop in &self.stops { - let _ = write!(f, ", {:?}", stop); - } - Ok(()) - } - } - - /// Computed values for one color stop in a linear gradient. - #[derive(Clone, PartialEq, Copy)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct ColorStop { - /// The color of this stop. - pub color: CSSColor, - - /// The position of this stop. If not specified, this stop is placed halfway between the - /// point that precedes it and the point that follows it per CSS-IMAGES § 3.4. - pub position: Option<LengthOrPercentage>, - } - - impl ::cssparser::ToCss for ColorStop { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.color.to_css(dest)); - if let Some(position) = self.position { - try!(dest.write_str(" ")); - try!(position.to_css(dest)); - } - Ok(()) - } - } - - impl fmt::Debug for ColorStop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let _ = write!(f, "{:?}", self.color); - self.position.map(|pos| { - let _ = write!(f, " {:?}", pos); - }); - Ok(()) - } - } - - impl ToComputedValue for specified::LinearGradient { - type ComputedValue = LinearGradient; - - #[inline] - fn to_computed_value(&self, context: &Context) -> LinearGradient { - let specified::LinearGradient { - angle_or_corner, - ref stops - } = *self; - LinearGradient { - angle_or_corner: angle_or_corner, - stops: stops.iter().map(|stop| { - ColorStop { - color: stop.color.parsed, - position: match stop.position { - None => None, - Some(value) => Some(value.to_computed_value(context)), - }, - } - }).collect() - } - } - } - pub type Length = Au; - pub type Number = CSSFloat; - pub type Opacity = CSSFloat; -} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs new file mode 100644 index 00000000000..cefe1c7d6ac --- /dev/null +++ b/components/style/values/computed/mod.rs @@ -0,0 +1,634 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use app_units::Au; +use euclid::size::Size2D; +use properties::ComputedValues; +use std::fmt; +use super::LocalToCss; +use super::specified::AngleOrCorner; +use super::{CSSFloat, specified}; +use url::Url; +pub use cssparser::Color as CSSColor; +pub use super::specified::{Angle, BorderStyle, Time, UrlExtraData}; + +pub struct Context<'a> { + pub is_root_element: bool, + pub viewport_size: Size2D<Au>, + pub inherited_style: &'a ComputedValues, + + /// Values access through this need to be in the properties "computed early": + /// color, text-decoration, font-size, display, position, float, border-*-style, outline-style + pub style: ComputedValues, +} + +impl<'a> Context<'a> { + pub fn is_root_element(&self) -> bool { self.is_root_element } + pub fn viewport_size(&self) -> Size2D<Au> { self.viewport_size } + pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style } + pub fn style(&self) -> &ComputedValues { &self.style } + pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style } +} + +pub trait ToComputedValue { + type ComputedValue; + + #[inline] + fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue; +} + +pub trait ComputedValueAsSpecified {} + +impl<T> ToComputedValue for T where T: ComputedValueAsSpecified + Clone { + type ComputedValue = T; + + #[inline] + fn to_computed_value(&self, _context: &Context) -> T { + self.clone() + } +} + +impl ToComputedValue for specified::CSSColor { + type ComputedValue = CSSColor; + + #[inline] + fn to_computed_value(&self, _context: &Context) -> CSSColor { + self.parsed + } +} + +impl ComputedValueAsSpecified for specified::BorderStyle {} + +impl ToComputedValue for specified::Length { + type ComputedValue = Au; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Au { + match *self { + specified::Length::Absolute(length) => length, + specified::Length::Calc(calc) => calc.to_computed_value(context).length(), + specified::Length::FontRelative(length) => + length.to_computed_value(context.style().get_font().clone_font_size(), + context.style().root_font_size()), + specified::Length::ViewportPercentage(length) => + length.to_computed_value(context.viewport_size()), + specified::Length::ServoCharacterWidth(length) => + length.to_computed_value(context.style().get_font().clone_font_size()) + } + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct CalcLengthOrPercentage { + pub length: Option<Au>, + pub percentage: Option<CSSFloat>, +} + +impl CalcLengthOrPercentage { + #[inline] + pub fn length(&self) -> Au { + self.length.unwrap_or(Au(0)) + } + + #[inline] + pub fn percentage(&self) -> CSSFloat { + self.percentage.unwrap_or(0.) + } +} + +impl From<LengthOrPercentage> for CalcLengthOrPercentage { + fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage { + match len { + LengthOrPercentage::Percentage(this) => { + CalcLengthOrPercentage { + length: None, + percentage: Some(this), + } + } + LengthOrPercentage::Length(this) => { + CalcLengthOrPercentage { + length: Some(this), + percentage: None, + } + } + LengthOrPercentage::Calc(this) => { + this + } + } + } +} + +impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> { + fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> { + match len { + LengthOrPercentageOrAuto::Percentage(this) => { + Some(CalcLengthOrPercentage { + length: None, + percentage: Some(this), + }) + } + LengthOrPercentageOrAuto::Length(this) => { + Some(CalcLengthOrPercentage { + length: Some(this), + percentage: None, + }) + } + LengthOrPercentageOrAuto::Calc(this) => { + Some(this) + } + LengthOrPercentageOrAuto::Auto => { + None + } + } + } +} + +impl ::cssparser::ToCss for CalcLengthOrPercentage { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match (self.length, self.percentage) { + (None, Some(p)) => write!(dest, "{}%", p * 100.), + (Some(l), None) => write!(dest, "{}px", Au::to_px(l)), + (Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.), + _ => unreachable!() + } + } +} + +impl ToComputedValue for specified::CalcLengthOrPercentage { + type ComputedValue = CalcLengthOrPercentage; + + fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage { + let mut length = None; + + if let Some(absolute) = self.absolute { + length = Some(length.unwrap_or(Au(0)) + absolute); + } + + for val in &[self.vw, self.vh, self.vmin, self.vmax] { + if let Some(val) = *val { + length = Some(length.unwrap_or(Au(0)) + + val.to_computed_value(context.viewport_size())); + } + } + for val in &[self.ch, self.em, self.ex, self.rem] { + if let Some(val) = *val { + length = Some(length.unwrap_or(Au(0)) + val.to_computed_value( + context.style().get_font().clone_font_size(), context.style().root_font_size())); + } + } + + CalcLengthOrPercentage { length: length, percentage: self.percentage.map(|p| p.0) } + } +} + + +#[derive(Debug, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>); + +impl BorderRadiusSize { + pub fn zero() -> BorderRadiusSize { + BorderRadiusSize(Size2D::new(LengthOrPercentage::Length(Au(0)), LengthOrPercentage::Length(Au(0)))) + } +} + +impl ToComputedValue for specified::BorderRadiusSize { + type ComputedValue = BorderRadiusSize; + + #[inline] + fn to_computed_value(&self, context: &Context) -> BorderRadiusSize { + let w = self.0.width.to_computed_value(context); + let h = self.0.height.to_computed_value(context); + BorderRadiusSize(Size2D::new(w, h)) + } +} + +impl ::cssparser::ToCss for BorderRadiusSize { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.0.width.to_css(dest)); + try!(dest.write_str("/")); + self.0.height.to_css(dest) + } +} + +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentage { + Length(Au), + Percentage(CSSFloat), + Calc(CalcLengthOrPercentage), +} + +impl LengthOrPercentage { + #[inline] + pub fn zero() -> LengthOrPercentage { + LengthOrPercentage::Length(Au(0)) + } + + /// Returns true if the computed value is absolute 0 or 0%. + /// + /// (Returns false for calc() values, even if ones that may resolve to zero.) + #[inline] + pub fn is_definitely_zero(&self) -> bool { + use self::LengthOrPercentage::*; + match *self { + Length(Au(0)) | Percentage(0.0) => true, + Length(_) | Percentage(_) | Calc(_) => false + } + } +} + +impl fmt::Debug for LengthOrPercentage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LengthOrPercentage::Length(length) => write!(f, "{:?}", length), + LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc), + } + } +} + +impl ToComputedValue for specified::LengthOrPercentage { + type ComputedValue = LengthOrPercentage; + + fn to_computed_value(&self, context: &Context) -> LengthOrPercentage { + match *self { + specified::LengthOrPercentage::Length(value) => { + LengthOrPercentage::Length(value.to_computed_value(context)) + } + specified::LengthOrPercentage::Percentage(value) => { + LengthOrPercentage::Percentage(value.0) + } + specified::LengthOrPercentage::Calc(calc) => { + LengthOrPercentage::Calc(calc.to_computed_value(context)) + } + } + } +} + +impl ::cssparser::ToCss for LengthOrPercentage { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentage::Length(length) => length.to_css(dest), + LengthOrPercentage::Percentage(percentage) + => write!(dest, "{}%", percentage * 100.), + LengthOrPercentage::Calc(calc) => calc.to_css(dest), + } + } +} + +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentageOrAuto { + Length(Au), + Percentage(CSSFloat), + Auto, + Calc(CalcLengthOrPercentage), +} + +impl LengthOrPercentageOrAuto { + /// Returns true if the computed value is absolute 0 or 0%. + /// + /// (Returns false for calc() values, even if ones that may resolve to zero.) + #[inline] + pub fn is_definitely_zero(&self) -> bool { + use self::LengthOrPercentageOrAuto::*; + match *self { + Length(Au(0)) | Percentage(0.0) => true, + Length(_) | Percentage(_) | Calc(_) | Auto => false + } + } +} + +impl fmt::Debug for LengthOrPercentageOrAuto { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length), + LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + LengthOrPercentageOrAuto::Auto => write!(f, "auto"), + LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc), + } + } +} + +impl ToComputedValue for specified::LengthOrPercentageOrAuto { + type ComputedValue = LengthOrPercentageOrAuto; + + #[inline] + fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAuto { + match *self { + specified::LengthOrPercentageOrAuto::Length(value) => { + LengthOrPercentageOrAuto::Length(value.to_computed_value(context)) + } + specified::LengthOrPercentageOrAuto::Percentage(value) => { + LengthOrPercentageOrAuto::Percentage(value.0) + } + specified::LengthOrPercentageOrAuto::Auto => { + LengthOrPercentageOrAuto::Auto + } + specified::LengthOrPercentageOrAuto::Calc(calc) => { + LengthOrPercentageOrAuto::Calc(calc.to_computed_value(context)) + } + } + } +} + +impl ::cssparser::ToCss for LengthOrPercentageOrAuto { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentageOrAuto::Length(length) => length.to_css(dest), + LengthOrPercentageOrAuto::Percentage(percentage) + => write!(dest, "{}%", percentage * 100.), + LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), + LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), + } + } +} + +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentageOrAutoOrContent { + Length(Au), + Percentage(CSSFloat), + Calc(CalcLengthOrPercentage), + Auto, + Content +} + +impl fmt::Debug for LengthOrPercentageOrAutoOrContent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LengthOrPercentageOrAutoOrContent::Length(length) => write!(f, "{:?}", length), + LengthOrPercentageOrAutoOrContent::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + LengthOrPercentageOrAutoOrContent::Calc(calc) => write!(f, "{:?}", calc), + LengthOrPercentageOrAutoOrContent::Auto => write!(f, "auto"), + LengthOrPercentageOrAutoOrContent::Content => write!(f, "content") + } + } +} + +impl ToComputedValue for specified::LengthOrPercentageOrAutoOrContent { + type ComputedValue = LengthOrPercentageOrAutoOrContent; + + #[inline] + fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrAutoOrContent { + match *self { + specified::LengthOrPercentageOrAutoOrContent::Length(value) => { + LengthOrPercentageOrAutoOrContent::Length(value.to_computed_value(context)) + }, + specified::LengthOrPercentageOrAutoOrContent::Percentage(value) => { + LengthOrPercentageOrAutoOrContent::Percentage(value.0) + }, + specified::LengthOrPercentageOrAutoOrContent::Calc(calc) => { + LengthOrPercentageOrAutoOrContent::Calc(calc.to_computed_value(context)) + }, + specified::LengthOrPercentageOrAutoOrContent::Auto => { + LengthOrPercentageOrAutoOrContent::Auto + }, + specified::LengthOrPercentageOrAutoOrContent::Content => { + LengthOrPercentageOrAutoOrContent::Content + } + } + } +} + +impl ::cssparser::ToCss for LengthOrPercentageOrAutoOrContent { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentageOrAutoOrContent::Length(length) => length.to_css(dest), + LengthOrPercentageOrAutoOrContent::Percentage(percentage) + => write!(dest, "{}%", percentage * 100.), + LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest), + LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"), + LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content") + } + } +} + +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentageOrNone { + Length(Au), + Percentage(CSSFloat), + Calc(CalcLengthOrPercentage), + None, +} + +impl fmt::Debug for LengthOrPercentageOrNone { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length), + LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.), + LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc), + LengthOrPercentageOrNone::None => write!(f, "none"), + } + } +} + +impl ToComputedValue for specified::LengthOrPercentageOrNone { + type ComputedValue = LengthOrPercentageOrNone; + + #[inline] + fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrNone { + match *self { + specified::LengthOrPercentageOrNone::Length(value) => { + LengthOrPercentageOrNone::Length(value.to_computed_value(context)) + } + specified::LengthOrPercentageOrNone::Percentage(value) => { + LengthOrPercentageOrNone::Percentage(value.0) + } + specified::LengthOrPercentageOrNone::Calc(calc) => { + LengthOrPercentageOrNone::Calc(calc.to_computed_value(context)) + } + specified::LengthOrPercentageOrNone::None => { + LengthOrPercentageOrNone::None + } + } + } +} + +impl ::cssparser::ToCss for LengthOrPercentageOrNone { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentageOrNone::Length(length) => length.to_css(dest), + LengthOrPercentageOrNone::Percentage(percentage) => + write!(dest, "{}%", percentage * 100.), + LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest), + LengthOrPercentageOrNone::None => dest.write_str("none"), + } + } +} + +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrNone { + Length(Au), + None, +} + +impl fmt::Debug for LengthOrNone { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LengthOrNone::Length(length) => write!(f, "{:?}", length), + LengthOrNone::None => write!(f, "none"), + } + } +} + +impl ToComputedValue for specified::LengthOrNone { + type ComputedValue = LengthOrNone; + + #[inline] + fn to_computed_value(&self, context: &Context) -> LengthOrNone { + match *self { + specified::LengthOrNone::Length(specified::Length::Calc(calc)) => { + LengthOrNone::Length(calc.to_computed_value(context).length()) + } + specified::LengthOrNone::Length(value) => { + LengthOrNone::Length(value.to_computed_value(context)) + } + specified::LengthOrNone::None => { + LengthOrNone::None + } + } + } +} + +impl ::cssparser::ToCss for LengthOrNone { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrNone::Length(length) => length.to_css(dest), + LengthOrNone::None => dest.write_str("none"), + } + } +} + +impl ToComputedValue for specified::Image { + type ComputedValue = Image; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Image { + match *self { + specified::Image::Url(ref url, ref extra_data) => { + Image::Url(url.clone(), extra_data.clone()) + }, + specified::Image::LinearGradient(ref linear_gradient) => { + Image::LinearGradient(linear_gradient.to_computed_value(context)) + } + } + } +} + + +/// Computed values for an image according to CSS-IMAGES. +#[derive(Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum Image { + Url(Url, UrlExtraData), + LinearGradient(LinearGradient), +} + +impl fmt::Debug for Image { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Image::Url(ref url, ref _extra_data) => write!(f, "url(\"{}\")", url), + Image::LinearGradient(ref grad) => write!(f, "linear-gradient({:?})", grad), + } + } +} + +/// Computed values for a CSS linear gradient. +#[derive(Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct LinearGradient { + /// The angle or corner of the gradient. + pub angle_or_corner: AngleOrCorner, + + /// The color stops. + pub stops: Vec<ColorStop>, +} + +impl ::cssparser::ToCss for LinearGradient { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("linear-gradient(")); + try!(self.angle_or_corner.to_css(dest)); + for stop in &self.stops { + try!(dest.write_str(", ")); + try!(stop.to_css(dest)); + } + try!(dest.write_str(")")); + Ok(()) + } +} + +impl fmt::Debug for LinearGradient { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = write!(f, "{:?}", self.angle_or_corner); + for stop in &self.stops { + let _ = write!(f, ", {:?}", stop); + } + Ok(()) + } +} + +/// Computed values for one color stop in a linear gradient. +#[derive(Clone, PartialEq, Copy)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct ColorStop { + /// The color of this stop. + pub color: CSSColor, + + /// The position of this stop. If not specified, this stop is placed halfway between the + /// point that precedes it and the point that follows it per CSS-IMAGES § 3.4. + pub position: Option<LengthOrPercentage>, +} + +impl ::cssparser::ToCss for ColorStop { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.color.to_css(dest)); + if let Some(position) = self.position { + try!(dest.write_str(" ")); + try!(position.to_css(dest)); + } + Ok(()) + } +} + +impl fmt::Debug for ColorStop { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = write!(f, "{:?}", self.color); + self.position.map(|pos| { + let _ = write!(f, " {:?}", pos); + }); + Ok(()) + } +} + +impl ToComputedValue for specified::LinearGradient { + type ComputedValue = LinearGradient; + + #[inline] + fn to_computed_value(&self, context: &Context) -> LinearGradient { + let specified::LinearGradient { + angle_or_corner, + ref stops + } = *self; + LinearGradient { + angle_or_corner: angle_or_corner, + stops: stops.iter().map(|stop| { + ColorStop { + color: stop.color.parsed, + position: match stop.position { + None => None, + Some(value) => Some(value.to_computed_value(context)), + }, + } + }).collect() + } + } +} +pub type Length = Au; +pub type Number = CSSFloat; +pub type Opacity = CSSFloat; diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs new file mode 100644 index 00000000000..e926685f11b --- /dev/null +++ b/components/style/values/mod.rs @@ -0,0 +1,98 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Common [values][values] used in CSS. +//! +//! [values]: https://drafts.csswg.org/css-values/ + +pub use cssparser::RGBA; + +use app_units::Au; +use cssparser::CssStringWriter; +use std::fmt::{self, Write}; +use url::Url; + +macro_rules! define_numbered_css_keyword_enum { + ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => { + define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+); + }; + ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => { + #[allow(non_camel_case_types)] + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Copy, RustcEncodable, Debug)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] + pub enum $name { + $( $variant = $value ),+ + } + + impl $name { + pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> { + match_ignore_ascii_case! { try!(input.expect_ident()), + $( $css => Ok($name::$variant), )+ + _ => Err(()) + } + } + } + + impl ::cssparser::ToCss for $name { + fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result + where W: ::std::fmt::Write { + match *self { + $( $name::$variant => dest.write_str($css) ),+ + } + } + } + } +} + +pub mod computed; +pub mod specified; + +/// The real ToCss trait can't be implemented for types in crates that don't +/// depend on each other. +pub trait LocalToCss { + /// Serialize `self` in CSS syntax, writing to `dest`. + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write; + + /// Serialize `self` in CSS syntax and return a string. + /// + /// (This is a convenience wrapper for `to_css` and probably should not be overridden.) + #[inline] + fn to_css_string(&self) -> String { + let mut s = String::new(); + self.to_css(&mut s).unwrap(); + s + } +} + +impl LocalToCss for Au { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + write!(dest, "{}px", self.to_f64_px()) + } +} + +impl LocalToCss for Url { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("url(\"")); + try!(write!(CssStringWriter::new(dest), "{}", self)); + try!(dest.write_str("\")")); + Ok(()) + } +} + +pub type CSSFloat = f32; + +pub const FONT_MEDIUM_PX: i32 = 16; + +pub trait HasViewportPercentage { + fn has_viewport_percentage(&self) -> bool; +} + +pub trait NoViewportPercentage {} + +impl<T> HasViewportPercentage for T where T: NoViewportPercentage { + fn has_viewport_percentage(&self) -> bool { + false + } +} + diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs new file mode 100644 index 00000000000..93b270bc117 --- /dev/null +++ b/components/style/values/specified/mod.rs @@ -0,0 +1,1609 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use app_units::Au; +use cssparser::{self, Parser, ToCss, Token}; +use euclid::size::Size2D; +#[cfg(feature = "gecko")] +use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI}; +use parser::{ParserContext, ParserContextExtraData}; +use std::ascii::AsciiExt; +use std::cmp; +use std::f32::consts::PI; +use std::fmt; +use std::ops::Mul; +use style_traits::values::specified::AllowedNumericType; +use super::computed::{Context, ToComputedValue}; +use super::{CSSFloat, FONT_MEDIUM_PX, HasViewportPercentage, LocalToCss, NoViewportPercentage}; +use url::Url; + +impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order + +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct CSSColor { + pub parsed: cssparser::Color, + pub authored: Option<String>, +} +impl CSSColor { + pub fn parse(input: &mut Parser) -> Result<CSSColor, ()> { + let start_position = input.position(); + let authored = match input.next() { + Ok(Token::Ident(s)) => Some(s.into_owned()), + _ => None, + }; + input.reset(start_position); + Ok(CSSColor { + parsed: try!(cssparser::Color::parse(input)), + authored: authored, + }) + } +} + +impl NoViewportPercentage for CSSColor {} + +impl ToCss for CSSColor { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.authored { + Some(ref s) => dest.write_str(s), + None => self.parsed.to_css(dest), + } + } +} + +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct CSSRGBA { + pub parsed: cssparser::RGBA, + pub authored: Option<String>, +} + +impl NoViewportPercentage for CSSRGBA {} + +impl ToCss for CSSRGBA { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.authored { + Some(ref s) => dest.write_str(s), + None => self.parsed.to_css(dest), + } + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum FontRelativeLength { + Em(CSSFloat), + Ex(CSSFloat), + Ch(CSSFloat), + Rem(CSSFloat) +} + +impl ToCss for FontRelativeLength { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + FontRelativeLength::Em(length) => write!(dest, "{}em", length), + FontRelativeLength::Ex(length) => write!(dest, "{}ex", length), + FontRelativeLength::Ch(length) => write!(dest, "{}ch", length), + FontRelativeLength::Rem(length) => write!(dest, "{}rem", length) + } + } +} + +impl FontRelativeLength { + pub fn to_computed_value(&self, + reference_font_size: Au, + root_font_size: Au) + -> Au + { + match *self { + FontRelativeLength::Em(length) => reference_font_size.scale_by(length), + FontRelativeLength::Ex(length) | FontRelativeLength::Ch(length) => { + // https://github.com/servo/servo/issues/7462 + let em_factor = 0.5; + reference_font_size.scale_by(length * em_factor) + }, + FontRelativeLength::Rem(length) => root_font_size.scale_by(length) + } + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum ViewportPercentageLength { + Vw(CSSFloat), + Vh(CSSFloat), + Vmin(CSSFloat), + Vmax(CSSFloat) +} + +impl HasViewportPercentage for ViewportPercentageLength { + fn has_viewport_percentage(&self) -> bool { + true + } +} + +impl ToCss for ViewportPercentageLength { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + ViewportPercentageLength::Vw(length) => write!(dest, "{}vw", length), + ViewportPercentageLength::Vh(length) => write!(dest, "{}vh", length), + ViewportPercentageLength::Vmin(length) => write!(dest, "{}vmin", length), + ViewportPercentageLength::Vmax(length) => write!(dest, "{}vmax", length) + } + } +} + +impl ViewportPercentageLength { + pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au { + macro_rules! to_unit { + ($viewport_dimension:expr) => { + $viewport_dimension.to_f32_px() / 100.0 + } + } + + let value = match *self { + ViewportPercentageLength::Vw(length) => + length * to_unit!(viewport_size.width), + ViewportPercentageLength::Vh(length) => + length * to_unit!(viewport_size.height), + ViewportPercentageLength::Vmin(length) => + length * to_unit!(cmp::min(viewport_size.width, viewport_size.height)), + ViewportPercentageLength::Vmax(length) => + length * to_unit!(cmp::max(viewport_size.width, viewport_size.height)), + }; + Au::from_f32_px(value) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct CharacterWidth(pub i32); + +impl CharacterWidth { + pub fn to_computed_value(&self, reference_font_size: Au) -> Au { + // This applies the *converting a character width to pixels* algorithm as specified + // in HTML5 § 14.5.4. + // + // TODO(pcwalton): Find these from the font. + let average_advance = reference_font_size.scale_by(0.5); + let max_advance = reference_font_size; + average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum Length { + Absolute(Au), // application units + FontRelative(FontRelativeLength), + ViewportPercentage(ViewportPercentageLength), + + /// HTML5 "character width", as defined in HTML5 § 14.5.4. + /// + /// This cannot be specified by the user directly and is only generated by + /// `Stylist::synthesize_rules_for_legacy_attributes()`. + ServoCharacterWidth(CharacterWidth), + + Calc(CalcLengthOrPercentage), +} + +impl HasViewportPercentage for Length { + fn has_viewport_percentage(&self) -> bool { + match *self { + Length::ViewportPercentage(_) => true, + _ => false + } + } +} + +impl ToCss for Length { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()), + Length::FontRelative(length) => length.to_css(dest), + Length::ViewportPercentage(length) => length.to_css(dest), + Length::Calc(calc) => calc.to_css(dest), + Length::ServoCharacterWidth(_) + => panic!("internal CSS values should never be serialized"), + } + } +} + +impl Mul<CSSFloat> for Length { + type Output = Length; + + #[inline] + fn mul(self, scalar: CSSFloat) -> Length { + match self { + Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)), + Length::FontRelative(v) => Length::FontRelative(v * scalar), + Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar), + Length::Calc(_) => panic!("Can't multiply Calc!"), + Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"), + } + } +} + +impl Mul<CSSFloat> for FontRelativeLength { + type Output = FontRelativeLength; + + #[inline] + fn mul(self, scalar: CSSFloat) -> FontRelativeLength { + match self { + FontRelativeLength::Em(v) => FontRelativeLength::Em(v * scalar), + FontRelativeLength::Ex(v) => FontRelativeLength::Ex(v * scalar), + FontRelativeLength::Ch(v) => FontRelativeLength::Ch(v * scalar), + FontRelativeLength::Rem(v) => FontRelativeLength::Rem(v * scalar), + } + } +} + +impl Mul<CSSFloat> for ViewportPercentageLength { + type Output = ViewportPercentageLength; + + #[inline] + fn mul(self, scalar: CSSFloat) -> ViewportPercentageLength { + match self { + ViewportPercentageLength::Vw(v) => ViewportPercentageLength::Vw(v * scalar), + ViewportPercentageLength::Vh(v) => ViewportPercentageLength::Vh(v * scalar), + ViewportPercentageLength::Vmin(v) => ViewportPercentageLength::Vmin(v * scalar), + ViewportPercentageLength::Vmax(v) => ViewportPercentageLength::Vmax(v * scalar), + } + } +} + +const AU_PER_PX: CSSFloat = 60.; +const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; +const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; +const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4; +const AU_PER_Q: CSSFloat = AU_PER_MM / 4.; +const AU_PER_PT: CSSFloat = AU_PER_IN / 72.; +const AU_PER_PC: CSSFloat = AU_PER_PT * 12.; +impl Length { + // https://drafts.csswg.org/css-fonts-3/#font-size-prop + pub fn from_str(s: &str) -> Option<Length> { + Some(match_ignore_ascii_case! { s, + "xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5), + "x-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4), + "small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9), + "medium" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX)), + "large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5), + "x-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2), + "xx-large" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2), + + // https://github.com/servo/servo/issues/3423#issuecomment-56321664 + "smaller" => Length::FontRelative(FontRelativeLength::Em(0.85)), + "larger" => Length::FontRelative(FontRelativeLength::Em(1.2)), + _ => return None + }) + } + + #[inline] + fn parse_internal(input: &mut Parser, context: &AllowedNumericType) -> Result<Length, ()> { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => + Length::parse_dimension(value.value, unit), + Token::Number(ref value) if value.value == 0. => + Ok(Length::Absolute(Au(0))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => + input.parse_nested_block(CalcLengthOrPercentage::parse_length), + _ => Err(()) + } + } + pub fn parse(input: &mut Parser) -> Result<Length, ()> { + Length::parse_internal(input, &AllowedNumericType::All) + } + pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> { + Length::parse_internal(input, &AllowedNumericType::NonNegative) + } + pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> { + match_ignore_ascii_case! { unit, + "px" => Ok(Length::from_px(value)), + "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))), + "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))), + "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))), + "q" => Ok(Length::Absolute(Au((value * AU_PER_Q) as i32))), + "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))), + "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))), + // font-relative + "em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))), + "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))), + "ch" => Ok(Length::FontRelative(FontRelativeLength::Ch(value))), + "rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))), + // viewport percentages + "vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))), + "vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))), + "vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))), + "vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value))), + _ => Err(()) + } + } + #[inline] + pub fn from_px(px_value: CSSFloat) -> Length { + Length::Absolute(Au((px_value * AU_PER_PX) as i32)) + } +} + +#[derive(Clone, Debug)] +struct CalcSumNode { + products: Vec<CalcProductNode>, +} + +#[derive(Clone, Debug)] +struct CalcProductNode { + values: Vec<CalcValueNode> +} + +#[derive(Clone, Debug)] +enum CalcValueNode { + Length(Length), + Angle(Angle), + Time(Time), + Percentage(CSSFloat), + Number(CSSFloat), + Sum(Box<CalcSumNode>), +} + +#[derive(Clone, Debug)] +struct SimplifiedSumNode { + values: Vec<SimplifiedValueNode>, +} +impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode { + type Output = SimplifiedSumNode; + + #[inline] + fn mul(self, scalar: CSSFloat) -> SimplifiedSumNode { + SimplifiedSumNode { + values: self.values.iter().map(|p| p * scalar).collect() + } + } +} + +#[derive(Clone, Debug)] +enum SimplifiedValueNode { + Length(Length), + Angle(Angle), + Time(Time), + Percentage(CSSFloat), + Number(CSSFloat), + Sum(Box<SimplifiedSumNode>), +} +impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode { + type Output = SimplifiedValueNode; + + #[inline] + fn mul(self, scalar: CSSFloat) -> SimplifiedValueNode { + match *self { + SimplifiedValueNode::Length(l) => SimplifiedValueNode::Length(l * scalar), + SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p * scalar), + SimplifiedValueNode::Angle(Angle(a)) => SimplifiedValueNode::Angle(Angle(a * scalar)), + SimplifiedValueNode::Time(Time(t)) => SimplifiedValueNode::Time(Time(t * scalar)), + SimplifiedValueNode::Number(n) => SimplifiedValueNode::Number(n * scalar), + SimplifiedValueNode::Sum(ref s) => { + let sum = &**s * scalar; + SimplifiedValueNode::Sum(Box::new(sum)) + } + } + } +} + +pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> { + match try!(input.next()) { + Token::Number(ref value) => value.int_value.ok_or(()), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer))); + + let mut result = None; + + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Number(val) => + result = Some(result.unwrap_or(0) + val as i32), + _ => unreachable!() + } + } + + match result { + Some(result) => Ok(result), + _ => Err(()) + } + } + _ => Err(()) + } +} + +pub fn parse_number(input: &mut Parser) -> Result<f32, ()> { + match try!(input.next()) { + Token::Number(ref value) => Ok(value.value), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Number))); + + let mut result = None; + + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Number(val) => + result = Some(result.unwrap_or(0.) + val), + _ => unreachable!() + } + } + + match result { + Some(result) => Ok(result), + _ => Err(()) + } + } + _ => Err(()) + } +} + +#[derive(Clone, Copy, PartialEq)] +enum CalcUnit { + Number, + Integer, + Length, + LengthOrPercentage, + Angle, + Time, +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct CalcLengthOrPercentage { + pub absolute: Option<Au>, + pub vw: Option<ViewportPercentageLength>, + pub vh: Option<ViewportPercentageLength>, + pub vmin: Option<ViewportPercentageLength>, + pub vmax: Option<ViewportPercentageLength>, + pub em: Option<FontRelativeLength>, + pub ex: Option<FontRelativeLength>, + pub ch: Option<FontRelativeLength>, + pub rem: Option<FontRelativeLength>, + pub percentage: Option<Percentage>, +} +impl CalcLengthOrPercentage { + fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> { + let mut products = Vec::new(); + products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); + + while let Ok(token) = input.next() { + match token { + Token::Delim('+') => { + products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); + } + Token::Delim('-') => { + let mut right = try!(CalcLengthOrPercentage::parse_product(input, expected_unit)); + right.values.push(CalcValueNode::Number(-1.)); + products.push(right); + } + _ => return Err(()) + } + } + + Ok(CalcSumNode { products: products }) + } + + fn parse_product(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcProductNode, ()> { + let mut values = Vec::new(); + values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit))); + + loop { + let position = input.position(); + match input.next() { + Ok(Token::Delim('*')) => { + values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit))); + } + Ok(Token::Delim('/')) if expected_unit != CalcUnit::Integer => { + if let Ok(Token::Number(ref value)) = input.next() { + if value.value == 0. { + return Err(()); + } + values.push(CalcValueNode::Number(1. / value.value)); + } else { + return Err(()); + } + } + _ => { + input.reset(position); + break + } + } + } + + Ok(CalcProductNode { values: values }) + } + + fn parse_value(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcValueNode, ()> { + match (try!(input.next()), expected_unit) { + (Token::Number(ref value), _) => Ok(CalcValueNode::Number(value.value)), + (Token::Dimension(ref value, ref unit), CalcUnit::Length) | + (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => { + Length::parse_dimension(value.value, unit).map(CalcValueNode::Length) + } + (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => { + Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle) + } + (Token::Dimension(ref value, ref unit), CalcUnit::Time) => { + Time::parse_dimension(value.value, unit).map(CalcValueNode::Time) + } + (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) => + Ok(CalcValueNode::Percentage(value.unit_value)), + (Token::ParenthesisBlock, _) => { + input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, expected_unit)) + .map(|result| CalcValueNode::Sum(Box::new(result))) + }, + _ => Err(()) + } + } + + fn simplify_value_to_number(node: &CalcValueNode) -> Option<CSSFloat> { + match *node { + CalcValueNode::Number(number) => Some(number), + CalcValueNode::Sum(ref sum) => CalcLengthOrPercentage::simplify_sum_to_number(sum), + _ => None + } + } + + fn simplify_sum_to_number(node: &CalcSumNode) -> Option<CSSFloat> { + let mut sum = 0.; + for ref product in &node.products { + match CalcLengthOrPercentage::simplify_product_to_number(product) { + Some(number) => sum += number, + _ => return None + } + } + Some(sum) + } + + fn simplify_product_to_number(node: &CalcProductNode) -> Option<CSSFloat> { + let mut product = 1.; + for ref value in &node.values { + match CalcLengthOrPercentage::simplify_value_to_number(value) { + Some(number) => product *= number, + _ => return None + } + } + Some(product) + } + + fn simplify_products_in_sum(node: &CalcSumNode) -> Result<SimplifiedValueNode, ()> { + let mut simplified = Vec::new(); + for product in &node.products { + match try!(CalcLengthOrPercentage::simplify_product(product)) { + SimplifiedValueNode::Sum(ref sum) => simplified.extend_from_slice(&sum.values), + val => simplified.push(val), + } + } + + if simplified.len() == 1 { + Ok(simplified[0].clone()) + } else { + Ok(SimplifiedValueNode::Sum(Box::new(SimplifiedSumNode { values: simplified }))) + } + } + + fn simplify_product(node: &CalcProductNode) -> Result<SimplifiedValueNode, ()> { + let mut multiplier = 1.; + let mut node_with_unit = None; + for node in &node.values { + match CalcLengthOrPercentage::simplify_value_to_number(&node) { + Some(number) => multiplier *= number, + _ if node_with_unit.is_none() => { + node_with_unit = Some(match *node { + CalcValueNode::Sum(ref sum) => + try!(CalcLengthOrPercentage::simplify_products_in_sum(sum)), + CalcValueNode::Length(l) => SimplifiedValueNode::Length(l), + CalcValueNode::Angle(a) => SimplifiedValueNode::Angle(a), + CalcValueNode::Time(t) => SimplifiedValueNode::Time(t), + CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p), + _ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer") + }) + }, + _ => return Err(()), + } + } + + match node_with_unit { + None => Ok(SimplifiedValueNode::Number(multiplier)), + Some(ref value) => Ok(value * multiplier) + } + } + + fn parse_length(input: &mut Parser) -> Result<Length, ()> { + CalcLengthOrPercentage::parse(input, CalcUnit::Length).map(Length::Calc) + } + + fn parse_length_or_percentage(input: &mut Parser) -> Result<CalcLengthOrPercentage, ()> { + CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage) + } + + fn parse(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> { + let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit)); + + let mut simplified = Vec::new(); + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values), + value => simplified.push(value), + } + } + + let mut absolute = None; + let mut vw = None; + let mut vh = None; + let mut vmax = None; + let mut vmin = None; + let mut em = None; + let mut ex = None; + let mut ch = None; + let mut rem = None; + let mut percentage = None; + let mut number = None; + + for value in simplified { + match value { + SimplifiedValueNode::Percentage(p) => + percentage = Some(percentage.unwrap_or(0.) + p), + SimplifiedValueNode::Length(Length::Absolute(Au(au))) => + absolute = Some(absolute.unwrap_or(0) + au), + SimplifiedValueNode::Length(Length::ViewportPercentage(v)) => + match v { + ViewportPercentageLength::Vw(val) => + vw = Some(vw.unwrap_or(0.) + val), + ViewportPercentageLength::Vh(val) => + vh = Some(vh.unwrap_or(0.) + val), + ViewportPercentageLength::Vmin(val) => + vmin = Some(vmin.unwrap_or(0.) + val), + ViewportPercentageLength::Vmax(val) => + vmax = Some(vmax.unwrap_or(0.) + val), + }, + SimplifiedValueNode::Length(Length::FontRelative(f)) => + match f { + FontRelativeLength::Em(val) => + em = Some(em.unwrap_or(0.) + val), + FontRelativeLength::Ex(val) => + ex = Some(ex.unwrap_or(0.) + val), + FontRelativeLength::Ch(val) => + ch = Some(ch.unwrap_or(0.) + val), + FontRelativeLength::Rem(val) => + rem = Some(rem.unwrap_or(0.) + val), + }, + SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), + _ => return Err(()), + } + } + + Ok(CalcLengthOrPercentage { + absolute: absolute.map(Au), + vw: vw.map(ViewportPercentageLength::Vw), + vh: vh.map(ViewportPercentageLength::Vh), + vmax: vmax.map(ViewportPercentageLength::Vmax), + vmin: vmin.map(ViewportPercentageLength::Vmin), + em: em.map(FontRelativeLength::Em), + ex: ex.map(FontRelativeLength::Ex), + ch: ch.map(FontRelativeLength::Ch), + rem: rem.map(FontRelativeLength::Rem), + percentage: percentage.map(Percentage), + }) + } + + pub fn parse_time(input: &mut Parser) -> Result<Time, ()> { + let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time)); + + let mut simplified = Vec::new(); + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values), + value => simplified.push(value), + } + } + + let mut time = None; + + for value in simplified { + match value { + SimplifiedValueNode::Time(Time(val)) => + time = Some(time.unwrap_or(0.) + val), + _ => return Err(()), + } + } + + match time { + Some(time) => Ok(Time(time)), + _ => Err(()) + } + } + + pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> { + let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle)); + + let mut simplified = Vec::new(); + for ref node in ast.products { + match try!(CalcLengthOrPercentage::simplify_product(node)) { + SimplifiedValueNode::Sum(sum) => simplified.extend_from_slice(&sum.values), + value => simplified.push(value), + } + } + + let mut angle = None; + let mut number = None; + + for value in simplified { + match value { + SimplifiedValueNode::Angle(Angle(val)) => + angle = Some(angle.unwrap_or(0.) + val), + SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val), + _ => unreachable!() + } + } + + match (angle, number) { + (Some(angle), None) => Ok(Angle(angle)), + (None, Some(value)) if value == 0. => Ok(Angle(0.)), + _ => Err(()) + } + } +} + +impl ToCss for CalcLengthOrPercentage { + #[allow(unused_assignments)] + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + macro_rules! count { + ( $( $val:ident ),* ) => { + { + let mut count = 0; + $( + if let Some(_) = self.$val { + count += 1; + } + )* + count + } + }; + } + + macro_rules! serialize { + ( $( $val:ident ),* ) => { + { + let mut first_value = true; + $( + if let Some(val) = self.$val { + if !first_value { + try!(write!(dest, " + ")); + } else { + first_value = false; + } + try!(val.to_css(dest)); + } + )* + } + }; + } + + let count = count!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); + assert!(count > 0); + + if count > 1 { + try!(write!(dest, "calc(")); + } + + serialize!(ch, em, ex, absolute, rem, vh, vmax, vmin, vw, percentage); + + if count > 1 { + try!(write!(dest, ")")); + } + Ok(()) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct Percentage(pub CSSFloat); // [0 .. 100%] maps to [0.0 .. 1.0] + +impl ToCss for Percentage { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + write!(dest, "{}%", self.0 * 100.) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentage { + Length(Length), + Percentage(Percentage), + Calc(CalcLengthOrPercentage), +} + +impl HasViewportPercentage for LengthOrPercentage { + fn has_viewport_percentage(&self) -> bool { + match *self { + LengthOrPercentage::Length(length) => length.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for LengthOrPercentage { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentage::Length(length) => length.to_css(dest), + LengthOrPercentage::Percentage(percentage) => percentage.to_css(dest), + LengthOrPercentage::Calc(calc) => calc.to_css(dest), + } + } +} +impl LengthOrPercentage { + pub fn zero() -> LengthOrPercentage { + LengthOrPercentage::Length(Length::Absolute(Au(0))) + } + + fn parse_internal(input: &mut Parser, context: &AllowedNumericType) + -> Result<LengthOrPercentage, ()> + { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => + Length::parse_dimension(value.value, unit).map(LengthOrPercentage::Length), + Token::Percentage(ref value) if context.is_ok(value.unit_value) => + Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))), + Token::Number(ref value) if value.value == 0. => + Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); + Ok(LengthOrPercentage::Calc(calc)) + }, + _ => Err(()) + } + } + #[inline] + pub fn parse(input: &mut Parser) -> Result<LengthOrPercentage, ()> { + LengthOrPercentage::parse_internal(input, &AllowedNumericType::All) + } + #[inline] + pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> { + LengthOrPercentage::parse_internal(input, &AllowedNumericType::NonNegative) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentageOrAuto { + Length(Length), + Percentage(Percentage), + Auto, + Calc(CalcLengthOrPercentage), +} + +impl HasViewportPercentage for LengthOrPercentageOrAuto { + fn has_viewport_percentage(&self) -> bool { + match *self { + LengthOrPercentageOrAuto::Length(length) => length.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for LengthOrPercentageOrAuto { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentageOrAuto::Length(length) => length.to_css(dest), + LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest), + LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), + LengthOrPercentageOrAuto::Calc(calc) => calc.to_css(dest), + } + } +} + +impl LengthOrPercentageOrAuto { + fn parse_internal(input: &mut Parser, context: &AllowedNumericType) + -> Result<LengthOrPercentageOrAuto, ()> + { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => + Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAuto::Length), + Token::Percentage(ref value) if context.is_ok(value.unit_value) => + Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))), + Token::Number(ref value) if value.value == 0. => + Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))), + Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => + Ok(LengthOrPercentageOrAuto::Auto), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); + Ok(LengthOrPercentageOrAuto::Calc(calc)) + }, + _ => Err(()) + } + } + #[inline] + pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { + LengthOrPercentageOrAuto::parse_internal(input, &AllowedNumericType::All) + } + #[inline] + pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { + LengthOrPercentageOrAuto::parse_internal(input, &AllowedNumericType::NonNegative) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentageOrNone { + Length(Length), + Percentage(Percentage), + Calc(CalcLengthOrPercentage), + None, +} + +impl HasViewportPercentage for LengthOrPercentageOrNone { + fn has_viewport_percentage(&self) -> bool { + match *self { + LengthOrPercentageOrNone::Length(length) => length.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for LengthOrPercentageOrNone { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentageOrNone::Length(length) => length.to_css(dest), + LengthOrPercentageOrNone::Percentage(percentage) => percentage.to_css(dest), + LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest), + LengthOrPercentageOrNone::None => dest.write_str("none"), + } + } +} +impl LengthOrPercentageOrNone { + fn parse_internal(input: &mut Parser, context: &AllowedNumericType) + -> Result<LengthOrPercentageOrNone, ()> + { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => + Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrNone::Length), + Token::Percentage(ref value) if context.is_ok(value.unit_value) => + Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))), + Token::Number(ref value) if value.value == 0. => + Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); + Ok(LengthOrPercentageOrNone::Calc(calc)) + }, + Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => + Ok(LengthOrPercentageOrNone::None), + _ => Err(()) + } + } + #[inline] + pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> { + LengthOrPercentageOrNone::parse_internal(input, &AllowedNumericType::All) + } + #[inline] + pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> { + LengthOrPercentageOrNone::parse_internal(input, &AllowedNumericType::NonNegative) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrNone { + Length(Length), + None, +} + +impl HasViewportPercentage for LengthOrNone { + fn has_viewport_percentage(&self) -> bool { + match *self { + LengthOrNone::Length(length) => length.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for LengthOrNone { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrNone::Length(length) => length.to_css(dest), + LengthOrNone::None => dest.write_str("none"), + } + } +} +impl LengthOrNone { + fn parse_internal(input: &mut Parser, context: &AllowedNumericType) + -> Result<LengthOrNone, ()> + { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => + Length::parse_dimension(value.value, unit).map(LengthOrNone::Length), + Token::Number(ref value) if value.value == 0. => + Ok(LengthOrNone::Length(Length::Absolute(Au(0)))), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => + input.parse_nested_block(CalcLengthOrPercentage::parse_length).map(LengthOrNone::Length), + Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => + Ok(LengthOrNone::None), + _ => Err(()) + } + } + #[inline] + pub fn parse(input: &mut Parser) -> Result<LengthOrNone, ()> { + LengthOrNone::parse_internal(input, &AllowedNumericType::All) + } + #[inline] + pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrNone, ()> { + LengthOrNone::parse_internal(input, &AllowedNumericType::NonNegative) + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum LengthOrPercentageOrAutoOrContent { + Length(Length), + Percentage(Percentage), + Calc(CalcLengthOrPercentage), + Auto, + Content +} + +impl HasViewportPercentage for LengthOrPercentageOrAutoOrContent { + fn has_viewport_percentage(&self) -> bool { + match *self { + LengthOrPercentageOrAutoOrContent::Length(length) => length.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for LengthOrPercentageOrAutoOrContent { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + LengthOrPercentageOrAutoOrContent::Length(len) => len.to_css(dest), + LengthOrPercentageOrAutoOrContent::Percentage(perc) => perc.to_css(dest), + LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"), + LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content"), + LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest), + } + } +} + +impl LengthOrPercentageOrAutoOrContent { + pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAutoOrContent, ()> { + let context = AllowedNumericType::NonNegative; + match try!(input.next()) { + Token::Dimension(ref value, ref unit) if context.is_ok(value.value) => + Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAutoOrContent::Length), + Token::Percentage(ref value) if context.is_ok(value.unit_value) => + Ok(LengthOrPercentageOrAutoOrContent::Percentage(Percentage(value.unit_value))), + Token::Number(ref value) if value.value == 0. => + Ok(LengthOrPercentageOrAutoOrContent::Length(Length::Absolute(Au(0)))), + Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => + Ok(LengthOrPercentageOrAutoOrContent::Auto), + Token::Ident(ref value) if value.eq_ignore_ascii_case("content") => + Ok(LengthOrPercentageOrAutoOrContent::Content), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage)); + Ok(LengthOrPercentageOrAutoOrContent::Calc(calc)) + }, + _ => Err(()) + } + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>); + +impl NoViewportPercentage for BorderRadiusSize {} + +impl BorderRadiusSize { + pub fn zero() -> BorderRadiusSize { + let zero = LengthOrPercentage::Length(Length::Absolute(Au(0))); + BorderRadiusSize(Size2D::new(zero, zero)) + } + + pub fn new(width: LengthOrPercentage, height: LengthOrPercentage) -> BorderRadiusSize { + BorderRadiusSize(Size2D::new(width, height)) + } + + pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize { + BorderRadiusSize(Size2D::new(radius, radius)) + } + + #[inline] + pub fn parse(input: &mut Parser) -> Result<BorderRadiusSize, ()> { + let first = try!(LengthOrPercentage::parse_non_negative(input)); + let second = input.try(LengthOrPercentage::parse_non_negative).unwrap_or(first); + Ok(BorderRadiusSize(Size2D::new(first, second))) + } +} + +impl ToCss for BorderRadiusSize { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.0.width.to_css(dest)); + try!(dest.write_str(" ")); + self.0.height.to_css(dest) + } +} + +// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position +#[derive(Clone, PartialEq, Copy)] +pub enum PositionComponent { + LengthOrPercentage(LengthOrPercentage), + Center, + Left, + Right, + Top, + Bottom, +} + +impl HasViewportPercentage for PositionComponent { + fn has_viewport_percentage(&self) -> bool { + match *self { + PositionComponent::LengthOrPercentage(length) => length.has_viewport_percentage(), + _ => false + } + } +} + +impl PositionComponent { + pub fn parse(input: &mut Parser) -> Result<PositionComponent, ()> { + input.try(LengthOrPercentage::parse) + .map(PositionComponent::LengthOrPercentage) + .or_else(|()| { + match try!(input.next()) { + Token::Ident(value) => { + match_ignore_ascii_case! { value, + "center" => Ok(PositionComponent::Center), + "left" => Ok(PositionComponent::Left), + "right" => Ok(PositionComponent::Right), + "top" => Ok(PositionComponent::Top), + "bottom" => Ok(PositionComponent::Bottom), + _ => Err(()) + } + }, + _ => Err(()) + } + }) + } + #[inline] + pub fn to_length_or_percentage(self) -> LengthOrPercentage { + match self { + PositionComponent::LengthOrPercentage(value) => value, + PositionComponent::Center => LengthOrPercentage::Percentage(Percentage(0.5)), + PositionComponent::Left | + PositionComponent::Top => LengthOrPercentage::Percentage(Percentage(0.0)), + PositionComponent::Right | + PositionComponent::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), + } + } +} + +#[derive(Clone, PartialEq, PartialOrd, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] +/// An angle, normalized to radians. +pub struct Angle(pub CSSFloat); + +impl ToCss for Angle { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + write!(dest, "{}rad", self.0) + } +} + +impl Angle { + #[inline] + pub fn radians(self) -> f32 { + self.0 + } + + #[inline] + pub fn from_radians(r: f32) -> Self { + Angle(r) + } +} + +const RAD_PER_DEG: CSSFloat = PI / 180.0; +const RAD_PER_GRAD: CSSFloat = PI / 200.0; +const RAD_PER_TURN: CSSFloat = PI * 2.0; + +impl Angle { + /// Parses an angle according to CSS-VALUES § 6.1. + pub fn parse(input: &mut Parser) -> Result<Angle, ()> { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit), + Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + input.parse_nested_block(CalcLengthOrPercentage::parse_angle) + }, + _ => Err(()) + } + } + + pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> { + match_ignore_ascii_case! { unit, + "deg" => Ok(Angle(value * RAD_PER_DEG)), + "grad" => Ok(Angle(value * RAD_PER_GRAD)), + "turn" => Ok(Angle(value * RAD_PER_TURN)), + "rad" => Ok(Angle(value)), + _ => Err(()) + } + } +} + +#[derive(PartialEq, Clone, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct UrlExtraData { + #[cfg(feature = "gecko")] + pub base: GeckoArcURI, + #[cfg(feature = "gecko")] + pub referrer: GeckoArcURI, + #[cfg(feature = "gecko")] + pub principal: GeckoArcPrincipal, +} + +impl UrlExtraData { + #[cfg(feature = "servo")] + pub fn make_from(_context: &ParserContext) -> Option<UrlExtraData> { + Some(UrlExtraData { }) + } + + #[cfg(feature = "gecko")] + pub fn make_from(context: &ParserContext) -> Option<UrlExtraData> { + match context.extra_data { + ParserContextExtraData { + base: Some(ref base), + referrer: Some(ref referrer), + principal: Some(ref principal), + } => { + Some(UrlExtraData { + base: base.clone(), + referrer: referrer.clone(), + principal: principal.clone(), + }) + }, + _ => None, + } + } +} + +/// Specified values for an image according to CSS-IMAGES. +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum Image { + Url(Url, UrlExtraData), + LinearGradient(LinearGradient), +} + +impl ToCss for Image { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + use values::LocalToCss; + match *self { + Image::Url(ref url, ref _extra_data) => { + url.to_css(dest) + } + Image::LinearGradient(ref gradient) => gradient.to_css(dest) + } + } +} + +impl Image { + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> { + if let Ok(url) = input.try(|input| input.expect_url()) { + match UrlExtraData::make_from(context) { + Some(extra_data) => { + Ok(Image::Url(context.parse_url(&url), extra_data)) + }, + None => { + // FIXME(heycam) should ensure we always have a principal, etc., when + // parsing style attributes and re-parsing due to CSS Variables. + println!("stylo: skipping declaration without ParserContextExtraData"); + Err(()) + }, + } + } else { + match_ignore_ascii_case! { try!(input.expect_function()), + "linear-gradient" => { + Ok(Image::LinearGradient(try!( + input.parse_nested_block(LinearGradient::parse_function)))) + }, + _ => Err(()) + } + } + } +} + +/// Specified values for a CSS linear gradient. +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct LinearGradient { + /// The angle or corner of the gradient. + pub angle_or_corner: AngleOrCorner, + + /// The color stops. + pub stops: Vec<ColorStop>, +} + +impl ToCss for LinearGradient { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("linear-gradient(")); + try!(self.angle_or_corner.to_css(dest)); + for stop in &self.stops { + try!(dest.write_str(", ")); + try!(stop.to_css(dest)); + } + try!(dest.write_str(")")); + Ok(()) + } +} + +/// Specified values for an angle or a corner in a linear gradient. +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum AngleOrCorner { + Angle(Angle), + Corner(HorizontalDirection, VerticalDirection), +} + +impl ToCss for AngleOrCorner { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + AngleOrCorner::Angle(angle) => angle.to_css(dest), + AngleOrCorner::Corner(horizontal, vertical) => { + try!(dest.write_str("to ")); + try!(horizontal.to_css(dest)); + try!(dest.write_str(" ")); + try!(vertical.to_css(dest)); + Ok(()) + } + } + } +} + +/// Specified values for one color stop in a linear gradient. +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct ColorStop { + /// The color of this stop. + pub color: CSSColor, + + /// The position of this stop. If not specified, this stop is placed halfway between the + /// point that precedes it and the point that follows it. + pub position: Option<LengthOrPercentage>, +} + +impl ToCss for ColorStop { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.color.to_css(dest)); + if let Some(position) = self.position { + try!(dest.write_str(" ")); + try!(position.to_css(dest)); + } + Ok(()) + } +} + +define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right); +define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom); + +fn parse_one_color_stop(input: &mut Parser) -> Result<ColorStop, ()> { + Ok(ColorStop { + color: try!(CSSColor::parse(input)), + position: input.try(LengthOrPercentage::parse).ok(), + }) +} + +impl LinearGradient { + /// Parses a linear gradient from the given arguments. + pub fn parse_function(input: &mut Parser) -> Result<LinearGradient, ()> { + let angle_or_corner = if input.try(|input| input.expect_ident_matching("to")).is_ok() { + let (horizontal, vertical) = + if let Ok(value) = input.try(HorizontalDirection::parse) { + (Some(value), input.try(VerticalDirection::parse).ok()) + } else { + let value = try!(VerticalDirection::parse(input)); + (input.try(HorizontalDirection::parse).ok(), Some(value)) + }; + try!(input.expect_comma()); + match (horizontal, vertical) { + (None, Some(VerticalDirection::Top)) => { + AngleOrCorner::Angle(Angle(0.0)) + }, + (Some(HorizontalDirection::Right), None) => { + AngleOrCorner::Angle(Angle(PI * 0.5)) + }, + (None, Some(VerticalDirection::Bottom)) => { + AngleOrCorner::Angle(Angle(PI)) + }, + (Some(HorizontalDirection::Left), None) => { + AngleOrCorner::Angle(Angle(PI * 1.5)) + }, + (Some(horizontal), Some(vertical)) => { + AngleOrCorner::Corner(horizontal, vertical) + } + (None, None) => unreachable!(), + } + } else if let Ok(angle) = input.try(Angle::parse) { + try!(input.expect_comma()); + AngleOrCorner::Angle(angle) + } else { + AngleOrCorner::Angle(Angle(PI)) + }; + // Parse the color stops. + let stops = try!(input.parse_comma_separated(parse_one_color_stop)); + if stops.len() < 2 { + return Err(()) + } + Ok(LinearGradient { + angle_or_corner: angle_or_corner, + stops: stops, + }) + } +} + +pub fn parse_border_radius(input: &mut Parser) -> Result<BorderRadiusSize, ()> { + input.try(BorderRadiusSize::parse).or_else(|()| { + match_ignore_ascii_case! { try!(input.expect_ident()), + "thin" => Ok(BorderRadiusSize::circle( + LengthOrPercentage::Length(Length::from_px(1.)))), + "medium" => Ok(BorderRadiusSize::circle( + LengthOrPercentage::Length(Length::from_px(3.)))), + "thick" => Ok(BorderRadiusSize::circle( + LengthOrPercentage::Length(Length::from_px(5.)))), + _ => Err(()) + } + }) +} + +pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> { + input.try(Length::parse_non_negative).or_else(|()| { + match_ignore_ascii_case! { try!(input.expect_ident()), + "thin" => Ok(Length::from_px(1.)), + "medium" => Ok(Length::from_px(3.)), + "thick" => Ok(Length::from_px(5.)), + _ => Err(()) + } + }) +} + +// The integer values here correspond to the border conflict resolution rules in CSS 2.1 § +// 17.6.2.1. Higher values override lower values. +define_numbered_css_keyword_enum! { BorderStyle: + "none" => none = -1, + "solid" => solid = 6, + "double" => double = 7, + "dotted" => dotted = 4, + "dashed" => dashed = 5, + "hidden" => hidden = -2, + "groove" => groove = 1, + "ridge" => ridge = 3, + "inset" => inset = 0, + "outset" => outset = 2, +} + +impl NoViewportPercentage for BorderStyle {} + +impl BorderStyle { + pub fn none_or_hidden(&self) -> bool { + matches!(*self, BorderStyle::none | BorderStyle::hidden) + } +} + +/// A time in seconds according to CSS-VALUES § 6.2. +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct Time(pub CSSFloat); + +impl Time { + /// Returns the time in fractional seconds. + pub fn seconds(self) -> f32 { + let Time(seconds) = self; + seconds + } + + /// Parses a time according to CSS-VALUES § 6.2. + fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Time, ()> { + if unit.eq_ignore_ascii_case("s") { + Ok(Time(value)) + } else if unit.eq_ignore_ascii_case("ms") { + Ok(Time(value / 1000.0)) + } else { + Err(()) + } + } + + pub fn parse(input: &mut Parser) -> Result<Time, ()> { + match input.next() { + Ok(Token::Dimension(ref value, ref unit)) => { + Time::parse_dimension(value.value, &unit) + } + Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => { + input.parse_nested_block(CalcLengthOrPercentage::parse_time) + } + _ => Err(()) + } + } +} + +impl ToComputedValue for Time { + type ComputedValue = Time; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Time { + *self + } +} + +impl ToCss for Time { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + write!(dest, "{}s", self.0) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct Number(pub CSSFloat); + +impl NoViewportPercentage for Number {} + +impl Number { + pub fn parse(input: &mut Parser) -> Result<Number, ()> { + parse_number(input).map(Number) + } + + fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> { + match parse_number(input) { + Ok(value) if value < min => Err(()), + value => value.map(Number), + } + } + + pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> { + Number::parse_with_minimum(input, 0.0) + } + + pub fn parse_at_least_one(input: &mut Parser) -> Result<Number, ()> { + Number::parse_with_minimum(input, 1.0) + } +} + +impl ToComputedValue for Number { + type ComputedValue = CSSFloat; + + #[inline] + fn to_computed_value(&self, _: &Context) -> CSSFloat { self.0 } +} + +impl ToCss for Number { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct Opacity(pub CSSFloat); + +impl NoViewportPercentage for Opacity {} + +impl Opacity { + pub fn parse(input: &mut Parser) -> Result<Opacity, ()> { + parse_number(input).map(Opacity) + } +} + +impl ToComputedValue for Opacity { + type ComputedValue = CSSFloat; + + #[inline] + fn to_computed_value(&self, _: &Context) -> CSSFloat { + if self.0 < 0.0 { + 0.0 + } else if self.0 > 1.0 { + 1.0 + } else { + self.0 + } + } +} + +impl ToCss for Opacity { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } +} diff --git a/components/util/Cargo.toml b/components/util/Cargo.toml index e5f0bc9b5d3..d32c015637f 100644 --- a/components/util/Cargo.toml +++ b/components/util/Cargo.toml @@ -20,7 +20,7 @@ bitflags = "0.7" euclid = "0.7.1" getopts = "0.2.11" heapsize = "0.3.0" -ipc-channel = {git = "https://github.com/servo/ipc-channel", optional = true} +ipc-channel = {version = "0.4.0", optional = true} lazy_static = "0.2" log = "0.3.5" num_cpus = "0.2.2" @@ -30,5 +30,8 @@ serde_macros = {version = "0.7.11", optional = true} url = "1.0.0" plugins = {path = "../plugins", optional = true} +[dev-dependencies] +env_logger = "0.3" + [target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))'.dependencies] xdg = "2.0" diff --git a/components/util/lib.rs b/components/util/lib.rs index c36ec47a4cb..13e763b9cbc 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(feature = "servo", feature(custom_derive))] #![cfg_attr(feature = "servo", feature(plugin))] +#![cfg_attr(feature = "servo", feature(nonzero))] #![cfg_attr(feature = "servo", feature(reflect_marker))] #![cfg_attr(feature = "servo", plugin(serde_macros))] #![cfg_attr(feature = "servo", plugin(plugins))] @@ -12,6 +13,7 @@ extern crate app_units; #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; +extern crate core; extern crate euclid; extern crate getopts; #[macro_use] extern crate heapsize; @@ -30,6 +32,7 @@ pub mod geometry; #[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod ipc; #[allow(unsafe_code)] pub mod opts; pub mod prefs; +#[cfg(feature = "servo")] pub mod remutex; pub mod resource_files; pub mod thread; pub mod thread_state; diff --git a/components/util/opts.rs b/components/util/opts.rs index 70926438540..81b83d2b273 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -191,6 +191,9 @@ pub struct Opts { /// True to show webrender profiling stats on screen. pub webrender_stats: bool, + /// True to show webrender debug on screen. + pub webrender_debug: bool, + /// True if WebRender should use multisample antialiasing. pub use_msaa: bool, @@ -289,6 +292,9 @@ pub struct DebugOptions { /// Show webrender profiling stats on screen. pub webrender_stats: bool, + /// Show webrender debug on screen. + pub webrender_debug: bool, + /// Use multisample antialiasing in WebRender. pub use_msaa: bool, @@ -328,6 +334,7 @@ impl DebugOptions { "load-webfonts-synchronously" => debug_options.load_webfonts_synchronously = true, "disable-vsync" => debug_options.disable_vsync = true, "wr-stats" => debug_options.webrender_stats = true, + "wr-debug" => debug_options.webrender_debug = true, "msaa" => debug_options.use_msaa = true, "full-backtraces" => debug_options.full_backtraces = true, "" => {}, @@ -377,6 +384,7 @@ pub fn print_debug_usage(app: &str) -> ! { print_option("wr-stats", "Show WebRender profiler on screen."); print_option("msaa", "Use multisample antialiasing in WebRender."); print_option("full-backtraces", "Print full backtraces for all errors"); + print_option("wr-debug", "Display webrender tile borders. Must be used with -w option."); println!(""); @@ -511,6 +519,7 @@ pub fn default_opts() -> Opts { config_dir: None, full_backtraces: false, is_printing_version: false, + webrender_debug: false, } } @@ -570,7 +579,6 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { "config directory following xdg spec on linux platform", ""); opts.optflag("v", "version", "Display servo version information"); - let opt_match = match opts.parse(args) { Ok(m) => m, Err(f) => args_fail(&f.to_string()), @@ -815,6 +823,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { config_dir: opt_match.opt_str("config-dir"), full_backtraces: debug_options.full_backtraces, is_printing_version: is_printing_version, + webrender_debug: debug_options.webrender_debug, }; set_defaults(opts); diff --git a/components/util/remutex.rs b/components/util/remutex.rs new file mode 100644 index 00000000000..ec1c27a3d1a --- /dev/null +++ b/components/util/remutex.rs @@ -0,0 +1,217 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! An implementation of re-entrant mutexes. +//! +//! Re-entrant mutexes are like mutexes, but where it is expected +//! that a single thread may own a lock more than once. + +//! It provides the same interface as https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/remutex.rs +//! so if those types are ever exported, we should be able to replace this implemtation. + +use core::nonzero::NonZero; +use std::cell::{Cell, UnsafeCell}; +use std::mem; +use std::ops::Deref; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{LockResult, Mutex, MutexGuard, PoisonError, TryLockError, TryLockResult}; + +/// A type for thread ids. + +// TODO: can we use the thread-id crate for this? + +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct ThreadId(NonZero<usize>); + +lazy_static!{ static ref THREAD_COUNT: AtomicUsize = AtomicUsize::new(1); } + +impl ThreadId { + #[allow(unsafe_code)] + fn new() -> ThreadId { + let number = THREAD_COUNT.fetch_add(1, Ordering::SeqCst); + ThreadId(unsafe { NonZero::new(number) }) + } + pub fn current() -> ThreadId { + THREAD_ID.with(|tls| tls.clone()) + } +} + +thread_local!{ static THREAD_ID: ThreadId = ThreadId::new() } + +/// A type for atomic storage of thread ids. +#[derive(Debug)] +pub struct AtomicOptThreadId(AtomicUsize); + +impl AtomicOptThreadId { + pub fn new() -> AtomicOptThreadId { + AtomicOptThreadId(AtomicUsize::new(0)) + } + pub fn store(&self, value: Option<ThreadId>, ordering: Ordering) { + let number = value.map(|id| *id.0).unwrap_or(0); + self.0.store(number, ordering); + } + #[allow(unsafe_code)] + pub fn load(&self, ordering: Ordering) -> Option<ThreadId> { + let number = self.0.load(ordering); + if number == 0 { None } else { Some(ThreadId(unsafe { NonZero::new(number) })) } + } + #[allow(unsafe_code)] + pub fn swap(&self, value: Option<ThreadId>, ordering: Ordering) -> Option<ThreadId> { + let number = value.map(|id| *id.0).unwrap_or(0); + let number = self.0.swap(number, ordering); + if number == 0 { None } else { Some(ThreadId(unsafe { NonZero::new(number) })) } + } +} + +/// A type for hand-over-hand mutexes. +/// +/// These support `lock` and `unlock` functions. `lock` blocks waiting to become the +/// mutex owner. `unlock` can only be called by the lock owner, and panics otherwise. +/// They have the same happens-before and poisoning semantics as `Mutex`. + +// TODO: Can we use `raw_lock` and `raw_unlock` from `parking_lot`'s `Mutex` for this? + +pub struct HandOverHandMutex { + mutex: Mutex<()>, + owner: AtomicOptThreadId, + guard: UnsafeCell<Option<MutexGuard<'static, ()>>>, +} + +impl HandOverHandMutex { + pub fn new() -> HandOverHandMutex { + HandOverHandMutex { + mutex: Mutex::new(()), + owner: AtomicOptThreadId::new(), + guard: UnsafeCell::new(None), + } + } + #[allow(unsafe_code)] + pub fn lock(&self) -> LockResult<()> { + let (guard, result) = match self.mutex.lock() { + Ok(guard) => (guard, Ok(())), + Err(err) => (err.into_inner(), Err(PoisonError::new(()))), + }; + unsafe { *self.guard.get().as_mut().unwrap() = mem::transmute(guard) }; + self.owner.store(Some(ThreadId::current()), Ordering::Relaxed); + result + } + #[allow(unsafe_code)] + pub fn try_lock(&self) -> TryLockResult<()> { + let (guard, result) = match self.mutex.try_lock() { + Ok(guard) => (guard, Ok(())), + Err(TryLockError::WouldBlock) => return Err(TryLockError::WouldBlock), + Err(TryLockError::Poisoned(err)) => (err.into_inner(), Err(TryLockError::Poisoned(PoisonError::new(())))), + }; + unsafe { *self.guard.get().as_mut().unwrap() = mem::transmute(guard) }; + self.owner.store(Some(ThreadId::current()), Ordering::Relaxed); + result + } + #[allow(unsafe_code)] + pub fn unlock(&self) { + assert_eq!(Some(ThreadId::current()), self.owner.load(Ordering::Relaxed)); + self.owner.store(None, Ordering::Relaxed); + unsafe { *self.guard.get().as_mut().unwrap() = None; } + } + pub fn owner(&self) -> Option<ThreadId> { + self.owner.load(Ordering::Relaxed) + } +} + +#[allow(unsafe_code)] +unsafe impl Send for HandOverHandMutex {} + +/// A type for re-entrant mutexes. +/// +/// It provides the same interface as https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/remutex.rs + +pub struct ReentrantMutex<T> { + mutex: HandOverHandMutex, + count: Cell<usize>, + data: T, +} + +#[allow(unsafe_code)] +unsafe impl<T> Sync for ReentrantMutex<T> where T: Send {} + +impl<T> ReentrantMutex<T> { + pub fn new(data: T) -> ReentrantMutex<T> { + debug!("{:?} Creating new lock.", ThreadId::current()); + ReentrantMutex { + mutex: HandOverHandMutex::new(), + count: Cell::new(0), + data: data, + } + } + + pub fn lock(&self) -> LockResult<ReentrantMutexGuard<T>> { + debug!("{:?} Locking.", ThreadId::current()); + if self.mutex.owner() != Some(ThreadId::current()) { + debug!("{:?} Becoming owner.", ThreadId::current()); + if let Err(_) = self.mutex.lock() { + debug!("{:?} Poison!", ThreadId::current()); + return Err(PoisonError::new(self.mk_guard())); + } + debug!("{:?} Became owner.", ThreadId::current()); + } + Ok(self.mk_guard()) + } + + pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<T>> { + debug!("{:?} Try locking.", ThreadId::current()); + if self.mutex.owner() != Some(ThreadId::current()) { + debug!("{:?} Becoming owner?", ThreadId::current()); + if let Err(err) = self.mutex.try_lock() { + match err { + TryLockError::WouldBlock => { + debug!("{:?} Would block.", ThreadId::current()); + return Err(TryLockError::WouldBlock) + }, + TryLockError::Poisoned(_) => { + debug!("{:?} Poison!", ThreadId::current()); + return Err(TryLockError::Poisoned(PoisonError::new(self.mk_guard()))); + }, + } + } + debug!("{:?} Became owner.", ThreadId::current()); + } + Ok(self.mk_guard()) + } + + fn unlock(&self) { + debug!("{:?} Unlocking.", ThreadId::current()); + let count = self.count.get().checked_sub(1).expect("Underflowed lock count."); + debug!("{:?} Decrementing count to {}.", ThreadId::current(), count); + self.count.set(count); + if count == 0 { + debug!("{:?} Releasing mutex.", ThreadId::current()); + self.mutex.unlock(); + } + } + + fn mk_guard(&self) -> ReentrantMutexGuard<T> { + let count = self.count.get().checked_add(1).expect("Overflowed lock count."); + debug!("{:?} Incrementing count to {}.", ThreadId::current(), count); + self.count.set(count); + ReentrantMutexGuard { mutex: self } + } +} + +#[must_use] +pub struct ReentrantMutexGuard<'a, T> where T: 'static { + mutex: &'a ReentrantMutex<T>, +} + +impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { + #[allow(unsafe_code)] + fn drop(&mut self) { + self.mutex.unlock() + } +} + +impl<'a, T> Deref for ReentrantMutexGuard<'a, T> { + type Target = T; + fn deref(&self) -> &T { + &self.mutex.data + } +} diff --git a/components/webdriver_server/Cargo.toml b/components/webdriver_server/Cargo.toml index 693c7981f82..9a1b8e5c600 100644 --- a/components/webdriver_server/Cargo.toml +++ b/components/webdriver_server/Cargo.toml @@ -13,7 +13,7 @@ path = "lib.rs" euclid = "0.7.1" hyper = "0.9.9" image = "0.10" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" log = "0.3.5" msg = {path = "../msg"} plugins = {path = "../plugins"} diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 050cb68b639..1119eace7d9 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -738,7 +738,9 @@ impl Handler { Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), Err(WebDriverJSError::Timeout) => Err(WebDriverError::new(ErrorStatus::Timeout, "")), Err(WebDriverJSError::UnknownType) => Err(WebDriverError::new( - ErrorStatus::UnsupportedOperation, "Unsupported return type")) + ErrorStatus::UnsupportedOperation, "Unsupported return type")), + Err(WebDriverJSError::BrowsingContextNotFound) => Err(WebDriverError::new( + ErrorStatus::JavascriptError, "Pipeline id not found in browsing context")) } } diff --git a/etc/ci/upload_nightly.sh b/etc/ci/upload_nightly.sh index e3033cc0902..0e5d19d8dc3 100755 --- a/etc/ci/upload_nightly.sh +++ b/etc/ci/upload_nightly.sh @@ -41,8 +41,8 @@ main() { extension=dmg package=target/*."${extension}" elif [[ "${platform}" == "windows" ]]; then - extension=tar.gz - package=target/*."${extension}" + extension=msi + package=target/release/msi/*.msi else usage >&2 return 1 diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 61cbc98c96e..9b6ea69083d 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -57,7 +57,7 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -71,7 +71,7 @@ dependencies = [ [[package]] name = "aster" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -87,8 +87,8 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "servo-skia 0.20130412.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -126,7 +126,7 @@ dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -183,7 +183,7 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -202,10 +202,10 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)", ] @@ -266,7 +266,7 @@ dependencies = [ "gfx_traits 0.0.1", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -274,8 +274,8 @@ dependencies = [ "plugins 0.0.1", "profile_traits 0.0.1", "script_traits 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -297,7 +297,7 @@ dependencies = [ "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", "gfx_traits 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "layout_traits 0.0.1", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -308,8 +308,8 @@ dependencies = [ "profile_traits 0.0.1", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", @@ -333,7 +333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -362,7 +362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -389,8 +389,8 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -441,13 +441,13 @@ version = "0.0.1" dependencies = [ "devtools_traits 0.0.1", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] @@ -460,10 +460,10 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,7 +576,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -676,7 +676,7 @@ dependencies = [ "harfbuzz-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -689,8 +689,8 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "range 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "simd 0.1.0 (git+https://github.com/huonw/simd)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -719,8 +719,8 @@ dependencies = [ "profile_traits 0.0.1", "range 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -847,8 +847,8 @@ dependencies = [ "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -874,7 +874,7 @@ dependencies = [ "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -906,7 +906,7 @@ dependencies = [ "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -940,13 +940,13 @@ dependencies = [ [[package]] name = "ipc-channel" version = "0.4.0" -source = "git+https://github.com/servo/ipc-channel#346456b792f0a8e86b4ed077997408a697a06a0f" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bincode 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -962,7 +962,7 @@ dependencies = [ [[package]] name = "js" version = "0.1.3" -source = "git+https://github.com/servo/rust-mozjs#bc9add648b3174120d70d0bef3935912bd6f1313" +source = "git+https://github.com/servo/rust-mozjs#14e4556d7cd3dc4fd5eaf5e19e725a1325be14e6" dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1028,7 +1028,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -1040,7 +1040,7 @@ dependencies = [ "script_layout_interface 0.0.1", "script_traits 0.0.1", "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -1064,7 +1064,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layout 0.0.1", "layout_traits 0.0.1", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1076,7 +1076,7 @@ dependencies = [ "script_layout_interface 0.0.1", "script_traits 0.0.1", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", @@ -1088,7 +1088,7 @@ name = "layout_traits" version = "0.0.1" dependencies = [ "gfx 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "net_traits 0.0.1", "profile_traits 0.0.1", @@ -1212,7 +1212,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1221,8 +1221,8 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1238,7 +1238,7 @@ dependencies = [ [[package]] name = "mozjs_sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#2af5849a97a9f18acd482940ba3fa0c6797ed7eb" +source = "git+https://github.com/servo/mozjs#94eabc218780b696933122184e524bd35544c378" dependencies = [ "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1253,10 +1253,10 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)", ] @@ -1274,7 +1274,7 @@ dependencies = [ "flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "immeta 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1320,13 +1320,13 @@ dependencies = [ "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1428,7 +1428,7 @@ dependencies = [ "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1491,42 +1491,42 @@ dependencies = [ [[package]] name = "phf" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_codegen" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_generator" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_macros" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_shared" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1554,13 +1554,12 @@ dependencies = [ [[package]] name = "png" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1569,15 +1568,15 @@ name = "profile" version = "0.0.1" dependencies = [ "heartbeats-simple 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "profile_traits 0.0.1", "regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "task_info 0.0.1", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", @@ -1587,32 +1586,32 @@ dependencies = [ name = "profile_traits" version = "0.0.1" dependencies = [ - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quasi_codegen" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi_macros" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quasi_codegen 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1640,8 +1639,8 @@ dependencies = [ "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1725,7 +1724,7 @@ dependencies = [ "html5ever 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "js 0.1.3 (git+https://github.com/servo/rust-mozjs)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1736,8 +1735,8 @@ dependencies = [ "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_macros 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "profile_traits 0.0.1", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1749,7 +1748,7 @@ dependencies = [ "script_layout_interface 0.0.1", "script_traits 0.0.1", "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -1758,6 +1757,7 @@ dependencies = [ "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "video-metadata 0.1.3 (git+https://github.com/GuillaumeGomez/video-metadata-rs)", "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)", "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1775,7 +1775,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -1803,7 +1803,7 @@ dependencies = [ "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.6 (git+https://github.com/servo/rust-layers)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -1812,8 +1812,8 @@ dependencies = [ "plugins 0.0.1", "profile_traits 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1843,23 +1843,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_codegen" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_macros 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_item 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen_internals 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "serde_item" -version = "0.2.0" +name = "serde_codegen_internals" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1868,15 +1868,15 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_macros" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_codegen 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1898,7 +1898,7 @@ dependencies = [ "gfx 0.0.1", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "glutin_app 0.0.1", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "layout 0.0.1", "layout_thread 0.0.1", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2054,9 +2054,9 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_generator 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2082,8 +2082,8 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", @@ -2102,8 +2102,8 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2185,8 +2185,9 @@ dependencies = [ [[package]] name = "tinyfiledialogs" version = "0.1.0" -source = "git+https://github.com/jdm/tinyfiledialogs#3a30f8f95686195cb3bcecfc77ff77277a624a53" +source = "git+https://github.com/jdm/tinyfiledialogs#54f6aa4f579edbc726b8a764fd759a6d6ed0dd84" dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2248,7 +2249,7 @@ dependencies = [ "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2282,14 +2283,14 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2300,7 +2301,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "video-metadata" +version = "0.1.3" +source = "git+https://github.com/GuillaumeGomez/video-metadata-rs#44c8d547f9212be5d368a38d9f1238d85bc6728e" +dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2388,7 +2400,7 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "plugins 0.0.1", @@ -2404,7 +2416,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.1.0" -source = "git+https://github.com/servo/webrender#fd38ab8994be39ba194f56182af8c467b4f9f929" +source = "git+https://github.com/servo/webrender#79b807160ea3c3cf558072813c51a59bbaccb8dd" dependencies = [ "app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2415,7 +2427,7 @@ dependencies = [ "fnv 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2428,7 +2440,7 @@ dependencies = [ [[package]] name = "webrender_traits" version = "0.2.0" -source = "git+https://github.com/servo/webrender_traits#d86e51ace4fd1b43123e0490dc80f631be0726d0" +source = "git+https://github.com/servo/webrender_traits#a26ebe4da490cc1fb60d830c73cbefb135b768b1" dependencies = [ "app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2436,10 +2448,10 @@ dependencies = [ "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)", + "ipc-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "offscreen_gl_context 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2520,8 +2532,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock index bfdf613270d..405fadd6627 100644 --- a/ports/geckolib/Cargo.lock +++ b/ports/geckolib/Cargo.lock @@ -34,7 +34,7 @@ dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -139,7 +139,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -282,7 +282,7 @@ dependencies = [ [[package]] name = "serde" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -298,7 +298,7 @@ dependencies = [ "gecko_bindings 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/ports/geckolib/data.rs b/ports/geckolib/data.rs index 8e0b98b4266..be287d66a98 100644 --- a/ports/geckolib/data.rs +++ b/ports/geckolib/data.rs @@ -77,6 +77,17 @@ impl PerDocumentStyleData { pub fn borrow_mut_from_raw<'a>(data: *mut RawServoStyleSet) -> &'a mut Self { unsafe { &mut *(data as *mut PerDocumentStyleData) } } + + pub fn flush_stylesheets(&mut self) { + // The stylist wants to be flushed if either the stylesheets change or the + // device dimensions change. When we add support for media queries, we'll + // need to detect the latter case and trigger a flush as well. + if self.stylesheets_changed { + let _ = Arc::get_mut(&mut self.stylist).unwrap() + .update(&self.stylesheets, true); + self.stylesheets_changed = false; + } + } } impl Drop for PerDocumentStyleData { diff --git a/ports/geckolib/gecko_bindings/bindings.rs b/ports/geckolib/gecko_bindings/bindings.rs index 2b861dc7069..10d2bbb7c43 100644 --- a/ports/geckolib/gecko_bindings/bindings.rs +++ b/ports/geckolib/gecko_bindings/bindings.rs @@ -135,6 +135,7 @@ use structs::nsStyleCoord_CalcValue as CalcValue; use structs::nsStyleCoord_Calc as Calc; use structs::nsRestyleHint; use structs::ServoElementSnapshot; +use structs::nsChangeHint; use structs::SheetParsingMode; use structs::nsMainThreadPtrHandle; use structs::nsMainThreadPtrHolder; @@ -293,6 +294,10 @@ extern "C" { pub fn Gecko_GetNodeFlags(node: *mut RawGeckoNode) -> u32; pub fn Gecko_SetNodeFlags(node: *mut RawGeckoNode, flags: u32); pub fn Gecko_UnsetNodeFlags(node: *mut RawGeckoNode, flags: u32); + pub fn Gecko_CalcAndStoreStyleDifference(element: *mut RawGeckoElement, + newstyle: + *mut ServoComputedValues) + -> nsChangeHint; pub fn Gecko_EnsureTArrayCapacity(array: *mut ::std::os::raw::c_void, capacity: usize, elem_size: usize); pub fn Gecko_EnsureImageLayersLength(layers: *mut nsStyleImageLayers, @@ -308,6 +313,8 @@ extern "C" { pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc); pub fn Servo_StylesheetFromUTF8Bytes(bytes: *const u8, length: u32, parsing_mode: SheetParsingMode, + base_bytes: *const u8, + base_length: u32, base: *mut ThreadSafeURIHolder, referrer: *mut ThreadSafeURIHolder, principal: @@ -369,7 +376,6 @@ extern "C" { snapshot: *mut ServoElementSnapshot, set: *mut RawServoStyleSet) -> nsRestyleHint; - pub fn Servo_StyleWorkerThreadCount() -> u32; pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont); pub fn Gecko_CopyConstruct_nsStyleFont(ptr: *mut nsStyleFont, other: *const nsStyleFont); diff --git a/ports/geckolib/gecko_bindings/structs_debug.rs b/ports/geckolib/gecko_bindings/structs_debug.rs index 91731e2e941..1ac5b06026e 100644 --- a/ports/geckolib/gecko_bindings/structs_debug.rs +++ b/ports/geckolib/gecko_bindings/structs_debug.rs @@ -188,12 +188,6 @@ pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69; pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1; pub const NSID_LENGTH: ::std::os::raw::c_uint = 39; pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2; -pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1; -pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1; -pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402; -pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304; -pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304; -pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304; pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6; pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1; pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2; @@ -212,29 +206,6 @@ pub const NS_CORNER_BOTTOM_RIGHT_X: ::std::os::raw::c_uint = 4; pub const NS_CORNER_BOTTOM_RIGHT_Y: ::std::os::raw::c_uint = 5; pub const NS_CORNER_BOTTOM_LEFT_X: ::std::os::raw::c_uint = 6; pub const NS_CORNER_BOTTOM_LEFT_Y: ::std::os::raw::c_uint = 7; -pub const NS_STYLE_CLIP_SHAPE_SIZING_NOBOX: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_CLIP_SHAPE_SIZING_CONTENT: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_CLIP_SHAPE_SIZING_PADDING: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_CLIP_SHAPE_SIZING_BORDER: ::std::os::raw::c_uint = 3; -pub const NS_STYLE_CLIP_SHAPE_SIZING_MARGIN: ::std::os::raw::c_uint = 4; -pub const NS_STYLE_CLIP_SHAPE_SIZING_FILL: ::std::os::raw::c_uint = 5; -pub const NS_STYLE_CLIP_SHAPE_SIZING_STROKE: ::std::os::raw::c_uint = 6; -pub const NS_STYLE_CLIP_SHAPE_SIZING_VIEW: ::std::os::raw::c_uint = 7; -pub const NS_STYLE_BASIC_SHAPE_POLYGON: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_BASIC_SHAPE_CIRCLE: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_BASIC_SHAPE_ELLIPSE: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_BASIC_SHAPE_INSET: ::std::os::raw::c_uint = 3; -pub const NS_STYLE_BOX_SHADOW_INSET: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_FLOAT_EDGE_CONTENT_BOX: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_FLOAT_EDGE_MARGIN_BOX: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_USER_FOCUS_NONE: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_USER_FOCUS_IGNORE: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_USER_FOCUS_NORMAL: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_USER_FOCUS_SELECT_ALL: ::std::os::raw::c_uint = 3; -pub const NS_STYLE_USER_FOCUS_SELECT_BEFORE: ::std::os::raw::c_uint = 4; -pub const NS_STYLE_USER_FOCUS_SELECT_AFTER: ::std::os::raw::c_uint = 5; -pub const NS_STYLE_USER_FOCUS_SELECT_SAME: ::std::os::raw::c_uint = 6; -pub const NS_STYLE_USER_FOCUS_SELECT_MENU: ::std::os::raw::c_uint = 7; pub const NS_STYLE_USER_SELECT_NONE: ::std::os::raw::c_uint = 0; pub const NS_STYLE_USER_SELECT_TEXT: ::std::os::raw::c_uint = 1; pub const NS_STYLE_USER_SELECT_ELEMENT: ::std::os::raw::c_uint = 2; @@ -376,6 +347,7 @@ pub const NS_STYLE_BORDER_STYLE_AUTO: ::std::os::raw::c_uint = 10; pub const NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH: ::std::os::raw::c_uint = 0; pub const NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT: ::std::os::raw::c_uint = 1; pub const NS_STYLE_BORDER_IMAGE_REPEAT_ROUND: ::std::os::raw::c_uint = 2; +pub const NS_STYLE_BORDER_IMAGE_REPEAT_SPACE: ::std::os::raw::c_uint = 3; pub const NS_STYLE_BORDER_IMAGE_SLICE_NOFILL: ::std::os::raw::c_uint = 0; pub const NS_STYLE_BORDER_IMAGE_SLICE_FILL: ::std::os::raw::c_uint = 1; pub const NS_STYLE_CLEAR_NONE: ::std::os::raw::c_uint = 0; @@ -511,10 +483,6 @@ pub const NS_STYLE_FLOAT_LEFT: ::std::os::raw::c_uint = 1; pub const NS_STYLE_FLOAT_RIGHT: ::std::os::raw::c_uint = 2; pub const NS_STYLE_FLOAT_INLINE_START: ::std::os::raw::c_uint = 3; pub const NS_STYLE_FLOAT_INLINE_END: ::std::os::raw::c_uint = 4; -pub const NS_STYLE_CLIP_PATH_NONE: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_CLIP_PATH_URL: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_CLIP_PATH_SHAPE: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_CLIP_PATH_BOX: ::std::os::raw::c_uint = 3; pub const NS_STYLE_FILTER_NONE: ::std::os::raw::c_uint = 0; pub const NS_STYLE_FILTER_URL: ::std::os::raw::c_uint = 1; pub const NS_STYLE_FILTER_BLUR: ::std::os::raw::c_uint = 2; @@ -1924,6 +1892,34 @@ fn bindgen_test_layout_NS_ConvertUTF8toUTF16() { assert_eq!(::std::mem::align_of::<NS_ConvertUTF8toUTF16>() , 8usize); } pub type nsVoidableString = nsAutoString; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtrTraits<U> { + pub _phantom0: ::std::marker::PhantomData<U>, +} +#[repr(C)] +#[derive(Debug)] +pub struct RefPtr<T> { + pub mRawPtr: *mut T, +} +#[repr(C)] +#[derive(Debug)] +pub struct RefPtr_Proxy<T, R, Args> { + pub mRawPtr: *mut T, + pub _phantom0: ::std::marker::PhantomData<R>, + pub _phantom1: ::std::marker::PhantomData<Args>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtr_ConstRemovingRefPtrTraits<T, U> { + pub _phantom0: ::std::marker::PhantomData<T>, + pub _phantom1: ::std::marker::PhantomData<U>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtrGetterAddRefs<T> { + pub mTargetSmartPtr: *mut RefPtr<T>, +} /** * A "unique identifier". This is modeled after OSF DCE UUIDs. */ @@ -2080,34 +2076,6 @@ fn bindgen_test_layout_QITableEntry() { assert_eq!(::std::mem::size_of::<QITableEntry>() , 16usize); assert_eq!(::std::mem::align_of::<QITableEntry>() , 8usize); } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtrTraits<U> { - pub _phantom0: ::std::marker::PhantomData<U>, -} -#[repr(C)] -#[derive(Debug)] -pub struct RefPtr<T> { - pub mRawPtr: *mut T, -} -#[repr(C)] -#[derive(Debug)] -pub struct RefPtr_Proxy<T, R, Args> { - pub mRawPtr: *mut T, - pub _phantom0: ::std::marker::PhantomData<R>, - pub _phantom1: ::std::marker::PhantomData<Args>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr_ConstRemovingRefPtrTraits<T, U> { - pub _phantom0: ::std::marker::PhantomData<T>, - pub _phantom1: ::std::marker::PhantomData<U>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtrGetterAddRefs<T> { - pub mTargetSmartPtr: *mut RefPtr<T>, -} pub enum TileClient { } #[repr(C)] #[derive(Debug, Copy)] @@ -2735,12 +2703,6 @@ impl ::std::clone::Clone for nsIExpandedPrincipal { fn clone(&self) -> Self { *self } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _Make_integer_sequence<_Tp, _ISeq> { - pub _phantom0: ::std::marker::PhantomData<_Tp>, - pub _phantom1: ::std::marker::PhantomData<_ISeq>, -} -#[repr(C)] #[derive(Debug, Copy)] pub struct nsIURI { pub _base: nsISupports, @@ -2792,7 +2754,7 @@ impl ::std::clone::Clone for nsIRequest { #[repr(C)] #[derive(Debug, Copy)] pub struct EventStates { - pub mStates: ::std::os::raw::c_ulong, + pub mStates: ::std::os::raw::c_ulonglong, } impl ::std::clone::Clone for EventStates { fn clone(&self) -> Self { *self } @@ -2856,6 +2818,11 @@ pub enum nsNodeSupportsWeakRefTearoff { } pub enum nsNodeWeakReference { } pub enum nsDOMMutationObserver { } pub enum ServoNodeData { } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DefaultDelete<> { + pub _phantom0: ::std::marker::PhantomData<ServoNodeData>, +} pub enum EventListenerManager { } pub enum BoxQuadOptions { } pub enum ConvertCoordinateOptions { } @@ -2922,7 +2889,7 @@ fn bindgen_test_layout_nsMutationGuard() { extern "C" { #[link_name = "_ZN15nsMutationGuard11sGenerationE"] pub static mut nsMutationGuard_consts_sGeneration: - ::std::os::raw::c_ulong; + ::std::os::raw::c_ulonglong; } pub type Float = f32; #[repr(i8)] @@ -3022,6 +2989,7 @@ pub enum FontType { SKIA = 3, CAIRO = 4, COREGRAPHICS = 5, + FONTCONFIG = 6, } #[repr(i8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -3918,7 +3886,43 @@ fn bindgen_test_layout_nsFont() { } #[repr(i8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleBasicShape { Polygon = 0, Circle = 1, Ellipse = 2, Inset = 3, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum StyleBoxSizing { Content = 0, Border = 1, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleBoxShadowType { Inset = 0, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleClipPathType { None_ = 0, URL = 1, Shape = 2, Box = 3, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleClipShapeSizing { + NoBox = 0, + Content = 1, + Padding = 2, + Border = 3, + Margin = 4, + Fill = 5, + Stroke = 6, + View = 7, +} +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleFloatEdge { ContentBox = 0, MarginBox = 1, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleUserFocus { + None_ = 0, + Ignore = 1, + Normal = 2, + SelectAll = 3, + SelectBefore = 4, + SelectAfter = 5, + SelectSame = 6, + SelectMenu = 7, +} pub const eCSSProperty_COUNT_DUMMY: nsCSSProperty = nsCSSProperty::eCSSProperty_z_index; pub const eCSSProperty_all: nsCSSProperty = @@ -4079,305 +4083,306 @@ pub enum nsCSSProperty { eCSSProperty_grid_template_rows = 141, eCSSProperty_height = 142, eCSSProperty_hyphens = 143, - eCSSProperty_image_orientation = 144, - eCSSProperty_image_region = 145, - eCSSProperty_image_rendering = 146, - eCSSProperty_ime_mode = 147, - eCSSProperty_inline_size = 148, - eCSSProperty_isolation = 149, - eCSSProperty_justify_content = 150, - eCSSProperty_justify_items = 151, - eCSSProperty_justify_self = 152, - eCSSProperty__x_lang = 153, - eCSSProperty_left = 154, - eCSSProperty_letter_spacing = 155, - eCSSProperty_lighting_color = 156, - eCSSProperty_line_height = 157, - eCSSProperty_list_style_image = 158, - eCSSProperty_list_style_position = 159, - eCSSProperty_list_style_type = 160, - eCSSProperty_margin_block_end = 161, - eCSSProperty_margin_block_start = 162, - eCSSProperty_margin_bottom = 163, - eCSSProperty_margin_inline_end = 164, - eCSSProperty_margin_inline_start = 165, - eCSSProperty_margin_left = 166, - eCSSProperty_margin_right = 167, - eCSSProperty_margin_top = 168, - eCSSProperty_marker_end = 169, - eCSSProperty_marker_mid = 170, - eCSSProperty_marker_offset = 171, - eCSSProperty_marker_start = 172, - eCSSProperty_mask = 173, - eCSSProperty_mask_type = 174, - eCSSProperty_math_display = 175, - eCSSProperty_math_variant = 176, - eCSSProperty_max_block_size = 177, - eCSSProperty_max_height = 178, - eCSSProperty_max_inline_size = 179, - eCSSProperty_max_width = 180, - eCSSProperty_min_block_size = 181, - eCSSProperty__moz_min_font_size_ratio = 182, - eCSSProperty_min_height = 183, - eCSSProperty_min_inline_size = 184, - eCSSProperty_min_width = 185, - eCSSProperty_mix_blend_mode = 186, - eCSSProperty_object_fit = 187, - eCSSProperty_object_position = 188, - eCSSProperty_offset_block_end = 189, - eCSSProperty_offset_block_start = 190, - eCSSProperty_offset_inline_end = 191, - eCSSProperty_offset_inline_start = 192, - eCSSProperty_opacity = 193, - eCSSProperty_order = 194, - eCSSProperty_orient = 195, - eCSSProperty_osx_font_smoothing = 196, - eCSSProperty_outline_color = 197, - eCSSProperty_outline_offset = 198, - eCSSProperty__moz_outline_radius_bottomLeft = 199, - eCSSProperty__moz_outline_radius_bottomRight = 200, - eCSSProperty__moz_outline_radius_topLeft = 201, - eCSSProperty__moz_outline_radius_topRight = 202, - eCSSProperty_outline_style = 203, - eCSSProperty_outline_width = 204, - eCSSProperty_overflow_clip_box = 205, - eCSSProperty_overflow_x = 206, - eCSSProperty_overflow_y = 207, - eCSSProperty_padding_block_end = 208, - eCSSProperty_padding_block_start = 209, - eCSSProperty_padding_bottom = 210, - eCSSProperty_padding_inline_end = 211, - eCSSProperty_padding_inline_start = 212, - eCSSProperty_padding_left = 213, - eCSSProperty_padding_right = 214, - eCSSProperty_padding_top = 215, - eCSSProperty_page_break_after = 216, - eCSSProperty_page_break_before = 217, - eCSSProperty_page_break_inside = 218, - eCSSProperty_paint_order = 219, - eCSSProperty_perspective = 220, - eCSSProperty_perspective_origin = 221, - eCSSProperty_pointer_events = 222, - eCSSProperty_position = 223, - eCSSProperty_quotes = 224, - eCSSProperty_resize = 225, - eCSSProperty_right = 226, - eCSSProperty_ruby_align = 227, - eCSSProperty_ruby_position = 228, - eCSSProperty_script_level = 229, - eCSSProperty_script_min_size = 230, - eCSSProperty_script_size_multiplier = 231, - eCSSProperty_scroll_behavior = 232, - eCSSProperty_scroll_snap_coordinate = 233, - eCSSProperty_scroll_snap_destination = 234, - eCSSProperty_scroll_snap_points_x = 235, - eCSSProperty_scroll_snap_points_y = 236, - eCSSProperty_scroll_snap_type_x = 237, - eCSSProperty_scroll_snap_type_y = 238, - eCSSProperty_shape_rendering = 239, - eCSSProperty__x_span = 240, - eCSSProperty_stack_sizing = 241, - eCSSProperty_stop_color = 242, - eCSSProperty_stop_opacity = 243, - eCSSProperty_stroke = 244, - eCSSProperty_stroke_dasharray = 245, - eCSSProperty_stroke_dashoffset = 246, - eCSSProperty_stroke_linecap = 247, - eCSSProperty_stroke_linejoin = 248, - eCSSProperty_stroke_miterlimit = 249, - eCSSProperty_stroke_opacity = 250, - eCSSProperty_stroke_width = 251, - eCSSProperty__x_system_font = 252, - eCSSProperty__moz_tab_size = 253, - eCSSProperty_table_layout = 254, - eCSSProperty_text_align = 255, - eCSSProperty_text_align_last = 256, - eCSSProperty_text_anchor = 257, - eCSSProperty_text_combine_upright = 258, - eCSSProperty_text_decoration_color = 259, - eCSSProperty_text_decoration_line = 260, - eCSSProperty_text_decoration_style = 261, - eCSSProperty_text_emphasis_color = 262, - eCSSProperty_text_emphasis_position = 263, - eCSSProperty_text_emphasis_style = 264, - eCSSProperty__webkit_text_fill_color = 265, - eCSSProperty_text_indent = 266, - eCSSProperty_text_orientation = 267, - eCSSProperty_text_overflow = 268, - eCSSProperty_text_rendering = 269, - eCSSProperty_text_shadow = 270, - eCSSProperty_text_size_adjust = 271, - eCSSProperty__webkit_text_stroke_color = 272, - eCSSProperty__webkit_text_stroke_width = 273, - eCSSProperty_text_transform = 274, - eCSSProperty__x_text_zoom = 275, - eCSSProperty_top = 276, - eCSSProperty__moz_top_layer = 277, - eCSSProperty_touch_action = 278, - eCSSProperty_transform = 279, - eCSSProperty_transform_box = 280, - eCSSProperty_transform_origin = 281, - eCSSProperty_transform_style = 282, - eCSSProperty_transition_delay = 283, - eCSSProperty_transition_duration = 284, - eCSSProperty_transition_property = 285, - eCSSProperty_transition_timing_function = 286, - eCSSProperty_unicode_bidi = 287, - eCSSProperty_user_focus = 288, - eCSSProperty_user_input = 289, - eCSSProperty_user_modify = 290, - eCSSProperty_user_select = 291, - eCSSProperty_vector_effect = 292, - eCSSProperty_vertical_align = 293, - eCSSProperty_visibility = 294, - eCSSProperty_white_space = 295, - eCSSProperty_width = 296, - eCSSProperty_will_change = 297, - eCSSProperty__moz_window_dragging = 298, - eCSSProperty__moz_window_shadow = 299, - eCSSProperty_word_break = 300, - eCSSProperty_word_spacing = 301, - eCSSProperty_overflow_wrap = 302, - eCSSProperty_writing_mode = 303, - eCSSProperty_z_index = 304, - eCSSProperty_COUNT_no_shorthands = 305, - eCSSProperty_animation = 306, - eCSSProperty_background = 307, - eCSSProperty_background_position = 308, - eCSSProperty_border = 309, - eCSSProperty_border_block_end = 310, - eCSSProperty_border_block_start = 311, - eCSSProperty_border_bottom = 312, - eCSSProperty_border_color = 313, - eCSSProperty_border_image = 314, - eCSSProperty_border_inline_end = 315, - eCSSProperty_border_inline_start = 316, - eCSSProperty_border_left = 317, - eCSSProperty_border_radius = 318, - eCSSProperty_border_right = 319, - eCSSProperty_border_style = 320, - eCSSProperty_border_top = 321, - eCSSProperty_border_width = 322, - eCSSProperty__moz_column_rule = 323, - eCSSProperty__moz_columns = 324, - eCSSProperty_flex = 325, - eCSSProperty_flex_flow = 326, - eCSSProperty_font = 327, - eCSSProperty_font_variant = 328, - eCSSProperty_grid = 329, - eCSSProperty_grid_area = 330, - eCSSProperty_grid_column = 331, - eCSSProperty_grid_gap = 332, - eCSSProperty_grid_row = 333, - eCSSProperty_grid_template = 334, - eCSSProperty_list_style = 335, - eCSSProperty_margin = 336, - eCSSProperty_marker = 337, - eCSSProperty_outline = 338, - eCSSProperty__moz_outline_radius = 339, - eCSSProperty_overflow = 340, - eCSSProperty_padding = 341, - eCSSProperty_scroll_snap_type = 342, - eCSSProperty_text_decoration = 343, - eCSSProperty_text_emphasis = 344, - eCSSProperty__webkit_text_stroke = 345, - eCSSProperty__moz_transform = 346, - eCSSProperty_transition = 347, - eCSSProperty_COUNT = 348, - eCSSPropertyAlias_MozTransformOrigin = 349, - eCSSPropertyAlias_MozPerspectiveOrigin = 350, - eCSSPropertyAlias_MozPerspective = 351, - eCSSPropertyAlias_MozTransformStyle = 352, - eCSSPropertyAlias_MozBackfaceVisibility = 353, - eCSSPropertyAlias_MozBorderImage = 354, - eCSSPropertyAlias_MozTransition = 355, - eCSSPropertyAlias_MozTransitionDelay = 356, - eCSSPropertyAlias_MozTransitionDuration = 357, - eCSSPropertyAlias_MozTransitionProperty = 358, - eCSSPropertyAlias_MozTransitionTimingFunction = 359, - eCSSPropertyAlias_MozAnimation = 360, - eCSSPropertyAlias_MozAnimationDelay = 361, - eCSSPropertyAlias_MozAnimationDirection = 362, - eCSSPropertyAlias_MozAnimationDuration = 363, - eCSSPropertyAlias_MozAnimationFillMode = 364, - eCSSPropertyAlias_MozAnimationIterationCount = 365, - eCSSPropertyAlias_MozAnimationName = 366, - eCSSPropertyAlias_MozAnimationPlayState = 367, - eCSSPropertyAlias_MozAnimationTimingFunction = 368, - eCSSPropertyAlias_MozBoxSizing = 369, - eCSSPropertyAlias_MozFontFeatureSettings = 370, - eCSSPropertyAlias_MozFontLanguageOverride = 371, - eCSSPropertyAlias_MozPaddingEnd = 372, - eCSSPropertyAlias_MozPaddingStart = 373, - eCSSPropertyAlias_MozMarginEnd = 374, - eCSSPropertyAlias_MozMarginStart = 375, - eCSSPropertyAlias_MozBorderEnd = 376, - eCSSPropertyAlias_MozBorderEndColor = 377, - eCSSPropertyAlias_MozBorderEndStyle = 378, - eCSSPropertyAlias_MozBorderEndWidth = 379, - eCSSPropertyAlias_MozBorderStart = 380, - eCSSPropertyAlias_MozBorderStartColor = 381, - eCSSPropertyAlias_MozBorderStartStyle = 382, - eCSSPropertyAlias_MozBorderStartWidth = 383, - eCSSPropertyAlias_MozHyphens = 384, - eCSSPropertyAlias_MozTextAlignLast = 385, - eCSSPropertyAlias_WebkitAnimation = 386, - eCSSPropertyAlias_WebkitAnimationDelay = 387, - eCSSPropertyAlias_WebkitAnimationDirection = 388, - eCSSPropertyAlias_WebkitAnimationDuration = 389, - eCSSPropertyAlias_WebkitAnimationFillMode = 390, - eCSSPropertyAlias_WebkitAnimationIterationCount = 391, - eCSSPropertyAlias_WebkitAnimationName = 392, - eCSSPropertyAlias_WebkitAnimationPlayState = 393, - eCSSPropertyAlias_WebkitAnimationTimingFunction = 394, - eCSSPropertyAlias_WebkitFilter = 395, - eCSSPropertyAlias_WebkitTextSizeAdjust = 396, - eCSSPropertyAlias_WebkitTransform = 397, - eCSSPropertyAlias_WebkitTransformOrigin = 398, - eCSSPropertyAlias_WebkitTransformStyle = 399, - eCSSPropertyAlias_WebkitBackfaceVisibility = 400, - eCSSPropertyAlias_WebkitPerspective = 401, - eCSSPropertyAlias_WebkitPerspectiveOrigin = 402, - eCSSPropertyAlias_WebkitTransition = 403, - eCSSPropertyAlias_WebkitTransitionDelay = 404, - eCSSPropertyAlias_WebkitTransitionDuration = 405, - eCSSPropertyAlias_WebkitTransitionProperty = 406, - eCSSPropertyAlias_WebkitTransitionTimingFunction = 407, - eCSSPropertyAlias_WebkitBorderRadius = 408, - eCSSPropertyAlias_WebkitBorderTopLeftRadius = 409, - eCSSPropertyAlias_WebkitBorderTopRightRadius = 410, - eCSSPropertyAlias_WebkitBorderBottomLeftRadius = 411, - eCSSPropertyAlias_WebkitBorderBottomRightRadius = 412, - eCSSPropertyAlias_WebkitBackgroundClip = 413, - eCSSPropertyAlias_WebkitBackgroundOrigin = 414, - eCSSPropertyAlias_WebkitBackgroundSize = 415, - eCSSPropertyAlias_WebkitBorderImage = 416, - eCSSPropertyAlias_WebkitBoxShadow = 417, - eCSSPropertyAlias_WebkitBoxSizing = 418, - eCSSPropertyAlias_WebkitBoxFlex = 419, - eCSSPropertyAlias_WebkitBoxOrdinalGroup = 420, - eCSSPropertyAlias_WebkitBoxOrient = 421, - eCSSPropertyAlias_WebkitBoxDirection = 422, - eCSSPropertyAlias_WebkitBoxAlign = 423, - eCSSPropertyAlias_WebkitBoxPack = 424, - eCSSPropertyAlias_WebkitFlexDirection = 425, - eCSSPropertyAlias_WebkitFlexWrap = 426, - eCSSPropertyAlias_WebkitFlexFlow = 427, - eCSSPropertyAlias_WebkitOrder = 428, - eCSSPropertyAlias_WebkitFlex = 429, - eCSSPropertyAlias_WebkitFlexGrow = 430, - eCSSPropertyAlias_WebkitFlexShrink = 431, - eCSSPropertyAlias_WebkitFlexBasis = 432, - eCSSPropertyAlias_WebkitJustifyContent = 433, - eCSSPropertyAlias_WebkitAlignItems = 434, - eCSSPropertyAlias_WebkitAlignSelf = 435, - eCSSPropertyAlias_WebkitAlignContent = 436, - eCSSPropertyAlias_WebkitUserSelect = 437, - eCSSProperty_COUNT_with_aliases = 438, - eCSSPropertyExtra_all_properties = 439, - eCSSPropertyExtra_x_none_value = 440, - eCSSPropertyExtra_x_auto_value = 441, - eCSSPropertyExtra_variable = 442, + eCSSProperty_initial_letter = 144, + eCSSProperty_image_orientation = 145, + eCSSProperty_image_region = 146, + eCSSProperty_image_rendering = 147, + eCSSProperty_ime_mode = 148, + eCSSProperty_inline_size = 149, + eCSSProperty_isolation = 150, + eCSSProperty_justify_content = 151, + eCSSProperty_justify_items = 152, + eCSSProperty_justify_self = 153, + eCSSProperty__x_lang = 154, + eCSSProperty_left = 155, + eCSSProperty_letter_spacing = 156, + eCSSProperty_lighting_color = 157, + eCSSProperty_line_height = 158, + eCSSProperty_list_style_image = 159, + eCSSProperty_list_style_position = 160, + eCSSProperty_list_style_type = 161, + eCSSProperty_margin_block_end = 162, + eCSSProperty_margin_block_start = 163, + eCSSProperty_margin_bottom = 164, + eCSSProperty_margin_inline_end = 165, + eCSSProperty_margin_inline_start = 166, + eCSSProperty_margin_left = 167, + eCSSProperty_margin_right = 168, + eCSSProperty_margin_top = 169, + eCSSProperty_marker_end = 170, + eCSSProperty_marker_mid = 171, + eCSSProperty_marker_offset = 172, + eCSSProperty_marker_start = 173, + eCSSProperty_mask = 174, + eCSSProperty_mask_type = 175, + eCSSProperty_math_display = 176, + eCSSProperty_math_variant = 177, + eCSSProperty_max_block_size = 178, + eCSSProperty_max_height = 179, + eCSSProperty_max_inline_size = 180, + eCSSProperty_max_width = 181, + eCSSProperty_min_block_size = 182, + eCSSProperty__moz_min_font_size_ratio = 183, + eCSSProperty_min_height = 184, + eCSSProperty_min_inline_size = 185, + eCSSProperty_min_width = 186, + eCSSProperty_mix_blend_mode = 187, + eCSSProperty_object_fit = 188, + eCSSProperty_object_position = 189, + eCSSProperty_offset_block_end = 190, + eCSSProperty_offset_block_start = 191, + eCSSProperty_offset_inline_end = 192, + eCSSProperty_offset_inline_start = 193, + eCSSProperty_opacity = 194, + eCSSProperty_order = 195, + eCSSProperty_orient = 196, + eCSSProperty_osx_font_smoothing = 197, + eCSSProperty_outline_color = 198, + eCSSProperty_outline_offset = 199, + eCSSProperty__moz_outline_radius_bottomLeft = 200, + eCSSProperty__moz_outline_radius_bottomRight = 201, + eCSSProperty__moz_outline_radius_topLeft = 202, + eCSSProperty__moz_outline_radius_topRight = 203, + eCSSProperty_outline_style = 204, + eCSSProperty_outline_width = 205, + eCSSProperty_overflow_clip_box = 206, + eCSSProperty_overflow_x = 207, + eCSSProperty_overflow_y = 208, + eCSSProperty_padding_block_end = 209, + eCSSProperty_padding_block_start = 210, + eCSSProperty_padding_bottom = 211, + eCSSProperty_padding_inline_end = 212, + eCSSProperty_padding_inline_start = 213, + eCSSProperty_padding_left = 214, + eCSSProperty_padding_right = 215, + eCSSProperty_padding_top = 216, + eCSSProperty_page_break_after = 217, + eCSSProperty_page_break_before = 218, + eCSSProperty_page_break_inside = 219, + eCSSProperty_paint_order = 220, + eCSSProperty_perspective = 221, + eCSSProperty_perspective_origin = 222, + eCSSProperty_pointer_events = 223, + eCSSProperty_position = 224, + eCSSProperty_quotes = 225, + eCSSProperty_resize = 226, + eCSSProperty_right = 227, + eCSSProperty_ruby_align = 228, + eCSSProperty_ruby_position = 229, + eCSSProperty_script_level = 230, + eCSSProperty_script_min_size = 231, + eCSSProperty_script_size_multiplier = 232, + eCSSProperty_scroll_behavior = 233, + eCSSProperty_scroll_snap_coordinate = 234, + eCSSProperty_scroll_snap_destination = 235, + eCSSProperty_scroll_snap_points_x = 236, + eCSSProperty_scroll_snap_points_y = 237, + eCSSProperty_scroll_snap_type_x = 238, + eCSSProperty_scroll_snap_type_y = 239, + eCSSProperty_shape_rendering = 240, + eCSSProperty__x_span = 241, + eCSSProperty_stack_sizing = 242, + eCSSProperty_stop_color = 243, + eCSSProperty_stop_opacity = 244, + eCSSProperty_stroke = 245, + eCSSProperty_stroke_dasharray = 246, + eCSSProperty_stroke_dashoffset = 247, + eCSSProperty_stroke_linecap = 248, + eCSSProperty_stroke_linejoin = 249, + eCSSProperty_stroke_miterlimit = 250, + eCSSProperty_stroke_opacity = 251, + eCSSProperty_stroke_width = 252, + eCSSProperty__x_system_font = 253, + eCSSProperty__moz_tab_size = 254, + eCSSProperty_table_layout = 255, + eCSSProperty_text_align = 256, + eCSSProperty_text_align_last = 257, + eCSSProperty_text_anchor = 258, + eCSSProperty_text_combine_upright = 259, + eCSSProperty_text_decoration_color = 260, + eCSSProperty_text_decoration_line = 261, + eCSSProperty_text_decoration_style = 262, + eCSSProperty_text_emphasis_color = 263, + eCSSProperty_text_emphasis_position = 264, + eCSSProperty_text_emphasis_style = 265, + eCSSProperty__webkit_text_fill_color = 266, + eCSSProperty_text_indent = 267, + eCSSProperty_text_orientation = 268, + eCSSProperty_text_overflow = 269, + eCSSProperty_text_rendering = 270, + eCSSProperty_text_shadow = 271, + eCSSProperty_text_size_adjust = 272, + eCSSProperty__webkit_text_stroke_color = 273, + eCSSProperty__webkit_text_stroke_width = 274, + eCSSProperty_text_transform = 275, + eCSSProperty__x_text_zoom = 276, + eCSSProperty_top = 277, + eCSSProperty__moz_top_layer = 278, + eCSSProperty_touch_action = 279, + eCSSProperty_transform = 280, + eCSSProperty_transform_box = 281, + eCSSProperty_transform_origin = 282, + eCSSProperty_transform_style = 283, + eCSSProperty_transition_delay = 284, + eCSSProperty_transition_duration = 285, + eCSSProperty_transition_property = 286, + eCSSProperty_transition_timing_function = 287, + eCSSProperty_unicode_bidi = 288, + eCSSProperty_user_focus = 289, + eCSSProperty_user_input = 290, + eCSSProperty_user_modify = 291, + eCSSProperty_user_select = 292, + eCSSProperty_vector_effect = 293, + eCSSProperty_vertical_align = 294, + eCSSProperty_visibility = 295, + eCSSProperty_white_space = 296, + eCSSProperty_width = 297, + eCSSProperty_will_change = 298, + eCSSProperty__moz_window_dragging = 299, + eCSSProperty__moz_window_shadow = 300, + eCSSProperty_word_break = 301, + eCSSProperty_word_spacing = 302, + eCSSProperty_overflow_wrap = 303, + eCSSProperty_writing_mode = 304, + eCSSProperty_z_index = 305, + eCSSProperty_COUNT_no_shorthands = 306, + eCSSProperty_animation = 307, + eCSSProperty_background = 308, + eCSSProperty_background_position = 309, + eCSSProperty_border = 310, + eCSSProperty_border_block_end = 311, + eCSSProperty_border_block_start = 312, + eCSSProperty_border_bottom = 313, + eCSSProperty_border_color = 314, + eCSSProperty_border_image = 315, + eCSSProperty_border_inline_end = 316, + eCSSProperty_border_inline_start = 317, + eCSSProperty_border_left = 318, + eCSSProperty_border_radius = 319, + eCSSProperty_border_right = 320, + eCSSProperty_border_style = 321, + eCSSProperty_border_top = 322, + eCSSProperty_border_width = 323, + eCSSProperty__moz_column_rule = 324, + eCSSProperty__moz_columns = 325, + eCSSProperty_flex = 326, + eCSSProperty_flex_flow = 327, + eCSSProperty_font = 328, + eCSSProperty_font_variant = 329, + eCSSProperty_grid = 330, + eCSSProperty_grid_area = 331, + eCSSProperty_grid_column = 332, + eCSSProperty_grid_gap = 333, + eCSSProperty_grid_row = 334, + eCSSProperty_grid_template = 335, + eCSSProperty_list_style = 336, + eCSSProperty_margin = 337, + eCSSProperty_marker = 338, + eCSSProperty_outline = 339, + eCSSProperty__moz_outline_radius = 340, + eCSSProperty_overflow = 341, + eCSSProperty_padding = 342, + eCSSProperty_scroll_snap_type = 343, + eCSSProperty_text_decoration = 344, + eCSSProperty_text_emphasis = 345, + eCSSProperty__webkit_text_stroke = 346, + eCSSProperty__moz_transform = 347, + eCSSProperty_transition = 348, + eCSSProperty_COUNT = 349, + eCSSPropertyAlias_MozTransformOrigin = 350, + eCSSPropertyAlias_MozPerspectiveOrigin = 351, + eCSSPropertyAlias_MozPerspective = 352, + eCSSPropertyAlias_MozTransformStyle = 353, + eCSSPropertyAlias_MozBackfaceVisibility = 354, + eCSSPropertyAlias_MozBorderImage = 355, + eCSSPropertyAlias_MozTransition = 356, + eCSSPropertyAlias_MozTransitionDelay = 357, + eCSSPropertyAlias_MozTransitionDuration = 358, + eCSSPropertyAlias_MozTransitionProperty = 359, + eCSSPropertyAlias_MozTransitionTimingFunction = 360, + eCSSPropertyAlias_MozAnimation = 361, + eCSSPropertyAlias_MozAnimationDelay = 362, + eCSSPropertyAlias_MozAnimationDirection = 363, + eCSSPropertyAlias_MozAnimationDuration = 364, + eCSSPropertyAlias_MozAnimationFillMode = 365, + eCSSPropertyAlias_MozAnimationIterationCount = 366, + eCSSPropertyAlias_MozAnimationName = 367, + eCSSPropertyAlias_MozAnimationPlayState = 368, + eCSSPropertyAlias_MozAnimationTimingFunction = 369, + eCSSPropertyAlias_MozBoxSizing = 370, + eCSSPropertyAlias_MozFontFeatureSettings = 371, + eCSSPropertyAlias_MozFontLanguageOverride = 372, + eCSSPropertyAlias_MozPaddingEnd = 373, + eCSSPropertyAlias_MozPaddingStart = 374, + eCSSPropertyAlias_MozMarginEnd = 375, + eCSSPropertyAlias_MozMarginStart = 376, + eCSSPropertyAlias_MozBorderEnd = 377, + eCSSPropertyAlias_MozBorderEndColor = 378, + eCSSPropertyAlias_MozBorderEndStyle = 379, + eCSSPropertyAlias_MozBorderEndWidth = 380, + eCSSPropertyAlias_MozBorderStart = 381, + eCSSPropertyAlias_MozBorderStartColor = 382, + eCSSPropertyAlias_MozBorderStartStyle = 383, + eCSSPropertyAlias_MozBorderStartWidth = 384, + eCSSPropertyAlias_MozHyphens = 385, + eCSSPropertyAlias_MozTextAlignLast = 386, + eCSSPropertyAlias_WebkitAnimation = 387, + eCSSPropertyAlias_WebkitAnimationDelay = 388, + eCSSPropertyAlias_WebkitAnimationDirection = 389, + eCSSPropertyAlias_WebkitAnimationDuration = 390, + eCSSPropertyAlias_WebkitAnimationFillMode = 391, + eCSSPropertyAlias_WebkitAnimationIterationCount = 392, + eCSSPropertyAlias_WebkitAnimationName = 393, + eCSSPropertyAlias_WebkitAnimationPlayState = 394, + eCSSPropertyAlias_WebkitAnimationTimingFunction = 395, + eCSSPropertyAlias_WebkitFilter = 396, + eCSSPropertyAlias_WebkitTextSizeAdjust = 397, + eCSSPropertyAlias_WebkitTransform = 398, + eCSSPropertyAlias_WebkitTransformOrigin = 399, + eCSSPropertyAlias_WebkitTransformStyle = 400, + eCSSPropertyAlias_WebkitBackfaceVisibility = 401, + eCSSPropertyAlias_WebkitPerspective = 402, + eCSSPropertyAlias_WebkitPerspectiveOrigin = 403, + eCSSPropertyAlias_WebkitTransition = 404, + eCSSPropertyAlias_WebkitTransitionDelay = 405, + eCSSPropertyAlias_WebkitTransitionDuration = 406, + eCSSPropertyAlias_WebkitTransitionProperty = 407, + eCSSPropertyAlias_WebkitTransitionTimingFunction = 408, + eCSSPropertyAlias_WebkitBorderRadius = 409, + eCSSPropertyAlias_WebkitBorderTopLeftRadius = 410, + eCSSPropertyAlias_WebkitBorderTopRightRadius = 411, + eCSSPropertyAlias_WebkitBorderBottomLeftRadius = 412, + eCSSPropertyAlias_WebkitBorderBottomRightRadius = 413, + eCSSPropertyAlias_WebkitBackgroundClip = 414, + eCSSPropertyAlias_WebkitBackgroundOrigin = 415, + eCSSPropertyAlias_WebkitBackgroundSize = 416, + eCSSPropertyAlias_WebkitBorderImage = 417, + eCSSPropertyAlias_WebkitBoxShadow = 418, + eCSSPropertyAlias_WebkitBoxSizing = 419, + eCSSPropertyAlias_WebkitBoxFlex = 420, + eCSSPropertyAlias_WebkitBoxOrdinalGroup = 421, + eCSSPropertyAlias_WebkitBoxOrient = 422, + eCSSPropertyAlias_WebkitBoxDirection = 423, + eCSSPropertyAlias_WebkitBoxAlign = 424, + eCSSPropertyAlias_WebkitBoxPack = 425, + eCSSPropertyAlias_WebkitFlexDirection = 426, + eCSSPropertyAlias_WebkitFlexWrap = 427, + eCSSPropertyAlias_WebkitFlexFlow = 428, + eCSSPropertyAlias_WebkitOrder = 429, + eCSSPropertyAlias_WebkitFlex = 430, + eCSSPropertyAlias_WebkitFlexGrow = 431, + eCSSPropertyAlias_WebkitFlexShrink = 432, + eCSSPropertyAlias_WebkitFlexBasis = 433, + eCSSPropertyAlias_WebkitJustifyContent = 434, + eCSSPropertyAlias_WebkitAlignItems = 435, + eCSSPropertyAlias_WebkitAlignSelf = 436, + eCSSPropertyAlias_WebkitAlignContent = 437, + eCSSPropertyAlias_WebkitUserSelect = 438, + eCSSProperty_COUNT_with_aliases = 439, + eCSSPropertyExtra_all_properties = 440, + eCSSPropertyExtra_x_none_value = 441, + eCSSPropertyExtra_x_auto_value = 442, + eCSSPropertyExtra_variable = 443, } #[repr(i32)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -5145,11 +5150,24 @@ pub type nsStyleUnion = nsStyleCoord_h_unnamed_18; * the unit is a must before asking for the value in any particular * form. */ + /** <div rustbindgen private accessor="unsafe"></div> */ #[repr(C)] #[derive(Debug)] pub struct nsStyleCoord { - pub mUnit: nsStyleUnit, - pub mValue: nsStyleUnion, + mUnit: nsStyleUnit, + mValue: nsStyleUnion, +} +impl nsStyleCoord { + #[inline] + pub unsafe fn get_mUnit(&self) -> &nsStyleUnit { &self.mUnit } + pub unsafe fn get_mUnit_mut(&mut self) -> &mut nsStyleUnit { + &mut self.mUnit + } + #[inline] + pub unsafe fn get_mValue(&self) -> &nsStyleUnion { &self.mValue } + pub unsafe fn get_mValue_mut(&mut self) -> &mut nsStyleUnion { + &mut self.mValue + } } #[repr(C)] #[derive(Debug, Copy)] @@ -5190,11 +5208,26 @@ fn bindgen_test_layout_nsStyleCoord() { * This is commonly used to hold the widths of the borders, margins, * or paddings of a box. */ + /** <div rustbindgen private accessor="unsafe"></div> */ #[repr(C)] #[derive(Debug)] pub struct nsStyleSides { - pub mUnits: [nsStyleUnit; 4usize], - pub mValues: [nsStyleUnion; 4usize], + mUnits: [nsStyleUnit; 4usize], + mValues: [nsStyleUnion; 4usize], +} +impl nsStyleSides { + #[inline] + pub unsafe fn get_mUnits(&self) -> &[nsStyleUnit; 4usize] { &self.mUnits } + pub unsafe fn get_mUnits_mut(&mut self) -> &mut [nsStyleUnit; 4usize] { + &mut self.mUnits + } + #[inline] + pub unsafe fn get_mValues(&self) -> &[nsStyleUnion; 4usize] { + &self.mValues + } + pub unsafe fn get_mValues_mut(&mut self) -> &mut [nsStyleUnion; 4usize] { + &mut self.mValues + } } #[test] fn bindgen_test_layout_nsStyleSides() { @@ -5206,11 +5239,26 @@ fn bindgen_test_layout_nsStyleSides() { * nsStyleCoord pairs. This is used to hold the dimensions of the * corners of a box (for, e.g., border-radius and outline-radius). */ + /** <div rustbindgen private accessor="unsafe"></div> */ #[repr(C)] #[derive(Debug)] pub struct nsStyleCorners { - pub mUnits: [nsStyleUnit; 8usize], - pub mValues: [nsStyleUnion; 8usize], + mUnits: [nsStyleUnit; 8usize], + mValues: [nsStyleUnion; 8usize], +} +impl nsStyleCorners { + #[inline] + pub unsafe fn get_mUnits(&self) -> &[nsStyleUnit; 8usize] { &self.mUnits } + pub unsafe fn get_mUnits_mut(&mut self) -> &mut [nsStyleUnit; 8usize] { + &mut self.mUnits + } + #[inline] + pub unsafe fn get_mValues(&self) -> &[nsStyleUnion; 8usize] { + &self.mValues + } + pub unsafe fn get_mValues_mut(&mut self) -> &mut [nsStyleUnion; 8usize] { + &mut self.mValues + } } #[test] fn bindgen_test_layout_nsStyleCorners() { @@ -5598,7 +5646,7 @@ pub struct nsStyleBorder { pub mBorderImageFill: u8, pub mBorderImageRepeatH: u8, pub mBorderImageRepeatV: u8, - pub mFloatEdge: u8, + pub mFloatEdge: StyleFloatEdge, pub mBoxDecorationBreak: u8, pub mComputedBorder: nsMargin, pub mBorder: nsMargin, @@ -5773,12 +5821,14 @@ pub struct nsStyleTextReset { pub mTextOverflow: nsStyleTextOverflow, pub mTextDecorationLine: u8, pub mUnicodeBidi: u8, + pub mInitialLetterSink: nscoord, + pub mInitialLetterSize: f32, pub mTextDecorationStyle: u8, pub mTextDecorationColor: nscolor, } #[test] fn bindgen_test_layout_nsStyleTextReset() { - assert_eq!(::std::mem::size_of::<nsStyleTextReset>() , 64usize); + assert_eq!(::std::mem::size_of::<nsStyleTextReset>() , 80usize); assert_eq!(::std::mem::align_of::<nsStyleTextReset>() , 8usize); } #[repr(C)] @@ -5881,14 +5931,6 @@ pub enum nsTimingFunction_Type { } #[repr(i32)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum nsTimingFunction_StepSyntax { - Keyword = 0, - FunctionalWithoutKeyword = 1, - FunctionalWithStartKeyword = 2, - FunctionalWithEndKeyword = 3, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum nsTimingFunction_Keyword { Implicit = 0, Explicit = 1, } #[repr(C)] #[derive(Debug, Copy)] @@ -5930,7 +5972,6 @@ fn bindgen_test_layout_nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct #[repr(C)] #[derive(Debug, Copy)] pub struct nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25 { - pub mStepSyntax: nsTimingFunction_StepSyntax, pub mSteps: u32, } impl ::std::clone::Clone for @@ -5940,7 +5981,7 @@ impl ::std::clone::Clone for #[test] fn bindgen_test_layout_nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25() { assert_eq!(::std::mem::size_of::<nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25>() - , 8usize); + , 4usize); assert_eq!(::std::mem::align_of::<nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25>() , 4usize); } @@ -6171,7 +6212,7 @@ fn bindgen_test_layout_nsCursorImage() { pub struct nsStyleUserInterface { pub mUserInput: u8, pub mUserModify: u8, - pub mUserFocus: u8, + pub mUserFocus: StyleUserFocus, pub mPointerEvents: u8, pub mCursor: u8, pub mCursorArrayLength: u32, @@ -6334,9 +6375,9 @@ fn bindgen_test_layout_nsStyleBasicShape() { #[repr(C)] #[derive(Debug)] pub struct nsStyleClipPath { - pub mType: i32, pub nsStyleClipPath_nsStyleStruct_h_unnamed_29: nsStyleClipPath_nsStyleStruct_h_unnamed_29, - pub mSizingBox: u8, + pub mType: StyleClipPathType, + pub mSizingBox: StyleClipShapeSizing, } #[repr(C)] #[derive(Debug, Copy)] @@ -6358,7 +6399,7 @@ fn bindgen_test_layout_nsStyleClipPath_nsStyleStruct_h_unnamed_29() { } #[test] fn bindgen_test_layout_nsStyleClipPath() { - assert_eq!(::std::mem::size_of::<nsStyleClipPath>() , 24usize); + assert_eq!(::std::mem::size_of::<nsStyleClipPath>() , 16usize); assert_eq!(::std::mem::align_of::<nsStyleClipPath>() , 8usize); } #[repr(C)] @@ -6406,7 +6447,7 @@ pub struct nsStyleSVGReset { } #[test] fn bindgen_test_layout_nsStyleSVGReset() { - assert_eq!(::std::mem::size_of::<nsStyleSVGReset>() , 216usize); + assert_eq!(::std::mem::size_of::<nsStyleSVGReset>() , 208usize); assert_eq!(::std::mem::align_of::<nsStyleSVGReset>() , 8usize); } #[repr(C)] diff --git a/ports/geckolib/gecko_bindings/structs_release.rs b/ports/geckolib/gecko_bindings/structs_release.rs index 75b061eb9bb..418b428cc16 100644 --- a/ports/geckolib/gecko_bindings/structs_release.rs +++ b/ports/geckolib/gecko_bindings/structs_release.rs @@ -188,12 +188,6 @@ pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69; pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1; pub const NSID_LENGTH: ::std::os::raw::c_uint = 39; pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2; -pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1; -pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1; -pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402; -pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304; -pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304; -pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304; pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6; pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1; pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2; @@ -212,29 +206,6 @@ pub const NS_CORNER_BOTTOM_RIGHT_X: ::std::os::raw::c_uint = 4; pub const NS_CORNER_BOTTOM_RIGHT_Y: ::std::os::raw::c_uint = 5; pub const NS_CORNER_BOTTOM_LEFT_X: ::std::os::raw::c_uint = 6; pub const NS_CORNER_BOTTOM_LEFT_Y: ::std::os::raw::c_uint = 7; -pub const NS_STYLE_CLIP_SHAPE_SIZING_NOBOX: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_CLIP_SHAPE_SIZING_CONTENT: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_CLIP_SHAPE_SIZING_PADDING: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_CLIP_SHAPE_SIZING_BORDER: ::std::os::raw::c_uint = 3; -pub const NS_STYLE_CLIP_SHAPE_SIZING_MARGIN: ::std::os::raw::c_uint = 4; -pub const NS_STYLE_CLIP_SHAPE_SIZING_FILL: ::std::os::raw::c_uint = 5; -pub const NS_STYLE_CLIP_SHAPE_SIZING_STROKE: ::std::os::raw::c_uint = 6; -pub const NS_STYLE_CLIP_SHAPE_SIZING_VIEW: ::std::os::raw::c_uint = 7; -pub const NS_STYLE_BASIC_SHAPE_POLYGON: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_BASIC_SHAPE_CIRCLE: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_BASIC_SHAPE_ELLIPSE: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_BASIC_SHAPE_INSET: ::std::os::raw::c_uint = 3; -pub const NS_STYLE_BOX_SHADOW_INSET: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_FLOAT_EDGE_CONTENT_BOX: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_FLOAT_EDGE_MARGIN_BOX: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_USER_FOCUS_NONE: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_USER_FOCUS_IGNORE: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_USER_FOCUS_NORMAL: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_USER_FOCUS_SELECT_ALL: ::std::os::raw::c_uint = 3; -pub const NS_STYLE_USER_FOCUS_SELECT_BEFORE: ::std::os::raw::c_uint = 4; -pub const NS_STYLE_USER_FOCUS_SELECT_AFTER: ::std::os::raw::c_uint = 5; -pub const NS_STYLE_USER_FOCUS_SELECT_SAME: ::std::os::raw::c_uint = 6; -pub const NS_STYLE_USER_FOCUS_SELECT_MENU: ::std::os::raw::c_uint = 7; pub const NS_STYLE_USER_SELECT_NONE: ::std::os::raw::c_uint = 0; pub const NS_STYLE_USER_SELECT_TEXT: ::std::os::raw::c_uint = 1; pub const NS_STYLE_USER_SELECT_ELEMENT: ::std::os::raw::c_uint = 2; @@ -376,6 +347,7 @@ pub const NS_STYLE_BORDER_STYLE_AUTO: ::std::os::raw::c_uint = 10; pub const NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH: ::std::os::raw::c_uint = 0; pub const NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT: ::std::os::raw::c_uint = 1; pub const NS_STYLE_BORDER_IMAGE_REPEAT_ROUND: ::std::os::raw::c_uint = 2; +pub const NS_STYLE_BORDER_IMAGE_REPEAT_SPACE: ::std::os::raw::c_uint = 3; pub const NS_STYLE_BORDER_IMAGE_SLICE_NOFILL: ::std::os::raw::c_uint = 0; pub const NS_STYLE_BORDER_IMAGE_SLICE_FILL: ::std::os::raw::c_uint = 1; pub const NS_STYLE_CLEAR_NONE: ::std::os::raw::c_uint = 0; @@ -511,10 +483,6 @@ pub const NS_STYLE_FLOAT_LEFT: ::std::os::raw::c_uint = 1; pub const NS_STYLE_FLOAT_RIGHT: ::std::os::raw::c_uint = 2; pub const NS_STYLE_FLOAT_INLINE_START: ::std::os::raw::c_uint = 3; pub const NS_STYLE_FLOAT_INLINE_END: ::std::os::raw::c_uint = 4; -pub const NS_STYLE_CLIP_PATH_NONE: ::std::os::raw::c_uint = 0; -pub const NS_STYLE_CLIP_PATH_URL: ::std::os::raw::c_uint = 1; -pub const NS_STYLE_CLIP_PATH_SHAPE: ::std::os::raw::c_uint = 2; -pub const NS_STYLE_CLIP_PATH_BOX: ::std::os::raw::c_uint = 3; pub const NS_STYLE_FILTER_NONE: ::std::os::raw::c_uint = 0; pub const NS_STYLE_FILTER_URL: ::std::os::raw::c_uint = 1; pub const NS_STYLE_FILTER_BLUR: ::std::os::raw::c_uint = 2; @@ -1924,6 +1892,34 @@ fn bindgen_test_layout_NS_ConvertUTF8toUTF16() { assert_eq!(::std::mem::align_of::<NS_ConvertUTF8toUTF16>() , 8usize); } pub type nsVoidableString = nsAutoString; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtrTraits<U> { + pub _phantom0: ::std::marker::PhantomData<U>, +} +#[repr(C)] +#[derive(Debug)] +pub struct RefPtr<T> { + pub mRawPtr: *mut T, +} +#[repr(C)] +#[derive(Debug)] +pub struct RefPtr_Proxy<T, R, Args> { + pub mRawPtr: *mut T, + pub _phantom0: ::std::marker::PhantomData<R>, + pub _phantom1: ::std::marker::PhantomData<Args>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtr_ConstRemovingRefPtrTraits<T, U> { + pub _phantom0: ::std::marker::PhantomData<T>, + pub _phantom1: ::std::marker::PhantomData<U>, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RefPtrGetterAddRefs<T> { + pub mTargetSmartPtr: *mut RefPtr<T>, +} /** * A "unique identifier". This is modeled after OSF DCE UUIDs. */ @@ -2080,34 +2076,6 @@ fn bindgen_test_layout_QITableEntry() { assert_eq!(::std::mem::size_of::<QITableEntry>() , 16usize); assert_eq!(::std::mem::align_of::<QITableEntry>() , 8usize); } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtrTraits<U> { - pub _phantom0: ::std::marker::PhantomData<U>, -} -#[repr(C)] -#[derive(Debug)] -pub struct RefPtr<T> { - pub mRawPtr: *mut T, -} -#[repr(C)] -#[derive(Debug)] -pub struct RefPtr_Proxy<T, R, Args> { - pub mRawPtr: *mut T, - pub _phantom0: ::std::marker::PhantomData<R>, - pub _phantom1: ::std::marker::PhantomData<Args>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr_ConstRemovingRefPtrTraits<T, U> { - pub _phantom0: ::std::marker::PhantomData<T>, - pub _phantom1: ::std::marker::PhantomData<U>, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtrGetterAddRefs<T> { - pub mTargetSmartPtr: *mut RefPtr<T>, -} pub enum TileClient { } #[repr(C)] #[derive(Debug, Copy)] @@ -2714,12 +2682,6 @@ impl ::std::clone::Clone for nsIExpandedPrincipal { fn clone(&self) -> Self { *self } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _Make_integer_sequence<_Tp, _ISeq> { - pub _phantom0: ::std::marker::PhantomData<_Tp>, - pub _phantom1: ::std::marker::PhantomData<_ISeq>, -} -#[repr(C)] #[derive(Debug, Copy)] pub struct nsIURI { pub _base: nsISupports, @@ -2771,7 +2733,7 @@ impl ::std::clone::Clone for nsIRequest { #[repr(C)] #[derive(Debug, Copy)] pub struct EventStates { - pub mStates: ::std::os::raw::c_ulong, + pub mStates: ::std::os::raw::c_ulonglong, } impl ::std::clone::Clone for EventStates { fn clone(&self) -> Self { *self } @@ -2835,6 +2797,11 @@ pub enum nsNodeSupportsWeakRefTearoff { } pub enum nsNodeWeakReference { } pub enum nsDOMMutationObserver { } pub enum ServoNodeData { } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DefaultDelete<> { + pub _phantom0: ::std::marker::PhantomData<ServoNodeData>, +} pub enum EventListenerManager { } pub enum BoxQuadOptions { } pub enum ConvertCoordinateOptions { } @@ -2901,7 +2868,7 @@ fn bindgen_test_layout_nsMutationGuard() { extern "C" { #[link_name = "_ZN15nsMutationGuard11sGenerationE"] pub static mut nsMutationGuard_consts_sGeneration: - ::std::os::raw::c_ulong; + ::std::os::raw::c_ulonglong; } pub type Float = f32; #[repr(i8)] @@ -3001,6 +2968,7 @@ pub enum FontType { SKIA = 3, CAIRO = 4, COREGRAPHICS = 5, + FONTCONFIG = 6, } #[repr(i8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -3897,7 +3865,43 @@ fn bindgen_test_layout_nsFont() { } #[repr(i8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleBasicShape { Polygon = 0, Circle = 1, Ellipse = 2, Inset = 3, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum StyleBoxSizing { Content = 0, Border = 1, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleBoxShadowType { Inset = 0, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleClipPathType { None_ = 0, URL = 1, Shape = 2, Box = 3, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleClipShapeSizing { + NoBox = 0, + Content = 1, + Padding = 2, + Border = 3, + Margin = 4, + Fill = 5, + Stroke = 6, + View = 7, +} +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleFloatEdge { ContentBox = 0, MarginBox = 1, } +#[repr(i8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum StyleUserFocus { + None_ = 0, + Ignore = 1, + Normal = 2, + SelectAll = 3, + SelectBefore = 4, + SelectAfter = 5, + SelectSame = 6, + SelectMenu = 7, +} pub const eCSSProperty_COUNT_DUMMY: nsCSSProperty = nsCSSProperty::eCSSProperty_z_index; pub const eCSSProperty_all: nsCSSProperty = @@ -4058,305 +4062,306 @@ pub enum nsCSSProperty { eCSSProperty_grid_template_rows = 141, eCSSProperty_height = 142, eCSSProperty_hyphens = 143, - eCSSProperty_image_orientation = 144, - eCSSProperty_image_region = 145, - eCSSProperty_image_rendering = 146, - eCSSProperty_ime_mode = 147, - eCSSProperty_inline_size = 148, - eCSSProperty_isolation = 149, - eCSSProperty_justify_content = 150, - eCSSProperty_justify_items = 151, - eCSSProperty_justify_self = 152, - eCSSProperty__x_lang = 153, - eCSSProperty_left = 154, - eCSSProperty_letter_spacing = 155, - eCSSProperty_lighting_color = 156, - eCSSProperty_line_height = 157, - eCSSProperty_list_style_image = 158, - eCSSProperty_list_style_position = 159, - eCSSProperty_list_style_type = 160, - eCSSProperty_margin_block_end = 161, - eCSSProperty_margin_block_start = 162, - eCSSProperty_margin_bottom = 163, - eCSSProperty_margin_inline_end = 164, - eCSSProperty_margin_inline_start = 165, - eCSSProperty_margin_left = 166, - eCSSProperty_margin_right = 167, - eCSSProperty_margin_top = 168, - eCSSProperty_marker_end = 169, - eCSSProperty_marker_mid = 170, - eCSSProperty_marker_offset = 171, - eCSSProperty_marker_start = 172, - eCSSProperty_mask = 173, - eCSSProperty_mask_type = 174, - eCSSProperty_math_display = 175, - eCSSProperty_math_variant = 176, - eCSSProperty_max_block_size = 177, - eCSSProperty_max_height = 178, - eCSSProperty_max_inline_size = 179, - eCSSProperty_max_width = 180, - eCSSProperty_min_block_size = 181, - eCSSProperty__moz_min_font_size_ratio = 182, - eCSSProperty_min_height = 183, - eCSSProperty_min_inline_size = 184, - eCSSProperty_min_width = 185, - eCSSProperty_mix_blend_mode = 186, - eCSSProperty_object_fit = 187, - eCSSProperty_object_position = 188, - eCSSProperty_offset_block_end = 189, - eCSSProperty_offset_block_start = 190, - eCSSProperty_offset_inline_end = 191, - eCSSProperty_offset_inline_start = 192, - eCSSProperty_opacity = 193, - eCSSProperty_order = 194, - eCSSProperty_orient = 195, - eCSSProperty_osx_font_smoothing = 196, - eCSSProperty_outline_color = 197, - eCSSProperty_outline_offset = 198, - eCSSProperty__moz_outline_radius_bottomLeft = 199, - eCSSProperty__moz_outline_radius_bottomRight = 200, - eCSSProperty__moz_outline_radius_topLeft = 201, - eCSSProperty__moz_outline_radius_topRight = 202, - eCSSProperty_outline_style = 203, - eCSSProperty_outline_width = 204, - eCSSProperty_overflow_clip_box = 205, - eCSSProperty_overflow_x = 206, - eCSSProperty_overflow_y = 207, - eCSSProperty_padding_block_end = 208, - eCSSProperty_padding_block_start = 209, - eCSSProperty_padding_bottom = 210, - eCSSProperty_padding_inline_end = 211, - eCSSProperty_padding_inline_start = 212, - eCSSProperty_padding_left = 213, - eCSSProperty_padding_right = 214, - eCSSProperty_padding_top = 215, - eCSSProperty_page_break_after = 216, - eCSSProperty_page_break_before = 217, - eCSSProperty_page_break_inside = 218, - eCSSProperty_paint_order = 219, - eCSSProperty_perspective = 220, - eCSSProperty_perspective_origin = 221, - eCSSProperty_pointer_events = 222, - eCSSProperty_position = 223, - eCSSProperty_quotes = 224, - eCSSProperty_resize = 225, - eCSSProperty_right = 226, - eCSSProperty_ruby_align = 227, - eCSSProperty_ruby_position = 228, - eCSSProperty_script_level = 229, - eCSSProperty_script_min_size = 230, - eCSSProperty_script_size_multiplier = 231, - eCSSProperty_scroll_behavior = 232, - eCSSProperty_scroll_snap_coordinate = 233, - eCSSProperty_scroll_snap_destination = 234, - eCSSProperty_scroll_snap_points_x = 235, - eCSSProperty_scroll_snap_points_y = 236, - eCSSProperty_scroll_snap_type_x = 237, - eCSSProperty_scroll_snap_type_y = 238, - eCSSProperty_shape_rendering = 239, - eCSSProperty__x_span = 240, - eCSSProperty_stack_sizing = 241, - eCSSProperty_stop_color = 242, - eCSSProperty_stop_opacity = 243, - eCSSProperty_stroke = 244, - eCSSProperty_stroke_dasharray = 245, - eCSSProperty_stroke_dashoffset = 246, - eCSSProperty_stroke_linecap = 247, - eCSSProperty_stroke_linejoin = 248, - eCSSProperty_stroke_miterlimit = 249, - eCSSProperty_stroke_opacity = 250, - eCSSProperty_stroke_width = 251, - eCSSProperty__x_system_font = 252, - eCSSProperty__moz_tab_size = 253, - eCSSProperty_table_layout = 254, - eCSSProperty_text_align = 255, - eCSSProperty_text_align_last = 256, - eCSSProperty_text_anchor = 257, - eCSSProperty_text_combine_upright = 258, - eCSSProperty_text_decoration_color = 259, - eCSSProperty_text_decoration_line = 260, - eCSSProperty_text_decoration_style = 261, - eCSSProperty_text_emphasis_color = 262, - eCSSProperty_text_emphasis_position = 263, - eCSSProperty_text_emphasis_style = 264, - eCSSProperty__webkit_text_fill_color = 265, - eCSSProperty_text_indent = 266, - eCSSProperty_text_orientation = 267, - eCSSProperty_text_overflow = 268, - eCSSProperty_text_rendering = 269, - eCSSProperty_text_shadow = 270, - eCSSProperty_text_size_adjust = 271, - eCSSProperty__webkit_text_stroke_color = 272, - eCSSProperty__webkit_text_stroke_width = 273, - eCSSProperty_text_transform = 274, - eCSSProperty__x_text_zoom = 275, - eCSSProperty_top = 276, - eCSSProperty__moz_top_layer = 277, - eCSSProperty_touch_action = 278, - eCSSProperty_transform = 279, - eCSSProperty_transform_box = 280, - eCSSProperty_transform_origin = 281, - eCSSProperty_transform_style = 282, - eCSSProperty_transition_delay = 283, - eCSSProperty_transition_duration = 284, - eCSSProperty_transition_property = 285, - eCSSProperty_transition_timing_function = 286, - eCSSProperty_unicode_bidi = 287, - eCSSProperty_user_focus = 288, - eCSSProperty_user_input = 289, - eCSSProperty_user_modify = 290, - eCSSProperty_user_select = 291, - eCSSProperty_vector_effect = 292, - eCSSProperty_vertical_align = 293, - eCSSProperty_visibility = 294, - eCSSProperty_white_space = 295, - eCSSProperty_width = 296, - eCSSProperty_will_change = 297, - eCSSProperty__moz_window_dragging = 298, - eCSSProperty__moz_window_shadow = 299, - eCSSProperty_word_break = 300, - eCSSProperty_word_spacing = 301, - eCSSProperty_overflow_wrap = 302, - eCSSProperty_writing_mode = 303, - eCSSProperty_z_index = 304, - eCSSProperty_COUNT_no_shorthands = 305, - eCSSProperty_animation = 306, - eCSSProperty_background = 307, - eCSSProperty_background_position = 308, - eCSSProperty_border = 309, - eCSSProperty_border_block_end = 310, - eCSSProperty_border_block_start = 311, - eCSSProperty_border_bottom = 312, - eCSSProperty_border_color = 313, - eCSSProperty_border_image = 314, - eCSSProperty_border_inline_end = 315, - eCSSProperty_border_inline_start = 316, - eCSSProperty_border_left = 317, - eCSSProperty_border_radius = 318, - eCSSProperty_border_right = 319, - eCSSProperty_border_style = 320, - eCSSProperty_border_top = 321, - eCSSProperty_border_width = 322, - eCSSProperty__moz_column_rule = 323, - eCSSProperty__moz_columns = 324, - eCSSProperty_flex = 325, - eCSSProperty_flex_flow = 326, - eCSSProperty_font = 327, - eCSSProperty_font_variant = 328, - eCSSProperty_grid = 329, - eCSSProperty_grid_area = 330, - eCSSProperty_grid_column = 331, - eCSSProperty_grid_gap = 332, - eCSSProperty_grid_row = 333, - eCSSProperty_grid_template = 334, - eCSSProperty_list_style = 335, - eCSSProperty_margin = 336, - eCSSProperty_marker = 337, - eCSSProperty_outline = 338, - eCSSProperty__moz_outline_radius = 339, - eCSSProperty_overflow = 340, - eCSSProperty_padding = 341, - eCSSProperty_scroll_snap_type = 342, - eCSSProperty_text_decoration = 343, - eCSSProperty_text_emphasis = 344, - eCSSProperty__webkit_text_stroke = 345, - eCSSProperty__moz_transform = 346, - eCSSProperty_transition = 347, - eCSSProperty_COUNT = 348, - eCSSPropertyAlias_MozTransformOrigin = 349, - eCSSPropertyAlias_MozPerspectiveOrigin = 350, - eCSSPropertyAlias_MozPerspective = 351, - eCSSPropertyAlias_MozTransformStyle = 352, - eCSSPropertyAlias_MozBackfaceVisibility = 353, - eCSSPropertyAlias_MozBorderImage = 354, - eCSSPropertyAlias_MozTransition = 355, - eCSSPropertyAlias_MozTransitionDelay = 356, - eCSSPropertyAlias_MozTransitionDuration = 357, - eCSSPropertyAlias_MozTransitionProperty = 358, - eCSSPropertyAlias_MozTransitionTimingFunction = 359, - eCSSPropertyAlias_MozAnimation = 360, - eCSSPropertyAlias_MozAnimationDelay = 361, - eCSSPropertyAlias_MozAnimationDirection = 362, - eCSSPropertyAlias_MozAnimationDuration = 363, - eCSSPropertyAlias_MozAnimationFillMode = 364, - eCSSPropertyAlias_MozAnimationIterationCount = 365, - eCSSPropertyAlias_MozAnimationName = 366, - eCSSPropertyAlias_MozAnimationPlayState = 367, - eCSSPropertyAlias_MozAnimationTimingFunction = 368, - eCSSPropertyAlias_MozBoxSizing = 369, - eCSSPropertyAlias_MozFontFeatureSettings = 370, - eCSSPropertyAlias_MozFontLanguageOverride = 371, - eCSSPropertyAlias_MozPaddingEnd = 372, - eCSSPropertyAlias_MozPaddingStart = 373, - eCSSPropertyAlias_MozMarginEnd = 374, - eCSSPropertyAlias_MozMarginStart = 375, - eCSSPropertyAlias_MozBorderEnd = 376, - eCSSPropertyAlias_MozBorderEndColor = 377, - eCSSPropertyAlias_MozBorderEndStyle = 378, - eCSSPropertyAlias_MozBorderEndWidth = 379, - eCSSPropertyAlias_MozBorderStart = 380, - eCSSPropertyAlias_MozBorderStartColor = 381, - eCSSPropertyAlias_MozBorderStartStyle = 382, - eCSSPropertyAlias_MozBorderStartWidth = 383, - eCSSPropertyAlias_MozHyphens = 384, - eCSSPropertyAlias_MozTextAlignLast = 385, - eCSSPropertyAlias_WebkitAnimation = 386, - eCSSPropertyAlias_WebkitAnimationDelay = 387, - eCSSPropertyAlias_WebkitAnimationDirection = 388, - eCSSPropertyAlias_WebkitAnimationDuration = 389, - eCSSPropertyAlias_WebkitAnimationFillMode = 390, - eCSSPropertyAlias_WebkitAnimationIterationCount = 391, - eCSSPropertyAlias_WebkitAnimationName = 392, - eCSSPropertyAlias_WebkitAnimationPlayState = 393, - eCSSPropertyAlias_WebkitAnimationTimingFunction = 394, - eCSSPropertyAlias_WebkitFilter = 395, - eCSSPropertyAlias_WebkitTextSizeAdjust = 396, - eCSSPropertyAlias_WebkitTransform = 397, - eCSSPropertyAlias_WebkitTransformOrigin = 398, - eCSSPropertyAlias_WebkitTransformStyle = 399, - eCSSPropertyAlias_WebkitBackfaceVisibility = 400, - eCSSPropertyAlias_WebkitPerspective = 401, - eCSSPropertyAlias_WebkitPerspectiveOrigin = 402, - eCSSPropertyAlias_WebkitTransition = 403, - eCSSPropertyAlias_WebkitTransitionDelay = 404, - eCSSPropertyAlias_WebkitTransitionDuration = 405, - eCSSPropertyAlias_WebkitTransitionProperty = 406, - eCSSPropertyAlias_WebkitTransitionTimingFunction = 407, - eCSSPropertyAlias_WebkitBorderRadius = 408, - eCSSPropertyAlias_WebkitBorderTopLeftRadius = 409, - eCSSPropertyAlias_WebkitBorderTopRightRadius = 410, - eCSSPropertyAlias_WebkitBorderBottomLeftRadius = 411, - eCSSPropertyAlias_WebkitBorderBottomRightRadius = 412, - eCSSPropertyAlias_WebkitBackgroundClip = 413, - eCSSPropertyAlias_WebkitBackgroundOrigin = 414, - eCSSPropertyAlias_WebkitBackgroundSize = 415, - eCSSPropertyAlias_WebkitBorderImage = 416, - eCSSPropertyAlias_WebkitBoxShadow = 417, - eCSSPropertyAlias_WebkitBoxSizing = 418, - eCSSPropertyAlias_WebkitBoxFlex = 419, - eCSSPropertyAlias_WebkitBoxOrdinalGroup = 420, - eCSSPropertyAlias_WebkitBoxOrient = 421, - eCSSPropertyAlias_WebkitBoxDirection = 422, - eCSSPropertyAlias_WebkitBoxAlign = 423, - eCSSPropertyAlias_WebkitBoxPack = 424, - eCSSPropertyAlias_WebkitFlexDirection = 425, - eCSSPropertyAlias_WebkitFlexWrap = 426, - eCSSPropertyAlias_WebkitFlexFlow = 427, - eCSSPropertyAlias_WebkitOrder = 428, - eCSSPropertyAlias_WebkitFlex = 429, - eCSSPropertyAlias_WebkitFlexGrow = 430, - eCSSPropertyAlias_WebkitFlexShrink = 431, - eCSSPropertyAlias_WebkitFlexBasis = 432, - eCSSPropertyAlias_WebkitJustifyContent = 433, - eCSSPropertyAlias_WebkitAlignItems = 434, - eCSSPropertyAlias_WebkitAlignSelf = 435, - eCSSPropertyAlias_WebkitAlignContent = 436, - eCSSPropertyAlias_WebkitUserSelect = 437, - eCSSProperty_COUNT_with_aliases = 438, - eCSSPropertyExtra_all_properties = 439, - eCSSPropertyExtra_x_none_value = 440, - eCSSPropertyExtra_x_auto_value = 441, - eCSSPropertyExtra_variable = 442, + eCSSProperty_initial_letter = 144, + eCSSProperty_image_orientation = 145, + eCSSProperty_image_region = 146, + eCSSProperty_image_rendering = 147, + eCSSProperty_ime_mode = 148, + eCSSProperty_inline_size = 149, + eCSSProperty_isolation = 150, + eCSSProperty_justify_content = 151, + eCSSProperty_justify_items = 152, + eCSSProperty_justify_self = 153, + eCSSProperty__x_lang = 154, + eCSSProperty_left = 155, + eCSSProperty_letter_spacing = 156, + eCSSProperty_lighting_color = 157, + eCSSProperty_line_height = 158, + eCSSProperty_list_style_image = 159, + eCSSProperty_list_style_position = 160, + eCSSProperty_list_style_type = 161, + eCSSProperty_margin_block_end = 162, + eCSSProperty_margin_block_start = 163, + eCSSProperty_margin_bottom = 164, + eCSSProperty_margin_inline_end = 165, + eCSSProperty_margin_inline_start = 166, + eCSSProperty_margin_left = 167, + eCSSProperty_margin_right = 168, + eCSSProperty_margin_top = 169, + eCSSProperty_marker_end = 170, + eCSSProperty_marker_mid = 171, + eCSSProperty_marker_offset = 172, + eCSSProperty_marker_start = 173, + eCSSProperty_mask = 174, + eCSSProperty_mask_type = 175, + eCSSProperty_math_display = 176, + eCSSProperty_math_variant = 177, + eCSSProperty_max_block_size = 178, + eCSSProperty_max_height = 179, + eCSSProperty_max_inline_size = 180, + eCSSProperty_max_width = 181, + eCSSProperty_min_block_size = 182, + eCSSProperty__moz_min_font_size_ratio = 183, + eCSSProperty_min_height = 184, + eCSSProperty_min_inline_size = 185, + eCSSProperty_min_width = 186, + eCSSProperty_mix_blend_mode = 187, + eCSSProperty_object_fit = 188, + eCSSProperty_object_position = 189, + eCSSProperty_offset_block_end = 190, + eCSSProperty_offset_block_start = 191, + eCSSProperty_offset_inline_end = 192, + eCSSProperty_offset_inline_start = 193, + eCSSProperty_opacity = 194, + eCSSProperty_order = 195, + eCSSProperty_orient = 196, + eCSSProperty_osx_font_smoothing = 197, + eCSSProperty_outline_color = 198, + eCSSProperty_outline_offset = 199, + eCSSProperty__moz_outline_radius_bottomLeft = 200, + eCSSProperty__moz_outline_radius_bottomRight = 201, + eCSSProperty__moz_outline_radius_topLeft = 202, + eCSSProperty__moz_outline_radius_topRight = 203, + eCSSProperty_outline_style = 204, + eCSSProperty_outline_width = 205, + eCSSProperty_overflow_clip_box = 206, + eCSSProperty_overflow_x = 207, + eCSSProperty_overflow_y = 208, + eCSSProperty_padding_block_end = 209, + eCSSProperty_padding_block_start = 210, + eCSSProperty_padding_bottom = 211, + eCSSProperty_padding_inline_end = 212, + eCSSProperty_padding_inline_start = 213, + eCSSProperty_padding_left = 214, + eCSSProperty_padding_right = 215, + eCSSProperty_padding_top = 216, + eCSSProperty_page_break_after = 217, + eCSSProperty_page_break_before = 218, + eCSSProperty_page_break_inside = 219, + eCSSProperty_paint_order = 220, + eCSSProperty_perspective = 221, + eCSSProperty_perspective_origin = 222, + eCSSProperty_pointer_events = 223, + eCSSProperty_position = 224, + eCSSProperty_quotes = 225, + eCSSProperty_resize = 226, + eCSSProperty_right = 227, + eCSSProperty_ruby_align = 228, + eCSSProperty_ruby_position = 229, + eCSSProperty_script_level = 230, + eCSSProperty_script_min_size = 231, + eCSSProperty_script_size_multiplier = 232, + eCSSProperty_scroll_behavior = 233, + eCSSProperty_scroll_snap_coordinate = 234, + eCSSProperty_scroll_snap_destination = 235, + eCSSProperty_scroll_snap_points_x = 236, + eCSSProperty_scroll_snap_points_y = 237, + eCSSProperty_scroll_snap_type_x = 238, + eCSSProperty_scroll_snap_type_y = 239, + eCSSProperty_shape_rendering = 240, + eCSSProperty__x_span = 241, + eCSSProperty_stack_sizing = 242, + eCSSProperty_stop_color = 243, + eCSSProperty_stop_opacity = 244, + eCSSProperty_stroke = 245, + eCSSProperty_stroke_dasharray = 246, + eCSSProperty_stroke_dashoffset = 247, + eCSSProperty_stroke_linecap = 248, + eCSSProperty_stroke_linejoin = 249, + eCSSProperty_stroke_miterlimit = 250, + eCSSProperty_stroke_opacity = 251, + eCSSProperty_stroke_width = 252, + eCSSProperty__x_system_font = 253, + eCSSProperty__moz_tab_size = 254, + eCSSProperty_table_layout = 255, + eCSSProperty_text_align = 256, + eCSSProperty_text_align_last = 257, + eCSSProperty_text_anchor = 258, + eCSSProperty_text_combine_upright = 259, + eCSSProperty_text_decoration_color = 260, + eCSSProperty_text_decoration_line = 261, + eCSSProperty_text_decoration_style = 262, + eCSSProperty_text_emphasis_color = 263, + eCSSProperty_text_emphasis_position = 264, + eCSSProperty_text_emphasis_style = 265, + eCSSProperty__webkit_text_fill_color = 266, + eCSSProperty_text_indent = 267, + eCSSProperty_text_orientation = 268, + eCSSProperty_text_overflow = 269, + eCSSProperty_text_rendering = 270, + eCSSProperty_text_shadow = 271, + eCSSProperty_text_size_adjust = 272, + eCSSProperty__webkit_text_stroke_color = 273, + eCSSProperty__webkit_text_stroke_width = 274, + eCSSProperty_text_transform = 275, + eCSSProperty__x_text_zoom = 276, + eCSSProperty_top = 277, + eCSSProperty__moz_top_layer = 278, + eCSSProperty_touch_action = 279, + eCSSProperty_transform = 280, + eCSSProperty_transform_box = 281, + eCSSProperty_transform_origin = 282, + eCSSProperty_transform_style = 283, + eCSSProperty_transition_delay = 284, + eCSSProperty_transition_duration = 285, + eCSSProperty_transition_property = 286, + eCSSProperty_transition_timing_function = 287, + eCSSProperty_unicode_bidi = 288, + eCSSProperty_user_focus = 289, + eCSSProperty_user_input = 290, + eCSSProperty_user_modify = 291, + eCSSProperty_user_select = 292, + eCSSProperty_vector_effect = 293, + eCSSProperty_vertical_align = 294, + eCSSProperty_visibility = 295, + eCSSProperty_white_space = 296, + eCSSProperty_width = 297, + eCSSProperty_will_change = 298, + eCSSProperty__moz_window_dragging = 299, + eCSSProperty__moz_window_shadow = 300, + eCSSProperty_word_break = 301, + eCSSProperty_word_spacing = 302, + eCSSProperty_overflow_wrap = 303, + eCSSProperty_writing_mode = 304, + eCSSProperty_z_index = 305, + eCSSProperty_COUNT_no_shorthands = 306, + eCSSProperty_animation = 307, + eCSSProperty_background = 308, + eCSSProperty_background_position = 309, + eCSSProperty_border = 310, + eCSSProperty_border_block_end = 311, + eCSSProperty_border_block_start = 312, + eCSSProperty_border_bottom = 313, + eCSSProperty_border_color = 314, + eCSSProperty_border_image = 315, + eCSSProperty_border_inline_end = 316, + eCSSProperty_border_inline_start = 317, + eCSSProperty_border_left = 318, + eCSSProperty_border_radius = 319, + eCSSProperty_border_right = 320, + eCSSProperty_border_style = 321, + eCSSProperty_border_top = 322, + eCSSProperty_border_width = 323, + eCSSProperty__moz_column_rule = 324, + eCSSProperty__moz_columns = 325, + eCSSProperty_flex = 326, + eCSSProperty_flex_flow = 327, + eCSSProperty_font = 328, + eCSSProperty_font_variant = 329, + eCSSProperty_grid = 330, + eCSSProperty_grid_area = 331, + eCSSProperty_grid_column = 332, + eCSSProperty_grid_gap = 333, + eCSSProperty_grid_row = 334, + eCSSProperty_grid_template = 335, + eCSSProperty_list_style = 336, + eCSSProperty_margin = 337, + eCSSProperty_marker = 338, + eCSSProperty_outline = 339, + eCSSProperty__moz_outline_radius = 340, + eCSSProperty_overflow = 341, + eCSSProperty_padding = 342, + eCSSProperty_scroll_snap_type = 343, + eCSSProperty_text_decoration = 344, + eCSSProperty_text_emphasis = 345, + eCSSProperty__webkit_text_stroke = 346, + eCSSProperty__moz_transform = 347, + eCSSProperty_transition = 348, + eCSSProperty_COUNT = 349, + eCSSPropertyAlias_MozTransformOrigin = 350, + eCSSPropertyAlias_MozPerspectiveOrigin = 351, + eCSSPropertyAlias_MozPerspective = 352, + eCSSPropertyAlias_MozTransformStyle = 353, + eCSSPropertyAlias_MozBackfaceVisibility = 354, + eCSSPropertyAlias_MozBorderImage = 355, + eCSSPropertyAlias_MozTransition = 356, + eCSSPropertyAlias_MozTransitionDelay = 357, + eCSSPropertyAlias_MozTransitionDuration = 358, + eCSSPropertyAlias_MozTransitionProperty = 359, + eCSSPropertyAlias_MozTransitionTimingFunction = 360, + eCSSPropertyAlias_MozAnimation = 361, + eCSSPropertyAlias_MozAnimationDelay = 362, + eCSSPropertyAlias_MozAnimationDirection = 363, + eCSSPropertyAlias_MozAnimationDuration = 364, + eCSSPropertyAlias_MozAnimationFillMode = 365, + eCSSPropertyAlias_MozAnimationIterationCount = 366, + eCSSPropertyAlias_MozAnimationName = 367, + eCSSPropertyAlias_MozAnimationPlayState = 368, + eCSSPropertyAlias_MozAnimationTimingFunction = 369, + eCSSPropertyAlias_MozBoxSizing = 370, + eCSSPropertyAlias_MozFontFeatureSettings = 371, + eCSSPropertyAlias_MozFontLanguageOverride = 372, + eCSSPropertyAlias_MozPaddingEnd = 373, + eCSSPropertyAlias_MozPaddingStart = 374, + eCSSPropertyAlias_MozMarginEnd = 375, + eCSSPropertyAlias_MozMarginStart = 376, + eCSSPropertyAlias_MozBorderEnd = 377, + eCSSPropertyAlias_MozBorderEndColor = 378, + eCSSPropertyAlias_MozBorderEndStyle = 379, + eCSSPropertyAlias_MozBorderEndWidth = 380, + eCSSPropertyAlias_MozBorderStart = 381, + eCSSPropertyAlias_MozBorderStartColor = 382, + eCSSPropertyAlias_MozBorderStartStyle = 383, + eCSSPropertyAlias_MozBorderStartWidth = 384, + eCSSPropertyAlias_MozHyphens = 385, + eCSSPropertyAlias_MozTextAlignLast = 386, + eCSSPropertyAlias_WebkitAnimation = 387, + eCSSPropertyAlias_WebkitAnimationDelay = 388, + eCSSPropertyAlias_WebkitAnimationDirection = 389, + eCSSPropertyAlias_WebkitAnimationDuration = 390, + eCSSPropertyAlias_WebkitAnimationFillMode = 391, + eCSSPropertyAlias_WebkitAnimationIterationCount = 392, + eCSSPropertyAlias_WebkitAnimationName = 393, + eCSSPropertyAlias_WebkitAnimationPlayState = 394, + eCSSPropertyAlias_WebkitAnimationTimingFunction = 395, + eCSSPropertyAlias_WebkitFilter = 396, + eCSSPropertyAlias_WebkitTextSizeAdjust = 397, + eCSSPropertyAlias_WebkitTransform = 398, + eCSSPropertyAlias_WebkitTransformOrigin = 399, + eCSSPropertyAlias_WebkitTransformStyle = 400, + eCSSPropertyAlias_WebkitBackfaceVisibility = 401, + eCSSPropertyAlias_WebkitPerspective = 402, + eCSSPropertyAlias_WebkitPerspectiveOrigin = 403, + eCSSPropertyAlias_WebkitTransition = 404, + eCSSPropertyAlias_WebkitTransitionDelay = 405, + eCSSPropertyAlias_WebkitTransitionDuration = 406, + eCSSPropertyAlias_WebkitTransitionProperty = 407, + eCSSPropertyAlias_WebkitTransitionTimingFunction = 408, + eCSSPropertyAlias_WebkitBorderRadius = 409, + eCSSPropertyAlias_WebkitBorderTopLeftRadius = 410, + eCSSPropertyAlias_WebkitBorderTopRightRadius = 411, + eCSSPropertyAlias_WebkitBorderBottomLeftRadius = 412, + eCSSPropertyAlias_WebkitBorderBottomRightRadius = 413, + eCSSPropertyAlias_WebkitBackgroundClip = 414, + eCSSPropertyAlias_WebkitBackgroundOrigin = 415, + eCSSPropertyAlias_WebkitBackgroundSize = 416, + eCSSPropertyAlias_WebkitBorderImage = 417, + eCSSPropertyAlias_WebkitBoxShadow = 418, + eCSSPropertyAlias_WebkitBoxSizing = 419, + eCSSPropertyAlias_WebkitBoxFlex = 420, + eCSSPropertyAlias_WebkitBoxOrdinalGroup = 421, + eCSSPropertyAlias_WebkitBoxOrient = 422, + eCSSPropertyAlias_WebkitBoxDirection = 423, + eCSSPropertyAlias_WebkitBoxAlign = 424, + eCSSPropertyAlias_WebkitBoxPack = 425, + eCSSPropertyAlias_WebkitFlexDirection = 426, + eCSSPropertyAlias_WebkitFlexWrap = 427, + eCSSPropertyAlias_WebkitFlexFlow = 428, + eCSSPropertyAlias_WebkitOrder = 429, + eCSSPropertyAlias_WebkitFlex = 430, + eCSSPropertyAlias_WebkitFlexGrow = 431, + eCSSPropertyAlias_WebkitFlexShrink = 432, + eCSSPropertyAlias_WebkitFlexBasis = 433, + eCSSPropertyAlias_WebkitJustifyContent = 434, + eCSSPropertyAlias_WebkitAlignItems = 435, + eCSSPropertyAlias_WebkitAlignSelf = 436, + eCSSPropertyAlias_WebkitAlignContent = 437, + eCSSPropertyAlias_WebkitUserSelect = 438, + eCSSProperty_COUNT_with_aliases = 439, + eCSSPropertyExtra_all_properties = 440, + eCSSPropertyExtra_x_none_value = 441, + eCSSPropertyExtra_x_auto_value = 442, + eCSSPropertyExtra_variable = 443, } #[repr(i32)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -5124,11 +5129,24 @@ pub type nsStyleUnion = nsStyleCoord_h_unnamed_18; * the unit is a must before asking for the value in any particular * form. */ + /** <div rustbindgen private accessor="unsafe"></div> */ #[repr(C)] #[derive(Debug)] pub struct nsStyleCoord { - pub mUnit: nsStyleUnit, - pub mValue: nsStyleUnion, + mUnit: nsStyleUnit, + mValue: nsStyleUnion, +} +impl nsStyleCoord { + #[inline] + pub unsafe fn get_mUnit(&self) -> &nsStyleUnit { &self.mUnit } + pub unsafe fn get_mUnit_mut(&mut self) -> &mut nsStyleUnit { + &mut self.mUnit + } + #[inline] + pub unsafe fn get_mValue(&self) -> &nsStyleUnion { &self.mValue } + pub unsafe fn get_mValue_mut(&mut self) -> &mut nsStyleUnion { + &mut self.mValue + } } #[repr(C)] #[derive(Debug, Copy)] @@ -5169,11 +5187,26 @@ fn bindgen_test_layout_nsStyleCoord() { * This is commonly used to hold the widths of the borders, margins, * or paddings of a box. */ + /** <div rustbindgen private accessor="unsafe"></div> */ #[repr(C)] #[derive(Debug)] pub struct nsStyleSides { - pub mUnits: [nsStyleUnit; 4usize], - pub mValues: [nsStyleUnion; 4usize], + mUnits: [nsStyleUnit; 4usize], + mValues: [nsStyleUnion; 4usize], +} +impl nsStyleSides { + #[inline] + pub unsafe fn get_mUnits(&self) -> &[nsStyleUnit; 4usize] { &self.mUnits } + pub unsafe fn get_mUnits_mut(&mut self) -> &mut [nsStyleUnit; 4usize] { + &mut self.mUnits + } + #[inline] + pub unsafe fn get_mValues(&self) -> &[nsStyleUnion; 4usize] { + &self.mValues + } + pub unsafe fn get_mValues_mut(&mut self) -> &mut [nsStyleUnion; 4usize] { + &mut self.mValues + } } #[test] fn bindgen_test_layout_nsStyleSides() { @@ -5185,11 +5218,26 @@ fn bindgen_test_layout_nsStyleSides() { * nsStyleCoord pairs. This is used to hold the dimensions of the * corners of a box (for, e.g., border-radius and outline-radius). */ + /** <div rustbindgen private accessor="unsafe"></div> */ #[repr(C)] #[derive(Debug)] pub struct nsStyleCorners { - pub mUnits: [nsStyleUnit; 8usize], - pub mValues: [nsStyleUnion; 8usize], + mUnits: [nsStyleUnit; 8usize], + mValues: [nsStyleUnion; 8usize], +} +impl nsStyleCorners { + #[inline] + pub unsafe fn get_mUnits(&self) -> &[nsStyleUnit; 8usize] { &self.mUnits } + pub unsafe fn get_mUnits_mut(&mut self) -> &mut [nsStyleUnit; 8usize] { + &mut self.mUnits + } + #[inline] + pub unsafe fn get_mValues(&self) -> &[nsStyleUnion; 8usize] { + &self.mValues + } + pub unsafe fn get_mValues_mut(&mut self) -> &mut [nsStyleUnion; 8usize] { + &mut self.mValues + } } #[test] fn bindgen_test_layout_nsStyleCorners() { @@ -5576,7 +5624,7 @@ pub struct nsStyleBorder { pub mBorderImageFill: u8, pub mBorderImageRepeatH: u8, pub mBorderImageRepeatV: u8, - pub mFloatEdge: u8, + pub mFloatEdge: StyleFloatEdge, pub mBoxDecorationBreak: u8, pub mComputedBorder: nsMargin, pub mBorder: nsMargin, @@ -5751,12 +5799,14 @@ pub struct nsStyleTextReset { pub mTextOverflow: nsStyleTextOverflow, pub mTextDecorationLine: u8, pub mUnicodeBidi: u8, + pub mInitialLetterSink: nscoord, + pub mInitialLetterSize: f32, pub mTextDecorationStyle: u8, pub mTextDecorationColor: nscolor, } #[test] fn bindgen_test_layout_nsStyleTextReset() { - assert_eq!(::std::mem::size_of::<nsStyleTextReset>() , 64usize); + assert_eq!(::std::mem::size_of::<nsStyleTextReset>() , 80usize); assert_eq!(::std::mem::align_of::<nsStyleTextReset>() , 8usize); } #[repr(C)] @@ -5859,14 +5909,6 @@ pub enum nsTimingFunction_Type { } #[repr(i32)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum nsTimingFunction_StepSyntax { - Keyword = 0, - FunctionalWithoutKeyword = 1, - FunctionalWithStartKeyword = 2, - FunctionalWithEndKeyword = 3, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum nsTimingFunction_Keyword { Implicit = 0, Explicit = 1, } #[repr(C)] #[derive(Debug, Copy)] @@ -5908,7 +5950,6 @@ fn bindgen_test_layout_nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct #[repr(C)] #[derive(Debug, Copy)] pub struct nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25 { - pub mStepSyntax: nsTimingFunction_StepSyntax, pub mSteps: u32, } impl ::std::clone::Clone for @@ -5918,7 +5959,7 @@ impl ::std::clone::Clone for #[test] fn bindgen_test_layout_nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25() { assert_eq!(::std::mem::size_of::<nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25>() - , 8usize); + , 4usize); assert_eq!(::std::mem::align_of::<nsTimingFunction_nsStyleStruct_h_unnamed_23_nsStyleStruct_h_unnamed_25>() , 4usize); } @@ -6148,7 +6189,7 @@ fn bindgen_test_layout_nsCursorImage() { pub struct nsStyleUserInterface { pub mUserInput: u8, pub mUserModify: u8, - pub mUserFocus: u8, + pub mUserFocus: StyleUserFocus, pub mPointerEvents: u8, pub mCursor: u8, pub mCursorArrayLength: u32, @@ -6311,9 +6352,9 @@ fn bindgen_test_layout_nsStyleBasicShape() { #[repr(C)] #[derive(Debug)] pub struct nsStyleClipPath { - pub mType: i32, pub nsStyleClipPath_nsStyleStruct_h_unnamed_29: nsStyleClipPath_nsStyleStruct_h_unnamed_29, - pub mSizingBox: u8, + pub mType: StyleClipPathType, + pub mSizingBox: StyleClipShapeSizing, } #[repr(C)] #[derive(Debug, Copy)] @@ -6335,7 +6376,7 @@ fn bindgen_test_layout_nsStyleClipPath_nsStyleStruct_h_unnamed_29() { } #[test] fn bindgen_test_layout_nsStyleClipPath() { - assert_eq!(::std::mem::size_of::<nsStyleClipPath>() , 24usize); + assert_eq!(::std::mem::size_of::<nsStyleClipPath>() , 16usize); assert_eq!(::std::mem::align_of::<nsStyleClipPath>() , 8usize); } #[repr(C)] @@ -6383,7 +6424,7 @@ pub struct nsStyleSVGReset { } #[test] fn bindgen_test_layout_nsStyleSVGReset() { - assert_eq!(::std::mem::size_of::<nsStyleSVGReset>() , 208usize); + assert_eq!(::std::mem::size_of::<nsStyleSVGReset>() , 200usize); assert_eq!(::std::mem::align_of::<nsStyleSVGReset>() , 8usize); } #[repr(C)] diff --git a/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs b/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs index 33dff1a705d..a13f08ea37b 100644 --- a/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs +++ b/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs @@ -3,24 +3,29 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use bindings::{Gecko_ResetStyleCoord, Gecko_SetStyleCoordCalcValue, Gecko_AddRefCalcArbitraryThread}; -use std::mem::transmute; use structs::{nsStyleCoord_Calc, nsStyleUnit, nsStyleUnion, nsStyleCoord, nsStyleSides, nsStyleCorners}; use structs::{nsStyleCoord_CalcValue, nscoord}; impl CoordData for nsStyleCoord { #[inline] fn unit(&self) -> nsStyleUnit { - self.mUnit + unsafe { + *self.get_mUnit() + } } #[inline] fn union(&self) -> nsStyleUnion { - self.mValue + unsafe { + *self.get_mValue() + } } } impl CoordDataMut for nsStyleCoord { unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) { - (&mut self.mUnit, &mut self.mValue) + let unit = self.get_mUnit_mut() as *mut _; + let value = self.get_mValue_mut() as *mut _; + (&mut *unit, &mut *value) } } @@ -53,26 +58,36 @@ pub struct SidesDataMut<'a> { impl<'a> CoordData for SidesData<'a> { #[inline] fn unit(&self) -> nsStyleUnit { - self.sides.mUnits[self.index] + unsafe { + self.sides.get_mUnits()[self.index] + } } #[inline] fn union(&self) -> nsStyleUnion { - self.sides.mValues[self.index] + unsafe { + self.sides.get_mValues()[self.index] + } } } impl<'a> CoordData for SidesDataMut<'a> { #[inline] fn unit(&self) -> nsStyleUnit { - self.sides.mUnits[self.index] + unsafe { + self.sides.get_mUnits()[self.index] + } } #[inline] fn union(&self) -> nsStyleUnion { - self.sides.mValues[self.index] + unsafe { + self.sides.get_mValues()[self.index] + } } } impl<'a> CoordDataMut for SidesDataMut<'a> { unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) { - (&mut self.sides.mUnits[self.index], &mut self.sides.mValues[self.index]) + let unit = &mut self.sides.get_mUnits_mut()[self.index] as *mut _; + let value = &mut self.sides.get_mValues_mut()[self.index] as *mut _; + (&mut *unit, &mut *value) } } @@ -104,23 +119,33 @@ pub struct CornersDataMut<'a> { impl<'a> CoordData for CornersData<'a> { fn unit(&self) -> nsStyleUnit { - self.corners.mUnits[self.index] + unsafe { + self.corners.get_mUnits()[self.index] + } } fn union(&self) -> nsStyleUnion { - self.corners.mValues[self.index] + unsafe { + self.corners.get_mValues()[self.index] + } } } impl<'a> CoordData for CornersDataMut<'a> { fn unit(&self) -> nsStyleUnit { - self.corners.mUnits[self.index] + unsafe { + self.corners.get_mUnits()[self.index] + } } fn union(&self) -> nsStyleUnion { - self.corners.mValues[self.index] + unsafe { + self.corners.get_mValues()[self.index] + } } } impl<'a> CoordDataMut for CornersDataMut<'a> { unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) { - (&mut self.corners.mUnits[self.index], &mut self.corners.mValues[self.index]) + let unit = &mut self.corners.get_mUnits_mut()[self.index] as *mut _; + let value = &mut self.corners.get_mValues_mut()[self.index] as *mut _; + (&mut *unit, &mut *value) } } @@ -179,6 +204,13 @@ pub trait CoordDataMut : CoordData { } } + #[inline] + unsafe fn copy_from_unchecked<T: CoordData>(&mut self, other: &T) { + let (unit, union) = self.values_mut(); + *unit = other.unit(); + *union = other.union(); + } + #[inline(always)] fn set_value(&mut self, value: CoordDataValue) { use self::CoordDataValue::*; @@ -254,7 +286,7 @@ pub trait CoordDataMut : CoordData { #[inline] unsafe fn as_calc_mut(&mut self) -> &mut nsStyleCoord_Calc { debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc); - transmute(*self.union().mPointer.as_mut() as *mut nsStyleCoord_Calc) + &mut *(*self.union().mPointer.as_mut() as *mut nsStyleCoord_Calc) } #[inline] @@ -328,6 +360,6 @@ pub trait CoordData { #[inline] unsafe fn as_calc(&self) -> &nsStyleCoord_Calc { debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc); - transmute(*self.union().mPointer.as_ref() as *const nsStyleCoord_Calc) + &*(*self.union().mPointer.as_ref() as *const nsStyleCoord_Calc) } } diff --git a/ports/geckolib/gecko_bindings/tools/regen.py b/ports/geckolib/gecko_bindings/tools/regen.py index 74fd3beb8ff..821a5e475a7 100755 --- a/ports/geckolib/gecko_bindings/tools/regen.py +++ b/ports/geckolib/gecko_bindings/tools/regen.py @@ -25,7 +25,7 @@ COMPILATION_TARGETS = { "-allow-unknown-types", "-no-bitfield-methods", "-no-type-renaming", "-no-namespaced-constants", "-DTRACING=1", "-DIMPL_LIBXUL", "-DMOZ_STYLO_BINDINGS=1", - "-DMOZILLA_INTERNAL_API", + "-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN", ], "search_dirs": [ "{}/dist/include", @@ -98,7 +98,6 @@ COMPILATION_TARGETS = { "ImageValue", "URLValue", "URLValueData", "nsIPrincipal", "nsDataHashtable", "imgIRequest" ], - "unsafe_field_types": ["nsStyleUnion", "nsStyleUnit"], }, # Generation of the ffi bindings. "bindings": { @@ -127,8 +126,7 @@ COMPILATION_TARGETS = { "nsStyleImageLayers::Layer", "nsStyleImageLayers::LayerType", "nsStyleUnit", "nsStyleUnion", "nsStyleCoord::CalcValue", "nsStyleCoord::Calc", "nsRestyleHint", "ServoElementSnapshot", - - "SheetParsingMode", "nsMainThreadPtrHandle", + "nsChangeHint", "SheetParsingMode", "nsMainThreadPtrHandle", "nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList", "FontFamilyType", "nsIAtom", ], @@ -212,7 +210,7 @@ def build(objdir, target_name, kind_name=None, if os.path.isdir(bindgen): bindgen = ["cargo", "run", "--manifest-path", - os.path.join(bindgen, "Cargo.toml"), "--"] + os.path.join(bindgen, "Cargo.toml"), "--features", "llvm_stable", "--"] else: bindgen = [bindgen] @@ -257,11 +255,6 @@ def build(objdir, target_name, kind_name=None, flags.append("-match") flags.append(header.format(objdir)) - if "unsafe_field_types" in current_target: - for ty in current_target["unsafe_field_types"]: - flags.append("-unsafe-field-type") - flags.append(ty.format(objdir)) - if "blacklist" in current_target: for ty in current_target["blacklist"]: flags.append("-blacklist-type") diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 95f316f5cc1..87e69aabef0 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -81,8 +81,6 @@ pub extern "C" fn Servo_Initialize() -> () { fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) { debug_assert!(node.is_element() || node.is_text_node()); - let per_doc_data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) }; - // Force the creation of our lazily-constructed initial computed values on // the main thread, since it's not safe to call elsewhere. // @@ -92,10 +90,9 @@ fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) { // along in startup than the sensible place to call Servo_Initialize. ComputedValues::initial_values(); - let _needs_dirtying = Arc::get_mut(&mut per_doc_data.stylist).unwrap() - .update(&per_doc_data.stylesheets, - per_doc_data.stylesheets_changed); - per_doc_data.stylesheets_changed = false; + // The stylist consumes stylesheets lazily. + let per_doc_data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) }; + per_doc_data.flush_stylesheets(); let local_context_data = LocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone()); @@ -113,13 +110,13 @@ fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) { timer: Timer::new(), }; - if node.is_dirty() || node.has_dirty_descendants() { - if per_doc_data.num_threads == 1 { - sequential::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context); - } else { - parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, - &mut per_doc_data.work_queue); - } + // We ensure this is true before calling Servo_RestyleSubtree() + debug_assert!(node.is_dirty() || node.has_dirty_descendants()); + if per_doc_data.num_threads == 1 { + sequential::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context); + } else { + parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, + &mut per_doc_data.work_queue); } } @@ -156,6 +153,8 @@ pub extern "C" fn Servo_DropNodeData(data: *mut ServoNodeData) -> () { pub extern "C" fn Servo_StylesheetFromUTF8Bytes(bytes: *const u8, length: u32, mode: SheetParsingMode, + base_bytes: *const u8, + base_length: u32, base: *mut ThreadSafeURIHolder, referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) @@ -168,8 +167,8 @@ pub extern "C" fn Servo_StylesheetFromUTF8Bytes(bytes: *const u8, SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, }; - // FIXME(heycam): Pass in the real base URL. - let url = Url::parse("about:none").unwrap(); + let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes, base_length as usize)) }; + let url = Url::parse(base_str).unwrap(); let extra_data = ParserContextExtraData { base: Some(GeckoArcURI::new(base)), referrer: Some(GeckoArcURI::new(referrer)), @@ -274,7 +273,9 @@ pub extern "C" fn Servo_GetComputedValuesForAnonymousBox(parent_style_or_null: * pseudo_tag: *mut nsIAtom, raw_data: *mut RawServoStyleSet) -> *mut ServoComputedValues { + // The stylist consumes stylesheets lazily. let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + data.flush_stylesheets(); let pseudo = match pseudo_element_from_atom(pseudo_tag, /* ua_stylesheet = */ true) { Ok(pseudo) => pseudo, @@ -319,7 +320,9 @@ pub extern "C" fn Servo_GetComputedValuesForPseudoElement(parent_style: *mut Ser }; + // The stylist consumes stylesheets lazily. let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); + data.flush_stylesheets(); let element = unsafe { GeckoElement::from_raw(match_element) }; diff --git a/ports/geckolib/string_cache/Cargo.toml b/ports/geckolib/string_cache/Cargo.toml index 864afbfce3a..bca87223593 100644 --- a/ports/geckolib/string_cache/Cargo.toml +++ b/ports/geckolib/string_cache/Cargo.toml @@ -20,4 +20,4 @@ cfg-if = "0.1.0" gecko_bindings = {version = "0.0.1", path = "../gecko_bindings"} heapsize = "0.3.5" libc = "0.2" -serde = "0.7.11" +serde = "0.7.15" diff --git a/python/mach_bootstrap.py b/python/mach_bootstrap.py index 0b5a31c7459..d63f66492d5 100644 --- a/python/mach_bootstrap.py +++ b/python/mach_bootstrap.py @@ -135,6 +135,7 @@ def _activate_virtualenv(topdir): requirements_paths = [ os.path.join("python", "requirements.txt"), os.path.join("tests", "wpt", "harness", "requirements.txt"), + os.path.join("tests", "wpt", "harness", "requirements_firefox.txt"), os.path.join("tests", "wpt", "harness", "requirements_servo.txt"), ] for req_rel_path in requirements_paths: diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index f344b050f4e..df727e2776f 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -236,6 +236,9 @@ class MachCommands(CommandBase): cargo_binary = "cargo" + BIN_SUFFIX + if sys.platform == "win32" or sys.platform == "msys": + env["RUSTFLAGS"] = "-C link-args=-Wl,--subsystem,windows" + status = call( [cargo_binary, "build"] + opts, env=env, cwd=self.servo_crate(), verbose=verbose) diff --git a/python/servo/package_commands.py b/python/servo/package_commands.py index d3d7877c674..1bd91e6eae1 100644 --- a/python/servo/package_commands.py +++ b/python/servo/package_commands.py @@ -9,8 +9,11 @@ from __future__ import print_function, unicode_literals -import os +import sys import os.path as path +sys.path.append(path.join(path.dirname(sys.argv[0]), "components", "style", "properties", "Mako-0.9.1.zip")) + +import os import shutil import subprocess import tarfile @@ -24,7 +27,9 @@ from mach.decorators import ( Command, ) -from servo.command_base import CommandBase, cd, BuildNotFound, is_macosx +from mako.template import Template + +from servo.command_base import CommandBase, cd, BuildNotFound, is_macosx, is_windows from servo.post_build_commands import find_dep_path_newest @@ -42,6 +47,11 @@ def otool(s): yield l.split(' ', 1)[0][1:] +def listfiles(directory): + return [f for f in os.listdir(directory) + if path.isfile(path.join(directory, f))] + + def install_name_tool(old, new, binary): try: subprocess.check_call(['install_name_tool', '-change', old, '@executable_path/' + new, binary]) @@ -76,7 +86,7 @@ class PackageCommands(CommandBase): env["ANT_FLAVOR"] = "release" dev_flag = "" - target_dir = os.path.dirname(binary_path) + target_dir = path.dirname(binary_path) output_apk = "{}.apk".format(binary_path) try: with cd(path.join("support", "android", "build-apk")): @@ -91,7 +101,7 @@ class PackageCommands(CommandBase): dir_to_app = dir_to_dmg + '/Servo.app' dir_to_resources = dir_to_app + '/Contents/Resources/' dir_to_root = '/'.join(binary_path.split('/')[:-3]) - if os.path.exists(dir_to_dmg): + if path.exists(dir_to_dmg): print("Cleaning up from previous packaging") delete(dir_to_dmg) browserhtml_path = find_dep_path_newest('browserhtml', binary_path) @@ -123,7 +133,7 @@ class PackageCommands(CommandBase): continue need_relinked = set(otool(f)) new_path = dir_to_app + '/Contents/MacOS/' + f.split('/')[-1] - if not os.path.exists(new_path): + if not path.exists(new_path): shutil.copyfile(f, new_path) for dylib in need_relinked: if '/System/Library' in dylib or '/usr/lib' in dylib or 'servo' in dylib: @@ -153,6 +163,45 @@ class PackageCommands(CommandBase): print("Cleaning up") delete(dir_to_dmg) print("Packaged Servo into " + dmg_path) + elif is_windows(): + dir_to_package = path.dirname(binary_path) + dir_to_root = self.get_top_dir() + dir_to_msi = path.join(dir_to_package, 'msi') + if path.exists(dir_to_msi): + print("Cleaning up from previous packaging") + delete(dir_to_msi) + os.makedirs(dir_to_msi) + top_path = dir_to_root + browserhtml_path = find_dep_path_newest('browserhtml', binary_path) + if browserhtml_path is None: + print("Could not find browserhtml package; perhaps you haven't built Servo.") + return 1 + browserhtml_path = path.join(browserhtml_path, "out") + # generate Servo.wxs + template_path = path.join(dir_to_root, "support", "windows", "Servo.wxs.mako") + template = Template(open(template_path).read()) + wxs_path = path.join(dir_to_msi, "Servo.wxs") + open(wxs_path, "w").write(template.render( + exe_path=dir_to_package, + top_path=top_path, + browserhtml_path=browserhtml_path)) + # run candle and light + print("Creating MSI") + try: + with cd(dir_to_msi): + subprocess.check_call(['candle', wxs_path]) + except subprocess.CalledProcessError as e: + print("WiX candle exited with return value %d" % e.returncode) + return e.returncode + try: + wxsobj_path = "{}.wixobj".format(path.splitext(wxs_path)[0]) + with cd(dir_to_msi): + subprocess.check_call(['light', wxsobj_path]) + except subprocess.CalledProcessError as e: + print("WiX light exited with return value %d" % e.returncode) + return e.returncode + msi_path = path.join(dir_to_msi, "Servo.msi") + print("Packaged Servo into {}".format(msi_path)) else: dir_to_package = '/'.join(binary_path.split('/')[:-1]) dir_to_root = '/'.join(binary_path.split('/')[:-3]) diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index b4c045d4a70..4776a9209d1 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -209,6 +209,9 @@ class MachCommands(CommandBase): env = self.build_env() env["RUST_BACKTRACE"] = "1" + if sys.platform == "win32" or sys.platform == "msys": + env["RUSTFLAGS"] = "-C link-args=-Wl,--subsystem,windows" + result = call(args, env=env, cwd=self.servo_crate()) if result != 0: return result diff --git a/python/tidy/servo_tidy/licenseck.py b/python/tidy/servo_tidy/licenseck.py index 03113da507d..75819bcefd2 100644 --- a/python/tidy/servo_tidy/licenseck.py +++ b/python/tidy/servo_tidy/licenseck.py @@ -32,6 +32,14 @@ licenses = [ """, """\ +#!/usr/bin/env python3 + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +""", + +"""\ // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/python/tidy/servo_tidy_tests/test_tidy.py b/python/tidy/servo_tidy_tests/test_tidy.py index 8db19a5efd7..6497fa016b7 100644 --- a/python/tidy/servo_tidy_tests/test_tidy.py +++ b/python/tidy/servo_tidy_tests/test_tidy.py @@ -93,6 +93,7 @@ class CheckTidiness(unittest.TestCase): def test_toml(self): errors = tidy.collect_errors_for_files(iterFile('test.toml'), [tidy.check_toml], [], print_text=False) self.assertEqual('found asterisk instead of minimum version number', errors.next()[2]) + self.assertEqual('.toml file should contain a valid license.', errors.next()[2]) self.assertNoMoreErrors(errors) def test_modeline(self): @@ -130,12 +131,12 @@ class CheckTidiness(unittest.TestCase): file_list = tidy.get_file_list(base_path, only_changed_files=False, exclude_dirs=[]) lst = list(file_list) - self.assertEqual([os.path.join(base_path, 'whee', 'test.rs')], lst) + self.assertEqual([os.path.join(base_path, 'whee', 'test.rs'), os.path.join(base_path, 'whee', 'foo', 'bar.rs')], lst) file_list = tidy.get_file_list(base_path, only_changed_files=False, - exclude_dirs=[os.path.join(base_path,'whee')]) + exclude_dirs=[os.path.join(base_path, 'whee', 'foo')]) lst = list(file_list) - self.assertEqual([], lst) + self.assertEqual([os.path.join(base_path, 'whee', 'test.rs')], lst) def do_tests(): suite = unittest.TestLoader().loadTestsFromTestCase(CheckTidiness) - unittest.TextTestRunner(verbosity=2).run(suite) + return 0 if unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful() else 1 diff --git a/resources/Servo.ico b/resources/Servo.ico Binary files differnew file mode 100644 index 00000000000..71d38a0c147 --- /dev/null +++ b/resources/Servo.ico diff --git a/resources/servo.css b/resources/servo.css index 8ec5e17bbf0..858d59226c2 100644 --- a/resources/servo.css +++ b/resources/servo.css @@ -9,7 +9,7 @@ input { color: black; font-family: sans-serif; font-size: 0.8333em; - white-space: nowrap; + white-space: pre; text-align: left; line-height: 1.8; } @@ -24,7 +24,7 @@ textarea { color: black; font-family: sans-serif; font-size: 0.8333em; - white-space: pre; + white-space: pre-wrap; } input::selection, diff --git a/resources/shaders/blur.fs.glsl b/resources/shaders/blur.fs.glsl index c20a774f488..2af2a7ebabb 100644 --- a/resources/shaders/blur.fs.glsl +++ b/resources/shaders/blur.fs.glsl @@ -28,7 +28,7 @@ void main(void) { lColorTexCoord.x <= 1.0 && lColorTexCoord.y >= 0.0 && lColorTexCoord.y <= 1.0 ? - Texture(sDiffuse, lColorTexCoord * sourceTextureUvSize + sourceTextureUvOrigin) : + texture(sDiffuse, lColorTexCoord * sourceTextureUvSize + sourceTextureUvOrigin) : vec4(0.0); // Alpha must be premultiplied in order to properly blur the alpha channel. diff --git a/resources/shaders/box_shadow.fs.glsl b/resources/shaders/box_shadow.fs.glsl index 5d7c6db6d59..e71ba6a193b 100644 --- a/resources/shaders/box_shadow.fs.glsl +++ b/resources/shaders/box_shadow.fs.glsl @@ -141,6 +141,8 @@ void main(void) { vec2 radii = vBorderRadii.xy; float sigma = vBlurRadius / 2.0; float value = color(pos, p0Rect, p1Rect, radii, sigma); - SetFragColor(vec4(vColor.rgb, max(value, 0.0))); + + value = max(value, 0.0); + SetFragColor(vec4(vColor.rgb, vColor.a == 0.0 ? 1.0 - value : value)); } diff --git a/resources/shaders/debug_color.fs.glsl b/resources/shaders/debug_color.fs.glsl index 658ac27488c..e9aae641382 100644 --- a/resources/shaders/debug_color.fs.glsl +++ b/resources/shaders/debug_color.fs.glsl @@ -4,5 +4,5 @@ void main(void) { - SetFragColor(vColor); + oFragColor = vColor; } diff --git a/resources/shaders/debug_font.fs.glsl b/resources/shaders/debug_font.fs.glsl index 8b68e085cfb..a10e0da4ceb 100644 --- a/resources/shaders/debug_font.fs.glsl +++ b/resources/shaders/debug_font.fs.glsl @@ -5,9 +5,9 @@ void main(void) { #ifdef SERVO_ES2 - float alpha = Texture(sDiffuse, vColorTexCoord.xy).a; + float alpha = texture(sDiffuse, vColorTexCoord.xy).a; #else - float alpha = Texture(sDiffuse, vColorTexCoord.xy).r; + float alpha = texture(sDiffuse, vColorTexCoord.xy).r; #endif - SetFragColor(vec4(vColor.xyz, vColor.w * alpha)); + oFragColor = vec4(vColor.xyz, vColor.w * alpha); } diff --git a/resources/shaders/es2_common.vs.glsl b/resources/shaders/es2_common.vs.glsl index 91d72015e49..ccb8c3dcec5 100644 --- a/resources/shaders/es2_common.vs.glsl +++ b/resources/shaders/es2_common.vs.glsl @@ -65,6 +65,6 @@ vec2 SnapToPixels(vec2 pos) // Snap the vertex to pixel position to guarantee correct texture // sampling when using bilinear filtering. - // TODO(gw): Do we ever get negative coords here? + // TODO(gw): ES2 doesn't have round(). Do we ever get negative coords here? return floor(0.5 + pos * uDevicePixelRatio) / uDevicePixelRatio; } diff --git a/resources/shaders/gl3_common.vs.glsl b/resources/shaders/gl3_common.vs.glsl index e24cef9437e..cffcfc80eb7 100644 --- a/resources/shaders/gl3_common.vs.glsl +++ b/resources/shaders/gl3_common.vs.glsl @@ -62,8 +62,5 @@ vec2 SnapToPixels(vec2 pos) { // Snap the vertex to pixel position to guarantee correct texture // sampling when using bilinear filtering. - - // Don't use round() because its behavior is implementation-defined on 0.5. - // TODO: Do we ever get negative coords here? - return floor(0.5 + pos * uDevicePixelRatio) / uDevicePixelRatio; + return round(pos * uDevicePixelRatio) / uDevicePixelRatio; } diff --git a/resources/shaders/prim_shared.glsl b/resources/shaders/prim_shared.glsl new file mode 100644 index 00000000000..7c21cada7fa --- /dev/null +++ b/resources/shaders/prim_shared.glsl @@ -0,0 +1,180 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define PST_INVALID uint(0) +#define PST_TOP_LEFT uint(1) +#define PST_TOP_RIGHT uint(2) +#define PST_BOTTOM_LEFT uint(3) +#define PST_BOTTOM_RIGHT uint(4) +#define PST_TOP uint(5) +#define PST_LEFT uint(6) +#define PST_BOTTOM uint(7) +#define PST_RIGHT uint(8) + +// Border styles as defined in webrender_traits/types.rs +#define BORDER_STYLE_NONE uint(0) +#define BORDER_STYLE_SOLID uint(1) +#define BORDER_STYLE_DOUBLE uint(2) +#define BORDER_STYLE_DOTTED uint(3) +#define BORDER_STYLE_DASHED uint(4) +#define BORDER_STYLE_HIDDEN uint(5) +#define BORDER_STYLE_GROOVE uint(6) +#define BORDER_STYLE_RIDGE uint(7) +#define BORDER_STYLE_INSET uint(8) +#define BORDER_STYLE_OUTSET uint(9) + +#ifdef WR_VERTEX_SHADER +struct Layer { + mat4 transform; + mat4 inv_transform; + ivec4 world_clip_rect; + vec4 screen_vertices[4]; +}; + +layout(std140) uniform Layers { + Layer layers[WR_MAX_PRIM_LAYERS]; +}; + +struct Tile { + uvec4 actual_rect; + uvec4 target_rect; +}; + +layout(std140) uniform Tiles { + Tile tiles[WR_MAX_PRIM_TILES]; +}; + +struct PrimitiveInfo { + uvec4 layer_tile_part; + vec4 local_clip_rect; + vec4 local_rect; +}; + +struct ClipCorner { + vec4 rect; + vec4 outer_inner_radius; +}; + +struct Clip { + vec4 rect; + ClipCorner top_left; + ClipCorner top_right; + ClipCorner bottom_left; + ClipCorner bottom_right; +}; + +bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t) +{ + float denom = dot(normal, ray_dir); + if (denom > 1e-6) { + vec3 d = point - ray_origin; + t = dot(d, normal) / denom; + return t >= 0.0; + } + + return false; +} + +vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) { + vec3 p = vec3(ref, -10000.0); + vec3 d = vec3(0, 0, 1.0); + + float t; + ray_plane(n, a, p, d, t); + vec3 c = p + d * t; + + vec4 r = inv_transform * vec4(c, 1.0); + return r; +} + +vec3 get_layer_pos(vec2 pos, uint layer_index) { + Layer layer = layers[layer_index]; + vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w; + vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w; + vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w; + vec3 n = normalize(cross(b-a, c-a)); + vec4 local_pos = untransform(pos, n, a, layer.inv_transform); + return local_pos.xyw; +} + +struct Rect { + vec2 p0; + vec2 p1; +}; + +struct VertexInfo { + Rect local_rect; + vec2 local_clamped_pos; + vec2 global_clamped_pos; +}; + +VertexInfo write_vertex(PrimitiveInfo info) { + Layer layer = layers[info.layer_tile_part.x]; + Tile tile = tiles[info.layer_tile_part.y]; + + vec2 p0 = floor(0.5 + info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (info.local_rect.xy + info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + + vec2 local_pos = mix(p0, p1, aPosition.xy); + + vec2 cp0 = floor(0.5 + info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp1 = floor(0.5 + (info.local_clip_rect.xy + info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + local_pos = clamp(local_pos, cp0, cp1); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + world_pos.xyz /= world_pos.w; + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); + + clamped_pos = clamp(clamped_pos, + vec2(layer.world_clip_rect.xy), + vec2(layer.world_clip_rect.xy + layer.world_clip_rect.zw)); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1); + local_clamped_pos.xyz /= local_clamped_pos.w; + + vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy); + + gl_Position = uTransform * vec4(final_pos, 0, 1); + + VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy, clamped_pos.xy); + return vi; +} +#endif + +#ifdef WR_FRAGMENT_SHADER +void do_clip(vec2 pos, vec4 clip_rect, vec4 radius) { + vec2 ref_tl = clip_rect.xy + vec2( radius.x, radius.x); + vec2 ref_tr = clip_rect.zy + vec2(-radius.y, radius.y); + vec2 ref_br = clip_rect.zw + vec2(-radius.z, -radius.z); + vec2 ref_bl = clip_rect.xw + vec2( radius.w, -radius.w); + + float d_tl = distance(pos, ref_tl); + float d_tr = distance(pos, ref_tr); + float d_br = distance(pos, ref_br); + float d_bl = distance(pos, ref_bl); + + bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius.x; + bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius.y; + bool out2 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius.z; + bool out3 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius.w; + + // TODO(gw): Alpha anti-aliasing based on edge distance! + if (out0 || out1 || out2 || out3) { + discard; + } +} + +bool point_in_rect(vec2 p, vec2 p0, vec2 p1) { + return p.x >= p0.x && + p.y >= p0.y && + p.x <= p1.x && + p.y <= p1.y; +} +#endif diff --git a/resources/shaders/ps_angle_gradient.fs.glsl b/resources/shaders/ps_angle_gradient.fs.glsl new file mode 100644 index 00000000000..944b90979f6 --- /dev/null +++ b/resources/shaders/ps_angle_gradient.fs.glsl @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +float offset(int index) { + return vOffsets[index / 4][index % 4]; +} + +float linearStep(float lo, float hi, float x) { + float d = hi - lo; + float v = x - lo; + if (d != 0.0) { + v /= d; + } + return clamp(v, 0.0, 1.0); +} + +void main(void) { + float angle = atan(-vEndPoint.y + vStartPoint.y, + vEndPoint.x - vStartPoint.x); + float sa = sin(angle); + float ca = cos(angle); + + float sx = vStartPoint.x * ca - vStartPoint.y * sa; + float ex = vEndPoint.x * ca - vEndPoint.y * sa; + float d = ex - sx; + + float x = vPos.x * ca - vPos.y * sa; + + oFragColor = mix(vColors[0], + vColors[1], + linearStep(sx + d * offset(0), sx + d * offset(1), x)); + + for (int i=1 ; i < vStopCount-1 ; ++i) { + oFragColor = mix(oFragColor, + vColors[i+1], + linearStep(sx + d * offset(i), sx + d * offset(i+1), x)); + } +} diff --git a/resources/shaders/ps_angle_gradient.glsl b/resources/shaders/ps_angle_gradient.glsl new file mode 100644 index 00000000000..fae2211af50 --- /dev/null +++ b/resources/shaders/ps_angle_gradient.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define MAX_STOPS_PER_ANGLE_GRADIENT 8 + +flat varying int vStopCount; +flat varying float vAngle; +flat varying vec2 vStartPoint; +flat varying vec2 vEndPoint; +varying vec2 vPos; +flat varying vec4 vColors[MAX_STOPS_PER_ANGLE_GRADIENT]; +flat varying vec4 vOffsets[MAX_STOPS_PER_ANGLE_GRADIENT/4]; diff --git a/resources/shaders/ps_angle_gradient.vs.glsl b/resources/shaders/ps_angle_gradient.vs.glsl new file mode 100644 index 00000000000..16296967bdb --- /dev/null +++ b/resources/shaders/ps_angle_gradient.vs.glsl @@ -0,0 +1,38 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct AngleGradient { + PrimitiveInfo info; + vec4 start_end_point; + uvec4 stop_count; + vec4 colors[MAX_STOPS_PER_ANGLE_GRADIENT]; + vec4 offsets[MAX_STOPS_PER_ANGLE_GRADIENT/4]; +}; + +layout(std140) uniform Items { + AngleGradient gradients[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + AngleGradient gradient = gradients[gl_InstanceID]; + VertexInfo vi = write_vertex(gradient.info); + + vStopCount = int(gradient.stop_count.x); + vPos = vi.local_clamped_pos; + + // Snap the start/end points to device pixel units. + // I'm not sure this is entirely correct, but the + // old render path does this, and it is needed to + // make the angle gradient ref tests pass. It might + // be better to fix this higher up in DL construction + // and not snap here? + vStartPoint = floor(0.5 + gradient.start_end_point.xy * uDevicePixelRatio) / uDevicePixelRatio; + vEndPoint = floor(0.5 + gradient.start_end_point.zw * uDevicePixelRatio) / uDevicePixelRatio; + + for (int i=0 ; i < int(gradient.stop_count.x) ; ++i) { + vColors[i] = gradient.colors[i]; + vOffsets[i] = gradient.offsets[i]; + } +} diff --git a/resources/shaders/ps_blend.fs.glsl b/resources/shaders/ps_blend.fs.glsl new file mode 100644 index 00000000000..12ccbf0b6cf --- /dev/null +++ b/resources/shaders/ps_blend.fs.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +uniform sampler2D sCache; + +void main(void) { + vec4 color = texture(sCache, vUv); + oFragColor = vec4(color.rgb, color.a * vOpacity); +} diff --git a/resources/shaders/ps_blend.glsl b/resources/shaders/ps_blend.glsl new file mode 100644 index 00000000000..773cf91e27e --- /dev/null +++ b/resources/shaders/ps_blend.glsl @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; +varying float vOpacity; diff --git a/resources/shaders/ps_blend.vs.glsl b/resources/shaders/ps_blend.vs.glsl new file mode 100644 index 00000000000..eb61903b5cc --- /dev/null +++ b/resources/shaders/ps_blend.vs.glsl @@ -0,0 +1,29 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Blend { + uvec4 target_rect; + uvec4 src_rect; + vec4 opacity; +}; + +layout(std140) uniform Items { + Blend blends[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Blend blend = blends[gl_InstanceID]; + + vec2 local_pos = mix(vec2(blend.target_rect.xy), + vec2(blend.target_rect.xy + blend.target_rect.zw), + aPosition.xy); + + vec2 st0 = vec2(blend.src_rect.xy) / 2048.0; + vec2 st1 = vec2(blend.src_rect.xy + blend.src_rect.zw) / 2048.0; + vUv = mix(st0, st1, aPosition.xy); + vOpacity = blend.opacity.x; + + gl_Position = uTransform * vec4(local_pos, 0, 1); +} diff --git a/resources/shaders/ps_border.fs.glsl b/resources/shaders/ps_border.fs.glsl new file mode 100644 index 00000000000..042b56f1d0a --- /dev/null +++ b/resources/shaders/ps_border.fs.glsl @@ -0,0 +1,184 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// draw a circle at position aDesiredPos with a aRadius +vec4 drawCircle(vec2 aPixel, vec2 aDesiredPos, float aRadius, vec3 aColor) { + float farFromCenter = length(aDesiredPos - aPixel) - aRadius; + float pixelInCircle = 1.00 - clamp(farFromCenter, 0.0, 1.0); + return vec4(aColor, pixelInCircle); +} + +// Draw a rectangle at aRect fill it with aColor. Only works on non-rotated +// rects. +vec4 drawRect(vec2 aPixel, vec4 aRect, vec3 aColor) { + // GLSL origin is bottom left, positive Y is up + bool inRect = (aRect.x <= aPixel.x) && (aPixel.x <= aRect.x + aRect.z) && + (aPixel.y >= aRect.y) && (aPixel.y <= aRect.y + aRect.w); + return vec4(aColor, float(inRect)); +} + +vec4 draw_dotted_edge() { + // Everything here should be in device pixels. + // We want the dot to be roughly the size of the whole border spacing + float border_spacing = min(vBorders.w, vBorders.z); + float radius = floor(border_spacing / 2.0); + float diameter = radius * 2.0; + // The amount of space between dots. 2.2 was chosen because it looks kind of + // like firefox. + float circleSpacing = diameter * 2.2; + + vec2 size = vec2(vBorders.z, vBorders.w); + // Get our position within this specific segment + vec2 position = vDevicePos - vBorders.xy; + + // Break our position into square tiles with circles in them. + vec2 circleCount = floor(size / circleSpacing); + circleCount = max(circleCount, 1.0); + + vec2 distBetweenCircles = size / circleCount; + vec2 circleCenter = distBetweenCircles / 2.0; + + // Find out which tile this pixel belongs to. + vec2 destTile = floor(position / distBetweenCircles); + destTile = destTile * distBetweenCircles; + + // Where we want to draw the actual circle. + vec2 tileCenter = destTile + circleCenter; + + // Find the position within the tile + vec2 positionInTile = mod(position, distBetweenCircles); + vec2 finalPosition = positionInTile + destTile; + + vec4 white = vec4(1.0, 1.0, 1.0, 1.0); + // See if we should draw a circle or not + vec4 circleColor = drawCircle(finalPosition, tileCenter, radius, vVerticalColor.xyz); + return mix(white, circleColor, circleColor.a); +} + +// Our current edge calculation is based only on +// the size of the border-size, but we need to draw +// the dashes in the center of the segment we're drawing. +// This calculates how much to nudge and which axis to nudge on. +vec2 get_dashed_nudge_factor(vec2 dash_size, bool is_corner) { + if (is_corner) { + return vec2(0.0, 0.0); + } + + bool xAxisFudge = vBorders.z > vBorders.w; + if (xAxisFudge) { + return vec2(dash_size.x / 2.0, 0); + } else { + return vec2(0.0, dash_size.y / 2.0); + } +} + +vec4 draw_dashed_edge(bool is_corner) { + // Everything here should be in device pixels. + // We want the dot to be roughly the size of the whole border spacing + // 5.5 here isn't a magic number, it's just what mostly looks like FF/Chrome + float dash_interval = min(vBorders.w, vBorders.z) * 5.5; + vec2 edge_size = vec2(vBorders.z, vBorders.w); + vec2 dash_size = vec2(dash_interval / 2.0, dash_interval / 2.0); + vec2 position = vDevicePos - vBorders.xy; + + vec2 dash_count = floor(edge_size/ dash_interval); + vec2 dist_between_dashes = edge_size / dash_count; + + vec2 target_rect_index = floor(position / dist_between_dashes); + vec2 target_rect_loc = target_rect_index * dist_between_dashes; + target_rect_loc += get_dashed_nudge_factor(dash_size, is_corner); + vec4 target_rect = vec4(target_rect_loc, dash_size); + + vec4 white = vec4(1.0, 1.0, 1.0, 1.0); + vec4 target_colored_rect = drawRect(position, target_rect, vVerticalColor.xyz); + return mix(white, target_colored_rect, target_colored_rect.a); +} + +void draw_dotted_border(void) { + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + case PST_TOP_RIGHT: + case PST_BOTTOM_LEFT: + case PST_BOTTOM_RIGHT: + { + // TODO: Fix for corners with a border-radius + oFragColor = draw_dotted_edge(); + break; + } + case PST_BOTTOM: + case PST_TOP: + case PST_LEFT: + case PST_RIGHT: + { + oFragColor = draw_dotted_edge(); + break; + } + } +} + +void draw_dashed_border(void) { + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + case PST_TOP_RIGHT: + case PST_BOTTOM_LEFT: + case PST_BOTTOM_RIGHT: + { + // TODO: Fix for corners with a border-radius + bool is_corner = true; + oFragColor = draw_dashed_edge(is_corner); + break; + } + case PST_BOTTOM: + case PST_TOP: + case PST_LEFT: + case PST_RIGHT: + { + bool is_corner = false; + oFragColor = draw_dashed_edge(is_corner); + break; + } + } +} + +void main(void) { + if (vRadii.x > 0.0 && + (distance(vRefPoint, vLocalPos) > vRadii.x || + distance(vRefPoint, vLocalPos) < vRadii.z)) { + discard; + } + + switch (vBorderStyle) { + case BORDER_STYLE_DASHED: + { + draw_dashed_border(); + break; + } + case BORDER_STYLE_DOTTED: + { + draw_dotted_border(); + break; + } + case BORDER_STYLE_OUTSET: + case BORDER_STYLE_INSET: + { + float color = step(0.0, vF); + oFragColor = mix(vVerticalColor, vHorizontalColor, color); + break; + } + case BORDER_STYLE_NONE: + case BORDER_STYLE_SOLID: + { + float color = step(0.0, vF); + oFragColor = mix(vHorizontalColor, vVerticalColor, color); + break; + } + default: + { + discard; + break; + } + } +} diff --git a/resources/shaders/ps_border.glsl b/resources/shaders/ps_border.glsl new file mode 100644 index 00000000000..26a1a6601e9 --- /dev/null +++ b/resources/shaders/ps_border.glsl @@ -0,0 +1,24 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// These two are interpolated +varying float vF; // This is a weighting as we get closer to the bottom right corner? + +// These are not changing. +flat varying vec4 vVerticalColor; // The vertical color, e.g. top/bottom +flat varying vec4 vHorizontalColor; // The horizontal color e.g. left/right +flat varying vec4 vRadii; // The border radius from CSS border-radius + +// These are in device space +varying vec2 vLocalPos; // The clamped position in local space. +varying vec2 vDevicePos; // The clamped position in device space. +flat varying vec4 vBorders; // the rect of the border in (x, y, width, height) form + +// for corners, this is the beginning of the corner. +// For the lines, this is the top left of the line. +flat varying vec2 vRefPoint; +flat varying uint vBorderStyle; +flat varying uint vBorderPart; // Which part of the border we're drawing. diff --git a/resources/shaders/ps_border.vs.glsl b/resources/shaders/ps_border.vs.glsl new file mode 100644 index 00000000000..99026b74eff --- /dev/null +++ b/resources/shaders/ps_border.vs.glsl @@ -0,0 +1,113 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Border { + PrimitiveInfo info; + vec4 verticalColor; + vec4 horizontalColor; + vec4 radii; + uvec4 border_style_trbl; +}; + +layout(std140) uniform Items { + Border borders[WR_MAX_PRIM_ITEMS]; +}; + +uint get_border_style(Border a_border, uint a_edge) { + switch (a_edge) { + case PST_TOP: + case PST_TOP_LEFT: + return a_border.border_style_trbl.x; + case PST_BOTTOM_LEFT: + case PST_LEFT: + return a_border.border_style_trbl.z; + case PST_BOTTOM_RIGHT: + case PST_BOTTOM: + return a_border.border_style_trbl.w; + case PST_TOP_RIGHT: + case PST_RIGHT: + return a_border.border_style_trbl.y; + } +} + +void main(void) { + Border border = borders[gl_InstanceID]; + VertexInfo vi = write_vertex(border.info); + + // Just our boring radius position. + vRadii = border.radii; + + float x0, y0, x1, y1; + vBorderPart = border.info.layer_tile_part.z; + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y; + // These are width / heights + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y + border.info.local_rect.w; + + // The radius here is the border-radius. This is 0, so vRefPoint will + // just be the top left (x,y) corner. + vRefPoint = vec2(x0, y0) + vRadii.xy; + break; + case PST_TOP_RIGHT: + x0 = border.info.local_rect.x + border.info.local_rect.z; + y0 = border.info.local_rect.y; + x1 = border.info.local_rect.x; + y1 = border.info.local_rect.y + border.info.local_rect.w; + vRefPoint = vec2(x0, y0) + vec2(-vRadii.x, vRadii.y); + break; + case PST_BOTTOM_LEFT: + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y + border.info.local_rect.w; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y; + vRefPoint = vec2(x0, y0) + vec2(vRadii.x, -vRadii.y); + break; + case PST_BOTTOM_RIGHT: + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y + border.info.local_rect.w; + vRefPoint = vec2(x1, y1) + vec2(-vRadii.x, -vRadii.y); + break; + case PST_TOP: + case PST_LEFT: + case PST_BOTTOM: + case PST_RIGHT: + vRefPoint = border.info.local_rect.xy; + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y + border.info.local_rect.w; + break; + } + + vBorderStyle = get_border_style(border, vBorderPart); + + // y1 - y0 is the height of the corner / line + // x1 - x0 is the width of the corner / line. + float width = x1 - x0; + float height = y1 - y0; + // This is just a weighting of the pixel colors it seems? + vF = (vi.local_clamped_pos.x - x0) * height - (vi.local_clamped_pos.y - y0) * width; + + // This is what was currently sent. + vVerticalColor = border.verticalColor; + vHorizontalColor = border.horizontalColor; + + // Local space + vLocalPos = vi.local_clamped_pos.xy; + + // These are in device space + vDevicePos = vi.global_clamped_pos; + + // These are in device space + vBorders = vec4(border.info.local_rect.x, border.info.local_rect.y, + border.info.local_rect.z, + border.info.local_rect.w) * uDevicePixelRatio; +} diff --git a/resources/shaders/ps_box_shadow.fs.glsl b/resources/shaders/ps_box_shadow.fs.glsl new file mode 100644 index 00000000000..9c485cba9fe --- /dev/null +++ b/resources/shaders/ps_box_shadow.fs.glsl @@ -0,0 +1,151 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// See http://asciimath.org to render the equations here. + +// The Gaussian function used for blurring: +// +// G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) +float gauss(float x, float sigma) { + float sigmaPow2 = sigma * sigma; + return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2)); +} + +// An approximation of the error function, which is related to the integral of the Gaussian +// function: +// +// "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt +// ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4 +// +// where: +// +// a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108 +// +// This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes. +// +// See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions +float erf(float x) { + bool negative = x < 0.0; + if (negative) + x = -x; + float x2 = x * x; + float x3 = x2 * x; + float x4 = x2 * x2; + float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4; + float result = 1.0 - 1.0 / (denom * denom * denom * denom); + return negative ? -result : result; +} + +// A useful helper for calculating integrals of the Gaussian function via the error function: +// +// "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx +// = "erf"(x/(sigma sqrt(2))) +float erfSigma(float x, float sigma) { + return erf(x / (sigma * 1.4142135623730951)); +} + +// Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is +// the vector distance to the top left corner of the box; `p_1` is the vector distance to its +// bottom right corner. +// +// "colorFromRect"_sigma(p_0, p_1) +// = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy +// = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x})) +// ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y})) +float colorFromRect(vec2 p0, vec2 p1, float sigma) { + return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) * + (erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0; +} + +// Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate: +// +// "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2) +float ellipsePoint(float y, float y0, vec2 radii) { + float bStep = (y - y0) / radii.y; + return radii.x * sqrt(1.0 - bStep * bStep); +} + +// A helper function to compute the value that needs to be subtracted to accommodate the border +// corners. +// +// "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b) +// = int_{y_{min}}^{y_{max}} +// int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx +// + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x) +// dx dy +// = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y) +// ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) + +// "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a)) +// +// with the outer integral evaluated numerically. +float colorCutoutGeneral(float x0l, + float x0r, + float y0, + float yMin, + float yMax, + vec2 radii, + float sigma) { + float sum = 0.0; + for (float y = yMin; y <= yMax; y += 1.0) { + float xEllipsePoint = ellipsePoint(y, y0, radii); + sum += gauss(y, sigma) * + (erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) + + erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma)); + } + return sum / 2.0; +} + +// The value that needs to be subtracted to accommodate the top border corners. +float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) { + return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma); +} + +// The value that needs to be subtracted to accommodate the bottom border corners. +float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) { + return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma); +} + +// The blurred color value for the point at `pos` with the top left corner of the box at +// `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`. +float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) { + // Compute the vector distances `p_0` and `p_1`. + vec2 p0 = p0Rect - pos, p1 = p1Rect - pos; + + // Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if + // the box is unrounded. + float cRect = colorFromRect(p0, p1, sigma); + if (radii.x == 0.0 || radii.y == 0.0) + return cRect; + + // Compute the inner corners of the box, taking border radii into account: `x_{0_l}`, + // `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`. + float x0l = p0.x + radii.x; + float y0t = p1.y - radii.y; + float x0r = p1.x - radii.x; + float y0b = p0.y + radii.y; + + // Compute the final color: + // + // "colorFromRect"_sigma(p_0, p_1) - + // ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) + + // "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b)) + float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma); + float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma); + return cRect - (cCutoutTop + cCutoutBottom); +} + +void main(void) { + vec2 pos = vPos.xy; + vec2 p0Rect = vBoxShadowRect.xy, p1Rect = vBoxShadowRect.zw; + vec2 radii = vBorderRadii.xy; + float sigma = vBlurRadius / 2.0; + float value = color(pos, p0Rect, p1Rect, radii, sigma); + + value = max(value, 0.0); + oFragColor = vColor * vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value); +} diff --git a/resources/shaders/ps_box_shadow.glsl b/resources/shaders/ps_box_shadow.glsl new file mode 100644 index 00000000000..26fdba588f3 --- /dev/null +++ b/resources/shaders/ps_box_shadow.glsl @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vPos; +flat varying vec4 vColor; +flat varying vec2 vBorderRadii; +flat varying float vBlurRadius; +flat varying vec4 vBoxShadowRect; +flat varying vec4 vSrcRect; +flat varying float vInverted; diff --git a/resources/shaders/ps_box_shadow.vs.glsl b/resources/shaders/ps_box_shadow.vs.glsl new file mode 100644 index 00000000000..cfcdacfa675 --- /dev/null +++ b/resources/shaders/ps_box_shadow.vs.glsl @@ -0,0 +1,29 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct BoxShadow { + PrimitiveInfo info; + vec4 color; + vec4 border_radii_blur_radius_inverted; + vec4 bs_rect; + vec4 src_rect; +}; + +layout(std140) uniform Items { + BoxShadow boxshadows[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + BoxShadow bs = boxshadows[gl_InstanceID]; + VertexInfo vi = write_vertex(bs.info); + + vPos = vi.local_clamped_pos; + vColor = bs.color; + vBorderRadii = bs.border_radii_blur_radius_inverted.xy; + vBlurRadius = bs.border_radii_blur_radius_inverted.z; + vBoxShadowRect = vec4(bs.bs_rect.xy, bs.bs_rect.xy + bs.bs_rect.zw); + vSrcRect = vec4(bs.src_rect.xy, bs.src_rect.xy + bs.src_rect.zw); + vInverted = bs.border_radii_blur_radius_inverted.w; +} diff --git a/resources/shaders/ps_clear.fs.glsl b/resources/shaders/ps_clear.fs.glsl new file mode 100644 index 00000000000..5ad3065f78d --- /dev/null +++ b/resources/shaders/ps_clear.fs.glsl @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + oFragColor = vec4(1, 1, 1, 1); +} diff --git a/resources/shaders/ps_clear.glsl b/resources/shaders/ps_clear.glsl new file mode 100644 index 00000000000..e0032240a4d --- /dev/null +++ b/resources/shaders/ps_clear.glsl @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/resources/shaders/ps_clear.vs.glsl b/resources/shaders/ps_clear.vs.glsl new file mode 100644 index 00000000000..5d3012fe46c --- /dev/null +++ b/resources/shaders/ps_clear.vs.glsl @@ -0,0 +1,23 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct ClearTile { + uvec4 rect; +}; + +layout(std140) uniform Tiles { + ClearTile tiles[WR_MAX_CLEAR_TILES]; +}; + + +void main() { + ClearTile tile = tiles[gl_InstanceID]; + + vec4 rect = vec4(tile.rect); + + vec4 pos = vec4(mix(rect.xy, rect.xy + rect.zw, aPosition.xy), 0, 1); + gl_Position = uTransform * pos; +} diff --git a/resources/shaders/ps_composite.fs.glsl b/resources/shaders/ps_composite.fs.glsl new file mode 100644 index 00000000000..c4e4099655b --- /dev/null +++ b/resources/shaders/ps_composite.fs.glsl @@ -0,0 +1,320 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define COMPOSITE_KIND_MIX_BLEND_MODE 0 +#define COMPOSITE_KIND_FILTER 1 + +uniform sampler2D sCache; + +vec3 rgbToHsv(vec3 c) { + float value = max(max(c.r, c.g), c.b); + + float chroma = value - min(min(c.r, c.g), c.b); + if (chroma == 0.0) { + return vec3(0.0); + } + float saturation = chroma / value; + + float hue; + if (c.r == value) + hue = (c.g - c.b) / chroma; + else if (c.g == value) + hue = 2.0 + (c.b - c.r) / chroma; + else // if (c.b == value) + hue = 4.0 + (c.r - c.g) / chroma; + + hue *= 1.0/6.0; + if (hue < 0.0) + hue += 1.0; + return vec3(hue, saturation, value); +} + +vec3 hsvToRgb(vec3 c) { + if (c.s == 0.0) { + return vec3(c.z); + } + + float hue = c.x * 6.0; + int sector = int(hue); + float residualHue = hue - float(sector); + + vec3 pqt = c.z * vec3(1.0 - c.y, 1.0 - c.y * residualHue, 1.0 - c.y * (1.0 - residualHue)); + if (sector == 0) + return vec3(c.z, pqt.z, pqt.x); + if (sector == 1) + return vec3(pqt.y, c.z, pqt.x); + if (sector == 2) + return vec3(pqt.x, c.z, pqt.z); + if (sector == 3) + return vec3(pqt.x, pqt.y, c.z); + if (sector == 4) + return vec3(pqt.z, pqt.x, c.z); + return vec3(c.z, pqt.x, pqt.y); +} + +float gauss(float x, float sigma) { + if (sigma == 0.0) + return 1.0; + return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma)); +} + +vec4 Blur(float radius, vec2 direction) { + // TODO(gw): Support blur in WR2! + return vec4(1, 1, 1, 1); +} + +vec4 Contrast(vec4 Cs, float amount) { + return vec4(Cs.rgb * amount - 0.5 * amount + 0.5, 1.0); +} + +vec4 Grayscale(vec4 Cs, float amount) { + float ia = 1.0 - amount; + return mat4(vec4(0.2126 + 0.7874 * ia, 0.2126 - 0.2126 * ia, 0.2126 - 0.2126 * ia, 0.0), + vec4(0.7152 - 0.7152 * ia, 0.7152 + 0.2848 * ia, 0.7152 - 0.7152 * ia, 0.0), + vec4(0.0722 - 0.0722 * ia, 0.0722 - 0.0722 * ia, 0.0722 + 0.9278 * ia, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)) * Cs; +} + +vec4 HueRotate(vec4 Cs, float amount) { + vec3 CsHsv = rgbToHsv(Cs.rgb); + CsHsv.x = mod(CsHsv.x + amount / 6.283185307179586, 1.0); + return vec4(hsvToRgb(CsHsv), Cs.a); +} + +vec4 Invert(vec4 Cs, float amount) { + return mix(Cs, vec4(1.0, 1.0, 1.0, Cs.a) - vec4(Cs.rgb, 0.0), amount); +} + +vec4 Saturate(vec4 Cs, float amount) { + return vec4(hsvToRgb(min(vec3(1.0, amount, 1.0) * rgbToHsv(Cs.rgb), vec3(1.0))), Cs.a); +} + +vec4 Sepia(vec4 Cs, float amount) { + float ia = 1.0 - amount; + return mat4(vec4(0.393 + 0.607 * ia, 0.349 - 0.349 * ia, 0.272 - 0.272 * ia, 0.0), + vec4(0.769 - 0.769 * ia, 0.686 + 0.314 * ia, 0.534 - 0.534 * ia, 0.0), + vec4(0.189 - 0.189 * ia, 0.168 - 0.168 * ia, 0.131 + 0.869 * ia, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)) * Cs; +} + +vec3 Multiply(vec3 Cb, vec3 Cs) { + return Cb * Cs; +} + +vec3 Screen(vec3 Cb, vec3 Cs) { + return Cb + Cs - (Cb * Cs); +} + +vec3 HardLight(vec3 Cb, vec3 Cs) { + vec3 m = Multiply(Cb, 2.0 * Cs); + vec3 s = Screen(Cb, 2.0 * Cs - 1.0); + vec3 edge = vec3(0.5, 0.5, 0.5); + return mix(m, s, step(edge, Cs)); +} + +// TODO: Worth doing with mix/step? Check GLSL output. +float ColorDodge(float Cb, float Cs) { + if (Cb == 0.0) + return 0.0; + else if (Cs == 1.0) + return 1.0; + else + return min(1.0, Cb / (1.0 - Cs)); +} + +// TODO: Worth doing with mix/step? Check GLSL output. +float ColorBurn(float Cb, float Cs) { + if (Cb == 1.0) + return 1.0; + else if (Cs == 0.0) + return 0.0; + else + return 1.0 - min(1.0, (1.0 - Cb) / Cs); +} + +float SoftLight(float Cb, float Cs) { + if (Cs <= 0.5) { + return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); + } else { + float D; + + if (Cb <= 0.25) + D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; + else + D = sqrt(Cb); + + return Cb + (2.0 * Cs - 1.0) * (D - Cb); + } +} + +vec3 Difference(vec3 Cb, vec3 Cs) { + return abs(Cb - Cs); +} + +vec3 Exclusion(vec3 Cb, vec3 Cs) { + return Cb + Cs - 2.0 * Cb * Cs; +} + +// These functions below are taken from the spec. +// There's probably a much quicker way to implement +// them in GLSL... +float Sat(vec3 c) { + return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); +} + +float Lum(vec3 c) { + vec3 f = vec3(0.3, 0.59, 0.11); + return dot(c, f); +} + +vec3 ClipColor(vec3 C) { + float L = Lum(C); + float n = min(C.r, min(C.g, C.b)); + float x = max(C.r, max(C.g, C.b)); + + if (n < 0.0) + C = L + (((C - L) * L) / (L - n)); + + if (x > 1.0) + C = L + (((C - L) * (1.0 - L)) / (x - L)); + + return C; +} + +vec3 SetLum(vec3 C, float l) { + float d = l - Lum(C); + return ClipColor(C + d); +} + +void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) { + if (Cmax > Cmin) { + Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin)); + Cmax = s; + } else { + Cmid = 0.0; + Cmax = 0.0; + } + Cmin = 0.0; +} + +vec3 SetSat(vec3 C, float s) { + if (C.r <= C.g) { + if (C.g <= C.b) { + SetSatInner(C.r, C.g, C.b, s); + } else { + if (C.r <= C.b) { + SetSatInner(C.r, C.b, C.g, s); + } else { + SetSatInner(C.b, C.r, C.g, s); + } + } + } else { + if (C.r <= C.b) { + SetSatInner(C.g, C.r, C.b, s); + } else { + if (C.g <= C.b) { + SetSatInner(C.g, C.b, C.r, s); + } else { + SetSatInner(C.b, C.g, C.r, s); + } + } + } + return C; +} + +vec3 Hue(vec3 Cb, vec3 Cs) { + return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); +} + +vec3 Saturation(vec3 Cb, vec3 Cs) { + return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); +} + +vec3 Color(vec3 Cb, vec3 Cs) { + return SetLum(Cs, Lum(Cb)); +} + +vec3 Luminosity(vec3 Cb, vec3 Cs) { + return SetLum(Cb, Lum(Cs)); +} + +void main(void) { + vec4 Cs = texture(sCache, vUv1); + vec4 Cb = texture(sCache, vUv0); + + // TODO(gw): This is a hack that's (probably) wrong. + // Instead of drawing the tile rect, draw the + // stacking context bounds instead? + if (Cs.a == 0.0) { + oFragColor = Cb; + return; + } + + int kind = vInfo.x; + int op = vInfo.y; + float amount = vAmount; + + // Return yellow if none of the branches match (shouldn't happen). + vec4 result = vec4(1.0, 1.0, 0.0, 1.0); + + switch (kind) { + case COMPOSITE_KIND_MIX_BLEND_MODE: + if (op == 2) { + result.rgb = Screen(Cb.rgb, Cs.rgb); + } else if (op == 3) { + result.rgb = HardLight(Cs.rgb, Cb.rgb); // Overlay is inverse of Hardlight + } else if (op == 6) { + result.r = ColorDodge(Cb.r, Cs.r); + result.g = ColorDodge(Cb.g, Cs.g); + result.b = ColorDodge(Cb.b, Cs.b); + } else if (op == 7) { + result.r = ColorBurn(Cb.r, Cs.r); + result.g = ColorBurn(Cb.g, Cs.g); + result.b = ColorBurn(Cb.b, Cs.b); + } else if (op == 8) { + result.rgb = HardLight(Cb.rgb, Cs.rgb); + } else if (op == 9) { + result.r = SoftLight(Cb.r, Cs.r); + result.g = SoftLight(Cb.g, Cs.g); + result.b = SoftLight(Cb.b, Cs.b); + } else if (op == 10) { + result.rgb = Difference(Cb.rgb, Cs.rgb); + } else if (op == 11) { + result.rgb = Exclusion(Cb.rgb, Cs.rgb); + } else if (op == 12) { + result.rgb = Hue(Cb.rgb, Cs.rgb); + } else if (op == 13) { + result.rgb = Saturation(Cb.rgb, Cs.rgb); + } else if (op == 14) { + result.rgb = Color(Cb.rgb, Cs.rgb); + } else if (op == 15) { + result.rgb = Luminosity(Cb.rgb, Cs.rgb); + } + break; + case COMPOSITE_KIND_FILTER: + if (op == 0) { + // Gaussian blur is specially handled: + result = Cs;// Blur(amount, vec2(0,0)); + } else { + if (op == 1) { + result = Contrast(Cs, amount); + } else if (op == 2) { + result = Grayscale(Cs, amount); + } else if (op == 3) { + result = HueRotate(Cs, amount); + } else if (op == 4) { + result = Invert(Cs, amount); + } else if (op == 5) { + result = Saturate(Cs, amount); + } else if (op == 6) { + result = Sepia(Cs, amount); + } + } + break; + } + + oFragColor = result; +} diff --git a/resources/shaders/ps_composite.glsl b/resources/shaders/ps_composite.glsl new file mode 100644 index 00000000000..68a8f978103 --- /dev/null +++ b/resources/shaders/ps_composite.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +flat varying ivec2 vInfo; +flat varying float vAmount; diff --git a/resources/shaders/ps_composite.vs.glsl b/resources/shaders/ps_composite.vs.glsl new file mode 100644 index 00000000000..c7f9cd05538 --- /dev/null +++ b/resources/shaders/ps_composite.vs.glsl @@ -0,0 +1,37 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Composite { + uvec4 src0; + uvec4 src1; + uvec4 target_rect; + ivec4 info; + vec4 amount; +}; + +layout(std140) uniform Items { + Composite composites[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Composite composite = composites[gl_InstanceID]; + + vec2 local_pos = mix(vec2(composite.target_rect.xy), + vec2(composite.target_rect.xy + composite.target_rect.zw), + aPosition.xy); + + vec2 st0 = vec2(composite.src0.xy) / 2048.0; + vec2 st1 = vec2(composite.src0.xy + composite.src0.zw) / 2048.0; + vUv0 = mix(st0, st1, aPosition.xy); + + st0 = vec2(composite.src1.xy) / 2048.0; + st1 = vec2(composite.src1.xy + composite.src1.zw) / 2048.0; + vUv1 = mix(st0, st1, aPosition.xy); + + vInfo = composite.info.xy; + vAmount = composite.amount.x; + + gl_Position = uTransform * vec4(local_pos, 0, 1); +} diff --git a/resources/shaders/ps_gradient.fs.glsl b/resources/shaders/ps_gradient.fs.glsl new file mode 100644 index 00000000000..b25faec6f54 --- /dev/null +++ b/resources/shaders/ps_gradient.fs.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + do_clip(vPos, vClipRect, vClipRadius); + oFragColor = mix(vColor0, vColor1, vF); +} diff --git a/resources/shaders/ps_gradient.glsl b/resources/shaders/ps_gradient.glsl new file mode 100644 index 00000000000..4b1efa7644d --- /dev/null +++ b/resources/shaders/ps_gradient.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying float vF; +varying vec2 vPos; +flat varying vec4 vColor0; +flat varying vec4 vColor1; +flat varying vec4 vClipRect; +flat varying vec4 vClipRadius; diff --git a/resources/shaders/ps_gradient.vs.glsl b/resources/shaders/ps_gradient.vs.glsl new file mode 100644 index 00000000000..60977165a2c --- /dev/null +++ b/resources/shaders/ps_gradient.vs.glsl @@ -0,0 +1,45 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define DIR_HORIZONTAL uint(0) +#define DIR_VERTICAL uint(1) + +struct Gradient { + PrimitiveInfo info; + vec4 color0; + vec4 color1; + uvec4 dir; + Clip clip; +}; + +layout(std140) uniform Items { + Gradient gradients[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Gradient gradient = gradients[gl_InstanceID]; + VertexInfo vi = write_vertex(gradient.info); + + vec2 f = (vi.local_clamped_pos - gradient.info.local_rect.xy) / gradient.info.local_rect.zw; + + switch (gradient.dir.x) { + case DIR_HORIZONTAL: + vF = f.x; + break; + case DIR_VERTICAL: + vF = f.y; + break; + } + + vClipRect = vec4(gradient.clip.rect.xy, gradient.clip.rect.xy + gradient.clip.rect.zw); + vClipRadius = vec4(gradient.clip.top_left.outer_inner_radius.x, + gradient.clip.top_right.outer_inner_radius.x, + gradient.clip.bottom_right.outer_inner_radius.x, + gradient.clip.bottom_left.outer_inner_radius.x); + vPos = vi.local_clamped_pos; + + vColor0 = gradient.color0; + vColor1 = gradient.color1; +} diff --git a/resources/shaders/ps_image.fs.glsl b/resources/shaders/ps_image.fs.glsl new file mode 100644 index 00000000000..a7d96850057 --- /dev/null +++ b/resources/shaders/ps_image.fs.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec2 st = vTextureOffset + vTextureSize * fract(vUv); + oFragColor = texture(sDiffuse, st); +} diff --git a/resources/shaders/ps_image.glsl b/resources/shaders/ps_image.glsl new file mode 100644 index 00000000000..e2c59d9ff69 --- /dev/null +++ b/resources/shaders/ps_image.glsl @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; // Location within the CSS box to draw. +flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. +flat varying vec2 vTextureSize; // Size of the image in the texture atlas. diff --git a/resources/shaders/ps_image.vs.glsl b/resources/shaders/ps_image.vs.glsl new file mode 100644 index 00000000000..0f6bcba6eba --- /dev/null +++ b/resources/shaders/ps_image.vs.glsl @@ -0,0 +1,24 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Image { + PrimitiveInfo info; + vec4 st_rect; // Location of the image texture in the texture atlas. + vec4 stretch_size; // Size of the actual image. +}; + +layout(std140) uniform Items { + Image images[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Image image = images[gl_InstanceID]; + VertexInfo vi = write_vertex(image.info); + + // vUv will contain how many times this image has wrapped around the image size. + vUv = (vi.local_clamped_pos - vi.local_rect.p0) / image.stretch_size.xy; + vTextureSize = image.st_rect.zw - image.st_rect.xy; + vTextureOffset = image.st_rect.xy; +} diff --git a/resources/shaders/ps_image_clip.fs.glsl b/resources/shaders/ps_image_clip.fs.glsl new file mode 100644 index 00000000000..2ec824e4414 --- /dev/null +++ b/resources/shaders/ps_image_clip.fs.glsl @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + do_clip(vPos, vClipRect, vClipRadius); + vec2 st = vTextureOffset + vTextureSize * fract(vUv); + oFragColor = texture(sDiffuse, st); +} diff --git a/resources/shaders/ps_image_clip.glsl b/resources/shaders/ps_image_clip.glsl new file mode 100644 index 00000000000..4ddd1a53290 --- /dev/null +++ b/resources/shaders/ps_image_clip.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; // Location within the CSS box to draw. +varying vec2 vPos; +flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. +flat varying vec2 vTextureSize; // Size of the image in the texture atlas. +flat varying vec4 vClipRect; +flat varying vec4 vClipRadius; diff --git a/resources/shaders/ps_image_clip.vs.glsl b/resources/shaders/ps_image_clip.vs.glsl new file mode 100644 index 00000000000..89c6198f990 --- /dev/null +++ b/resources/shaders/ps_image_clip.vs.glsl @@ -0,0 +1,32 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Image { + PrimitiveInfo info; + vec4 st_rect; // Location of the image texture in the texture atlas. + vec4 stretch_size; // Size of the actual image. + Clip clip; +}; + +layout(std140) uniform Items { + Image images[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Image image = images[gl_InstanceID]; + VertexInfo vi = write_vertex(image.info); + + vClipRect = vec4(image.clip.rect.xy, image.clip.rect.xy + image.clip.rect.zw); + vClipRadius = vec4(image.clip.top_left.outer_inner_radius.x, + image.clip.top_right.outer_inner_radius.x, + image.clip.bottom_right.outer_inner_radius.x, + image.clip.bottom_left.outer_inner_radius.x); + vPos = vi.local_clamped_pos; + + // vUv will contain how many times this image has wrapped around the image size. + vUv = (vi.local_clamped_pos - image.info.local_rect.xy) / image.stretch_size.xy; + vTextureSize = image.st_rect.zw - image.st_rect.xy; + vTextureOffset = image.st_rect.xy; +} diff --git a/resources/shaders/ps_image_transform.fs.glsl b/resources/shaders/ps_image_transform.fs.glsl new file mode 100644 index 00000000000..57fdc563ade --- /dev/null +++ b/resources/shaders/ps_image_transform.fs.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec2 pos = vPos.xy / vPos.z; + + if (!point_in_rect(pos, vRect.xy, vRect.xy + vRect.zw)) { + discard; + } + + oFragColor = texture(sDiffuse, vUv / vPos.z); +} diff --git a/resources/shaders/ps_image_transform.glsl b/resources/shaders/ps_image_transform.glsl new file mode 100644 index 00000000000..77c0eb20719 --- /dev/null +++ b/resources/shaders/ps_image_transform.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; + +varying vec3 vPos; +flat varying vec4 vRect; diff --git a/resources/shaders/ps_image_transform.vs.glsl b/resources/shaders/ps_image_transform.vs.glsl new file mode 100644 index 00000000000..b9fcf7c24c2 --- /dev/null +++ b/resources/shaders/ps_image_transform.vs.glsl @@ -0,0 +1,65 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Image { + PrimitiveInfo info; + vec4 st_rect; + vec4 stretch_size; // Size of the actual image. +}; + +layout(std140) uniform Items { + Image images[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Image image = images[gl_InstanceID]; + Layer layer = layers[image.info.layer_tile_part.x]; + Tile tile = tiles[image.info.layer_tile_part.y]; + + vec2 p0 = image.info.local_rect.xy; + vec2 p1 = image.info.local_rect.xy + vec2(image.info.local_rect.z, 0.0); + vec2 p2 = image.info.local_rect.xy + vec2(0.0, image.info.local_rect.w); + vec2 p3 = image.info.local_rect.xy + image.info.local_rect.zw; + + vec4 t0 = layer.transform * vec4(p0, 0, 1); + vec4 t1 = layer.transform * vec4(p1, 0, 1); + vec4 t2 = layer.transform * vec4(p2, 0, 1); + vec4 t3 = layer.transform * vec4(p3, 0, 1); + + vec2 tp0 = t0.xy / t0.w; + vec2 tp1 = t1.xy / t1.w; + vec2 tp2 = t2.xy / t2.w; + vec2 tp3 = t3.xy / t3.w; + + vec2 min_pos = min(tp0.xy, min(tp1.xy, min(tp2.xy, tp3.xy))); + vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy))); + + vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); + + vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); + + vec2 clamped_pos = mix(min_pos_clamped, + max_pos_clamped, + aPosition.xy); + + vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, image.info.layer_tile_part.x); + + vRect = image.info.local_rect; + vPos = layer_pos; + + vec2 f = (layer_pos.xy - image.info.local_rect.xy) / image.info.local_rect.zw; + + vUv = mix(image.st_rect.xy, + image.st_rect.zw, + f); + + vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy); + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/resources/shaders/ps_rectangle.fs.glsl b/resources/shaders/ps_rectangle.fs.glsl new file mode 100644 index 00000000000..61837732d31 --- /dev/null +++ b/resources/shaders/ps_rectangle.fs.glsl @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + oFragColor = vColor; +} diff --git a/resources/shaders/ps_rectangle.glsl b/resources/shaders/ps_rectangle.glsl new file mode 100644 index 00000000000..6fcfc4255bf --- /dev/null +++ b/resources/shaders/ps_rectangle.glsl @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec4 vColor; diff --git a/resources/shaders/ps_rectangle.vs.glsl b/resources/shaders/ps_rectangle.vs.glsl new file mode 100644 index 00000000000..01a4e5dc185 --- /dev/null +++ b/resources/shaders/ps_rectangle.vs.glsl @@ -0,0 +1,19 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Rectangle { + PrimitiveInfo info; + vec4 color; +}; + +layout(std140) uniform Items { + Rectangle rects[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Rectangle rect = rects[gl_InstanceID]; + write_vertex(rect.info); + vColor = rect.color; +} diff --git a/resources/shaders/ps_rectangle_clip.fs.glsl b/resources/shaders/ps_rectangle_clip.fs.glsl new file mode 100644 index 00000000000..fe3af9162ad --- /dev/null +++ b/resources/shaders/ps_rectangle_clip.fs.glsl @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + do_clip(vPos, vClipRect, vClipRadius); + + oFragColor = vColor; +} diff --git a/resources/shaders/ps_rectangle_clip.glsl b/resources/shaders/ps_rectangle_clip.glsl new file mode 100644 index 00000000000..3d50dd162a5 --- /dev/null +++ b/resources/shaders/ps_rectangle_clip.glsl @@ -0,0 +1,10 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec4 vColor; +varying vec2 vPos; +flat varying vec4 vClipRect; +flat varying vec4 vClipRadius; diff --git a/resources/shaders/ps_rectangle_clip.vs.glsl b/resources/shaders/ps_rectangle_clip.vs.glsl new file mode 100644 index 00000000000..b181638d010 --- /dev/null +++ b/resources/shaders/ps_rectangle_clip.vs.glsl @@ -0,0 +1,28 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Rectangle { + PrimitiveInfo info; + vec4 color; + Clip clip; +}; + +layout(std140) uniform Items { + Rectangle rects[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Rectangle rect = rects[gl_InstanceID]; + VertexInfo vi = write_vertex(rect.info); + + vClipRect = vec4(rect.clip.rect.xy, rect.clip.rect.xy + rect.clip.rect.zw); + vClipRadius = vec4(rect.clip.top_left.outer_inner_radius.x, + rect.clip.top_right.outer_inner_radius.x, + rect.clip.bottom_right.outer_inner_radius.x, + rect.clip.bottom_left.outer_inner_radius.x); + vPos = vi.local_clamped_pos; + + vColor = rect.color; +} diff --git a/resources/shaders/ps_rectangle_transform.fs.glsl b/resources/shaders/ps_rectangle_transform.fs.glsl new file mode 100644 index 00000000000..a8ac40a8451 --- /dev/null +++ b/resources/shaders/ps_rectangle_transform.fs.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec2 pos = vPos.xy / vPos.z; + + if (!point_in_rect(pos, vRect.xy, vRect.xy + vRect.zw)) { + discard; + } + + oFragColor = vColor; +} diff --git a/resources/shaders/ps_rectangle_transform.glsl b/resources/shaders/ps_rectangle_transform.glsl new file mode 100644 index 00000000000..0ae7f839aa9 --- /dev/null +++ b/resources/shaders/ps_rectangle_transform.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec4 vColor; + +varying vec3 vPos; +flat varying vec4 vRect; diff --git a/resources/shaders/ps_rectangle_transform.vs.glsl b/resources/shaders/ps_rectangle_transform.vs.glsl new file mode 100644 index 00000000000..0df46710492 --- /dev/null +++ b/resources/shaders/ps_rectangle_transform.vs.glsl @@ -0,0 +1,59 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Rectangle { + PrimitiveInfo info; + vec4 color; +}; + +layout(std140) uniform Items { + Rectangle rects[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Rectangle rect = rects[gl_InstanceID]; + Layer layer = layers[rect.info.layer_tile_part.x]; + Tile tile = tiles[rect.info.layer_tile_part.y]; + + vec2 p0 = rect.info.local_rect.xy; + vec2 p1 = rect.info.local_rect.xy + vec2(rect.info.local_rect.z, 0.0); + vec2 p2 = rect.info.local_rect.xy + vec2(0.0, rect.info.local_rect.w); + vec2 p3 = rect.info.local_rect.xy + rect.info.local_rect.zw; + + vec4 t0 = layer.transform * vec4(p0, 0, 1); + vec4 t1 = layer.transform * vec4(p1, 0, 1); + vec4 t2 = layer.transform * vec4(p2, 0, 1); + vec4 t3 = layer.transform * vec4(p3, 0, 1); + + vec2 tp0 = t0.xy / t0.w; + vec2 tp1 = t1.xy / t1.w; + vec2 tp2 = t2.xy / t2.w; + vec2 tp3 = t3.xy / t3.w; + + vec2 min_pos = min(tp0.xy, min(tp1.xy, min(tp2.xy, tp3.xy))); + vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy))); + + vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); + + vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); + + vec2 clamped_pos = mix(min_pos_clamped, + max_pos_clamped, + aPosition.xy); + + vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, rect.info.layer_tile_part.x); + + vRect = rect.info.local_rect; + vPos = layer_pos; + vColor = rect.color; + + vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy); + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/resources/shaders/ps_text.fs.glsl b/resources/shaders/ps_text.fs.glsl new file mode 100644 index 00000000000..175102f790e --- /dev/null +++ b/resources/shaders/ps_text.fs.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + float a = texture(sDiffuse, vUv).a; + oFragColor = vec4(vColor.rgb, vColor.a * a); +} diff --git a/resources/shaders/ps_text.glsl b/resources/shaders/ps_text.glsl new file mode 100644 index 00000000000..dad284fb0a2 --- /dev/null +++ b/resources/shaders/ps_text.glsl @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +flat varying vec4 vColor; +varying vec2 vUv; diff --git a/resources/shaders/ps_text.vs.glsl b/resources/shaders/ps_text.vs.glsl new file mode 100644 index 00000000000..39e72bf8688 --- /dev/null +++ b/resources/shaders/ps_text.vs.glsl @@ -0,0 +1,26 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Glyph { + PrimitiveInfo info; + vec4 color; + vec4 st_rect; +}; + +layout(std140) uniform Items { + Glyph glyphs[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Glyph glyph = glyphs[gl_InstanceID]; + VertexInfo vi = write_vertex(glyph.info); + + vec2 f = (vi.local_clamped_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0); + + vColor = glyph.color; + vUv = mix(glyph.st_rect.xy, + glyph.st_rect.zw, + f); +} diff --git a/resources/shaders/shared.glsl b/resources/shaders/shared.glsl new file mode 100644 index 00000000000..4696272d0f4 --- /dev/null +++ b/resources/shaders/shared.glsl @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//====================================================================================== +// Vertex shader attributes and uniforms +//====================================================================================== +#ifdef WR_VERTEX_SHADER + #define varying out + + // Uniform inputs + uniform mat4 uTransform; // Orthographic projection + uniform float uDevicePixelRatio; + + // Attribute inputs + in vec3 aPosition; +#endif + +//====================================================================================== +// Fragment shader attributes and uniforms +//====================================================================================== +#ifdef WR_FRAGMENT_SHADER + precision highp float; + + #define varying in + + // Uniform inputs + uniform sampler2D sDiffuse; + uniform sampler2D sMask; + + // Fragment shader outputs + out vec4 oFragColor; +#endif + +//====================================================================================== +// Interpolator definitions +//====================================================================================== + +//====================================================================================== +// VS only types and UBOs +//====================================================================================== + +//====================================================================================== +// VS only functions +//====================================================================================== diff --git a/resources/shaders/shared_other.glsl b/resources/shaders/shared_other.glsl new file mode 100644 index 00000000000..847fd1c143c --- /dev/null +++ b/resources/shaders/shared_other.glsl @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//====================================================================================== +// Vertex shader attributes and uniforms +//====================================================================================== +#ifdef WR_VERTEX_SHADER + in vec4 aColorTexCoordRectTop; + in vec4 aColorRectTL; + + // box-shadow + in vec4 aBorderPosition; + in vec4 aBorderRadii; + in float aBlurRadius; + + // blur + in vec2 aDestTextureSize; + in vec2 aSourceTextureSize; +#endif + +//====================================================================================== +// Fragment shader attributes and uniforms +//====================================================================================== +#ifdef WR_FRAGMENT_SHADER + uniform vec2 uDirection; +#endif + +//====================================================================================== +// Interpolator definitions +//====================================================================================== + +// Hacks to be removed (needed for text etc) +varying vec2 vColorTexCoord; +varying vec4 vColor; + +// box_shadow +varying vec2 vPosition; +varying vec4 vBorderPosition; +varying vec4 vBorderRadii; +varying float vBlurRadius; + +// blur +varying vec2 vSourceTextureSize; +varying vec2 vDestTextureSize; + +//====================================================================================== +// VS only types and UBOs +//====================================================================================== + +//====================================================================================== +// VS only functions +//====================================================================================== + +//====================================================================================== +// FS only functions +//====================================================================================== +#ifdef WR_FRAGMENT_SHADER + +void SetFragColor(vec4 color) { + oFragColor = color; +} + +#endif diff --git a/rust-nightly-date b/rust-nightly-date index 570434df0cb..03237ba6f69 100644 --- a/rust-nightly-date +++ b/rust-nightly-date @@ -1 +1 @@ -2016-06-24 +2016-07-25 diff --git a/support/windows/Servo.wxs.mako b/support/windows/Servo.wxs.mako new file mode 100644 index 00000000000..dab08c418ca --- /dev/null +++ b/support/windows/Servo.wxs.mako @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="utf-8"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Product Name="Servo Tech Demo" + Manufacturer="Mozilla Research" + Id="5807391a-3a17-476b-a5d2-5f1912569762" + UpgradeCode="060cd15d-eab1-4614-b438-3988e3efdcf1" + Language="1033" + Codepage="1252" + Version="1.0.0"> + <Package Id="*" + Keywords="Installer" + Description="Servo Tech Demo Installer" + Manufacturer="Mozilla Research" + InstallerVersion="200" + Platform="x64" + Languages="1033" + SummaryCodepage="1252" + Compressed="yes"/> + <Media Id="1" + Cabinet="Servo.cab" + EmbedCab="yes"/> + <Directory Id="TARGETDIR" Name="SourceDir"> + <Directory Id="ProgramFiles64Folder" Name="PFiles"> + <Directory Id="MozResearch" Name="Mozilla Research"> + <Directory Id="INSTALLDIR" Name="Servo Tech Demo"> + <Component Id="Servo" + Guid="95bcea71-78bb-4ec8-9766-44bc01443840" + Win64="yes"> + <File Id="ServoEXE" + Name="servo.exe" + DiskId="1" + Source="${windowize(exe_path)}\servo.exe" + KeyPath="yes"> + <Shortcut Id="StartMenuServoTechDemo" + Directory="ProgramMenuDir" + Name="Servo Tech Demo" + WorkingDirectory="INSTALLDIR" + Icon="Servo.ico" + IconIndex="0" + Arguments="-w --pref dom.mozbrowser.enabled --pref shell.builtin-key-shortcuts.enabled=false browserhtml\index.html" + Advertise="yes"/> + </File> + <File Id="ServoManifest" + Name="servo.exe.manifest" + Source="${windowize(exe_path)}\servo.exe.manifest" + DiskId="1"/> + + <File Id="StdcxxDLL" + Name="libstdc++-6.dll" + Source="C:\msys64\mingw64\bin\libstdc++-6.dll" + DiskId="1"/> + <File Id="WinpthreadDll" + Name="libwinpthread-1.dll" + Source="C:\msys64\mingw64\bin\libwinpthread-1.dll" + DiskId="1"/> + <File Id="Bzip2Dll" + Name="libbz2-1.dll" + Source="C:\msys64\mingw64\bin\libbz2-1.dll" + DiskId="1"/> + <File Id="GccsehDll" + Name="libgcc_s_seh-1.dll" + Source="C:\msys64\mingw64\bin\libgcc_s_seh-1.dll" + DiskId="1"/> + <File Id="ExpatDll" + Name="libexpat-1.dll" + Source="C:\msys64\mingw64\bin\libexpat-1.dll" + DiskId="1"/> + <File Id="ZlibDll" + Name="zlib1.dll" + Source="C:\msys64\mingw64\bin\zlib1.dll" + DiskId="1"/> + <File Id="PngDll" + Name="libpng16-16.dll" + Source="C:\msys64\mingw64\bin\libpng16-16.dll" + DiskId="1"/> + <File Id="IconvDll" + Name="libiconv-2.dll" + Source="C:\msys64\mingw64\bin\libiconv-2.dll" + DiskId="1"/> + <File Id="GlibDll" + Name="libglib-2.0-0.dll" + Source="C:\msys64\mingw64\bin\libglib-2.0-0.dll" + DiskId="1"/> + <File Id="GraphiteDll" + Name="libgraphite2.dll" + Source="C:\msys64\mingw64\bin\libgraphite2.dll" + DiskId="1"/> + <File Id="IntlDll" + Name="libintl-8.dll" + Source="C:\msys64\mingw64\bin\libintl-8.dll" + DiskId="1"/> + <File Id="PcreDll" + Name="libpcre-1.dll" + Source="C:\msys64\mingw64\bin\libpcre-1.dll" + DiskId="1"/> + <File Id="Eay32Dll" + Name="libeay32.dll" + Source="C:\msys64\mingw64\bin\libeay32.dll" + DiskId="1"/> + <File Id="Ssleay32Dll" + Name="ssleay32.dll" + Source="C:\msys64\mingw64\bin\ssleay32.dll" + DiskId="1"/> + <File Id="HarfbuzzDll" + Name="libharfbuzz-0.dll" + Source="C:\msys64\mingw64\bin\libharfbuzz-0.dll" + DiskId="1"/> + <File Id="FreetypeDll" + Name="libfreetype-6.dll" + Source="C:\msys64\mingw64\bin\libfreetype-6.dll" + DiskId="1"/> + <File Id="FontconfigDll" + Name="libfontconfig-1.dll" + Source="C:\msys64\mingw64\bin\libfontconfig-1.dll" + DiskId="1"/> + <File Id="AVUtil" + Name="avutil-55.dll" + Source="C:\msys64\mingw64\bin\avutil-55.dll" + DiskId="1"/> + <File Id="AVFormat" + Name="avformat-57.dll" + Source="C:\msys64\mingw64\bin\avformat-57.dll" + DiskId="1"/> + </Component> + + <Directory Id="EtcDir" Name="etc"> + <Directory Id="FontsDir" Name="fonts"> + <Component Id="FontsDir" + Guid="8d37ee61-9237-438d-b976-f163bd6b0578" + Win64="yes"> + <File Id="ServoFontsConfig" + KeyPath="yes" + Name="fonts.conf" + Source="${windowize(top_path)}\support\windows\fonts.conf" + DiskId="1"/> + </Component> + </Directory> + </Directory> + + ${include_directory(path.join(top_path, "resources"), "resources")} + ${include_directory(browserhtml_path, "browserhtml")} + </Directory> + </Directory> + </Directory> + + <Directory Id="ProgramMenuFolder" Name="Programs"> + <Directory Id="ProgramMenuDir" Name="Servo Tech Demo"> + <Component Id="ProgramMenuDir" Guid="e04737ce-16eb-4977-9b4c-ed2db8a5a77d"> + <RemoveFolder Id="ProgramMenuDir" On="uninstall"/> + <RegistryValue Root="HKCU" + Key="Software\Mozilla Research\Servo Tech Demo" + Type="string" + Value="" + KeyPath="yes"/> + </Component> + </Directory> + </Directory> + </Directory> + + <Feature Id="Complete" Level="1"> + <ComponentRef Id="Servo"/> + <ComponentRef Id="FontsDir"/> + % for c in components: + <ComponentRef Id="${c}"/> + % endfor + <ComponentRef Id="ProgramMenuDir"/> + </Feature> + + <Icon Id="Servo.ico" SourceFile="${windowize(top_path)}\resources\Servo.ico"/> + </Product> +</Wix> +<%! +import os +import os.path as path +import re +import uuid + +def make_id(s): + return "Id{}".format(s.replace("-", "_").replace("/", "_")) + +def listfiles(directory): + return [f for f in os.listdir(directory) + if path.isfile(path.join(directory, f))] + +def listdirs(directory): + return [f for f in os.listdir(directory) + if path.isdir(path.join(directory, f))] + +def windowize(p): + if not p.startswith("/"): + return p + return re.sub("^/([^/])+", "\\1:", p) + +components = [] +%> +<%def name="include_directory(d, n)"> +<Directory Id="${make_id(path.basename(d))}" Name="${n}"> + <Component Id="${make_id(path.basename(d))}" + Guid="${uuid.uuid4()}" + Win64="yes"> + <CreateFolder/> + <% components.append(make_id(path.basename(d))) %> + % for f in listfiles(d): + <File Id="${make_id(path.join(d, f))}" + Name="${f}" + Source="${windowize(path.join(d, f))}" + DiskId="1"/> + % endfor + </Component> + + % for f in listdirs(d): + ${include_directory(path.join(d, f), f)} + % endfor +</Directory> +</%def> diff --git a/support/windows/fonts.conf b/support/windows/fonts.conf new file mode 100644 index 00000000000..904c9832eb9 --- /dev/null +++ b/support/windows/fonts.conf @@ -0,0 +1,777 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> +<fontconfig> + <dir>C:\Windows\Fonts</dir> +<!-- + Accept deprecated 'mono' alias, replacing it with 'monospace' +--> + <match target="pattern"> + <test qual="any" name="family"> + <string>mono</string> + </test> + <edit name="family" mode="assign" binding="same"> + <string>monospace</string> + </edit> + </match> + +<!-- + Accept alternate 'sans serif' spelling, replacing it with 'sans-serif' +--> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans serif</string> + </test> + <edit name="family" mode="assign" binding="same"> + <string>sans-serif</string> + </edit> + </match> + +<!-- + Accept deprecated 'sans' alias, replacing it with 'sans-serif' +--> + <match target="pattern"> + <test qual="any" name="family"> + <string>sans</string> + </test> + <edit name="family" mode="assign" binding="same"> + <string>sans-serif</string> + </edit> + </match> + + + +<!-- Font cache directory list --> + +<cachedir>~/.fontconfig</cachedir> + + + + +<!-- + Mark common families with their generics so we'll get + something reasonable +--> + +<!-- + Serif faces + --> + <alias> + <family>Nazli</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Lotoos</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Mitra</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Ferdosi</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Badr</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Zar</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Titr</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Jadid</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Kochi Mincho</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>AR PL SungtiL GB</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>AR PL Mingti2L Big5</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>MS 明朝</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>NanumMyeongjo</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>UnBatang</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Baekmuk Batang</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>MgOpen Canonica</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Sazanami Mincho</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>AR PL ZenKai Uni</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>ZYSong18030</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>FreeSerif</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>SimSun</family> + <default><family>serif</family></default> + </alias> +<!-- + Sans-serif faces + --> + <alias> + <family>Arshia</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Elham</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Farnaz</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Nasim</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Sina</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Roya</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Koodak</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Terafik</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Kochi Gothic</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>AR PL KaitiM GB</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>AR PL KaitiM Big5</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>MS ゴシック</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>NanumGothic</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>UnDotum</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Baekmuk Dotum</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>MgOpen Modata</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Sazanami Gothic</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>AR PL ShanHeiSun Uni</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>ZYSong18030</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>FreeSans</family> + <default><family>sans-serif</family></default> + </alias> +<!-- + Monospace faces + --> + <alias> + <family>NSimSun</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>ZYSong18030</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>NanumGothicCoding</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>FreeMono</family> + <default><family>monospace</family></default> + </alias> + +<!-- + Fantasy faces + --> + <alias> + <family>Homa</family> + <default><family>fantasy</family></default> + </alias> + <alias> + <family>Kamran</family> + <default><family>fantasy</family></default> + </alias> + <alias> + <family>Fantezi</family> + <default><family>fantasy</family></default> + </alias> + <alias> + <family>Tabassom</family> + <default><family>fantasy</family></default> + </alias> + +<!-- + Cursive faces + --> + <alias> + <family>IranNastaliq</family> + <default><family>cursive</family></default> + </alias> + <alias> + <family>Nafees Nastaleeq</family> + <default><family>cursive</family></default> + </alias> + +<!-- + Mark common families with their generics so we'll get + something reasonable +--> + +<!-- + Serif faces + --> + <alias> + <family>Bitstream Vera Serif</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>DejaVu Serif</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Liberation Serif</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Times New Roman</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Times</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Nimbus Roman No9 L</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Nimbus Roman</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Luxi Serif</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Thorndale AMT</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Thorndale</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Georgia</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Garamond</family> + <default><family>serif</family></default> + </alias> + <alias> + <family>Palatino Linotype</family> + <default><family>serif</family></default> + </alias> +<!-- + Sans-serif faces + --> + <alias> + <family>Bitstream Vera Sans</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>DejaVu Sans</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Liberation Sans</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Arial</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Helvetica</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Verdana</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Albany AMT</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Albany</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Nimbus Sans L</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Nimbus Sans</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Luxi Sans</family> + <default><family>sans-serif</family></default> + </alias> + <alias> + <family>Trebuchet MS</family> + <default><family>sans-serif</family></default> + </alias> +<!-- + Monospace faces + --> + <alias> + <family>Bitstream Vera Sans Mono</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>DejaVu Sans Mono</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Liberation Mono</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Inconsolata</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Courier New</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Courier</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Andale Mono</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Luxi Mono</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Cumberland AMT</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Cumberland</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Nimbus Mono L</family> + <default><family>monospace</family></default> + </alias> + <alias> + <family>Nimbus Mono</family> + <default><family>monospace</family></default> + </alias> +<!-- + Fantasy faces + --> + <alias> + <family>Impact</family> + <default><family>fantasy</family></default> + </alias> + <alias> + <family>Copperplate Gothic Std</family> + <default><family>fantasy</family></default> + </alias> + <alias> + <family>Cooper Std</family> + <default><family>fantasy</family></default> + </alias> + <alias> + <family>Bauhaus Std</family> + <default><family>fantasy</family></default> + </alias> +<!-- + Cursive faces + --> + <alias> + <family>ITC Zapf Chancery Std</family> + <default><family>cursive</family></default> + </alias> + <alias> + <family>Zapfino</family> + <default><family>cursive</family></default> + </alias> + <alias> + <family>Comic Sans MS</family> + <default><family>cursive</family></default> + </alias> + +<!-- + If the font still has no generic name, add sans-serif + --> + <match target="pattern"> + <test qual="all" name="family" compare="not_eq"> + <string>sans-serif</string> + </test> + <test qual="all" name="family" compare="not_eq"> + <string>serif</string> + </test> + <test qual="all" name="family" compare="not_eq"> + <string>monospace</string> + </test> + <edit name="family" mode="append_last"> + <string>sans-serif</string> + </edit> + </match> + <alias> + <family>serif</family> + <prefer> + <family>Bitstream Vera Serif</family> + <family>DejaVu Serif</family> + <family>Times New Roman</family> + <family>Thorndale AMT</family> + <family>Luxi Serif</family> + <family>Nimbus Roman No9 L</family> + <family>Nimbus Roman</family> + <family>Times</family> + </prefer> + </alias> + <alias> + <family>sans-serif</family> + <prefer> + <family>Bitstream Vera Sans</family> + <family>DejaVu Sans</family> + <family>Verdana</family> + <family>Arial</family> + <family>Albany AMT</family> + <family>Luxi Sans</family> + <family>Nimbus Sans L</family> + <family>Nimbus Sans</family> + <family>Helvetica</family> + <family>Lucida Sans Unicode</family> + <family>BPG Glaho International</family> <!-- lat,cyr,arab,geor --> + <family>Tahoma</family> <!-- lat,cyr,greek,heb,arab,thai --> + </prefer> + </alias> + <alias> + <family>monospace</family> + <prefer> + <family>Bitstream Vera Sans Mono</family> + <family>DejaVu Sans Mono</family> + <family>Inconsolata</family> + <family>Andale Mono</family> + <family>Courier New</family> + <family>Cumberland AMT</family> + <family>Luxi Mono</family> + <family>Nimbus Mono L</family> + <family>Nimbus Mono</family> + <family>Courier</family> + </prefer> + </alias> +<!-- + Fantasy faces + --> + <alias> + <family>fantasy</family> + <prefer> + <family>Impact</family> + <family>Copperplate Gothic Std</family> + <family>Cooper Std</family> + <family>Bauhaus Std</family> + </prefer> + </alias> +<!-- + Cursive faces + --> + <alias> + <family>cursive</family> + <prefer> + <family>ITC Zapf Chancery Std</family> + <family>Zapfino</family> + <family>Comic Sans MS</family> + </prefer> + </alias> + + <alias> + <family>serif</family> + <prefer> + <family>Artsounk</family> <!-- armenian --> + <family>BPG UTF8 M</family> <!-- georgian --> + <family>Kinnari</family> <!-- thai --> + <family>Norasi</family> <!-- thai --> + <family>Frank Ruehl</family> <!-- hebrew --> + <family>Dror</family> <!-- hebrew --> + <family>JG LaoTimes</family> <!-- lao --> + <family>Saysettha Unicode</family> <!-- lao --> + <family>Pigiarniq</family> <!-- canadian syllabics --> + <family>B Davat</family> <!-- arabic (fa) --> + <family>B Compset</family> <!-- arabic (fa) --> + <family>Kacst-Qr</family> <!-- arabic (ar) --> + <family>Urdu Nastaliq Unicode</family> <!-- arabic (ur) --> + <family>Raghindi</family> <!-- devanagari --> + <family>Mukti Narrow</family> <!-- bengali --> + <family>malayalam</family> <!-- malayalam --> + <family>Sampige</family> <!-- kannada --> + <family>padmaa</family> <!-- gujarati --> + <family>Hapax Berbère</family> <!-- tifinagh --> + <family>MS Mincho</family> <!-- han (ja) --> + <family>SimSun</family> <!-- han (zh-cn,zh-tw) --> + <family>PMingLiu</family> <!-- han (zh-tw) --> + <family>WenQuanYi Zen Hei</family> <!-- han (zh-cn,zh-tw) --> + <family>WenQuanYi Bitmap Song</family> <!-- han (zh-cn,zh-tw) --> + <family>AR PL ShanHeiSun Uni</family> <!-- han (ja,zh-cn,zh-tw) --> + <family>AR PL New Sung</family> <!-- han (zh-cn,zh-tw) --> + <family>ZYSong18030</family> <!-- han (zh-cn,zh-tw) --> + <family>HanyiSong</family> <!-- han (zh-cn,zh-tw) --> + <family>MgOpen Canonica</family> + <family>Sazanami Mincho</family> + <family>IPAMonaMincho</family> + <family>IPAMincho</family> + <family>Kochi Mincho</family> + <family>AR PL SungtiL GB</family> + <family>AR PL Mingti2L Big5</family> + <family>AR PL Zenkai Uni</family> + <family>MS 明朝</family> + <family>ZYSong18030</family> + <family>NanumMyeongjo</family> <!-- hangul (ko) --> + <family>UnBatang</family> <!-- hangul (ko) --> + <family>Baekmuk Batang</family> <!-- hangul (ko) --> + <family>KacstQura</family> + <family>Frank Ruehl CLM</family> + <family>Lohit Bengali</family> + <family>Lohit Gujarati</family> + <family>Lohit Hindi</family> + <family>Lohit Marathi</family> + <family>Lohit Maithili</family> + <family>Lohit Kashmiri</family> + <family>Lohit Konkani</family> + <family>Lohit Nepali</family> + <family>Lohit Sindhi</family> + <family>Lohit Punjabi</family> + <family>Lohit Tamil</family> + <family>Meera</family> + <family>Lohit Malayalam</family> + <family>Lohit Kannada</family> + <family>Lohit Telugu</family> + <family>Lohit Oriya</family> + <family>LKLUG</family> + </prefer> + </alias> + <alias> + <family>sans-serif</family> + <prefer> + <family>Nachlieli</family> <!-- hebrew --> + <family>Lucida Sans Unicode</family> + <family>Yudit Unicode</family> + <family>Kerkis</family> <!-- greek --> + <family>ArmNet Helvetica</family> <!-- armenian --> + <family>Artsounk</family> <!-- armenian --> + <family>BPG UTF8 M</family> <!-- georgian --> + <family>Waree</family> <!-- thai --> + <family>Loma</family> <!-- thai --> + <family>Garuda</family> <!-- thai --> + <family>Umpush</family> <!-- thai --> + <family>Saysettha Unicode</family> <!-- lao? --> + <family>JG Lao Old Arial</family> <!-- lao --> + <family>GF Zemen Unicode</family> <!-- ethiopic --> + <family>Pigiarniq</family> <!-- canadian syllabics --> + <family>B Davat</family> <!-- arabic (fa) --> + <family>B Compset</family> <!-- arabic (fa) --> + <family>Kacst-Qr</family> <!-- arabic (ar) --> + <family>Urdu Nastaliq Unicode</family> <!-- arabic (ur) --> + <family>Raghindi</family> <!-- devanagari --> + <family>Mukti Narrow</family> <!-- bengali --> + <family>malayalam</family> <!-- malayalam --> + <family>Sampige</family> <!-- kannada --> + <family>padmaa</family> <!-- gujarati --> + <family>Hapax Berbère</family> <!-- tifinagh --> + <family>MS Gothic</family> <!-- han (ja) --> + <family>UmePlus P Gothic</family> <!-- han (ja) --> + <!-- chinese fonts are actually serifed --> + <family>SimSun</family> <!-- han (zh-cn,zh-tw) --> + <family>PMingLiu</family> <!-- han (zh-tw) --> + <family>WenQuanYi Zen Hei</family> <!-- han (zh-cn,zh-tw) --> + <family>WenQuanYi Bitmap Song</family> <!-- han (zh-cn,zh-tw) --> + <family>AR PL ShanHeiSun Uni</family> <!--han (ja,zh-cn,zh-tw) --> + <family>AR PL New Sung</family> <!-- han (zh-cn,zh-tw) --> + <family>MgOpen Modata</family> + <family>VL Gothic</family> + <family>IPAMonaGothic</family> + <family>IPAGothic</family> + <family>Sazanami Gothic</family> + <family>Kochi Gothic</family> + <family>AR PL KaitiM GB</family> + <family>AR PL KaitiM Big5</family> + <family>AR PL ShanHeiSun Uni</family> + <family>AR PL SungtiL GB</family> + <family>AR PL Mingti2L Big5</family> + <family>MS ゴシック</family> + <family>ZYSong18030</family> <!-- han (zh-cn,zh-tw) --> + <family>TSCu_Paranar</family> <!-- tamil --> + <family>NanumGothic</family> <!-- hangul (ko) --> + <family>UnDotum</family> <!-- hangul (ko) --> + <family>Baekmuk Dotum</family> <!-- hangul (ko) --> + <family>Baekmuk Gulim</family> <!-- hangul (ko) --> + <family>KacstQura</family> + <family>Lohit Bengali</family> + <family>Lohit Gujarati</family> + <family>Lohit Hindi</family> + <family>Lohit Marathi</family> + <family>Lohit Maithili</family> + <family>Lohit Kashmiri</family> + <family>Lohit Konkani</family> + <family>Lohit Nepali</family> + <family>Lohit Sindhi</family> + <family>Lohit Punjabi</family> + <family>Lohit Tamil</family> + <family>Meera</family> + <family>Lohit Malayalam</family> + <family>Lohit Kannada</family> + <family>Lohit Telugu</family> + <family>Lohit Oriya</family> + <family>LKLUG</family> + </prefer> + </alias> + <alias> + <family>monospace</family> + <prefer> + <family>Miriam Mono</family> <!-- hebrew --> + <family>VL Gothic</family> + <family>IPAMonaGothic</family> + <family>IPAGothic</family> + <family>Sazanami Gothic</family> + <family>Kochi Gothic</family> + <family>AR PL KaitiM GB</family> + <family>MS Gothic</family> <!-- han (ja) --> + <family>UmePlus Gothic</family> <!-- han (ja) --> + <family>NSimSun</family> <!-- han (zh-cn,zh-tw) --> + <family>MingLiu</family> <!-- han (zh-tw) --> + <family>AR PL ShanHeiSun Uni</family> <!-- han (ja,zh-cn,zh-tw) --> + <family>AR PL New Sung Mono</family> <!-- han (zh-cn,zh-tw) --> + <family>HanyiSong</family> <!-- han (zh-cn) --> + <family>AR PL SungtiL GB</family> + <family>AR PL Mingti2L Big5</family> + <family>ZYSong18030</family> <!-- han (zh-cn,zh-tw) --> + <family>NanumGothicCoding</family> <!-- hangul (ko) --> + <family>NanumGothic</family> <!-- hangul (ko) --> + <family>UnDotum</family> <!-- hangul (ko) --> + <family>Baekmuk Dotum</family> <!-- hangul (ko) --> + <family>Baekmuk Gulim</family> <!-- hangul (ko) --> + <family>TlwgTypo</family> <!-- thai --> + <family>TlwgTypist</family> <!-- thai --> + <family>TlwgTypewriter</family> <!-- thai --> + <family>TlwgMono</family> <!-- thai --> + <family>Hasida</family> <!-- hebrew --> + <family>Mitra Mono</family> <!-- bengali --> + <family>GF Zemen Unicode</family> <!-- ethiopic --> + <family>Hapax Berbère</family> <!-- tifinagh --> + <family>Lohit Bengali</family> + <family>Lohit Gujarati</family> + <family>Lohit Hindi</family> + <family>Lohit Marathi</family> + <family>Lohit Maithili</family> + <family>Lohit Kashmiri</family> + <family>Lohit Konkani</family> + <family>Lohit Nepali</family> + <family>Lohit Sindhi</family> + <family>Lohit Punjabi</family> + <family>Lohit Tamil</family> + <family>Meera</family> + <family>Lohit Malayalam</family> + <family>Lohit Kannada</family> + <family>Lohit Telugu</family> + <family>Lohit Oriya</family> + <family>LKLUG</family> + </prefer> + </alias> + <alias> + <family>serif</family> + <prefer> + <family>FreeSerif</family> + <family>Code2000</family> + <family>Code2001</family> <!-- plane1 and beyond --> + </prefer> + </alias> + <alias> + <family>sans-serif</family> + <prefer> + <family>FreeSans</family> + <family>Arial Unicode MS</family> + <family>Arial Unicode</family> + <family>Code2000</family> <!-- almost everything; serif actually --> + <family>Code2001</family> <!-- plane1 and beyond --> + </prefer> + </alias> + <alias> + <family>monospace</family> + <prefer> + <family>FreeMono</family> + </prefer> + </alias> + +</fontconfig> diff --git a/tests/html/bluetooth/bluetooth_battery_level.html b/tests/html/bluetooth/bluetooth_battery_level.html new file mode 100644 index 00000000000..77dccf1e40c --- /dev/null +++ b/tests/html/bluetooth/bluetooth_battery_level.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<title>Battery Level</title> +<body> + <button type="button" onclick="onButtonClick()">Get Bluetooth Device's Battery Level</button> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + function onButtonClick() { + clear(); + var options = {filters: [{services: ['battery_service']}], optionalServices: []}; + + try { + log('Requesting Bluetooth Device...'); + var bluetooth = window.navigator.bluetooth; + var device = bluetooth.requestDevice(options); + + log('Connecting to GATT Server on device...'); + var server = device.gatt.connect(); + + log('Getting Battery Service...'); + var service = server.getPrimaryService('battery_service'); + + log('Getting Battery Level Characteristic...'); + var characteristic = service.getCharacteristic('battery_level'); + + log('Reading Battery Level...'); + var value = asciiToDecimal(characteristic.readValue()); + log('> Battery Level is ' + value + '%'); + } catch(err) { + log(err); + } + } + </script> +</body> +</html> diff --git a/tests/html/bluetooth_battery_level.html b/tests/html/bluetooth/bluetooth_battery_level_with_filter.html index 8618df07859..269aa4e5ab2 100644 --- a/tests/html/bluetooth_battery_level.html +++ b/tests/html/bluetooth/bluetooth_battery_level_with_filter.html @@ -1,23 +1,24 @@ <!DOCTYPE html> <html> -<title>Battery Level</title> +<title>Battery Level with filters</title> <body> <input id="name" type="text" placeholder="Device Name"> <input id="namePrefix" type="text" placeholder="Device Name Prefix"> <button type="button" onclick="onButtonClick()">Get Bluetooth Device's Battery Level</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> function onButtonClick() { clear(); - var options = {filters: [{services: ['battery_service']}], optinalServices: []}; + var options = {filters: [{services: ['battery_service']}], optionalServices: []}; var filterName = document.getElementById('name').value; if (filterName) - options.filters.push({name: filterName}); + options.filters[0].name = filterName; var filterNamePrefix = document.getElementById('namePrefix').value; if (filterNamePrefix) - options.filters.push({namePrefix: filterNamePrefix}); + options.filters[0].namePrefix = filterNamePrefix; try { log('Requesting Bluetooth Device...'); @@ -34,28 +35,12 @@ var characteristic = service.getCharacteristic('battery_level'); log('Reading Battery Level...'); - var value = AsciiToDecimal(characteristic.readValue()); + var value = asciiToDecimal(characteristic.readValue()); log('> Battery Level is ' + value + '%'); } catch(err) { log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } - - function AsciiToDecimal(bytestr) { - var result = []; - for(i = 0; i < bytestr.length; i++) { - result[i] = bytestr[i].charCodeAt(0) ; - } - return result; - } </script> </body> </html> diff --git a/tests/html/bluetooth_characteristic_info.html b/tests/html/bluetooth/bluetooth_characteristic_info.html index 84cebd83014..d3eb3a2d255 100644 --- a/tests/html/bluetooth_characteristic_info.html +++ b/tests/html/bluetooth/bluetooth_characteristic_info.html @@ -6,14 +6,19 @@ <input id="characteristic" type="text" autofocus placeholder="Bluetooth Characteristic"> <button type="button" onclick="onButtonClick()">Get Characteristic Info</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> function onButtonClick() { clear(); var serviceUuid = document.getElementById('service').value; + var characteristicUuid = document.getElementById('characteristic').value; + + if (!serviceUuid || !characteristicUuid) { + return log('All input field must be filled!'); + } if (serviceUuid.startsWith('0x')) serviceUuid = parseInt(serviceUuid, 16); - var characteristicUuid = document.getElementById('characteristic').value; if (characteristicUuid.startsWith('0x')) characteristicUuid = parseInt(characteristicUuid, 16); @@ -43,27 +48,11 @@ log('> Queued Write: ' + characteristic.properties.reliableWrite); log('> Writable Auxiliaries: ' + characteristic.properties.writableAuxiliaries); characteristic.readValue(); - log('> Characteristic value: ' + AsciiToDecimal(characteristic.value)); + log('> Characteristic value: ' + asciiToDecimal(characteristic.value)); } catch(err) { log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } - - function AsciiToDecimal(bytestr) { - var result = []; - for(i = 0; i < bytestr.length; i++) { - result[i] = bytestr[i].charCodeAt(0) ; - } - return result; - } </script> </body> </html> diff --git a/tests/html/bluetooth/bluetooth_characteristic_read_value_test_cases.html b/tests/html/bluetooth/bluetooth_characteristic_read_value_test_cases.html new file mode 100644 index 00000000000..45b60128de9 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_characteristic_read_value_test_cases.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<title>Characterstic's ReadValue Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({characteristic: 'body_sensor_location', mustDisconnect: true}); + //Test 2 + testCases.push({characteristic: 'gap.reconnection_address', mustDisconnect: false}); + //Test 3 + testCases.push({characteristic: 'serial_number_string', mustDisconnect: false}); + //Test 4 + testCases.push({characteristic: 0x00002a03, mustDisconnect: false}); + //Test 5 + testCases.push({characteristic: 0x00002a25, mustDisconnect: false}); + //Test 6 + testCases.push({characteristic: '00002a03-0000-1000-8000-00805f9b34fb', mustDisconnect: false}); + //Test 7 + testCases.push({characteristic: '00002a25-0000-1000-8000-00805f9b34fb', mustDisconnect: false}); + //Test 8 + testCases.push({characteristic: 'body_sensor_location', mustDisconnect: false}); + //Test 9 + testCases.push({characteristic: 0x00002a38, mustDisconnect: false}); + //Test 10 + testCases.push({characteristic: '00002a38-0000-1000-8000-00805f9b34fb', mustDisconnect: false}); + //Test 11 + testCases.push({characteristic: 'heart_rate_control_point', mustDisconnect: false}); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]}); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "heart_rate"...'); + var primaryService = server.getPrimaryService('heart_rate'); + + log('Getting Characteristic "' + testCases[testNumber].characteristic + '"...'); + var characteristic = primaryService.getCharacteristic(testCases[testNumber].characteristic); + + log('Characteristic found!'); + + if (testCases[testNumber].mustDisconnect) { + log('Disconnecting from server...'); + device.gatt.disconnect(); + } + + log('Reading the value of the Characteristic...'); + characteristic.readValue(); + log('> Characteristic value: ' + asciiToDecimal(characteristic.value)); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_characteristic_write_value_test_cases.html b/tests/html/bluetooth/bluetooth_characteristic_write_value_test_cases.html new file mode 100644 index 00000000000..db9d9ce084f --- /dev/null +++ b/tests/html/bluetooth/bluetooth_characteristic_write_value_test_cases.html @@ -0,0 +1,80 @@ +<!DOCTYPE html> +<html> +<title>Characterstic's WriteValue Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({characteristic: 0x2345, valueToWrite: [11], mustDisconnect: true}); + //Test 2 + testCases.push({characteristic: 0x2345, valueToWrite: new Array(513), mustDisconnect: false}); + //Test 3 + testCases.push({characteristic: 'gap.reconnection_address', valueToWrite: [1], mustDisconnect: false}); + //Test 4 + testCases.push({characteristic: 'serial_number_string', valueToWrite: [2], mustDisconnect: false}); + //Test 5 + testCases.push({characteristic: 0x00002a02, valueToWrite: [3], mustDisconnect: false}); + //Test 6 + testCases.push({characteristic: 0x00002a03, valueToWrite: [3], mustDisconnect: false}); + //Test 7 + testCases.push({characteristic: 0x00002a25, valueToWrite: [4], mustDisconnect: false}); + //Test 8 + testCases.push({characteristic: '00002a02-0000-1000-8000-00805f9b34fb', valueToWrite: [6], mustDisconnect: false}); + //Test 9 + testCases.push({characteristic: '00002a03-0000-1000-8000-00805f9b34fb', valueToWrite: [5], mustDisconnect: false}); + //Test 10 + testCases.push({characteristic: '00002a25-0000-1000-8000-00805f9b34fb', valueToWrite: [6], mustDisconnect: false}); + //Test 11 + testCases.push({characteristic: 0x2345, valueToWrite: [11]}); + //Test 12 + testCases.push({characteristic: '00002345-0000-1000-8000-00805f9b34fb', valueToWrite: [22], mustDisconnect: false}); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice({filters: [{services: [0x1234]}]}); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "Test Service"...'); + var primaryService = server.getPrimaryService(0x1234); + + log('Getting Characteristic "' + testCases[testNumber].characteristic + '"...'); + var characteristic = primaryService.getCharacteristic(testCases[testNumber].characteristic); + + log('Characteristic found!'); + + log('Reading the old value of the Characteristic...'); + characteristic.readValue(); + log('> Characteristic value: ' + asciiToDecimal(characteristic.value)); + + if (testCases[testNumber].mustDisconnect) { + log('Disconnecting from server...'); + device.gatt.disconnect(); + } + + if (testNumber !== 1) { + log('Writing the value of the Characteristic with: ' + testCases[testNumber].valueToWrite + '...'); + } else { + log('Writing the value of the Characteristic with a 513 long array...'); + } + + characteristic.writeValue(testCases[testNumber].valueToWrite); + + log('Reading the new value of the Characteristic...'); + characteristic.readValue(); + log('> Characteristic value: ' + asciiToDecimal(characteristic.value)); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth_descriptor_info.html b/tests/html/bluetooth/bluetooth_descriptor_info.html index c657d217697..47d9e294295 100644 --- a/tests/html/bluetooth_descriptor_info.html +++ b/tests/html/bluetooth/bluetooth_descriptor_info.html @@ -7,18 +7,23 @@ <input id="descriptor" type="text" autofocus placeholder="Bluetooth Descriptor"> <button type="button" onclick="onButtonClick()">Get Descriptor Info</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> function onButtonClick() { clear(); var serviceUuid = document.getElementById('service').value; + var characteristicUuid = document.getElementById('characteristic').value; + var descriptorUuid = document.getElementById('descriptor').value; + + if (!serviceUuid || !characteristicUuid || !descriptorUuid) { + return log('All input field must be filled!'); + } if (serviceUuid.startsWith('0x')) serviceUuid = parseInt(serviceUuid, 16); - var characteristicUuid = document.getElementById('characteristic').value; if (characteristicUuid.startsWith('0x')) characteristicUuid = parseInt(characteristicUuid, 16); - var descriptorUuid = document.getElementById('descriptor').value; if (descriptorUuid.startsWith('0x')) descriptorUuid = parseInt(descriptorUuid, 16); @@ -42,27 +47,11 @@ log('> Descriptor characteristic: ' + descriptor.characteristic.uuid); log('> Descriptor UUID: ' + descriptor.uuid); descriptor.readValue(); - log('> Descriptor value: ' + AsciiToDecimal(descriptor.value)); + log('> Descriptor value: ' + asciiToDecimal(descriptor.value)); } catch(err) { log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } - - function AsciiToDecimal(bytestr) { - var result = []; - for(i = 0; i < bytestr.length; i++) { - result[i] = bytestr[i].charCodeAt(0) ; - } - return result; - } </script> </body> </html> diff --git a/tests/html/bluetooth/bluetooth_descriptor_read_value_test_cases.html b/tests/html/bluetooth/bluetooth_descriptor_read_value_test_cases.html new file mode 100644 index 00000000000..8a2e553652b --- /dev/null +++ b/tests/html/bluetooth/bluetooth_descriptor_read_value_test_cases.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<title>Descriptor's ReadValue Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({descriptor: 'gatt.client_characteristic_configuration', mustDisconnect: true}); + //Test 2 + testCases.push({descriptor: 0x2902, mustDisconnect: true}); + //Test 3 + testCases.push({descriptor: '00002902-0000-1000-8000-00805f9b34fb', mustDisconnect: true}); + //Test 4 + testCases.push({descriptor: 'gatt.client_characteristic_configuration', mustDisconnect: false}); + //Test 5 + testCases.push({descriptor: 0x2902, mustDisconnect: false}); + //Test 6 + testCases.push({descriptor: '00002902-0000-1000-8000-00805f9b34fb', mustDisconnect: false}); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]}); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "heart_rate"...'); + var primaryService = server.getPrimaryService('heart_rate'); + + log('Getting Characteristic "heart_rate_measurement"...'); + var characteristic = primaryService.getCharacteristic('heart_rate_measurement'); + + log('Getting Descriptor "' + testCases[testNumber].descriptor + '"...'); + var descriptor = characteristic.getDescriptor(testCases[testNumber].descriptor); + + log('Descriptor found!'); + if (testCases[testNumber].mustDisconnect) { + log('Disconecting from GATTserver'); + device.gatt.disconnect(); + } + log("Reading descriptor's value..."); + descriptor.readValue(); + log('> Descriptor value: ' + asciiToDecimal(descriptor.value)); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_descriptor_write_value_test_cases.html b/tests/html/bluetooth/bluetooth_descriptor_write_value_test_cases.html new file mode 100644 index 00000000000..0553023ca7c --- /dev/null +++ b/tests/html/bluetooth/bluetooth_descriptor_write_value_test_cases.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html> +<title>Descriptor's WriteValue Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({descriptor: '00003456-0000-1000-8000-00805f9b34fb', valueToWrite: [11], mustDisconnect: true}); + //Test 2 + testCases.push({descriptor: '00003456-0000-1000-8000-00805f9b34fb', valueToWrite: new Array(513), mustDisconnect: false}); + //Test 3 + testCases.push({descriptor: '00002902-0000-1000-8000-00805f9b34fb', valueToWrite: [1], mustDisconnect: false}); + //Test 4 + testCases.push({descriptor: 0x00002902, valueToWrite: [2], mustDisconnect: false}); + //Test 5 + testCases.push({descriptor: 0x3456, valueToWrite: [11], mustDisconnect: false}); + //Test 6 + testCases.push({descriptor: '00003456-0000-1000-8000-00805f9b34fb', valueToWrite: [22], mustDisconnect: false}); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice({filters: [{services: [0x1234]}]}); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "Test Service"...'); + var primaryService = server.getPrimaryService(0x1234); + + log('Getting Characteristic "Test Characteristic (0x2345)"...'); + var characteristic = primaryService.getCharacteristic(0x2345); + + log('Characteristic found!'); + + log('Getting Descriptor "' + testCases[testNumber].descriptor + '"...'); + var descriptor = characteristic.getDescriptor(testCases[testNumber].descriptor); + + log('Reading the old value of the Descriptor...'); + descriptor.readValue(); + log('> Descriptor value: ' + asciiToDecimal(descriptor.value)); + + if (testCases[testNumber].mustDisconnect) { + log('Disconnecting from server...'); + device.gatt.disconnect(); + } + + if (testNumber !== 1) { + log('Writing the value of the Descriptor with: ' + testCases[testNumber].valueToWrite + '...'); + } else { + log('Writing the value of the Descriptor with a 513 long array...'); + } + + descriptor.writeValue(testCases[testNumber].valueToWrite); + + log('Reading the new value of the Descriptor...'); + descriptor.readValue(); + log('> Descriptor value: ' + asciiToDecimal(descriptor.value)); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth_device_disconnect.html b/tests/html/bluetooth/bluetooth_device_disconnect.html index 715d3d16a24..3f9771dfee6 100644 --- a/tests/html/bluetooth_device_disconnect.html +++ b/tests/html/bluetooth/bluetooth_device_disconnect.html @@ -9,33 +9,34 @@ <button type="button" onclick="onDisconnectButtonClick()">Disconnect()</button> <button type="button" onclick="onReconnectButtonClick()">Reconnect()</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> var bluetoothDevice; function onScanButtonClick() { clear(); - var options = {filters: []}; + var options = {filters: [{}]}; var filterService = document.getElementById('service').value; - if (filterService.startsWith('0x')) - filterService = parseInt(filterService, 16); - - if (filterService) - options.filters.push({services: [filterService]}); + if (filterService) { + if (filterService.startsWith('0x')) + filterService = parseInt(filterService, 16); + options.filters[0].services = [filterService]; + } var filterName = document.getElementById('name').value; if (filterName) - options.filters.push({name: filterName}); + options.filters[0].name = filterName; var filterNamePrefix = document.getElementById('namePrefix').value; if (filterNamePrefix) - options.filters.push({namePrefix: filterNamePrefix}); - - bluetoothDevice = null; + options.filters[0].namePrefix = filterNamePrefix; try { + clear(); log('Requesting Bluetooth Device...'); bluetoothDevice = window.navigator.bluetooth.requestDevice(options); + log('Connecting to Bluetooth Device...'); connect(); } catch(err) { log(err); @@ -45,7 +46,7 @@ function onDisconnectButtonClick() { clear(); if (!bluetoothDevice) - return; + return log('> There is no connected Bluetooth Device instance, from which we can disconnect'); try { log('Disconnecting from Bluetooth Device...'); @@ -63,32 +64,24 @@ function onReconnectButtonClick() { clear(); if (!bluetoothDevice) - log('> There is no connected Bluetooth Device instance') + log('> There is no connected Bluetooth Device instance, so we cannot reconnect') if (bluetoothDevice.gatt.connected) { log('> Bluetooth Device is already connected'); return; } else { + log('Connecting to Bluetooth Device...'); connect(); } } function connect() { try { - log('Connecting to Bluetooth Device...'); - bluetoothDevice.gatt.connect(); + log('Result of the connect() method of the GATT Server: ' + bluetoothDevice.gatt.connect()); log('> Bluetooth Device connected: ' + bluetoothDevice.gatt.connected); } catch(err) { log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } </script> </body> </html> diff --git a/tests/html/bluetooth_device_info.html b/tests/html/bluetooth/bluetooth_device_info.html index 906dc200362..6df38acbeae 100644 --- a/tests/html/bluetooth_device_info.html +++ b/tests/html/bluetooth/bluetooth_device_info.html @@ -7,17 +7,18 @@ <input id="namePrefix" type="text" placeholder="Device Name Prefix"> <button type="button" onclick="onButtonClick()">Get Bluetooth Device Info</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> function onButtonClick() { clear(); - var options = {filters: [], optinalServices: []}; + var options = {filters: [], optionalServices: []}; var filterService = document.getElementById('service').value; - if (filterService.startsWith('0x')) - filterService = parseInt(filterService, 16); - - if (filterService) + if (filterService) { + if (filterService.startsWith('0x')) + filterService = parseInt(filterService, 16); options.filters.push({services: [filterService]}); + } var filterName = document.getElementById('name').value; if (filterName) @@ -41,14 +42,6 @@ log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } </script> </body> </html> diff --git a/tests/html/bluetooth/bluetooth_functions.js b/tests/html/bluetooth/bluetooth_functions.js new file mode 100644 index 00000000000..b0f73c79c0a --- /dev/null +++ b/tests/html/bluetooth/bluetooth_functions.js @@ -0,0 +1,32 @@ +function clear() { + document.getElementById("log").textContent = ""; +} + +function log(line) { + document.getElementById("log").textContent += timeStamp() + line + '\n'; +} + +function asciiToDecimal(bytestr) { + var result = []; + for(i = 0; i < bytestr.length; i++) { + result[i] = bytestr.charCodeAt(i) ; + } + return result; +} + +function populate(testCases){ + for(i = 0; i < testCases.length; ++i) { + var btn = document.createElement('button'); + btn.setAttribute('onclick','onButtonClick(' + i + ')'); + btn.innerHTML = 'Test '+ (i+1); + document.getElementById('buttons').appendChild(btn); + } +} + +function timeStamp() { + var date = new Date; + var hours = date.getHours(); + var minutes = "0" + date.getMinutes(); + var seconds = "0" + date.getSeconds(); + return hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2) + ' '; +} diff --git a/tests/html/bluetooth/bluetooth_get_characteristic_test_cases.html b/tests/html/bluetooth/bluetooth_get_characteristic_test_cases.html new file mode 100644 index 00000000000..5c9c2fe4f73 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_characteristic_test_cases.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<html> +<title>GetCharacteristic Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({characteristic: 'not_a_characteristic_name', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 2 + testCases.push({characteristic: 'battery_level', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 3 + testCases.push({characteristic: '1234567891000-1000-8000-00805f9b34fb', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 4 + testCases.push({characteristic: '11', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 5 + testCases.push({characteristic: '12345678-1234-1234-1234-123456789abc', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 6 + testCases.push({characteristic: '00000000-0000-0000-0000-000000000000', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 7 + testCases.push({characteristic: 0x0000, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 8 + testCases.push({characteristic: 0x000000000, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 9 + testCases.push({characteristic: 0x2a19, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 10 + testCases.push({characteristic: 0x12345678, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 11 + testCases.push({characteristic: 0x00002a19, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 12 + testCases.push({characteristic: 0x00002a03, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 13 + testCases.push({characteristic: 0x00002a25, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 14 + testCases.push({characteristic: 0x2a03, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 15 + testCases.push({characteristic: 0x2a25, service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 16 + testCases.push({characteristic: '00002a03-0000-1000-8000-00805f9b34fb', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 17 + testCases.push({characteristic: '00002a25-0000-1000-8000-00805f9b34fb', service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber].options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "' + testCases[testNumber].service + '"...'); + var primaryService = server.getPrimaryService(testCases[testNumber].service); + + log('Getting Characteristic "' + testCases[testNumber].characteristic + '"...'); + var characteristic = primaryService.getCharacteristic(testCases[testNumber].characteristic); + + log('Characteristic found!'); + log('> Characteristic service: ' + characteristic.service.uuid); + log('> Characteristic UUID: ' + characteristic.uuid); + log('> Broadcast: ' + characteristic.properties.broadcast); + log('> Read: ' + characteristic.properties.read); + log('> Write w/o response: ' + characteristic.properties.writeWithoutResponse); + log('> Write: ' + characteristic.properties.write); + log('> Notify: ' + characteristic.properties.notify); + log('> Indicate: ' + characteristic.properties.indicate); + log('> Signed Write: ' + characteristic.properties.authenticatedSignedWrites); + log('> Queued Write: ' + characteristic.properties.reliableWrite); + log('> Writable Auxiliaries: ' + characteristic.properties.writableAuxiliaries); + characteristic.readValue(); + log('> Characteristic value: ' + asciiToDecimal(characteristic.value)); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_characteristics_test_cases.html b/tests/html/bluetooth/bluetooth_get_characteristics_test_cases.html new file mode 100644 index 00000000000..81c3e42bb47 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_characteristics_test_cases.html @@ -0,0 +1,87 @@ +<!DOCTYPE html> +<html> +<title>GetCharacteristics Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({service: 'battery_service', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 2 + testCases.push({characteristic: 'not_a_characteristic_name', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 3 + testCases.push({characteristic: 'body_sensor_location', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 4 + testCases.push({characteristic: '1234567891000-1000-8000-00805f9b34fb', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 5 + testCases.push({characteristic: '11', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 6 + testCases.push({characteristic: '12345678-1234-1234-1234-123456789abc', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 7 + testCases.push({characteristic: '00000000-0000-0000-0000-000000000000', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 8 + testCases.push({characteristic: 0x0000, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 9 + testCases.push({characteristic: 0x000000000, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 10 + testCases.push({characteristic: 0x2a38, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 11 + testCases.push({characteristic: 0x12345678, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 12 + testCases.push({characteristic: 0x00002a38, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 13 + testCases.push({characteristic: 0x00002a03, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 14 + testCases.push({characteristic: 0x00002a25, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 15 + testCases.push({characteristic: 0x2a03, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 16 + testCases.push({characteristic: 0x2a25, service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 17 + testCases.push({characteristic: '00002a03-0000-1000-8000-00805f9b34fb', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + //Test 18 + testCases.push({characteristic: '00002a25-0000-1000-8000-00805f9b34fb', service: 'heart_rate', options: {filters: [{services: ['heart_rate']}], optionalServices: ['cycling_power']} }); + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber].options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "' + testCases[testNumber].service + '"...'); + var primaryService = server.getPrimaryService(testCases[testNumber].service); + + log('Getting Characteristic "' + testCases[testNumber].characteristic + '"...'); + var characteristics = primaryService.getCharacteristics(testCases[testNumber].characteristic); + + log('> List of Characteristics on the current device:'); + + for(i = 0; i < characteristics.length; ++i) { + log('> #' + (i+1)); + log('> Characteristic service: ' + characteristics[i].service.uuid); + log('> Characteristic UUID: ' + characteristics[i].uuid); + log('> Broadcast: ' + characteristics[i].properties.broadcast); + log('> Read: ' + characteristics[i].properties.read); + log('> Write w/o response: ' + characteristics[i].properties.writeWithoutResponse); + log('> Write: ' + characteristics[i].properties.write); + log('> Notify: ' + characteristics[i].properties.notify); + log('> Indicate: ' + characteristics[i].properties.indicate); + log('> Signed Write: ' + characteristics[i].properties.authenticatedSignedWrites); + log('> Queued Write: ' + characteristics[i].properties.reliableWrite); + log('> Writable Auxiliaries: ' + characteristics[i].properties.writableAuxiliaries); + characteristics[i].readValue(); + log('> Characteristic value: ' + asciiToDecimal(characteristics[i].value)); + } + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_descriptor_test_cases.html b/tests/html/bluetooth/bluetooth_get_descriptor_test_cases.html new file mode 100644 index 00000000000..e37a0dabd28 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_descriptor_test_cases.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<title>GetDescriptor Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push('not_a_descriptor_name'); + //Test 2 + testCases.push('gatt.client_characteristic_configuration'); + //Test 3 + testCases.push('1234567891000-1000-8000-00805f9b34fb'); + //Test 4 + testCases.push('11'); + //Test 5 + testCases.push('12345678-1234-1234-1234-123456789abc'); + //Test 6 + testCases.push('00000000-0000-0000-0000-000000000000'); + //Test 7 + testCases.push(0x0000); + //Test 8 + testCases.push(0x00000000); + //Test 9 + testCases.push(0x2902); + //Test 10 + testCases.push('00002902-0000-1000-8000-00805f9b34fb'); + //Test 11 + testCases.push(0x12345678); + //Test 12 + testCases.push(0x00002902); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]}); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "heart_rate"...'); + var primaryService = server.getPrimaryService('heart_rate'); + + log('Getting Characteristic "heart_rate_measurement"...'); + var characteristic = primaryService.getCharacteristic('heart_rate_measurement'); + + log('Getting Descriptor "' + testCases[testNumber] + '"...'); + var descriptor = characteristic.getDescriptor(testCases[testNumber]); + + log('Descriptor found!'); + log('> Descriptor characteristic: ' + descriptor.characteristic.uuid); + log('> Descriptor UUID: ' + descriptor.uuid); + descriptor.readValue(); + log('> Descriptor value: ' + asciiToDecimal(descriptor.value)); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_descriptors_test_cases.html b/tests/html/bluetooth/bluetooth_get_descriptors_test_cases.html new file mode 100644 index 00000000000..3c71e27267c --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_descriptors_test_cases.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> +<title>GetDescriptors Test Cases</title> +<body> + <div id="buttons"></div> + <button onclick="onButtonClick2()">Test 12</button> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push('not_a_descriptor_name'); + //Test 2 + testCases.push('gatt.client_characteristic_configuration'); + //Test 3 + testCases.push('1234567891000-1000-8000-00805f9b34fb'); + //Test 4 + testCases.push('11'); + //Test 5 + testCases.push('12345678-1234-1234-1234-123456789abc'); + //Test 6 + testCases.push('00000000-0000-0000-0000-000000000000'); + //Test 7 + testCases.push(0x0000); + //Test 8 + testCases.push(0x00000000); + //Test 9 + testCases.push(0x2902); + //Test 10 + testCases.push(0x12345678); + //Test 11 + testCases.push(0x00002902); + //Test 12 + testCases.push(undefined); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]}); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "heart_rate"...'); + var primaryService = server.getPrimaryService('heart_rate'); + + log('Getting Characteristic "heart_rate_measurement"...'); + var characteristic = primaryService.getCharacteristic('heart_rate_measurement'); + + log('Getting Descriptors "' + testCases[testNumber] + '"...'); + var descriptors = characteristic.getDescriptors(testCases[testNumber]); + + for(i = 0; i < descriptors.length; ++i) { + log('> #' + (i+1)); + log('> UUID: ' + descriptors[i].uuid); + descriptors[i].readValue(); + log('> Descriptor value: ' + asciiToDecimal(descriptors[i].value)); + } + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_included_service_test_cases.html b/tests/html/bluetooth/bluetooth_get_included_service_test_cases.html new file mode 100644 index 00000000000..54e877546b5 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_included_service_test_cases.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<title>GetIncludedService Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 'not_a_service_name', options: {filters: [{services: ['battery_service']}]} }); + //Test 2 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '1234567891000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 3 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '11', options: {filters: [{services: ['battery_service']}]} }); + //Test 4 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '12345678-1234-1234-1234-123456789abc', options: {filters: [{services: ['battery_service']}]} }); + //Test 5 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '00000000-0000-0000-0000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 6 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x0000, options: {filters: [{services: ['battery_service']}]} }); + //Test 7 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x00000000, options: {filters: [{services: ['battery_service']}]} }); + //Test 8 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x12345678, options: {filters: [{services: ['battery_service']}]} }); + //Test 9 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x0000180f, options: {filters: [{services: ['battery_service']}]} }); + //Test 10 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '00001812-0000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 11 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 'f000ffc0-0451-4000-b000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 12 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '00001530-1212-efde-1523-785feabcd123', options: {filters: [{services: ['battery_service']}]} }); + //Test 13 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x00001812, options: {filters: [{services: ['battery_service']}]} }); + //Test 14 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0xf000ffc0, options: {filters: [{services: ['battery_service']}]} }); + //Test 15 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x00001530, options: {filters: [{services: ['battery_service']}]} }); + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber].options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "' + testCases[testNumber].requestedService + '"...'); + var primaryService = server.getPrimaryService(testCases[testNumber].requestedService); + + log('Getting Included Service "' + testCases[testNumber].requestedIncludedService + '"...') + var includedService = primaryService.getIncludedService(testCases[testNumber].requestedIncludedService); + + log('Primary Service found on device: ' + includedService.device.name); + log('> UUID: ' + includedService.uuid); + log('> Is primary: ' + includedService.isPrimary); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_included_services_test_cases.html b/tests/html/bluetooth/bluetooth_get_included_services_test_cases.html new file mode 100644 index 00000000000..f0291469de7 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_included_services_test_cases.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> +<title>GetIncludedServices Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 'not_a_service_name', options: {filters: [{services: ['battery_service']}]} }); + //Test 2 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '1234567891000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 3 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '11', options: {filters: [{services: ['battery_service']}]} }); + //Test 4 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '12345678-1234-1234-1234-123456789abc', options: {filters: [{services: ['battery_service']}]} }); + //Test 5 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '00000000-0000-0000-0000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 6 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x0000, options: {filters: [{services: ['battery_service']}]} }); + //Test 7 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x00000000, options: {filters: [{services: ['battery_service']}]} }); + //Test 8 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x12345678, options: {filters: [{services: ['battery_service']}]} }); + //Test 9 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x0000180f, options: {filters: [{services: ['battery_service']}]} }); + //Test 10 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '00001812-0000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 11 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 'f000ffc0-0451-4000-b000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 12 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: '00001530-1212-efde-1523-785feabcd123', options: {filters: [{services: ['battery_service']}]} }); + //Test 13 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x00001812, options: {filters: [{services: ['battery_service']}]} }); + //Test 14 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0xf000ffc0, options: {filters: [{services: ['battery_service']}]} }); + //Test 15 + testCases.push({ requestedService: 'battery_service', requestedIncludedService: 0x00001530, options: {filters: [{services: ['battery_service']}]} }); + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber].options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "' + testCases[testNumber].requestedService + '"...'); + var primaryService = server.getPrimaryService(testCases[testNumber].requestedService); + + log('Getting Included Service "' + testCases[testNumber].requestedIncludedService + '"...') + var includedServices = primaryService.getIncludedServices(testCases[testNumber].requestedIncludedService); + + for(i = 0; i < includedServices.length; ++i) { + log('> #' + (i+1)); + log('> UUID: ' + includedServices[i].uuid); + log('> Is primary: ' + includedServices[i].isPrimary); + } + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_primary_service_test_cases.html b/tests/html/bluetooth/bluetooth_get_primary_service_test_cases.html new file mode 100644 index 00000000000..160703754cf --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_primary_service_test_cases.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> +<title>GetPrimaryService Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({ requestedService: 'heart_rate', options: {filters: [{services: ['battery_service']}]} }); + //Test 2 + testCases.push({ requestedService: 'heart_rate', options: {filters: [{services: ['battery_service', 'heart_rate']}]} }); + //Test 3 + testCases.push({ requestedService: 'not_a_service_name', options: {filters: [{services: ['battery_service']}]} }); + //Test 4 + testCases.push({ requestedService: 'battery_service', options: {filters: [{services: ['battery_service']}]} }); + //Test 5 + testCases.push({ requestedService: '1234567891000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 6 + testCases.push({ requestedService: '11', options: {filters: [{services: ['battery_service']}]} }); + //Test 7 + testCases.push({ requestedService: '12345678-1234-1234-1234-123456789abc', options: {filters: [{services: ['battery_service']}]} }); + //Test 8 + testCases.push({ requestedService: 0x0000, options: {filters: [{services: ['battery_service']}]} }); + //Test 9 + testCases.push({ requestedService: 0x00000000, options: {filters: [{services: ['battery_service']}]} }); + //Test 10 + testCases.push({ requestedService: 0x180f, options: {filters: [{services: ['battery_service']}]} }); + //Test 11 + testCases.push({ requestedService: 0x12345678, options: {filters: [{services: ['battery_service']}]} }); + //Test 12 + testCases.push({ requestedService: 0x0000180f, options: {filters: [{services: ['battery_service']}]} }); + //Test 13 + testCases.push({ requestedService: 0x00001812, options: {filters: [{services: ['battery_service']}]} }); + //Test 14 + testCases.push({ requestedService: 'f000ffc0-0451-4000-b000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 15 + testCases.push({ requestedService: '00001530-1212-efde-1523-785feabcd123', options: {filters: [{services: ['battery_service']}]} }); + //Test 16 + testCases.push({ requestedService: 0xf000ffc0, options: {filters: [{services: ['battery_service']}], optionalServices: [0xf000ffc0]} }); + //Test 17 + testCases.push({ requestedService: 0x00001530, options: {filters: [{services: ['battery_service']}], optionalServices: [0x00001530]} }); + //Test 18 + testCases.push({ requestedService: '0000180f-0000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 19 + testCases.push({ requestedService: 'cycling_power', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 20 + testCases.push({ requestedService: '00001818-0000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber].options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "' + testCases[testNumber].requestedService + '"...'); + var primaryService = server.getPrimaryService(testCases[testNumber].requestedService); + + log('Primary Service found on device: ' + primaryService.device.name); + log('> UUID: ' + primaryService.uuid); + log('> Is primary: ' + primaryService.isPrimary); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_get_primary_services_test_cases.html b/tests/html/bluetooth/bluetooth_get_primary_services_test_cases.html new file mode 100644 index 00000000000..4a00c0efa32 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_get_primary_services_test_cases.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<html> +<title>GetPrimaryServices Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({ requestedService: 'heart_rate', options: {filters: [{services: ['battery_service']}]} }); + //Test 2 + testCases.push({ requestedService: 'not_a_service_name', options: {filters: [{services: ['battery_service']}]} }); + //Test 3 + testCases.push({ requestedService: 'battery_service', options: {filters: [{services: ['battery_service']}]} }); + //Test 4 + testCases.push({ requestedService: '1234567891000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 5 + testCases.push({ requestedService: '11', options: {filters: [{services: ['battery_service']}]} }); + //Test 6 + testCases.push({ requestedService: '12345678-1234-1234-1234-123456789abc', options: {filters: [{services: ['battery_service']}]} }); + //Test 7 + testCases.push({ requestedService: '00000000-0000-0000-0000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 8 + testCases.push({ requestedService: 0x0000, options: {filters: [{services: ['battery_service']}]} }); + //Test 9 + testCases.push({ requestedService: 0x00000000, options: {filters: [{services: ['battery_service']}]} }); + //Test 10 + testCases.push({ requestedService: 0x180f, options: {filters: [{services: ['battery_service']}]} }); + //Test 11 + testCases.push({ requestedService: 0x12345678, options: {filters: [{services: ['battery_service']}]} }); + //Test 12 + testCases.push({ requestedService: 0x0000180f, options: {filters: [{services: ['battery_service']}]} }); + //Test 13 + testCases.push({ requestedService: 0x00001812, options: {filters: [{services: ['battery_service']}]} }); + //Test 14 + testCases.push({ requestedService: 'f000ffc0-0451-4000-b000-000000000000', options: {filters: [{services: ['battery_service']}]} }); + //Test 15 + testCases.push({ requestedService: '00001530-1212-efde-1523-785feabcd123', options: {filters: [{services: ['battery_service']}]} }); + //Test 16 + testCases.push({ requestedService: 0xf000ffc0, options: {filters: [{services: ['battery_service']}], optionalServices: [0xf000ffc0]} }); + //Test 17 + testCases.push({ requestedService: 0x00001530, options: {filters: [{services: ['battery_service']}], optionalServices: [0x00001530]} }); + //Test 18 + testCases.push({ requestedService: '0000180f-0000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}]} }); + //Test 19 + testCases.push({ requestedService: 'cycling_power', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + //Test 20 + testCases.push({ requestedService: '00001818-0000-1000-8000-00805f9b34fb', options: {filters: [{services: ['battery_service']}], optionalServices: ['cycling_power']} }); + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber].options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service "' + testCases[testNumber].requestedService + '"...'); + var primaryServices = server.getPrimaryServices(testCases[testNumber].requestedService); + + for(i = 0; i < primaryServices.length; ++i) { + log('> #' + (i+1)); + log('> UUID: ' + primaryServices[i].uuid); + log('> Is primary: ' + primaryServices[i].isPrimary); + } + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/html/bluetooth_included_service_info.html b/tests/html/bluetooth/bluetooth_included_service_info.html index 76a351606b7..094ce5fd6a5 100644 --- a/tests/html/bluetooth_included_service_info.html +++ b/tests/html/bluetooth/bluetooth_included_service_info.html @@ -7,17 +7,18 @@ <input id="namePrefix" type="text" placeholder="Device Name Prefix"> <button type="button" onclick="onButtonClick()">Get Primary Service Info</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> function onButtonClick() { clear(); - var options = {filters: [], optinalServices: []}; + var options = {filters: [], optionalServices: []}; var filterService = document.getElementById('service').value; - if (filterService.startsWith('0x')) - filterService = parseInt(filterService, 16); - - if (filterService) + if (filterService) { + if (filterService.startsWith('0x')) + filterService = parseInt(filterService, 16); options.filters.push({services: [filterService]}); + } var filterName = document.getElementById('name').value; if (filterName) @@ -49,14 +50,6 @@ log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } </script> </body> </html> diff --git a/tests/html/bluetooth_primary_service_info.html b/tests/html/bluetooth/bluetooth_primary_service_info.html index 606d342c85d..3187400b00a 100644 --- a/tests/html/bluetooth_primary_service_info.html +++ b/tests/html/bluetooth/bluetooth_primary_service_info.html @@ -7,17 +7,18 @@ <input id="namePrefix" type="text" placeholder="Device Name Prefix"> <button type="button" onclick="onButtonClick()">Get Primary Service Info</button> <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> <script> function onButtonClick() { clear(); - var options = {filters: [], optinalServices: []}; + var options = {filters: [], optionalServices: []}; var filterService = document.getElementById('service').value; - if (filterService.startsWith('0x')) - filterService = parseInt(filterService, 16); - - if (filterService) + if (filterService) { + if (filterService.startsWith('0x')) + filterService = parseInt(filterService, 16); options.filters.push({services: [filterService]}); + } var filterName = document.getElementById('name').value; if (filterName) @@ -44,14 +45,6 @@ log(err); } } - - function clear() { - document.getElementById("log").textContent = ""; - } - - function log(line) { - document.getElementById("log").textContent += line + '\n'; - } </script> </body> </html> diff --git a/tests/html/bluetooth/bluetooth_primary_services_info.html b/tests/html/bluetooth/bluetooth_primary_services_info.html new file mode 100644 index 00000000000..cab413f8360 --- /dev/null +++ b/tests/html/bluetooth/bluetooth_primary_services_info.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<title>Primary Services info</title> +<body> + <input id="service" type="text" autofocus placeholder="Bluetooth Service"> + <input id="name" type="text" placeholder="Device Name"> + <input id="namePrefix" type="text" placeholder="Device Name Prefix"> + <button type="button" onclick="onButtonClick()">Get Primary Services Info</button> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + function onButtonClick() { + clear(); + var options = {filters: [], optionalServices: []}; + + var filterService = document.getElementById('service').value; + if (filterService) { + if (filterService.startsWith('0x')) + filterService = parseInt(filterService, 16); + options.filters.push({services: [filterService]}); + } + + var filterName = document.getElementById('name').value; + if (filterName) + options.filters.push({name: filterName}); + + var filterNamePrefix = document.getElementById('namePrefix').value; + if (filterNamePrefix) + options.filters.push({namePrefix: filterNamePrefix}); + + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(options); + + log('Connecting to GATTserver on device...'); + var server = device.gatt.connect(); + + log('Getting Primary Service...'); + var primaryServices; + if (filterService) { + primaryServices = server.getPrimaryServices(filterService); + } else { + primaryServices = server.getPrimaryServices(); + } + log('> List of Services on the current device:'); + for(i = 0; i < primaryServices.length; ++i) { + log('> #' + (i+1)); + log('> UUID: ' + primaryServices[i].uuid); + log('> Is primary: ' + primaryServices[i].isPrimary); + } + } catch(err) { + log(err); + } + } + </script> +</body> +</html> diff --git a/tests/html/bluetooth/bluetooth_request_device_test_cases.html b/tests/html/bluetooth/bluetooth_request_device_test_cases.html new file mode 100644 index 00000000000..4e42fdeeeab --- /dev/null +++ b/tests/html/bluetooth/bluetooth_request_device_test_cases.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html> +<title>RequestDevice Test Cases</title> +<body> + <div id="buttons"></div> + <pre id="log"></pre> + <script src="bluetooth_functions.js"></script> + <script> + var testCases = []; + //Test 1 + testCases.push({filters: []}); + //Test 2 + testCases.push({filters: [{notExpectedMember: []}]}); + //Test 3 + testCases.push({filters: [{services: ['battery_service']}]}); + //Test 4 + testCases.push({filters: [{name: 'raspberrypi'}]}); + //Test 5 + testCases.push({filters: [{namePrefix: 'rasp'}]}); + //Test 6 + testCases.push({filters:[{services: []}]}); + //Test 7 + testCases.push({filters:[{services: [], namePrefix:'rasp'}]}); + //Test 8 + testCases.push({filters: [{services: ['not_a_service_name']}]}); + //Test 9 + testCases.push({filters: [{services: ['1234567891000-1000-8000-00805f9b34fb']}]}); + //Test 10 + testCases.push({filters: [{services: ['12345678-1234-1234-1234-123456789abc']}]}); + //Test 11 + testCases.push({filters: [{services: [0x0000]}]}); + //Test 12 + testCases.push({filters: [{services: [0x180f]}]}); + //Test 13 + testCases.push({filters: [{services: [0x12345678]}]}); + //Test 14 + testCases.push({filters: [{services: [0x00001812]}]}); + //Test 15 + testCases.push({filters: [{services: ['f000ffc0-0451-4000-b000-000000000000']}]}); + //Test 16 + testCases.push({filters: [{name: 'this_device_name_is_longer_than_29_bytes'}]}); + //Test 17 + testCases.push({filters: [{namePrefix: 'this_device_name_prefix_is_longer_than_29_bytes'}]}); + //Test 18 + testCases.push({filters: [{namePrefix: ''}]}); + //Test 19 + testCases.push({filters: [{namePrefix: 'rasp'}], optionalServices: ['1234567891000-1000-8000-00805f9b34fb']}); + //Test 20 + testCases.push({filters: [{namePrefix: 'rasp'}], optionalServices: ['12345678-1234-1234-1234-123456789abc']}); + //Test 21 + testCases.push({filters: [{namePrefix: 'rasp'}], optionalServices: ['f000ffc0-0451-4000-b000-000000000000', 0x1812]}); + + function onButtonClick(testNumber) { + clear(); + try { + log('Requesting Bluetooth Device...'); + var device = window.navigator.bluetooth.requestDevice(testCases[testNumber]); + + log('Found a device!'); + log('> Name: ' + device.name); + log('> Id: ' + device.id); + log('> Appearance: ' + device.adData.appearance); + log('> Tx Power: ' + device.adData.txPower + ' dBm'); + log('> RSSI: ' + device.adData.rssi + ' dBm'); + } catch(err) { + log(err); + } + } + + populate(testCases); + </script> +</body> +</html> diff --git a/tests/unit/gfx/Cargo.toml b/tests/unit/gfx/Cargo.toml index 6a3ad210458..060bb09b01e 100644 --- a/tests/unit/gfx/Cargo.toml +++ b/tests/unit/gfx/Cargo.toml @@ -11,5 +11,5 @@ doctest = false [dependencies] gfx = {path = "../../../components/gfx"} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" style = {path = "../../../components/style"} diff --git a/tests/unit/net/Cargo.toml b/tests/unit/net/Cargo.toml index 77da7edc652..3f87e8fe429 100644 --- a/tests/unit/net/Cargo.toml +++ b/tests/unit/net/Cargo.toml @@ -15,7 +15,7 @@ cookie = "0.2" devtools_traits = {path = "../../../components/devtools_traits"} flate2 = "0.2.0" hyper = "0.9.9" -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" msg = {path = "../../../components/msg"} net = {path = "../../../components/net"} net_traits = {path = "../../../components/net_traits"} diff --git a/tests/unit/net/fetch.rs b/tests/unit/net/fetch.rs index c59be9349d3..f2fe7500a51 100644 --- a/tests/unit/net/fetch.rs +++ b/tests/unit/net/fetch.rs @@ -2,23 +2,31 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use hyper::header::{AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowOrigin}; -use hyper::header::{AccessControlAllowMethods, AccessControlMaxAge}; -use hyper::header::{AccessControlRequestHeaders, AccessControlRequestMethod}; -use hyper::header::{CacheControl, ContentLanguage, ContentType, Expires, LastModified}; -use hyper::header::{Headers, HttpDate, Location, SetCookie, Pragma}; +use devtools_traits::DevtoolsControlMsg; +use devtools_traits::HttpRequest as DevtoolsHttpRequest; +use devtools_traits::HttpResponse as DevtoolsHttpResponse; +use http_loader::{expect_devtools_http_request, expect_devtools_http_response}; +use hyper::LanguageTag; +use hyper::header::{Accept, AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowOrigin}; +use hyper::header::{AccessControlAllowMethods, AccessControlMaxAge, AcceptLanguage, AcceptEncoding}; +use hyper::header::{AccessControlRequestHeaders, AccessControlRequestMethod, UserAgent, Date}; +use hyper::header::{CacheControl, ContentLanguage, ContentLength, ContentType, Expires, LastModified}; +use hyper::header::{Headers, HttpDate, Host, Location, SetCookie, Pragma, Encoding, qitem}; +use hyper::http::RawStatus; use hyper::method::Method; use hyper::mime::{Mime, TopLevel, SubLevel}; use hyper::server::{Handler, Listening, Server}; use hyper::server::{Request as HyperRequest, Response as HyperResponse}; use hyper::status::StatusCode; use hyper::uri::RequestUri; +use msg::constellation_msg::PipelineId; use net::fetch::cors_cache::CORSCache; use net::fetch::methods::{FetchContext, fetch, fetch_with_cors_cache}; use net::http_loader::HttpState; use net_traits::FetchTaskTarget; use net_traits::request::{Origin, RedirectMode, Referer, Request, RequestMode}; use net_traits::response::{CacheState, Response, ResponseBody, ResponseType}; +use std::borrow::Cow; use std::fs::File; use std::io::Read; use std::rc::Rc; @@ -31,16 +39,19 @@ use unicase::UniCase; use url::{Origin as UrlOrigin, Url}; use util::resource_files::resources_dir_path; +const DEFAULT_USER_AGENT: &'static str = "Such Browser. Very Layout. Wow."; + // TODO write a struct that impls Handler for storing test values struct FetchResponseCollector { sender: Sender<Response>, } -fn new_fetch_context() -> FetchContext { +fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext { FetchContext { state: HttpState::new(), - user_agent: "Such Browser. Very Layout. Wow.".into(), + user_agent: DEFAULT_USER_AGENT.into(), + devtools_chan: dc, } } impl FetchTaskTarget for FetchResponseCollector { @@ -54,14 +65,14 @@ impl FetchTaskTarget for FetchResponseCollector { } } -fn fetch_async(request: Request, target: Box<FetchTaskTarget + Send>) { +fn fetch_async(request: Request, target: Box<FetchTaskTarget + Send>, dc: Option<Sender<DevtoolsControlMsg>>) { thread::spawn(move || { - fetch(Rc::new(request), &mut Some(target), new_fetch_context()); + fetch(Rc::new(request), &mut Some(target), new_fetch_context(dc)); }); } -fn fetch_sync(request: Request) -> Response { - fetch(Rc::new(request), &mut None, new_fetch_context()) +fn fetch_sync(request: Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response { + fetch(Rc::new(request), &mut None, new_fetch_context(dc)) } fn make_server<H: Handler + 'static>(handler: H) -> (Listening, Url) { @@ -83,9 +94,9 @@ fn test_fetch_response_is_not_network_error() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); if fetch_response.is_network_error() { @@ -102,9 +113,9 @@ fn test_fetch_response_body_matches_const_message() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(!fetch_response.is_network_error()); @@ -122,9 +133,9 @@ fn test_fetch_response_body_matches_const_message() { fn test_fetch_aboutblank() { let url = Url::parse("about:blank").unwrap(); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); assert!(!fetch_response.is_network_error()); assert!(*fetch_response.body.lock().unwrap() == ResponseBody::Done(vec![])); } @@ -133,10 +144,10 @@ fn test_fetch_aboutblank() { fn test_fetch_data() { let url = Url::parse("data:text/html,<p>Servo</p>").unwrap(); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); request.same_origin_data.set(true); let expected_resp_body = "<p>Servo</p>".to_owned(); - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); assert!(!fetch_response.is_network_error()); assert_eq!(fetch_response.headers.len(), 1); @@ -162,10 +173,10 @@ fn test_fetch_file() { let url = Url::from_file_path(path.clone()).unwrap(); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); request.same_origin_data.set(true); - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); assert!(!fetch_response.is_network_error()); assert_eq!(fetch_response.headers.len(), 1); let content_type: &ContentType = fetch_response.headers.get().unwrap(); @@ -203,11 +214,11 @@ fn test_cors_preflight_fetch() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(UrlOrigin::new_opaque()); - let mut request = Request::new(url, Some(origin), false); + let mut request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; request.use_cors_preflight = true; request.mode = RequestMode::CORSMode; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(!fetch_response.is_network_error()); @@ -240,15 +251,17 @@ fn test_cors_preflight_cache_fetch() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(UrlOrigin::new_opaque()); - let mut request = Request::new(url.clone(), Some(origin.clone()), false); + let mut request = Request::new(url.clone(), Some(origin.clone()), false, None); *request.referer.borrow_mut() = Referer::NoReferer; request.use_cors_preflight = true; request.mode = RequestMode::CORSMode; let wrapped_request0 = Rc::new(request.clone()); let wrapped_request1 = Rc::new(request); - let fetch_response0 = fetch_with_cors_cache(wrapped_request0.clone(), &mut cache, &mut None, new_fetch_context()); - let fetch_response1 = fetch_with_cors_cache(wrapped_request1.clone(), &mut cache, &mut None, new_fetch_context()); + let fetch_response0 = fetch_with_cors_cache(wrapped_request0.clone(), &mut cache, + &mut None, new_fetch_context(None)); + let fetch_response1 = fetch_with_cors_cache(wrapped_request1.clone(), &mut cache, + &mut None, new_fetch_context(None)); let _ = server.close(); assert!(!fetch_response0.is_network_error() && !fetch_response1.is_network_error()); @@ -289,12 +302,12 @@ fn test_cors_preflight_fetch_network_error() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(UrlOrigin::new_opaque()); - let mut request = Request::new(url, Some(origin), false); + let mut request = Request::new(url, Some(origin), false, None); *request.method.borrow_mut() = Method::Extension("CHICKEN".to_owned()); *request.referer.borrow_mut() = Referer::NoReferer; request.use_cors_preflight = true; request.mode = RequestMode::CORSMode; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(fetch_response.is_network_error()); @@ -313,9 +326,9 @@ fn test_fetch_response_is_basic_filtered() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(!fetch_response.is_network_error()); @@ -358,10 +371,10 @@ fn test_fetch_response_is_cors_filtered() { // an origin mis-match will stop it from defaulting to a basic filtered response let origin = Origin::Origin(UrlOrigin::new_opaque()); - let mut request = Request::new(url, Some(origin), false); + let mut request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; request.mode = RequestMode::CORSMode; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(!fetch_response.is_network_error()); @@ -390,9 +403,9 @@ fn test_fetch_response_is_opaque_filtered() { // an origin mis-match will fall through to an Opaque filtered response let origin = Origin::Origin(UrlOrigin::new_opaque()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(!fetch_response.is_network_error()); @@ -437,10 +450,10 @@ fn test_fetch_response_is_opaque_redirect_filtered() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; request.redirect_mode.set(RedirectMode::Manual); - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); assert!(!fetch_response.is_network_error()); @@ -471,13 +484,13 @@ fn test_fetch_with_local_urls_only() { let do_fetch = |url: Url| { let origin = Origin::Origin(url.origin()); - let mut request = Request::new(url, Some(origin), false); + let mut request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; // Set the flag. request.local_urls_only = true; - fetch_sync(request) + fetch_sync(request, None) }; let local_url = Url::parse("about:blank").unwrap(); @@ -512,9 +525,9 @@ fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; - let fetch_response = fetch_sync(request); + let fetch_response = fetch_sync(request, None); let _ = server.close(); fetch_response } @@ -595,11 +608,11 @@ fn test_fetch_redirect_updates_method_runner(tx: Sender<bool>, status_code: Stat let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; *request.method.borrow_mut() = method; - let _ = fetch_sync(request); + let _ = fetch_sync(request, None); let _ = server.close(); } @@ -670,7 +683,7 @@ fn test_fetch_async_returns_complete_response() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; let (tx, rx) = channel(); @@ -678,7 +691,7 @@ fn test_fetch_async_returns_complete_response() { sender: tx.clone() }); - fetch_async(request, listener); + fetch_async(request, listener, None); let fetch_response = rx.recv().unwrap(); let _ = server.close(); @@ -695,7 +708,7 @@ fn test_opaque_filtered_fetch_async_returns_complete_response() { // an origin mis-match will fall through to an Opaque filtered response let origin = Origin::Origin(UrlOrigin::new_opaque()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; let (tx, rx) = channel(); @@ -703,7 +716,7 @@ fn test_opaque_filtered_fetch_async_returns_complete_response() { sender: tx.clone() }); - fetch_async(request, listener); + fetch_async(request, listener, None); let fetch_response = rx.recv().unwrap(); let _ = server.close(); @@ -735,7 +748,7 @@ fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() { let (mut server, url) = make_server(handler); let origin = Origin::Origin(url.origin()); - let request = Request::new(url, Some(origin), false); + let request = Request::new(url, Some(origin), false, None); *request.referer.borrow_mut() = Referer::NoReferer; request.redirect_mode.set(RedirectMode::Manual); @@ -744,10 +757,83 @@ fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() { sender: tx.clone() }); - fetch_async(request, listener); + fetch_async(request, listener, None); let fetch_response = rx.recv().unwrap(); let _ = server.close(); assert_eq!(fetch_response.response_type, ResponseType::OpaqueRedirect); assert_eq!(response_is_done(&fetch_response), true); } + +#[test] +fn test_fetch_with_devtools() { + static MESSAGE: &'static [u8] = b"Yay!"; + let handler = move |_: HyperRequest, response: HyperResponse| { + response.send(MESSAGE).unwrap(); + }; + + let (mut server, url) = make_server(handler); + + let origin = Origin::Origin(url.origin()); + let pipeline_id = PipelineId::fake_root_pipeline_id(); + let request = Request::new(url.clone(), Some(origin), false, Some(pipeline_id)); + *request.referer.borrow_mut() = Referer::NoReferer; + + let (devtools_chan, devtools_port) = channel::<DevtoolsControlMsg>(); + + let _ = fetch_sync(request, Some(devtools_chan)); + let _ = server.close(); + + // notification received from devtools + let devhttprequest = expect_devtools_http_request(&devtools_port); + let mut devhttpresponse = expect_devtools_http_response(&devtools_port); + + //Creating default headers for request + let mut headers = Headers::new(); + + headers.set(AcceptEncoding(vec![ + qitem(Encoding::Gzip), + qitem(Encoding::Deflate), + qitem(Encoding::EncodingExt("br".to_owned())) + ])); + + headers.set(Host { hostname: url.host_str().unwrap().to_owned() , port: url.port().to_owned() }); + + let accept = Accept(vec![qitem(Mime(TopLevel::Star, SubLevel::Star, vec![]))]); + headers.set(accept); + + let mut en_us: LanguageTag = Default::default(); + en_us.language = Some("en".to_owned()); + en_us.region = Some("US".to_owned()); + headers.set(AcceptLanguage(vec![qitem(en_us)])); + + headers.set(UserAgent(DEFAULT_USER_AGENT.to_owned())); + + let httprequest = DevtoolsHttpRequest { + url: url, + method: Method::Get, + headers: headers, + body: None, + pipeline_id: pipeline_id, + startedDateTime: devhttprequest.startedDateTime, + timeStamp: devhttprequest.timeStamp, + connect_time: devhttprequest.connect_time, + send_time: devhttprequest.send_time, + is_xhr: true, + }; + + let content = "Yay!"; + let mut response_headers = Headers::new(); + response_headers.set(ContentLength(content.len() as u64)); + devhttpresponse.headers.as_mut().unwrap().remove::<Date>(); + + let httpresponse = DevtoolsHttpResponse { + headers: Some(response_headers), + status: Some(RawStatus(200, Cow::Borrowed("OK"))), + body: None, + pipeline_id: pipeline_id, + }; + + assert_eq!(devhttprequest, httprequest); + assert_eq!(devhttpresponse, httpresponse); +} diff --git a/tests/unit/net/filemanager_thread.rs b/tests/unit/net/filemanager_thread.rs index 40549eb2101..7266157481a 100644 --- a/tests/unit/net/filemanager_thread.rs +++ b/tests/unit/net/filemanager_thread.rs @@ -2,10 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use ipc_channel::ipc::{self, IpcSender}; -use net::filemanager_thread::{FileManagerThreadFactory, UIProvider}; +use ipc_channel::ipc; +use net::filemanager_thread::{FileManager, UIProvider}; use net_traits::blob_url_store::BlobURLStoreError; -use net_traits::filemanager_thread::{FilterPattern, FileManagerThreadMsg, FileManagerThreadError}; +use net_traits::filemanager_thread::{FilterPattern, FileManagerThreadMsg, FileManagerThreadError, ReadFileProgress}; use std::fs::File; use std::io::Read; use std::path::PathBuf; @@ -16,54 +16,73 @@ struct TestProvider; impl UIProvider for TestProvider { fn open_file_dialog(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<String> { - Some("test.txt".to_string()) + Some("test.jpeg".to_string()) } fn open_file_dialog_multi(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<Vec<String>> { - Some(vec!["test.txt".to_string()]) + Some(vec!["test.jpeg".to_string()]) } } #[test] fn test_filemanager() { - let chan: IpcSender<FileManagerThreadMsg> = FileManagerThreadFactory::new(TEST_PROVIDER); + let filemanager = FileManager::new(TEST_PROVIDER); - // Try to open a dummy file "tests/unit/net/test.txt" in tree - let mut handler = File::open("test.txt").expect("test.txt is stolen"); + // Try to open a dummy file "tests/unit/net/test.jpeg" in tree + let mut handler = File::open("test.jpeg").expect("test.jpeg is stolen"); let mut test_file_content = vec![]; handler.read_to_end(&mut test_file_content) - .expect("Read tests/unit/net/test.txt error"); + .expect("Read tests/unit/net/test.jpeg error"); let patterns = vec![FilterPattern(".txt".to_string())]; let origin = "test.com".to_string(); { - // Try to select a dummy file "tests/unit/net/test.txt" + // Try to select a dummy file "tests/unit/net/test.jpeg" let (tx, rx) = ipc::channel().unwrap(); - chan.send(FileManagerThreadMsg::SelectFile(patterns.clone(), tx, origin.clone(), None)).unwrap(); + filemanager.handle(FileManagerThreadMsg::SelectFile(patterns.clone(), tx, origin.clone(), None), None); let selected = rx.recv().expect("Broken channel") - .expect("The file manager failed to find test.txt"); + .expect("The file manager failed to find test.jpeg"); // Expecting attributes conforming the spec - assert!(selected.filename == PathBuf::from("test.txt")); - assert!(selected.type_string == "text/plain".to_string()); + assert_eq!(selected.filename, PathBuf::from("test.jpeg")); + assert_eq!(selected.type_string, "image/jpeg".to_string()); // Test by reading, expecting same content { let (tx2, rx2) = ipc::channel().unwrap(); - chan.send(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone(), false, origin.clone())).unwrap(); + filemanager.handle(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone(), false, origin.clone()), None); let msg = rx2.recv().expect("Broken channel"); - let blob_buf = msg.expect("File manager reading failure is unexpected"); - assert_eq!(test_file_content, blob_buf.bytes, "Read content differs"); + if let ReadFileProgress::Meta(blob_buf) = msg.expect("File manager reading failure is unexpected") { + let mut bytes = blob_buf.bytes; + + loop { + match rx2.recv().expect("Broken channel").expect("File manager reading failure is unexpected") { + ReadFileProgress::Meta(_) => { + panic!("Invalid FileManager reply"); + } + ReadFileProgress::Partial(mut bytes_in) => { + bytes.append(&mut bytes_in); + } + ReadFileProgress::EOF => { + break; + } + } + } + + assert_eq!(test_file_content, bytes, "Read content differs"); + } else { + panic!("Invalid FileManager reply"); + } } // Delete the id { let (tx2, rx2) = ipc::channel().unwrap(); - chan.send(FileManagerThreadMsg::DecRef(selected.id.clone(), origin.clone(), tx2)).unwrap(); + filemanager.handle(FileManagerThreadMsg::DecRef(selected.id.clone(), origin.clone(), tx2), None); let ret = rx2.recv().expect("Broken channel"); assert!(ret.is_ok(), "DecRef is not okay"); @@ -72,7 +91,7 @@ fn test_filemanager() { // Test by reading again, expecting read error because we invalidated the id { let (tx2, rx2) = ipc::channel().unwrap(); - chan.send(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone(), false, origin.clone())).unwrap(); + filemanager.handle(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone(), false, origin.clone()), None); let msg = rx2.recv().expect("Broken channel"); @@ -84,13 +103,4 @@ fn test_filemanager() { } } } - - let _ = chan.send(FileManagerThreadMsg::Exit); - - { - let (tx, rx) = ipc::channel().unwrap(); - let _ = chan.send(FileManagerThreadMsg::SelectFile(patterns.clone(), tx, origin.clone(), None)); - - assert!(rx.try_recv().is_err(), "The thread should not respond normally after exited"); - } } diff --git a/tests/unit/net/http_loader.rs b/tests/unit/net/http_loader.rs index dad9d3d945c..53f79178aab 100644 --- a/tests/unit/net/http_loader.rs +++ b/tests/unit/net/http_loader.rs @@ -339,7 +339,7 @@ impl HttpRequest for AssertMustHaveBodyRequest { } } -fn expect_devtools_http_request(devtools_port: &Receiver<DevtoolsControlMsg>) -> DevtoolsHttpRequest { +pub fn expect_devtools_http_request(devtools_port: &Receiver<DevtoolsControlMsg>) -> DevtoolsHttpRequest { match devtools_port.recv().unwrap() { DevtoolsControlMsg::FromChrome( ChromeToDevtoolsControlMsg::NetworkEvent(_, net_event)) => { @@ -355,7 +355,7 @@ fn expect_devtools_http_request(devtools_port: &Receiver<DevtoolsControlMsg>) -> } } -fn expect_devtools_http_response(devtools_port: &Receiver<DevtoolsControlMsg>) -> DevtoolsHttpResponse { +pub fn expect_devtools_http_response(devtools_port: &Receiver<DevtoolsControlMsg>) -> DevtoolsHttpResponse { match devtools_port.recv().unwrap() { DevtoolsControlMsg::FromChrome( ChromeToDevtoolsControlMsg::NetworkEvent(_, net_event_response)) => { @@ -526,6 +526,7 @@ fn test_request_and_response_data_with_network_messages() { timeStamp: devhttprequest.timeStamp, connect_time: devhttprequest.connect_time, send_time: devhttprequest.send_time, + is_xhr: false, }; let content = "Yay!"; @@ -586,6 +587,52 @@ fn test_request_and_response_message_from_devtool_without_pipeline_id() { assert!(devtools_port.try_recv().is_err()); } +#[test] +fn test_redirected_request_to_devtools() { + struct Factory; + + impl HttpRequestFactory for Factory { + type R = MockRequest; + + fn create(&self, url: Url, method: Method, _: Headers) -> Result<MockRequest, LoadError> { + if url.domain().unwrap() == "mozilla.com" { + assert_eq!(Method::Post, method); + Ok(MockRequest::new(ResponseType::Redirect("http://mozilla.org".to_owned()))) + } else { + assert_eq!(Method::Get, method); + Ok(MockRequest::new(ResponseType::Text(<[_]>::to_vec("Yay!".as_bytes())))) + } + } + } + + let url = Url::parse("http://mozilla.com").unwrap(); + let mut load_data = LoadData::new(LoadContext::Browsing, url.clone(), &HttpTest); + + load_data.method = Method::Post; + + let http_state = HttpState::new(); + let ui_provider = TestProvider::new(); + let (devtools_chan, devtools_port) = mpsc::channel::<DevtoolsControlMsg>(); + + let _ = load(&load_data, &ui_provider, &http_state, Some(devtools_chan), &Factory, + DEFAULT_USER_AGENT.to_owned(), &CancellationListener::new(None), None); + + let devhttprequest = expect_devtools_http_request(&devtools_port); + let devhttpresponse = expect_devtools_http_response(&devtools_port); + + assert!(devhttprequest.method == Method::Post); + assert!(devhttprequest.url == url); + assert!(devhttpresponse.status == Some(RawStatus(301, Cow::Borrowed("Moved Permanently")))); + + let devhttprequest = expect_devtools_http_request(&devtools_port); + let devhttpresponse = expect_devtools_http_response(&devtools_port); + let url = Url::parse("http://mozilla.org").unwrap(); + + assert!(devhttprequest.method == Method::Get); + assert!(devhttprequest.url == url); + assert!(devhttpresponse.status == Some(RawStatus(200, Cow::Borrowed("Ok")))); +} + #[test] diff --git a/tests/unit/net/resource_thread.rs b/tests/unit/net/resource_thread.rs index 1820ea73039..b6da4f4f524 100644 --- a/tests/unit/net/resource_thread.rs +++ b/tests/unit/net/resource_thread.rs @@ -4,7 +4,6 @@ use ipc_channel::ipc; use msg::constellation_msg::{PipelineId, ReferrerPolicy}; -use net::filemanager_thread::{FileManagerThreadFactory, TFDProvider}; use net::resource_thread::new_core_resource_thread; use net_traits::hosts::{parse_hostsfile, host_replacement}; use net_traits::{CoreResourceMsg, LoadData, LoadConsumer, LoadContext}; @@ -16,8 +15,6 @@ use std::net::IpAddr; use std::sync::mpsc::channel; use url::Url; -const TFD_PROVIDER: &'static TFDProvider = &TFDProvider; - fn ip(s: &str) -> IpAddr { s.parse().unwrap() } @@ -40,8 +37,8 @@ impl LoadOrigin for ResourceTest { fn test_exit() { let (tx, _rx) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap(); - let filemanager_chan = FileManagerThreadFactory::new(TFD_PROVIDER); - let (resource_thread, _) = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx), filemanager_chan); + let (resource_thread, _) = new_core_resource_thread( + "".to_owned(), None, ProfilerChan(tx), None); resource_thread.send(CoreResourceMsg::Exit(sender)).unwrap(); receiver.recv().unwrap(); } @@ -50,8 +47,8 @@ fn test_exit() { fn test_bad_scheme() { let (tx, _rx) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap(); - let filemanager_chan = FileManagerThreadFactory::new(TFD_PROVIDER); - let (resource_thread, _) = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx), filemanager_chan); + let (resource_thread, _) = new_core_resource_thread( + "".to_owned(), None, ProfilerChan(tx), None); let (start_chan, start) = ipc::channel().unwrap(); let url = Url::parse("bogus://whatever").unwrap(); resource_thread.send(CoreResourceMsg::Load(LoadData::new(LoadContext::Browsing, url, &ResourceTest), @@ -230,8 +227,8 @@ fn test_cancelled_listener() { let (tx, _rx) = ipc::channel().unwrap(); let (exit_sender, exit_receiver) = ipc::channel().unwrap(); - let filemanager_chan = FileManagerThreadFactory::new(TFD_PROVIDER); - let (resource_thread, _) = new_core_resource_thread("".to_owned(), None, ProfilerChan(tx), filemanager_chan); + let (resource_thread, _) = new_core_resource_thread( + "".to_owned(), None, ProfilerChan(tx), None); let (sender, receiver) = ipc::channel().unwrap(); let (id_sender, id_receiver) = ipc::channel().unwrap(); let (sync_sender, sync_receiver) = ipc::channel().unwrap(); diff --git a/tests/unit/net/test.jpeg b/tests/unit/net/test.jpeg Binary files differindex 1a0bdb7acd1..08f084cf549 100644 --- a/tests/unit/net/test.jpeg +++ b/tests/unit/net/test.jpeg diff --git a/tests/unit/net/test.txt b/tests/unit/net/test.txt deleted file mode 100644 index 75bdfe4ef1c..00000000000 --- a/tests/unit/net/test.txt +++ /dev/null @@ -1 +0,0 @@ -hello, servo
\ No newline at end of file diff --git a/tests/unit/profile/Cargo.toml b/tests/unit/profile/Cargo.toml index f8f9b8de25e..0c79370271c 100644 --- a/tests/unit/profile/Cargo.toml +++ b/tests/unit/profile/Cargo.toml @@ -12,4 +12,4 @@ doctest = false [dependencies] profile = {path = "../../../components/profile"} profile_traits = {path = "../../../components/profile_traits"} -ipc-channel = {git = "https://github.com/servo/ipc-channel"} +ipc-channel = "0.4.0" diff --git a/tests/unit/style/attr.rs b/tests/unit/style/attr.rs index 4ae614eae2d..0521df3a690 100644 --- a/tests/unit/style/attr.rs +++ b/tests/unit/style/attr.rs @@ -15,6 +15,24 @@ fn test_parse_double() { } #[test] +fn test_parse_double_negative_prefix() { + let value = String::from("-5.6"); + match AttrValue::from_double(value, 0.0) { + AttrValue::Double(_, num) => assert_eq!(num, -5.6f64), + _ => panic!("expected a double value") + } +} + +#[test] +fn test_parse_double_positive_prefix() { + let value = String::from("+5.6"); + match AttrValue::from_double(value, 0.0) { + AttrValue::Double(_, num) => assert_eq!(num, 5.6f64), + _ => panic!("expected a double value") + } +} + +#[test] fn test_from_limited_i32_should_be_default_when_less_than_0() { let value = String::from("-1"); match AttrValue::from_limited_i32(value, 0) { diff --git a/tests/unit/util/lib.rs b/tests/unit/util/lib.rs index 1ad4e55d965..96506d5973c 100644 --- a/tests/unit/util/lib.rs +++ b/tests/unit/util/lib.rs @@ -8,4 +8,5 @@ extern crate util; mod opts; mod prefs; +mod remutex; mod thread; diff --git a/tests/unit/util/remutex.rs b/tests/unit/util/remutex.rs new file mode 100644 index 00000000000..a005d761d5f --- /dev/null +++ b/tests/unit/util/remutex.rs @@ -0,0 +1,89 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// These tests came from https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/remutex.rs + +use std::cell::RefCell; +use std::sync::Arc; +use std::thread; +use util::remutex::{ReentrantMutex, ReentrantMutexGuard}; + +#[test] +fn smoke() { + let m = ReentrantMutex::new(()); + { + let a = m.lock().unwrap(); + { + let b = m.lock().unwrap(); + { + let c = m.lock().unwrap(); + assert_eq!(*c, ()); + } + assert_eq!(*b, ()); + } + assert_eq!(*a, ()); + } +} + +#[test] +fn is_mutex() { + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + let m2 = m.clone(); + let lock = m.lock().unwrap(); + let child = thread::spawn(move || { + let lock = m2.lock().unwrap(); + assert_eq!(*lock.borrow(), 4950); + }); + for i in 0..100 { + let lock = m.lock().unwrap(); + *lock.borrow_mut() += i; + } + drop(lock); + child.join().unwrap(); +} + +#[test] +fn trylock_works() { + let m = Arc::new(ReentrantMutex::new(())); + let m2 = m.clone(); + let _lock = m.try_lock().unwrap(); + let _lock2 = m.try_lock().unwrap(); + thread::spawn(move || { + let lock = m2.try_lock(); + assert!(lock.is_err()); + }).join().unwrap(); + let _lock3 = m.try_lock().unwrap(); +} + +pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>); +impl<'a> Drop for Answer<'a> { + fn drop(&mut self) { + *self.0.borrow_mut() = 42; + } +} + +#[test] +fn poison_works() { + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + let mc = m.clone(); + let result = thread::spawn(move ||{ + let lock = mc.lock().unwrap(); + *lock.borrow_mut() = 1; + let lock2 = mc.lock().unwrap(); + *lock.borrow_mut() = 2; + let _answer = Answer(lock2); + println!("Intentionally panicking."); + panic!("What the answer to my lifetimes dilemma is?"); + }).join(); + assert!(result.is_err()); + let r = m.lock().err().unwrap().into_inner(); + assert_eq!(*r.borrow(), 42); +} + diff --git a/tests/wpt/README.md b/tests/wpt/README.md index e0aa6406c41..76073333c46 100644 --- a/tests/wpt/README.md +++ b/tests/wpt/README.md @@ -77,6 +77,18 @@ first adding the following to the system's hosts file: and then running `python serve` from `tests/wpt/web-platform-tests`. Then navigate Servo to `http://web-platform.test:8000/path/to/test`. +Running the tests in Firefox +---------------------------- + +When working with tests, you may want to compare Servo's result with Firefox. +You can supply `--product firefox` along with the path to a Firefox binary (as +well as few more odds and ends) to run tests in Firefox from your Servo +checkout: + + GECKO="$HOME/projects/mozilla/gecko" + GECKO_BINS="$GECKO/obj-firefox-release-artifact/dist/Nightly.app/Contents/MacOS" + ./mach test-wpt dom --product firefox --binary $GECKO_BINS/firefox --certutil-binary $GECKO_BINS/certutil --prefs-root $GECKO/testing/profiles + Updating test expectations ========================== @@ -191,5 +203,4 @@ MANIFEST.json can be regenerated automatically with the mach command `update-man This is equivalent to running - ./mach test-wpt --manifest-update SKIP_TESTS - + ./mach test-wpt --manifest-update SKIP_TESTS diff --git a/tests/wpt/config.ini b/tests/wpt/config.ini index abd24963da4..7673f0aab8e 100644 --- a/tests/wpt/config.ini +++ b/tests/wpt/config.ini @@ -1,6 +1,7 @@ [products] servo = servodriver = +firefox = [web-platform-tests] remote_url = https://github.com/w3c/web-platform-tests.git diff --git a/tests/wpt/include.ini b/tests/wpt/include.ini index d37502e0356..867bfa03b5c 100644 --- a/tests/wpt/include.ini +++ b/tests/wpt/include.ini @@ -17,6 +17,12 @@ skip: true skip: false [eventsource] skip: false +[fetch] + skip: true + [api] + skip: true + [headers] + skip: false [FileAPI] skip: false [hr-time] diff --git a/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transforms-3d-on-anonymous-block-001.htm.ini b/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transforms-3d-on-anonymous-block-001.htm.ini index 605b45575ea..09c75600242 100644 --- a/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transforms-3d-on-anonymous-block-001.htm.ini +++ b/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transforms-3d-on-anonymous-block-001.htm.ini @@ -1,4 +1,2 @@ [css-transforms-3d-on-anonymous-block-001.htm] type: reftest - expected: - if os == "linux": FAIL diff --git a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform-input-019.htm.ini b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform-input-019.htm.ini index e82b6718013..8e2a7b49f90 100644 --- a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform-input-019.htm.ini +++ b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform-input-019.htm.ini @@ -1,3 +1,4 @@ [transform-input-019.htm] type: reftest - expected: FAIL + expected: + if os == "linux": FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-002.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-002.htm.ini deleted file mode 100644 index ea6943c1c80..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-002.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[margin-collapse-clear-002.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-003.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-003.htm.ini deleted file mode 100644 index ef6e83de26c..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-003.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[margin-collapse-clear-003.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-008.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-008.htm.ini deleted file mode 100644 index 4a1f3812c59..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-008.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[margin-collapse-clear-008.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-009.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-009.htm.ini deleted file mode 100644 index 62b047475e6..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/margin-collapse-clear-009.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[margin-collapse-clear-009.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/FileAPI/FileReaderSync.worker.js.ini b/tests/wpt/metadata/FileAPI/FileReaderSync.worker.js.ini index 3e0c3c418dc..249873f6547 100644 --- a/tests/wpt/metadata/FileAPI/FileReaderSync.worker.js.ini +++ b/tests/wpt/metadata/FileAPI/FileReaderSync.worker.js.ini @@ -1,9 +1,5 @@ [FileReaderSync.worker] type: testharness - expected: ERROR - [Interface] - expected: FAIL - [readAsText] expected: FAIL diff --git a/tests/wpt/metadata/FileAPI/blob/Blob-XHR-revoke.html.ini b/tests/wpt/metadata/FileAPI/blob/Blob-XHR-revoke.html.ini index b7e66c83a20..6fb7d0ba5ca 100644 --- a/tests/wpt/metadata/FileAPI/blob/Blob-XHR-revoke.html.ini +++ b/tests/wpt/metadata/FileAPI/blob/Blob-XHR-revoke.html.ini @@ -2,4 +2,3 @@ type: testharness expected: CRASH bug: https://github.com/servo/servo/issues/10539 - diff --git a/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini b/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini index d9c18b41655..1134394834f 100644 --- a/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini +++ b/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini @@ -12,7 +12,3 @@ expected: FAIL bug: https://github.com/servo/servo/issues/10911 - [Using special character in fileName] - expected: FAIL - bug: https://github.com/w3c/FileAPI/issues/41 - diff --git a/tests/wpt/metadata/FileAPI/idlharness.html.ini b/tests/wpt/metadata/FileAPI/idlharness.html.ini index 1957439c798..a2b56459bec 100644 --- a/tests/wpt/metadata/FileAPI/idlharness.html.ini +++ b/tests/wpt/metadata/FileAPI/idlharness.html.ini @@ -30,3 +30,12 @@ [FileReader interface: calling readAsArrayBuffer(Blob) on new FileReader() with too few arguments must throw TypeError] expected: FAIL + [FileReader interface: operation readAsBinaryString(Blob)] + expected: FAIL + + [FileReader interface: new FileReader() must inherit property "readAsBinaryString" with the proper type (1)] + expected: FAIL + + [FileReader interface: calling readAsBinaryString(Blob) on new FileReader() with too few arguments must throw TypeError] + expected: FAIL + diff --git a/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini b/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini index 2123dd254f3..1c1a2484345 100644 --- a/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini +++ b/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini @@ -12,18 +12,6 @@ [FileReader interface: calling readAsArrayBuffer(Blob) on new FileReader() with too few arguments must throw TypeError] expected: FAIL - [FileReaderSync interface: existence and properties of interface object] - expected: FAIL - - [FileReaderSync interface object length] - expected: FAIL - - [FileReaderSync interface: existence and properties of interface prototype object] - expected: FAIL - - [FileReaderSync interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - [FileReaderSync interface: operation readAsArrayBuffer(Blob)] expected: FAIL @@ -33,12 +21,6 @@ [FileReaderSync interface: operation readAsDataURL(Blob)] expected: FAIL - [FileReaderSync must be primary interface of new FileReaderSync()] - expected: FAIL - - [Stringification of new FileReaderSync()] - expected: FAIL - [FileReaderSync interface: new FileReaderSync() must inherit property "readAsArrayBuffer" with the proper type (0)] expected: FAIL @@ -57,9 +39,6 @@ [FileReaderSync interface: calling readAsDataURL(Blob) on new FileReaderSync() with too few arguments must throw TypeError] expected: FAIL - [FileReaderSync interface object name] - expected: FAIL - [Window interface: existence and properties of interface object] expected: FAIL @@ -75,15 +54,27 @@ [Event interface: existence and properties of interface object] expected: FAIL - [Blob interface: existence and properties of interface object] + [FileReader interface: operation readAsBinaryString(Blob)] + expected: FAIL + + [FileReader interface: new FileReader() must inherit property "readAsBinaryString" with the proper type (1)] + expected: FAIL + + [FileReader interface: calling readAsBinaryString(Blob) on new FileReader() with too few arguments must throw TypeError] + expected: FAIL + + [FileReaderSync interface: operation readAsBinaryString(Blob)] + expected: FAIL + + [FileReaderSync interface: new FileReaderSync() must inherit property "readAsBinaryString" with the proper type (1)] expected: FAIL - [File interface: existence and properties of interface object] + [FileReaderSync interface: calling readAsBinaryString(Blob) on new FileReaderSync() with too few arguments must throw TypeError] expected: FAIL - [FileList interface: existence and properties of interface object] + [FileReaderSync interface: new FileReaderSync() must inherit property "readAsText" with the proper type (2)] expected: FAIL - [FileReader interface: existence and properties of interface object] + [FileReaderSync interface: new FileReaderSync() must inherit property "readAsDataURL" with the proper type (3)] expected: FAIL diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index cb936f17478..5606390b636 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -15226,6 +15226,10 @@ "url": "/dom/nodes/prepend-on-Document.html" }, { + "path": "dom/nodes/remove-row.html", + "url": "/dom/nodes/remove-row.html" + }, + { "path": "dom/nodes/remove-unscopable.html", "url": "/dom/nodes/remove-unscopable.html" }, @@ -37201,15 +37205,29 @@ ] }, "local_changes": { - "deleted": [], + "deleted": [ + "dom/nodes/remove-row.html" + ], "deleted_reftests": {}, "items": { "testharness": { + "html/semantics/interactive-elements/the-dialog-element/dialog-open.html": [ + { + "path": "html/semantics/interactive-elements/the-dialog-element/dialog-open.html", + "url": "/html/semantics/interactive-elements/the-dialog-element/dialog-open.html" + } + ], "html/semantics/scripting-1/the-script-element/script-charset-03.html": [ { "path": "html/semantics/scripting-1/the-script-element/script-charset-03.html", "url": "/html/semantics/scripting-1/the-script-element/script-charset-03.html" } + ], + "html/semantics/tabular-data/the-table-element/remove-row.html": [ + { + "path": "html/semantics/tabular-data/the-table-element/remove-row.html", + "url": "/html/semantics/tabular-data/the-table-element/remove-row.html" + } ] } }, diff --git a/tests/wpt/metadata/dom/nodes/getElementsByClassName-21.htm.ini b/tests/wpt/metadata/dom/nodes/getElementsByClassName-21.htm.ini deleted file mode 100644 index 143ad1185c4..00000000000 --- a/tests/wpt/metadata/dom/nodes/getElementsByClassName-21.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[getElementsByClassName-21.htm] - type: testharness - [delete element from collection] - expected: FAIL - diff --git a/tests/wpt/metadata/fetch/api/headers/headers-basic.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-basic.html.ini new file mode 100644 index 00000000000..16379eaa71a --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-basic.html.ini @@ -0,0 +1,44 @@ +[headers-basic.html] + type: testharness + [Create headers from empty object] + expected: FAIL + + [Create headers with sequence] + expected: FAIL + + [Create headers with OpenEndedDictionary] + expected: FAIL + + [Create headers with existing headers] + expected: FAIL + + [Check append method] + expected: FAIL + + [Check set method] + expected: FAIL + + [Check has method] + expected: FAIL + + [Check delete method] + expected: FAIL + + [Check get method] + expected: FAIL + + [Check keys method] + expected: FAIL + + [Check values method] + expected: FAIL + + [Check entries method] + expected: FAIL + + [Check Symbol.iterator method] + expected: FAIL + + [Check forEach method] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/headers/headers-casing.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-casing.html.ini new file mode 100644 index 00000000000..c9b0c365129 --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-casing.html.ini @@ -0,0 +1,14 @@ +[headers-casing.html] + type: testharness + [Create headers, names use characters with different case] + expected: FAIL + + [Check append method, names use characters with different case] + expected: FAIL + + [Check set method, names use characters with different case] + expected: FAIL + + [Check delete method, names use characters with different case] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/headers/headers-combine.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-combine.html.ini new file mode 100644 index 00000000000..1403b64a1c8 --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-combine.html.ini @@ -0,0 +1,14 @@ +[headers-combine.html] + type: testharness + [Create headers using same name for different values] + expected: FAIL + + [Check delete and has methods when using same name for different values] + expected: FAIL + + [Check set methods when called with already used name] + expected: FAIL + + [Check append methods when called with already used name] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/headers/headers-errors.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-errors.html.ini new file mode 100644 index 00000000000..96439e158ec --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-errors.html.ini @@ -0,0 +1,8 @@ +[headers-errors.html] + type: testharness + [Headers forEach throws if argument is not callable] + expected: FAIL + + [Headers forEach loop should stop if callback is throwing exception] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/headers/headers-idl.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-idl.html.ini new file mode 100644 index 00000000000..5a6cbcf6505 --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-idl.html.ini @@ -0,0 +1,3 @@ +[headers-idl.html] + type: testharness + expected: TIMEOUT diff --git a/tests/wpt/metadata/fetch/api/headers/headers-normalize.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-normalize.html.ini new file mode 100644 index 00000000000..1ba80cd1437 --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-normalize.html.ini @@ -0,0 +1,11 @@ +[headers-normalize.html] + type: testharness + [Create headers with not normalized values] + expected: FAIL + + [Check append method whith not normalized values] + expected: FAIL + + [Check set method whith not normalized values] + expected: FAIL + diff --git a/tests/wpt/metadata/fetch/api/headers/headers-structure.html.ini b/tests/wpt/metadata/fetch/api/headers/headers-structure.html.ini new file mode 100644 index 00000000000..6c517acf6ab --- /dev/null +++ b/tests/wpt/metadata/fetch/api/headers/headers-structure.html.ini @@ -0,0 +1,12 @@ +[headers-structure.html] + type: testharness + expected: OK + [Headers has entries method] + expected: FAIL + + [Headers has keys method] + expected: FAIL + + [Headers has values method] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html.ini deleted file mode 100644 index bd6d242444a..00000000000 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/PopStateEvent.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[PopStateEvent.html] - type: testharness - [Dispatching a synthetic PopStateEvent] - expected: FAIL - diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/browsing_context_name_cross_origin.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/browsing_context_name_cross_origin.html.ini index ee105e85389..2dac566a5d3 100644 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/browsing_context_name_cross_origin.html.ini +++ b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/browsing_context_name_cross_origin.html.ini @@ -1,5 +1,3 @@ [browsing_context_name_cross_origin.html] type: testharness - [Restoring window.name on cross-origin history traversal] - expected: FAIL - + disabled: see https://github.com/whatwg/html/issues/490 diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-basic.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-basic.html.ini index 3e73c51da3a..5e99880706b 100644 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-basic.html.ini +++ b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-basic.html.ini @@ -3,9 +3,6 @@ [Default value is "auto"] expected: FAIL - [It is writable] - expected: FAIL - [Invalid values are ignored] expected: FAIL diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/001.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/001.html.ini index b3538369e2e..46c10baad28 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/001.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/001.html.ini @@ -1,3 +1,101 @@ [001.html] type: testharness - expected: TIMEOUT + [history.length should update when loading pages in an iframe] + expected: FAIL + + [history.length should update when setting location.hash] + expected: FAIL + + [history.pushState must exist] + expected: FAIL + + [history.pushState must exist within iframes] + expected: FAIL + + [initial history.state should be null] + expected: FAIL + + [history.length should update when pushing a state] + expected: FAIL + + [history.state should update after a state is pushed] + expected: FAIL + + [traversing history must traverse pushed states] + expected: FAIL + + [pushState must not be allowed to create invalid URLs] + expected: FAIL + + [pushState must not be allowed to create cross-origin URLs] + expected: FAIL + + [pushState must not be allowed to create cross-origin URLs (about:blank)] + expected: FAIL + + [pushState must not be allowed to create cross-origin URLs (data:URI)] + expected: FAIL + + [security errors are expected to be thrown in the context of the document that owns the history object] + expected: FAIL + + [location.hash must be allowed to change (part 1)] + expected: FAIL + + [location.hash must be allowed to change (part 2)] + expected: FAIL + + [pushState must not alter location.hash when no URL is provided] + expected: FAIL + + [pushState must remove all history after the current state] + expected: FAIL + + [pushState must be able to set location.hash] + expected: FAIL + + [pushState must remove any tasks queued by the history traversal task source] + expected: FAIL + + [pushState must be able to set location.pathname] + expected: FAIL + + [pushState must be able to set absolute URLs to the same host] + expected: FAIL + + [pushState must not be able to use a function as data] + expected: FAIL + + [pushState must not be able to use a DOM node as data] + expected: FAIL + + [pushState must not be able to use an error object as data] + expected: FAIL + + [security errors are expected to be thrown in the context of the document that owns the history object (2)] + expected: FAIL + + [pushState must be able to make structured clones of complex objects] + expected: FAIL + + [history.state should also reference a clone of the original object] + expected: FAIL + + [popstate event should fire when navigation occurs] + expected: FAIL + + [popstate event should pass the state data] + expected: FAIL + + [state data should cope with circular object references] + expected: FAIL + + [state data should be a clone of the original object, not a reference to it] + expected: FAIL + + [history.state should also reference a clone of the original object (2)] + expected: FAIL + + [history.state should be a separate clone of the object, not a reference to the object passed to the event handler] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/002.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/002.html.ini index 29a2058d988..1228df18521 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/002.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/002.html.ini @@ -1,3 +1,98 @@ [002.html] type: testharness - expected: TIMEOUT + [history.length should update when loading pages in an iframe] + expected: FAIL + + [history.length should update when setting location.hash] + expected: FAIL + + [history.replaceState must exist] + expected: FAIL + + [history.replaceState must exist within iframes] + expected: FAIL + + [initial history.state should be null] + expected: FAIL + + [history.length should not update when replacing a state with no URL] + expected: FAIL + + [history.state should update after a state is pushed] + expected: FAIL + + [hash should not change when replaceState is called without a URL] + expected: FAIL + + [history.length should not update when replacing a state with a URL] + expected: FAIL + + [hash should change when replaceState is called with a URL] + expected: FAIL + + [replaceState must replace the existing state without altering the forward history] + expected: FAIL + + [replaceState must not be allowed to create invalid URLs] + expected: FAIL + + [replaceState must not be allowed to create cross-origin URLs] + expected: FAIL + + [replaceState must not be allowed to create cross-origin URLs (about:blank)] + expected: FAIL + + [replaceState must not be allowed to create cross-origin URLs (data:URI)] + expected: FAIL + + [security errors are expected to be thrown in the context of the document that owns the history object] + expected: FAIL + + [replaceState must be able to set location.pathname] + expected: FAIL + + [replaceState must be able to set absolute URLs to the same host] + expected: FAIL + + [replaceState must not remove any tasks queued by the history traversal task source] + expected: FAIL + + [.go must queue a task with the history traversal task source (run asynchronously)] + expected: FAIL + + [replaceState must not be able to use a function as data] + expected: FAIL + + [replaceState must not be able to use a DOM node as data] + expected: FAIL + + [replaceState must not be able to use an error object as data] + expected: FAIL + + [security errors are expected to be thrown in the context of the document that owns the history object (2)] + expected: FAIL + + [replaceState must be able to make structured clones of complex objects] + expected: FAIL + + [history.state should also reference a clone of the original object] + expected: FAIL + + [popstate event should fire when navigation occurs] + expected: FAIL + + [popstate event should pass the state data] + expected: FAIL + + [state data should cope with circular object references] + expected: FAIL + + [state data should be a clone of the original object, not a reference to it] + expected: FAIL + + [history.state should also reference a clone of the original object (2)] + expected: FAIL + + [history.state should be a separate clone of the object, not a reference to the object passed to the event handler] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini index 2c1c228a251..fa42d1a0762 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini @@ -1,3 +1,11 @@ [004.html] type: testharness - expected: TIMEOUT + [.go commands should be queued until the thread has ended] + expected: FAIL + + [browser needs to support hashchange events for this testcase] + expected: FAIL + + [queued .go commands should all be executed when the queue is processed] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/005.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/005.html.ini index 4982b00f15c..76099606688 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/005.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/005.html.ini @@ -1,6 +1,11 @@ [005.html] type: testharness - expected: TIMEOUT [history.pushState support is needed for this testcase] expected: FAIL + [<body onpopstate="..."> should register a listener for the popstate event] + expected: FAIL + + [window.onpopstate should register a listener for the popstate event] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/007.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/007.html.ini index e346ad78fcf..5c3b95e454e 100644 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/007.html.ini +++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/007.html.ini @@ -1,6 +1,5 @@ [007.html] type: testharness - expected: TIMEOUT [history.state should initially be null] expected: FAIL @@ -10,3 +9,15 @@ [history.state should reflect pushed state] expected: FAIL + [popstate event should fire before onload fires] + expected: FAIL + + [the correct state should be restored when navigating during initial load] + expected: FAIL + + [history.state should reflect the navigated state onload] + expected: FAIL + + [history.state should reflect the navigated state after onload] + expected: FAIL + diff --git a/tests/wpt/metadata/html/browsers/history/the-location-interface/location_assign_about_blank.html.ini b/tests/wpt/metadata/html/browsers/history/the-location-interface/location_assign_about_blank.html.ini deleted file mode 100644 index c144ee2f49f..00000000000 --- a/tests/wpt/metadata/html/browsers/history/the-location-interface/location_assign_about_blank.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[location_assign_about_blank.html] - type: testharness - [location.assign with initial about:blank browsing context] - expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index 63aaf524f22..9cf7bd0c315 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -1572,15 +1572,9 @@ [HTMLUListElement interface: attribute type] expected: FAIL - [HTMLLIElement interface: attribute value] - expected: FAIL - [HTMLLIElement interface: attribute type] expected: FAIL - [HTMLLIElement interface: document.createElement("li") must inherit property "value" with the proper type (0)] - expected: FAIL - [HTMLLIElement interface: document.createElement("li") must inherit property "type" with the proper type (1)] expected: FAIL @@ -3237,9 +3231,6 @@ [HTMLAreaElement interface: document.createElement("area") must inherit property "noHref" with the proper type (10)] expected: FAIL - [HTMLTableElement interface: operation deleteRow(long)] - expected: FAIL - [HTMLTableElement interface: attribute sortable] expected: FAIL @@ -3267,12 +3258,6 @@ [HTMLTableElement interface: attribute cellSpacing] expected: FAIL - [HTMLTableElement interface: document.createElement("table") must inherit property "deleteRow" with the proper type (13)] - expected: FAIL - - [HTMLTableElement interface: calling deleteRow(long) on document.createElement("table") with too few arguments must throw TypeError] - expected: FAIL - [HTMLTableElement interface: document.createElement("table") must inherit property "sortable" with the proper type (14)] expected: FAIL @@ -5613,45 +5598,18 @@ [BarProp interface: attribute visible] expected: FAIL - [History interface: existence and properties of interface object] - expected: FAIL - - [History interface object length] - expected: FAIL - - [History interface: existence and properties of interface prototype object] - expected: FAIL - - [History interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - [History interface: attribute length] expected: FAIL [History interface: attribute state] expected: FAIL - [History interface: operation go(long)] - expected: FAIL - - [History interface: operation back()] - expected: FAIL - - [History interface: operation forward()] - expected: FAIL - [History interface: operation pushState(any,DOMString,DOMString)] expected: FAIL [History interface: operation replaceState(any,DOMString,DOMString)] expected: FAIL - [History must be primary interface of window.history] - expected: FAIL - - [Stringification of window.history] - expected: FAIL - [History interface: window.history must inherit property "length" with the proper type (0)] expected: FAIL @@ -5661,9 +5619,6 @@ [History interface: window.history must inherit property "go" with the proper type (2)] expected: FAIL - [History interface: calling go(long) on window.history with too few arguments must throw TypeError] - expected: FAIL - [History interface: window.history must inherit property "back" with the proper type (3)] expected: FAIL @@ -7236,9 +7191,6 @@ [BarProp interface object name] expected: FAIL - [History interface object name] - expected: FAIL - [ApplicationCache interface object name] expected: FAIL @@ -7290,15 +7242,6 @@ [History interface: window.history must inherit property "state" with the proper type (2)] expected: FAIL - [History interface: window.history must inherit property "go" with the proper type (3)] - expected: FAIL - - [History interface: window.history must inherit property "back" with the proper type (4)] - expected: FAIL - - [History interface: window.history must inherit property "forward" with the proper type (5)] - expected: FAIL - [History interface: window.history must inherit property "pushState" with the proper type (6)] expected: FAIL diff --git a/tests/wpt/metadata/html/dom/reflection-grouping.html.ini b/tests/wpt/metadata/html/dom/reflection-grouping.html.ini index 7ecf978bf18..ab78b68717b 100644 --- a/tests/wpt/metadata/html/dom/reflection-grouping.html.ini +++ b/tests/wpt/metadata/html/dom/reflection-grouping.html.ini @@ -6303,186 +6303,6 @@ [li.tabIndex: IDL set to -2147483648 followed by getAttribute()] expected: FAIL - [li.value: typeof IDL attribute] - expected: FAIL - - [li.value: IDL get with DOM attribute unset] - expected: FAIL - - [li.value: setAttribute() to -36 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to -1 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 0 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 1 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 2147483647 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to -2147483648 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 2147483648 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to -2147483649 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 4294967295 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 4294967296 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "-1" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "-0" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "0" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "1" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07 \\b\\t\\n\\v\\f\\r\\x0e\\x0f \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17 \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f foo " followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "\\t7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "\\v7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "\\f7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "\\n7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "\\r7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "
7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "
7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to " 7" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to undefined followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to 1.5 followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to true followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to false followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to object "[object Object\]" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to NaN followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to Infinity followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to -Infinity followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to "\\0" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to object "2" followed by IDL get] - expected: FAIL - - [li.value: setAttribute() to object "3" followed by IDL get] - expected: FAIL - - [li.value: IDL set to -36 followed by getAttribute()] - expected: FAIL - - [li.value: IDL set to -1 followed by getAttribute()] - expected: FAIL - - [li.value: IDL set to 0 followed by getAttribute()] - expected: FAIL - - [li.value: IDL set to 1 followed by getAttribute()] - expected: FAIL - - [li.value: IDL set to 2147483647 followed by getAttribute()] - expected: FAIL - - [li.value: IDL set to -2147483648 followed by getAttribute()] - expected: FAIL - [li.type: typeof IDL attribute] expected: FAIL diff --git a/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/close/sending-messages.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/error-codes/error.html.ini index 379fec0c3ec..7280d3b7e4f 100644 --- a/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/close/sending-messages.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/error-codes/error.html.ini @@ -1,6 +1,6 @@ -[sending-messages.html] +[error.html] type: testharness expected: TIMEOUT - [close() and sending messages] + [audio.error after successful load] expected: TIMEOUT diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata.html.ini index efd785bce04..249d3fa61f6 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata.html.ini @@ -7,3 +7,6 @@ [setting src attribute on autoplay video should trigger loadeddata event] expected: NOTRUN + [setting src attribute on autoplay audio should trigger loadeddata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html.ini new file mode 100644 index 00000000000..7c16b52bdbe --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html.ini @@ -0,0 +1,6 @@ +[event_loadeddata_noautoplay.html] + type: testharness + expected: TIMEOUT + [setting src attribute on non-autoplay audio should trigger loadeddata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadedmetadata.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadedmetadata.html.ini new file mode 100644 index 00000000000..90e0b6b2fad --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadedmetadata.html.ini @@ -0,0 +1,6 @@ +[event_loadedmetadata.html] + type: testharness + expected: TIMEOUT + [setting src attribute on autoplay audio should trigger loadedmetadata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html.ini new file mode 100644 index 00000000000..7d4abbe6b77 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html.ini @@ -0,0 +1,6 @@ +[event_loadedmetadata_noautoplay.html] + type: testharness + expected: TIMEOUT + [setting src attribute on non-autoplay audio should trigger loadedmetadata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html.ini new file mode 100644 index 00000000000..ef23353c3bc --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html.ini @@ -0,0 +1,6 @@ +[event_order_loadedmetadata_loadeddata.html] + type: testharness + expected: TIMEOUT + [setting src attribute on autoplay audio should trigger loadedmetadata then loadeddata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html.ini new file mode 100644 index 00000000000..f765e6bca1d --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html.ini @@ -0,0 +1,6 @@ +[readyState_during_loadeddata.html] + type: testharness + expected: TIMEOUT + [audio.readyState should be >= HAVE_CURRENT_DATA during loadeddata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html.ini new file mode 100644 index 00000000000..a3aaca7f389 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html.ini @@ -0,0 +1,6 @@ +[readyState_during_loadedmetadata.html] + type: testharness + expected: TIMEOUT + [audio.readyState should be >= HAVE_METADATA during loadedmetadata event] + expected: NOTRUN + diff --git a/tests/wpt/metadata/html/semantics/grouping-content/the-li-element/grouping-li.html.ini b/tests/wpt/metadata/html/semantics/grouping-content/the-li-element/grouping-li.html.ini index ea4e02e4cac..57509d09e74 100644 --- a/tests/wpt/metadata/html/semantics/grouping-content/the-li-element/grouping-li.html.ini +++ b/tests/wpt/metadata/html/semantics/grouping-content/the-li-element/grouping-li.html.ini @@ -3,33 +3,3 @@ [li should have a 'value' attribute] expected: FAIL - [Default (unspecified) value of value is 0.] - expected: FAIL - - [.value property reflects content attribute - and both parse value of '2' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '-10' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '4.03' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '-4.03' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '4.9' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '-4.9' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '7e2' correctly.] - expected: FAIL - - [IDL and content attribute parse value of '.5' correctly.] - expected: FAIL - - [IDL and content attribute parse value of 'A' correctly.] - expected: FAIL - diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/more/functions/readPixelsBadArgs.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/more/functions/readPixelsBadArgs.html.ini index 104168d037f..7f14a9449b1 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/more/functions/readPixelsBadArgs.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/more/functions/readPixelsBadArgs.html.ini @@ -1,6 +1,6 @@ [readPixelsBadArgs.html] type: testharness - expected: CRASH + expected: TIMEOUT [WebGL test #0: testReadPixels] expected: FAIL diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/reading/read-pixels-pack-alignment.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/reading/read-pixels-pack-alignment.html.ini index d37219b0864..1b3d09229b9 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/reading/read-pixels-pack-alignment.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/reading/read-pixels-pack-alignment.html.ini @@ -1,6 +1,6 @@ [read-pixels-pack-alignment.html] type: testharness - expected: CRASH + expected: TIMEOUT [WebGL test #3: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).] expected: FAIL diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-arrays-out-of-bounds.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-arrays-out-of-bounds.html.ini index 1459ace05e4..64503c921e5 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-arrays-out-of-bounds.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-arrays-out-of-bounds.html.ini @@ -1,3 +1,3 @@ [draw-arrays-out-of-bounds.html] type: testharness - expected: CRASH + expected: TIMEOUT diff --git a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-elements-out-of-bounds.html.ini b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-elements-out-of-bounds.html.ini index 5c4701a6660..73287c519b5 100644 --- a/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-elements-out-of-bounds.html.ini +++ b/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/rendering/draw-elements-out-of-bounds.html.ini @@ -1,3 +1,3 @@ [draw-elements-out-of-bounds.html] type: testharness - expected: CRASH + expected: TIMEOUT diff --git a/tests/wpt/metadata/workers/WorkerGlobalScope_close.htm.ini b/tests/wpt/metadata/workers/WorkerGlobalScope_close.htm.ini deleted file mode 100644 index 95efa590227..00000000000 --- a/tests/wpt/metadata/workers/WorkerGlobalScope_close.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[WorkerGlobalScope_close.htm] - type: testharness - [ WorkerGlobalScope close(): clear events queue ] - expected: FAIL - diff --git a/tests/wpt/metadata/workers/constructors/Worker/unexpected-self-properties.html.ini b/tests/wpt/metadata/workers/constructors/Worker/unexpected-self-properties.html.ini deleted file mode 100644 index 9c2d5495179..00000000000 --- a/tests/wpt/metadata/workers/constructors/Worker/unexpected-self-properties.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[unexpected-self-properties.html] - type: testharness - [unexpected members/interface objects/constructors] - expected: FAIL - diff --git a/tests/wpt/metadata/workers/interfaces.worker.js.ini b/tests/wpt/metadata/workers/interfaces.worker.js.ini index cb9d2850693..3928e5f88e0 100644 --- a/tests/wpt/metadata/workers/interfaces.worker.js.ini +++ b/tests/wpt/metadata/workers/interfaces.worker.js.ini @@ -21,9 +21,6 @@ [DedicatedWorkerGlobalScope interface: attribute onmessage] expected: FAIL - [WorkerGlobalScope interface: self must inherit property "close" with the proper type (2)] - expected: FAIL - [WorkerGlobalScope interface: self must inherit property "onerror" with the proper type (3)] expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 3fedff120e5..20107d1e105 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -1032,6 +1032,18 @@ "url": "/_mozilla/css/box_shadow_blur_a.html" } ], + "css/box_shadow_blur_fixed.html": [ + { + "path": "css/box_shadow_blur_fixed.html", + "references": [ + [ + "/_mozilla/css/box_shadow_blur_fixed_ref.html", + "==" + ] + ], + "url": "/_mozilla/css/box_shadow_blur_fixed.html" + } + ], "css/box_shadow_border_box_a.html": [ { "path": "css/box_shadow_border_box_a.html", @@ -5260,6 +5272,18 @@ "url": "/_mozilla/css/text_transform_uppercase_a.html" } ], + "css/textarea_space_calculation.html": [ + { + "path": "css/textarea_space_calculation.html", + "references": [ + [ + "/_mozilla/css/textarea_space_calculation-ref.html", + "==" + ] + ], + "url": "/_mozilla/css/textarea_space_calculation.html" + } + ], "css/transform_3d.html": [ { "path": "css/transform_3d.html", @@ -5782,16 +5806,16 @@ "url": "/_mozilla/css/word_break_a.html" } ], - "mozilla/blob_url_upload.html": [ + "mozilla/FileAPI/blob_url_upload.html": [ { - "path": "mozilla/blob_url_upload.html", + "path": "mozilla/FileAPI/blob_url_upload.html", "references": [ [ - "/_mozilla/mozilla/blob_url_upload_ref.html", + "/_mozilla/mozilla/FileAPI/blob_url_upload_ref.html", "==" ] ], - "url": "/_mozilla/mozilla/blob_url_upload.html" + "url": "/_mozilla/mozilla/FileAPI/blob_url_upload.html" } ], "mozilla/canvas/drawimage_html_image_1.html": [ @@ -6022,6 +6046,18 @@ "url": "/_mozilla/mozilla/table_valign_middle.html" } ], + "mozilla/table_valign_uneven_height.html": [ + { + "path": "mozilla/table_valign_uneven_height.html", + "references": [ + [ + "/_mozilla/mozilla/table_valign_uneven_height_ref.html", + "==" + ] + ], + "url": "/_mozilla/mozilla/table_valign_uneven_height.html" + } + ], "mozilla/webgl/clearcolor.html": [ { "path": "mozilla/webgl/clearcolor.html", @@ -6126,6 +6162,12 @@ "url": "/_mozilla/css/animations/basic-linear-width.html" } ], + "css/animations/basic-transition.html": [ + { + "path": "css/animations/basic-transition.html", + "url": "/_mozilla/css/animations/basic-transition.html" + } + ], "css/empty-keyframes.html": [ { "path": "css/empty-keyframes.html", @@ -6192,6 +6234,24 @@ "url": "/_mozilla/mozilla/Event.html" } ], + "mozilla/FileAPI/blob.html": [ + { + "path": "mozilla/FileAPI/blob.html", + "url": "/_mozilla/mozilla/FileAPI/blob.html" + } + ], + "mozilla/FileAPI/file-select.html": [ + { + "path": "mozilla/FileAPI/file-select.html", + "url": "/_mozilla/mozilla/FileAPI/file-select.html" + } + ], + "mozilla/FileAPI/file-upload.html": [ + { + "path": "mozilla/FileAPI/file-upload.html", + "url": "/_mozilla/mozilla/FileAPI/file-upload.html" + } + ], "mozilla/FocusEvent.html": [ { "path": "mozilla/FocusEvent.html", @@ -6216,12 +6276,6 @@ "url": "/_mozilla/mozilla/binding_keyword.html" } ], - "mozilla/blob.html": [ - { - "path": "mozilla/blob.html", - "url": "/_mozilla/mozilla/blob.html" - } - ], "mozilla/body_listener.html": [ { "path": "mozilla/body_listener.html", @@ -6498,12 +6552,6 @@ "url": "/_mozilla/mozilla/event_listener.html" } ], - "mozilla/file_upload.html": [ - { - "path": "mozilla/file_upload.html", - "url": "/_mozilla/mozilla/file_upload.html" - } - ], "mozilla/focus_blur.html": [ { "path": "mozilla/focus_blur.html", @@ -10120,6 +10168,18 @@ "url": "/_mozilla/css/box_shadow_blur_a.html" } ], + "css/box_shadow_blur_fixed.html": [ + { + "path": "css/box_shadow_blur_fixed.html", + "references": [ + [ + "/_mozilla/css/box_shadow_blur_fixed_ref.html", + "==" + ] + ], + "url": "/_mozilla/css/box_shadow_blur_fixed.html" + } + ], "css/box_shadow_border_box_a.html": [ { "path": "css/box_shadow_border_box_a.html", @@ -14348,6 +14408,18 @@ "url": "/_mozilla/css/text_transform_uppercase_a.html" } ], + "css/textarea_space_calculation.html": [ + { + "path": "css/textarea_space_calculation.html", + "references": [ + [ + "/_mozilla/css/textarea_space_calculation-ref.html", + "==" + ] + ], + "url": "/_mozilla/css/textarea_space_calculation.html" + } + ], "css/transform_3d.html": [ { "path": "css/transform_3d.html", @@ -14870,16 +14942,16 @@ "url": "/_mozilla/css/word_break_a.html" } ], - "mozilla/blob_url_upload.html": [ + "mozilla/FileAPI/blob_url_upload.html": [ { - "path": "mozilla/blob_url_upload.html", + "path": "mozilla/FileAPI/blob_url_upload.html", "references": [ [ - "/_mozilla/mozilla/blob_url_upload_ref.html", + "/_mozilla/mozilla/FileAPI/blob_url_upload_ref.html", "==" ] ], - "url": "/_mozilla/mozilla/blob_url_upload.html" + "url": "/_mozilla/mozilla/FileAPI/blob_url_upload.html" } ], "mozilla/canvas/drawimage_html_image_1.html": [ @@ -15110,6 +15182,18 @@ "url": "/_mozilla/mozilla/table_valign_middle.html" } ], + "mozilla/table_valign_uneven_height.html": [ + { + "path": "mozilla/table_valign_uneven_height.html", + "references": [ + [ + "/_mozilla/mozilla/table_valign_uneven_height_ref.html", + "==" + ] + ], + "url": "/_mozilla/mozilla/table_valign_uneven_height.html" + } + ], "mozilla/webgl/clearcolor.html": [ { "path": "mozilla/webgl/clearcolor.html", diff --git a/tests/wpt/mozilla/meta/mozilla/blob_url_upload.html.ini b/tests/wpt/mozilla/meta/mozilla/FileAPI/blob_url_upload.html.ini index 6ad257ede65..6ad257ede65 100644 --- a/tests/wpt/mozilla/meta/mozilla/blob_url_upload.html.ini +++ b/tests/wpt/mozilla/meta/mozilla/FileAPI/blob_url_upload.html.ini diff --git a/tests/wpt/mozilla/meta/mozilla/file_upload.html.ini b/tests/wpt/mozilla/meta/mozilla/FileAPI/file-select.html.ini index 8c9a7d45d7d..b047e230d99 100644 --- a/tests/wpt/mozilla/meta/mozilla/file_upload.html.ini +++ b/tests/wpt/mozilla/meta/mozilla/FileAPI/file-select.html.ini @@ -1,3 +1,3 @@ -[file_upload.html] +[file-select.html] type: testharness prefs: [dom.testing.htmlinputelement.select_files.enabled:true] diff --git a/tests/wpt/mozilla/meta/mozilla/FileAPI/file-upload.html.ini b/tests/wpt/mozilla/meta/mozilla/FileAPI/file-upload.html.ini new file mode 100644 index 00000000000..f3715f47bf9 --- /dev/null +++ b/tests/wpt/mozilla/meta/mozilla/FileAPI/file-upload.html.ini @@ -0,0 +1,3 @@ +[file-upload.html] + type: testharness + prefs: [dom.testing.htmlinputelement.select_files.enabled:true] diff --git a/tests/wpt/mozilla/tests/css/animations/basic-transition.html b/tests/wpt/mozilla/tests/css/animations/basic-transition.html new file mode 100644 index 00000000000..b80e8a666a6 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/animations/basic-transition.html @@ -0,0 +1,34 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Transition test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +#check-me, #check-me-2 { + background-color: #F00; + width: 10px; + height: 10px; + transition: background-color 1s linear; +} +#check-me-2 { + background-color: #000; +} +</style> +<div id=check-me><span>a</span></div> +<script> +var div = document.getElementById('check-me'); +var span = div.childNodes[0]; +async_test(function(t) { + window.addEventListener('load', function() { + assert_equals(getComputedStyle(div).getPropertyValue('background-color'), 'rgb(255, 0, 0)'); + div.id = "check-me-2"; + requestAnimationFrame(function() { + var test = new window.TestBinding(); + test.advanceClock(2000); + span.innerHTML = "a"; + assert_equals(getComputedStyle(div).getPropertyValue('background-color'), 'rgb(0, 0, 0)'); + t.done(); + }); + }) +}) +</script> diff --git a/tests/wpt/mozilla/tests/css/box_shadow_blur_fixed.html b/tests/wpt/mozilla/tests/css/box_shadow_blur_fixed.html new file mode 100644 index 00000000000..429a18dbc80 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/box_shadow_blur_fixed.html @@ -0,0 +1,24 @@ +<head> + <link rel='match' href='box_shadow_blur_fixed_ref.html'> + <style> + #div_outer { + width: 100%; + position: fixed; + top: 100px; + left: 0; + } + + #div_inner { + background: lightgrey; + height: 40px; + box-shadow: 0 0 30px 30px darkblue; + } + </style> +</head> + +<body> + <div id="div_outer"> + <div id="div_inner"> + </div> + </div> +</body>
\ No newline at end of file diff --git a/tests/wpt/mozilla/tests/css/box_shadow_blur_fixed_ref.html b/tests/wpt/mozilla/tests/css/box_shadow_blur_fixed_ref.html new file mode 100644 index 00000000000..03e79789470 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/box_shadow_blur_fixed_ref.html @@ -0,0 +1,23 @@ +<head> + <style> + #div_outer { + width: 100%; + position: absolute; + top: 100px; + left: 0; + } + + #div_inner { + background: lightgrey; + height: 40px; + box-shadow: 0 0 30px 30px darkblue; + } + </style> +</head> + +<body> + <div id="div_outer"> + <div id="div_inner"> + </div> + </div> +</body>
\ No newline at end of file diff --git a/tests/wpt/mozilla/tests/css/textarea_space_calculation-ref.html b/tests/wpt/mozilla/tests/css/textarea_space_calculation-ref.html new file mode 100644 index 00000000000..b777beb062b --- /dev/null +++ b/tests/wpt/mozilla/tests/css/textarea_space_calculation-ref.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>REFERENCE: textarea does not take up more space than it takes up</title> +<style> +textarea{height:2em;width:2em} +div{width:2em;font-size:12px;line-height:3px} +</style> +<h1>To pass, no red should be visible</h1> +<div> +<textarea> +1 +2 +3 +4 +5 +6 +8 +9 +</textarea> +</div> diff --git a/tests/wpt/mozilla/tests/css/textarea_space_calculation.html b/tests/wpt/mozilla/tests/css/textarea_space_calculation.html new file mode 100644 index 00000000000..20945e971b5 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/textarea_space_calculation.html @@ -0,0 +1,21 @@ +<!doctype html> +<meta charset="utf-8"> +<title>textarea does not take up more space than it takes up</title> +<link rel="match" href="textarea_space_calculation-ref.html"> +<style> +textarea{height:2em;width:2em} +div{background:red;width:2em;font-size:12px;line-height:3px} +</style> +<h1>To pass, no red should be visible</h1> +<div> +<textarea> +1 +2 +3 +4 +5 +6 +8 +9 +</textarea> +</div> diff --git a/tests/wpt/mozilla/tests/mozilla/blob.html b/tests/wpt/mozilla/tests/mozilla/FileAPI/blob.html index 3f932083542..3f932083542 100644 --- a/tests/wpt/mozilla/tests/mozilla/blob.html +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/blob.html diff --git a/tests/wpt/mozilla/tests/mozilla/blob_url_upload.html b/tests/wpt/mozilla/tests/mozilla/FileAPI/blob_url_upload.html index 17c8e3ad0b4..17c8e3ad0b4 100644 --- a/tests/wpt/mozilla/tests/mozilla/blob_url_upload.html +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/blob_url_upload.html diff --git a/tests/wpt/mozilla/tests/mozilla/blob_url_upload_ref.html b/tests/wpt/mozilla/tests/mozilla/FileAPI/blob_url_upload_ref.html index 2ae08600b45..6f95c43ac32 100644 --- a/tests/wpt/mozilla/tests/mozilla/blob_url_upload_ref.html +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/blob_url_upload_ref.html @@ -2,6 +2,6 @@ <meta charset="utf-8"> <title>Reference: Blob URL with File Upload</title> <body> - <img src="test.jpg" id="image"> + <img src="../test.jpg" id="image"> <input type="file" id="file-input""> </body> diff --git a/tests/wpt/mozilla/tests/mozilla/file_upload.html b/tests/wpt/mozilla/tests/mozilla/FileAPI/file-select.html index ad911097f6c..06a5f30dd44 100644 --- a/tests/wpt/mozilla/tests/mozilla/file_upload.html +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/file-select.html @@ -1,6 +1,6 @@ <!doctype html> <meta charset="utf-8"> -<title>Test of uploading a file through input element</title> +<title>Test of selecting a file through input element</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> diff --git a/tests/wpt/mozilla/tests/mozilla/FileAPI/file-upload-frame.html b/tests/wpt/mozilla/tests/mozilla/FileAPI/file-upload-frame.html new file mode 100644 index 00000000000..13951bb37d0 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/file-upload-frame.html @@ -0,0 +1,8 @@ +<form id="testform" enctype="multipart/form-data" action="resource/file-submission.py" method="post"> +<input type="file" name="file-input" id="file-input" /> +</form> + +<script type="text/javascript"> + var e = document.getElementById("file-input"); + e.selectFiles(["./tests/wpt/mozilla/tests/mozilla/FileAPI/resource/upload.txt"]); +</script> diff --git a/tests/wpt/mozilla/tests/mozilla/FileAPI/file-upload.html b/tests/wpt/mozilla/tests/mozilla/FileAPI/file-upload.html new file mode 100644 index 00000000000..bff5fb1ee7a --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/file-upload.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +function run_test() { + var t = async_test("form submission of uploaded file"); + + var testframe = document.getElementById("testframe"); + var testdocument = testframe.contentWindow.document; + + testframe.onload = function() { + t.step(function () { + var response = testframe.contentDocument.documentElement.textContent; + assert_equals(response, "OK"); + }); + t.done(); + }; + testdocument.getElementById("testform").submit(); +} +</script> +<iframe id=testframe src="file-upload-frame.html" onload="run_test();"></iframe> diff --git a/tests/wpt/mozilla/tests/mozilla/FileAPI/resource/file-submission.py b/tests/wpt/mozilla/tests/mozilla/FileAPI/resource/file-submission.py new file mode 100644 index 00000000000..aa278cb4c4d --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/resource/file-submission.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +def fail(msg): + return ([("Content-Type", "text/plain")], "FAIL: " + msg) + + +def main(request, response): + content_type = request.headers.get('Content-Type').split("; ") + + if len(content_type) != 2: + return fail("content type length is incorrect") + + if content_type[0] != 'multipart/form-data': + return fail("content type first field is incorrect") + + boundary = content_type[1].strip("boundary=") + + body = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"file-input\"; filename=\"upload.txt\"" + body += "\r\n" + "text/plain\r\n\r\nHello\r\n--" + boundary + "--" + + if body != request.body: + return fail("request body doesn't match: " + body + "+++++++" + request.body) + + return ([("Content-Type", "text/plain")], "OK") diff --git a/tests/wpt/mozilla/tests/mozilla/FileAPI/resource/upload.txt b/tests/wpt/mozilla/tests/mozilla/FileAPI/resource/upload.txt new file mode 100644 index 00000000000..5ab2f8a4323 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/FileAPI/resource/upload.txt @@ -0,0 +1 @@ +Hello
\ No newline at end of file diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html index 95dfa65ad82..f037f9a879e 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html @@ -49,6 +49,7 @@ test_interfaces([ "FormData", "HashChangeEvent", "Headers", + "History", "HTMLAnchorElement", "HTMLAppletElement", "HTMLAreaElement", diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js index 79b99d4f1de..68d5cfbcedf 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js @@ -41,45 +41,18 @@ test_interfaces([ "File", "FileList", "FileReader", + "FileReaderSync", "FocusEvent", "FormData", "HashChangeEvent", - "Headers", - "HTMLAnchorElement", - "HTMLAppletElement", - "HTMLAreaElement", - "HTMLAudioElement", - "HTMLBaseElement", - "HTMLBodyElement", - "HTMLBRElement", - "HTMLButtonElement", + "Headers", + "History", "HTMLCanvasElement", "HTMLCollection", - "HTMLDataElement", - "HTMLDataListElement", - "HTMLDetailsElement", - "HTMLDialogElement", - "HTMLDirectoryElement", - "HTMLDivElement", - "HTMLDListElement", "HTMLElement", - "HTMLEmbedElement", - "HTMLFieldSetElement", - "HTMLFontElement", "HTMLFormControlsCollection", "HTMLFormElement", - "HTMLFrameElement", - "HTMLFrameSetElement", "HTMLHeadElement", - "HTMLHeadingElement", - "HTMLHRElement", - "HTMLHtmlElement", - "HTMLIFrameElement", - "HTMLImageElement", - "HTMLInputElement", - "HTMLLabelElement", - "HTMLLegendElement", - "HTMLLIElement", "HTMLLinkElement", "HTMLMapElement", "HTMLMediaElement", @@ -91,34 +64,8 @@ test_interfaces([ "HTMLOptGroupElement", "HTMLOptionElement", "HTMLOutputElement", - "HTMLParagraphElement", - "HTMLParamElement", - "HTMLPreElement", - "HTMLProgressElement", - "HTMLQuoteElement", "HTMLScriptElement", - "HTMLSelectElement", - "HTMLSourceElement", - "HTMLSpanElement", - "HTMLStyleElement", - "HTMLTableCaptionElement", - "HTMLTableCellElement", - "HTMLTableColElement", - "HTMLTableDataCellElement", - "HTMLTableElement", - "HTMLTableHeaderCellElement", - "HTMLTableRowElement", - "HTMLTableSectionElement", - "HTMLTemplateElement", - "HTMLTextAreaElement", - "HTMLTimeElement", - "HTMLTitleElement", - "HTMLTrackElement", - "HTMLUListElement", - "HTMLUnknownElement", - "HTMLVideoElement", "ImageData", - "Image", "KeyboardEvent", "Location", "MediaError", diff --git a/tests/wpt/mozilla/tests/mozilla/table_valign_uneven_height.html b/tests/wpt/mozilla/tests/mozilla/table_valign_uneven_height.html new file mode 100644 index 00000000000..6668070831a --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/table_valign_uneven_height.html @@ -0,0 +1,34 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Vertical Alignment for row with uneven height cells</title> +<link rel="match" href="table_valign_uneven_height_ref.html"> +<style> + td { + border: 5px black solid; + border-spacing: 0; + padding: 0; + } + td { + vertical-align: middle; + background-color: green; + } + .b { + vertical-align: bottom; + } + div { + height: 50px; + width: 50px; + background-color: blue; + } + .c { + height: 100px !important; + background-color: red !important; + } +</style> +<table> + <tr> + <td><div class="c"></div></td> + <td><div></div></td> + <td class="b"><div></div></td> + </tr> +</table> diff --git a/tests/wpt/mozilla/tests/mozilla/table_valign_uneven_height_ref.html b/tests/wpt/mozilla/tests/mozilla/table_valign_uneven_height_ref.html new file mode 100644 index 00000000000..321132b7e7e --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/table_valign_uneven_height_ref.html @@ -0,0 +1,34 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Reference: Vertical Alignment for row with uneven height cells</title> +<style> + td { + background-color: green; + border: 5px black solid; + border-spacing: 0; + padding: 0; + } + div { + height: 50px; + width: 50px; + background-color: blue; + } + .c { + height: 100px !important; + background-color: #f00 !important; + } + .middle { + margin-top: 25px; + margin-bottom: 25px; + } + .bottom { + margin-top: 50px; + } +</style> +<table> + <tr> + <td class="a"><div class="c"></div></td> + <td class="a"><div class="middle"></div></td> + <td class="b"><div class="bottom"></div></td> + </tr> +</table> diff --git a/tests/wpt/web-platform-tests/FileAPI/idlharness.idl b/tests/wpt/web-platform-tests/FileAPI/idlharness.idl index 62e6c5d9f21..d8f31b43a80 100644 --- a/tests/wpt/web-platform-tests/FileAPI/idlharness.idl +++ b/tests/wpt/web-platform-tests/FileAPI/idlharness.idl @@ -1,5 +1,7 @@ -[Constructor, - Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> blobParts, optional BlobPropertyBag options), Exposed=Window,Worker] +// https://w3c.github.io/FileAPI/#idl-index + +[Constructor(optional sequence<BlobPart> blobParts, optional BlobPropertyBag options), +Exposed=(Window,Worker)] interface Blob { readonly attribute unsigned long long size; @@ -9,8 +11,8 @@ interface Blob { //slice Blob into byte-ranged chunks Blob slice([Clamp] optional long long start, - [Clamp] optional long long end, - optional DOMString contentType); + [Clamp] optional long long end, + optional DOMString contentType); void close(); }; @@ -19,32 +21,33 @@ dictionary BlobPropertyBag { DOMString type = ""; }; -[Constructor(sequence<(Blob or DOMString or ArrayBufferView or ArrayBuffer)> fileBits, -[EnsureUTF16] DOMString fileName, optional FilePropertyBag options), Exposed=Window,Worker] -interface File : Blob { +typedef (BufferSource or Blob or USVString) BlobPart; +[Constructor(sequence<BlobPart> fileBits, + [EnsureUTF16] DOMString fileName, + optional FilePropertyBag options), +Exposed=(Window,Worker)] +interface File : Blob { readonly attribute DOMString name; readonly attribute long long lastModified; - }; -dictionary FilePropertyBag { - - DOMString type = ""; +dictionary FilePropertyBag : BlobPropertyBag { long long lastModified; - }; -[Exposed=Window,Worker] interface FileList { +[Exposed=(Window,Worker)] +interface FileList { getter File? item(unsigned long index); readonly attribute unsigned long length; }; -[Constructor, Exposed=Window,Worker] +[Constructor, Exposed=(Window,Worker)] interface FileReader: EventTarget { // async read methods void readAsArrayBuffer(Blob blob); + void readAsBinaryString(Blob blob); void readAsText(Blob blob, optional DOMString label); void readAsDataURL(Blob blob); @@ -55,6 +58,7 @@ interface FileReader: EventTarget { const unsigned short LOADING = 1; const unsigned short DONE = 2; + readonly attribute unsigned short readyState; // File or Blob data @@ -62,7 +66,7 @@ interface FileReader: EventTarget { readonly attribute DOMError? error; - // event handler attributes + // event handler content attributes attribute EventHandler onloadstart; attribute EventHandler onprogress; attribute EventHandler onload; @@ -72,20 +76,19 @@ interface FileReader: EventTarget { }; -partial interface URL { - - static DOMString createObjectURL(Blob blob); - static DOMString createFor(Blob blob); - static void revokeObjectURL(DOMString url); - -}; - [Constructor, Exposed=Worker] interface FileReaderSync { - // Synchronously return strings ArrayBuffer readAsArrayBuffer(Blob blob); + DOMString readAsBinaryString(Blob blob); DOMString readAsText(Blob blob, optional DOMString label); DOMString readAsDataURL(Blob blob); }; + +[Exposed=(Window,DedicatedWorker,SharedWorker)] +partial interface URL { + static DOMString createObjectURL(Blob blob); + static DOMString createFor(Blob blob); + static void revokeObjectURL(DOMString url); +}; diff --git a/tests/wpt/web-platform-tests/fetch/api/headers/headers-basic.html b/tests/wpt/web-platform-tests/fetch/api/headers/headers-basic.html index 5c374ed1faf..26bbfe35935 100644 --- a/tests/wpt/web-platform-tests/fetch/api/headers/headers-basic.html +++ b/tests/wpt/web-platform-tests/fetch/api/headers/headers-basic.html @@ -66,7 +66,7 @@ assert_equals(headers2.get(name), String(headerDict[name]), "name: " + name + " has value: " + headerDict[name]); } - }, "Create headers whith existing headers"); + }, "Create headers with existing headers"); test(function() { var headers = new Headers(); diff --git a/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-open.html b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-open.html new file mode 100644 index 00000000000..4719f63b853 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-open.html @@ -0,0 +1,30 @@ +<!doctype html> +<meta charset="utf-8"> +<title>dialog element: open</title> +<link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#dom-dialog-open"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<dialog id="d1"> + <p>foobar</p> + <button>OK</button> +</dialog> +<dialog id="d2" open> + <p>foobar</p> + <button>OK</button> +</dialog> +<script> + var d1 = document.getElementById('d1'); + var d2 = document.getElementById('d2'); + + test(function(){ + assert_false(d1.open); + assert_true(d2.open); + }, "On getting, the IDL open attribute must return true if the content open attribute is set, and false if it is absent."); + + test(function(){ + d1.open = true; + assert_true(d1.hasAttribute("open")); + d2.open = false; + assert_false(d2.hasAttribute("open")); + }, "On setting, the content open attribute must be removed if the IDL open attribute is set to false, and must be present if the IDL open attribute is set to true."); +</script> diff --git a/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/remove-row.html b/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/remove-row.html new file mode 100644 index 00000000000..b0e529f91ec --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/tabular-data/the-table-element/remove-row.html @@ -0,0 +1,50 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Delete Row tests</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<table id="element"> + <thead> + <th>First column</th> + <th>Second column</th> + </thead> + <tbody> + <tr> + <td>1.1</td> + <td>1.2</td> + </tr> + <tr> + <td>2.1</td> + <td>2.2</td> + </tr> + </tbody> +</table> + +<script> +var el = document.getElementById('element'); + +test(function() { + assert_throws("IndexSizeError", function() { + el.deleteRow(-2) + }) +}, 'deleteRow function invalid argument'); +test(function() { + assert_throws("IndexSizeError", function() { + el.deleteRow(el.rows.length) + }) +}, 'deleteRow function invalid argument bis'); + +test(function() { + var old_length = el.rows.length; + el.insertRow(-1); + el.deleteRow(-1); + assert_equals(old_length, el.rows.length); +}, "check normal deleteRow"); +test(function() { + while (el.rows.length > 1) { + el.deleteRow(-1); + } + assert_equals(1, el.rows.length); +}, "check normal deleteRow bis"); +</script> |