diff options
103 files changed, 3494 insertions, 2278 deletions
diff --git a/Cargo.lock b/Cargo.lock index 86b293b867e..ea2fc66c898 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ version = "0.0.1" dependencies = [ "compositing 0.0.1", "gfx 0.0.1", + "glfw_app 0.0.1", "layout 0.0.1", "msg 0.0.1", "net 0.0.1", @@ -32,7 +33,7 @@ dependencies = [ "egl 0.1.0 (git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220)", "freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)", "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", - "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#7ccfaca315a43d97914e1601c90ad348ef190edf)", + "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b)", "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", "skia-sys 0.0.20130412 (git+https://github.com/servo/skia#6d696712962fd0d41120b7a414a48417da8e6a92)", @@ -64,8 +65,6 @@ dependencies = [ "devtools_traits 0.0.1", "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", "gfx 0.0.1", - "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#7ccfaca315a43d97914e1601c90ad348ef190edf)", - "glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)", "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", "layout_traits 0.0.1", "msg 0.0.1", @@ -195,7 +194,7 @@ dependencies = [ [[package]] name = "glfw" version = "0.0.1" -source = "git+https://github.com/servo/glfw-rs?ref=servo#7ccfaca315a43d97914e1601c90ad348ef190edf" +source = "git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b" dependencies = [ "glfw-sys 3.0.4 (git+https://github.com/servo/glfw?ref=cargo-3.0.4#65a2b4721276589d9de24f6a9999a2db37286cae)", "semver 0.0.1 (git+https://github.com/rust-lang/semver#d04583a173395b76c1eaa15cc630a5f6f8f0ae10)", @@ -207,11 +206,16 @@ version = "3.0.4" source = "git+https://github.com/servo/glfw?ref=cargo-3.0.4#65a2b4721276589d9de24f6a9999a2db37286cae" [[package]] -name = "glut" +name = "glfw_app" version = "0.0.1" -source = "git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949" dependencies = [ - "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", + "alert 0.1.0 (git+https://github.com/servo/rust-alert#fdc24f13be8d8a2d15214ec228d166b3221b809e)", + "compositing 0.0.1", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "msg 0.0.1", + "util 0.0.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2472f99be99..a48a9b7ecd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = ["The Servo Project Developers"] [lib] name = "servo" -crate-type = ["rlib", "dylib"] +crate-type = ["rlib"] [[bin]] name = "servo" @@ -24,6 +24,8 @@ name = "contenttest" path = "tests/contenttest.rs" harness = false +[features] +default = ["glfw_app"] [dependencies.compositing] path = "components/compositing" @@ -46,5 +48,9 @@ path = "components/layout" [dependencies.gfx] path = "components/gfx" +[dependencies.glfw_app] +path = "ports/glfw" +optional = true + [dependencies.url] git = "https://github.com/servo/rust-url" diff --git a/README.md b/README.md index 5794bf98b55..c544152555c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ On Debian-based Linuxes: sudo apt-get install curl freeglut3-dev \ libfreetype6-dev libgl1-mesa-dri libglib2.0-dev xorg-dev \ msttcorefonts gperf g++ cmake python-virtualenv \ - libssl-dev libglfw3-dev + libssl-dev libglfw-dev ``` On Fedora: @@ -89,7 +89,6 @@ git clone https://github.com/servo/servo cd servo ANDROID_TOOLCHAIN=/path/to/toolchain ANDROID_NDK=/path/to/ndk PATH=$PATH:/path/to/toolchain/bin ./mach build --android cd ports/android -ANDROID_NDK=/path/to/ndk ANDROID_SDK=/path/to/sdk make ANDROID_SDK=/path/to/sdk make install ``` diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index e306ae8fd94..83a4bbee5cc 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -40,10 +40,6 @@ git = "https://github.com/servo/rust-azure" [dependencies.geom] git = "https://github.com/servo/rust-geom" -[dependencies.glfw] -git = "https://github.com/servo/glfw-rs" -branch = "servo" - [dependencies.layers] git = "https://github.com/servo/rust-layers" @@ -61,7 +57,3 @@ git = "https://github.com/servo/rust-core-graphics" [dependencies.core_text] git = "https://github.com/servo/rust-core-text" - -[dependencies.glut] -git = "https://github.com/servo/rust-glut" - diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index af19496be88..6aa0ca46913 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -11,7 +11,6 @@ use constellation::SendableFrameTree; use events; use events::ScrollPositionChanged; use pipeline::CompositionPipeline; -use platform::{Application, Window}; use windowing; use windowing::{FinishedWindowEvent, IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent}; use windowing::{MouseWindowEvent, MouseWindowEventClass, MouseWindowMouseDownEvent}; @@ -54,7 +53,7 @@ use time::precise_time_s; use url::Url; -pub struct IOCompositor { +pub struct IOCompositor<Window: WindowMethods> { /// The application window. window: Rc<Window>, @@ -136,22 +135,13 @@ enum ShutdownState { FinishedShuttingDown, } -impl IOCompositor { - fn new(app: &Application, - opts: Opts, - port: Receiver<Msg>, - constellation_chan: ConstellationChan, - time_profiler_chan: TimeProfilerChan, - memory_profiler_chan: MemoryProfilerChan) -> IOCompositor { - - let scale_factor = match opts.device_pixels_per_px { - Some(device_pixels_per_px) => device_pixels_per_px, - None => ScaleFactor(1.0), - }; - let framebuffer_size = opts.initial_window_size.as_f32() * scale_factor; - - let window: Rc<Window> = WindowMethods::new(app, opts.output_file.is_none(), - framebuffer_size.as_uint()); +impl<Window: WindowMethods> IOCompositor<Window> { + fn new(window: Rc<Window>, + opts: Opts, + port: Receiver<Msg>, + constellation_chan: ConstellationChan, + time_profiler_chan: TimeProfilerChan, + memory_profiler_chan: MemoryProfilerChan) -> IOCompositor<Window> { // Create an initial layer tree. // @@ -192,13 +182,13 @@ impl IOCompositor { } } - pub fn create(app: &Application, + pub fn create(window: Rc<Window>, opts: Opts, port: Receiver<Msg>, constellation_chan: ConstellationChan, time_profiler_chan: TimeProfilerChan, memory_profiler_chan: MemoryProfilerChan) { - let mut compositor = IOCompositor::new(app, + let mut compositor = IOCompositor::new(window, opts, port, constellation_chan, diff --git a/components/compositing/compositor_task.rs b/components/compositing/compositor_task.rs index 786c05f27da..aa133741cea 100644 --- a/components/compositing/compositor_task.rs +++ b/components/compositing/compositor_task.rs @@ -7,8 +7,7 @@ pub use windowing; use compositor; use headless; pub use constellation::SendableFrameTree; -use windowing::{ApplicationMethods, WindowMethods}; -use platform::Application; +use windowing::WindowMethods; use azure::azure_hl::{SourceSurfaceMethods, Color}; use geom::point::Point2D; @@ -23,6 +22,7 @@ use servo_util::memory::MemoryProfilerChan; use servo_util::opts::Opts; use servo_util::time::TimeProfilerChan; use std::comm::{channel, Sender, Receiver}; +use std::rc::Rc; use url::Url; @@ -183,28 +183,9 @@ pub enum Msg { LoadComplete(PipelineId, Url), } -pub enum CompositorMode { - Windowed(Application), - Headless -} - -pub struct CompositorTask { - pub mode: CompositorMode, -} +pub struct CompositorTask; impl CompositorTask { - fn new(is_headless: bool) -> CompositorTask { - let mode: CompositorMode = if is_headless { - Headless - } else { - Windowed(ApplicationMethods::new()) - }; - - CompositorTask { - mode: mode - } - } - /// Creates a graphics context. Platform-specific. /// /// FIXME(pcwalton): Probably could be less platform-specific, using the metadata abstraction. @@ -217,24 +198,24 @@ impl CompositorTask { NativeCompositingGraphicsContext::new() } - pub fn create(opts: Opts, + pub fn create<Window: WindowMethods>( + window: Option<Rc<Window>>, + opts: Opts, port: Receiver<Msg>, constellation_chan: ConstellationChan, time_profiler_chan: TimeProfilerChan, memory_profiler_chan: MemoryProfilerChan) { - let compositor = CompositorTask::new(opts.headless); - - match compositor.mode { - Windowed(ref app) => { - compositor::IOCompositor::create(app, + match window { + Some(window) => { + compositor::IOCompositor::create(window, opts, port, constellation_chan.clone(), time_profiler_chan, memory_profiler_chan) } - Headless => { + None => { headless::NullCompositor::create(port, constellation_chan.clone(), time_profiler_chan, diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index 1b8131ec299..44592caa61c 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -19,10 +19,6 @@ extern crate azure; extern crate devtools_traits; extern crate geom; extern crate gfx; -#[cfg(not(target_os="android"))] -extern crate glfw; -#[cfg(target_os="android")] -extern crate glut; extern crate layers; extern crate layout_traits; extern crate opengles; @@ -56,7 +52,4 @@ mod headless; pub mod pipeline; pub mod constellation; -mod windowing; - -#[path="platform/mod.rs"] -pub mod platform; +pub mod windowing; diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 6a90167628a..5091ee50f15 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -10,7 +10,6 @@ use geom::size::TypedSize2D; use layers::geometry::DevicePixel; use servo_msg::compositor_msg::{ReadyState, RenderState}; use servo_util::geometry::ScreenPx; -use std::rc::Rc; pub enum MouseWindowEvent { MouseWindowClickEvent(uint, TypedPoint2D<DevicePixel, f32>), @@ -54,14 +53,7 @@ pub enum WindowEvent { QuitWindowEvent, } -/// Methods for an abstract Application. -pub trait ApplicationMethods { - fn new() -> Self; -} - -pub trait WindowMethods<A> { - /// Creates a new window. - fn new(app: &A, is_foreground: bool, size: TypedSize2D<DevicePixel, uint>) -> Rc<Self>; +pub trait WindowMethods { /// Returns the size of the window in hardware pixels. fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, uint>; /// Returns the size of the window in density-independent "px" units. diff --git a/components/layout/block.rs b/components/layout/block.rs index ae4f8753d3b..d36f4b873e6 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -26,7 +26,6 @@ use model::{Auto, IntrinsicISizes, MarginCollapseInfo, MarginsCollapse}; use model::{MarginsCollapseThrough, MaybeAuto, NoCollapsibleMargins, Specified, specified}; use model::{specified_or_none}; use wrapper::ThreadSafeLayoutNode; -use style::ComputedValues; use style::computed_values::{clear, position}; use collections::dlist::DList; @@ -298,7 +297,7 @@ impl CandidateBSizeIterator { /// Creates a new candidate block-size iterator. `block_container_block-size` is `None` if the block-size /// of the block container has not been determined yet. It will always be `Some` in the case of /// absolutely-positioned containing blocks. - pub fn new(style: &ComputedValues, block_container_block_size: Option<Au>) + pub fn new(fragment: &Fragment, block_container_block_size: Option<Au>) -> CandidateBSizeIterator { // Per CSS 2.1 § 10.7, (assuming an horizontal writing mode,) // percentages in `min-height` and `max-height` refer to the height of @@ -306,21 +305,21 @@ impl CandidateBSizeIterator { // If that is not determined yet by the time we need to resolve // `min-height` and `max-height`, percentage values are ignored. - let block_size = match (style.content_block_size(), block_container_block_size) { + let block_size = match (fragment.style.content_block_size(), block_container_block_size) { (LPA_Percentage(percent), Some(block_container_block_size)) => { Specified(block_container_block_size.scale_by(percent)) } (LPA_Percentage(_), None) | (LPA_Auto, _) => Auto, (LPA_Length(length), _) => Specified(length), }; - let max_block_size = match (style.max_block_size(), block_container_block_size) { + let max_block_size = match (fragment.style.max_block_size(), block_container_block_size) { (LPN_Percentage(percent), Some(block_container_block_size)) => { Some(block_container_block_size.scale_by(percent)) } (LPN_Percentage(_), None) | (LPN_None, _) => None, (LPN_Length(length), _) => Some(length), }; - let min_block_size = match (style.min_block_size(), block_container_block_size) { + let min_block_size = match (fragment.style.min_block_size(), block_container_block_size) { (LP_Percentage(percent), Some(block_container_block_size)) => { block_container_block_size.scale_by(percent) } @@ -328,12 +327,22 @@ impl CandidateBSizeIterator { (LP_Length(length), _) => length, }; - CandidateBSizeIterator { - block_size: block_size, - max_block_size: max_block_size, - min_block_size: min_block_size, + // If the style includes `box-sizing: border-box`, subtract the border and padding. + let adjustment_for_box_sizing = match fragment.style.get_box().box_sizing { + box_sizing::border_box => fragment.border_padding.block_start_end(), + box_sizing::content_box => Au(0), + }; + + return CandidateBSizeIterator { + block_size: block_size.map(|size| adjust(size, adjustment_for_box_sizing)), + max_block_size: max_block_size.map(|size| adjust(size, adjustment_for_box_sizing)), + min_block_size: adjust(min_block_size, adjustment_for_box_sizing), candidate_value: Au(0), status: InitialCandidateBSizeStatus, + }; + + fn adjust(size: Au, delta: Au) -> Au { + max(size - delta, Au(0)) } } } @@ -964,7 +973,7 @@ impl BlockFlow { // Compute any explicitly-specified block size. // Can't use `for` because we assign to `candidate_block_size_iterator.candidate_value`. let mut candidate_block_size_iterator = CandidateBSizeIterator::new( - self.fragment.style(), + &self.fragment, self.base.block_container_explicit_block_size); loop { match candidate_block_size_iterator.next() { @@ -978,30 +987,14 @@ impl BlockFlow { } } + // Adjust `cur_b` as necessary to account for the explicitly-specified block-size. + block_size = candidate_block_size_iterator.candidate_value; + let delta = block_size - (cur_b - block_start_offset); + translate_including_floats(&mut cur_b, delta, &mut floats); - match self.fragment.style().get_box().box_sizing { - box_sizing::content_box => { - // Adjust `cur_b` as necessary to account for the explicitly-specified block-size. - block_size = candidate_block_size_iterator.candidate_value; - let delta = block_size - (cur_b - block_start_offset); - translate_including_floats(&mut cur_b, delta, &mut floats); - - // Take border and padding into account. - let block_end_offset = self.fragment.border_padding.block_end; - translate_including_floats(&mut cur_b, block_end_offset, &mut floats); - } - box_sizing::border_box => { - // Adjust `cur_b` as necessary to account for the explicitly-specified block-size. - block_size = candidate_block_size_iterator.candidate_value; - let delta = block_size - cur_b; - translate_including_floats(&mut cur_b, delta, &mut floats); - - // Take padding into account. - let block_end_offset = self.fragment.border_padding.block_end - - self.fragment.border_width().block_end; - translate_including_floats(&mut cur_b, block_end_offset, &mut floats); - } - } + // Take border and padding into account. + let block_end_offset = self.fragment.border_padding.block_end; + translate_including_floats(&mut cur_b, block_end_offset, &mut floats); // Now that `cur_b` is at the block-end of the border box, compute the final border box // position. @@ -1048,8 +1041,7 @@ impl BlockFlow { let info = PlacementInfo { size: LogicalSize::new( self.fragment.style.writing_mode, - self.base.position.size.inline + self.fragment.margin.inline_start_end() + - self.fragment.border_padding.inline_start_end(), + self.base.position.size.inline, block_size + self.fragment.margin.block_start_end()), ceiling: clearance + float_info.float_ceiling, max_inline_size: float_info.containing_inline_size, @@ -1105,7 +1097,8 @@ impl BlockFlow { DList::new())); } - accumulator.finish(&mut *self, display_list); + accumulator.finish(&mut display_list); + self.base.display_list = display_list; self.base.layers = child_layers } @@ -1187,16 +1180,17 @@ impl BlockFlow { available_block_size, static_b_offset)); } else { - let style = self.fragment.style(); let mut candidate_block_size_iterator = - CandidateBSizeIterator::new(style, Some(containing_block_block_size)); + CandidateBSizeIterator::new(&self.fragment, Some(containing_block_block_size)); - // Can't use `for` because we assign to candidate_block_size_iterator.candidate_value + // Can't use `for` because we assign to + // `candidate_block_size_iterator.candidate_value`. loop { match candidate_block_size_iterator.next() { Some(block_size_used_val) => { solution = - Some(BSizeConstraintSolution::solve_vertical_constraints_abs_nonreplaced( + Some(BSizeConstraintSolution:: + solve_vertical_constraints_abs_nonreplaced( block_size_used_val, margin_block_start, margin_block_end, @@ -1222,12 +1216,7 @@ impl BlockFlow { self.base.position.start.b = solution.block_start + self.fragment.margin.block_start; - let block_size = match self.fragment.style().get_box().box_sizing { - box_sizing::content_box => { - solution.block_size + self.fragment.border_padding.block_start_end() - } - box_sizing::border_box => solution.block_size, - }; + let block_size = solution.block_size + self.fragment.border_padding.block_start_end(); self.fragment.border_box.size.block = block_size; self.base.position.size.block = block_size; } @@ -1630,10 +1619,6 @@ impl Flow for BlockFlow { let padding_and_borders = self.fragment.border_padding.inline_start_end(); let content_inline_size = self.fragment.border_box.size.inline - padding_and_borders; - if self.is_float() { - self.base.position.size.inline = content_inline_size; - } - self.propagate_assigned_inline_size_to_children(inline_start_content_edge, content_inline_size, None); } @@ -1914,16 +1899,27 @@ pub trait ISizeAndMarginsComputer { /// calculation involving min-inline-size and max-inline-size, we don't need to /// recompute these. fn compute_inline_size_constraint_inputs(&self, - block: &mut BlockFlow, - parent_flow_inline_size: Au, - ctx: &LayoutContext) - -> ISizeConstraintInput { - let containing_block_inline_size = self.containing_block_inline_size(block, parent_flow_inline_size, ctx); - let computed_inline_size = self.initial_computed_inline_size(block, parent_flow_inline_size, ctx); + block: &mut BlockFlow, + parent_flow_inline_size: Au, + layout_context: &LayoutContext) + -> ISizeConstraintInput { + let containing_block_inline_size = + self.containing_block_inline_size(block, parent_flow_inline_size, layout_context); block.fragment.compute_border_padding_margins(containing_block_inline_size); + let mut computed_inline_size = self.initial_computed_inline_size(block, + parent_flow_inline_size, + layout_context); + let style = block.fragment.style(); + match (computed_inline_size, style.get_box().box_sizing) { + (Specified(size), box_sizing::border_box) => { + computed_inline_size = + Specified(size - block.fragment.border_padding.inline_start_end()) + } + (Auto, box_sizing::border_box) | (_, box_sizing::content_box) => {} + } // The text alignment of a block flow is the text alignment of its box's style. block.base.flags.set_text_align(style.get_inheritedtext().text_align); @@ -1955,6 +1951,7 @@ pub trait ISizeAndMarginsComputer { block: &mut BlockFlow, solution: ISizeConstraintSolution) { let inline_size; + let extra_inline_size_from_margin; { let fragment = block.fragment(); fragment.margin.inline_start = solution.margin_inline_start; @@ -1964,21 +1961,20 @@ pub trait ISizeAndMarginsComputer { fragment.border_box.start.i = fragment.margin.inline_start; // The associated fragment has the border box of this flow. - inline_size = match fragment.style().get_box().box_sizing { - box_sizing::content_box => { - solution.inline_size + fragment.border_padding.inline_start_end() - } - box_sizing::border_box => solution.inline_size, - }; - + inline_size = solution.inline_size + fragment.border_padding.inline_start_end(); fragment.border_box.size.inline = inline_size; + + // To calculate the total size of this block, we also need to account for any additional + // size contribution from positive margins. Negative margins means the block isn't made + // larger at all by the margin. + extra_inline_size_from_margin = max(Au(0), fragment.margin.inline_start) + + max(Au(0), fragment.margin.inline_end); } // We also resize the block itself, to ensure that overflow is not calculated // as the inline-size of our parent. We might be smaller and we might be larger if we // overflow. - let flow = flow::mut_base(block); - flow.position.size.inline = inline_size; + flow::mut_base(block).position.size.inline = inline_size + extra_inline_size_from_margin; } /// Set the x coordinate of the given flow if it is absolutely positioned. diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index d618851a175..2c5207e7fd9 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -19,7 +19,6 @@ use servo_util::str::DOMString; use std::mem; use std::hash::{Hash, sip}; use std::slice::Items; -use style; use style::{After, Before, ComputedValues, DeclarationBlock, Stylist, TElement, TNode}; use style::cascade; use sync::Arc; @@ -299,13 +298,13 @@ pub trait MatchMethods { fn recalc_style_for_subtree(&self, stylist: &Stylist, layout_context: &LayoutContext, - parent_bf: &mut Option<BloomFilter>, + parent_bf: &mut Option<Box<BloomFilter>>, applicable_declarations: &mut ApplicableDeclarations, parent: Option<LayoutNode>); fn match_node(&self, stylist: &Stylist, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, applicable_declarations: &mut ApplicableDeclarations, shareable: &mut bool); @@ -421,7 +420,7 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> { impl<'ln> MatchMethods for LayoutNode<'ln> { fn match_node(&self, stylist: &Stylist, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, applicable_declarations: &mut ApplicableDeclarations, shareable: &mut bool) { let style_attribute = self.as_element().style_attribute().as_ref(); @@ -506,13 +505,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { element.get_id().map(|id| bf.insert(&id)); // TODO: case-sensitivity depends on the document type and quirks mode - element - .get_attr(&ns!(""), "class") - .map(|attr| { - for c in attr.split(style::SELECTOR_WHITESPACE) { - bf.insert(&c); - } - }); + element.each_class(|class| bf.insert(class)); } fn remove_from_bloom_filter(&self, bf: &mut BloomFilter) { @@ -525,19 +518,13 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { element.get_id().map(|id| bf.remove(&id)); // TODO: case-sensitivity depends on the document type and quirks mode - element - .get_attr(&ns!(""), "class") - .map(|attr| { - for c in attr.split(style::SELECTOR_WHITESPACE) { - bf.remove(&c); - } - }); + element.each_class(|class| bf.remove(class)); } fn recalc_style_for_subtree(&self, stylist: &Stylist, layout_context: &LayoutContext, - parent_bf: &mut Option<BloomFilter>, + parent_bf: &mut Option<Box<BloomFilter>>, applicable_declarations: &mut ApplicableDeclarations, parent: Option<LayoutNode>) { self.initialize_layout_data(layout_context.shared.layout_chan.clone()); @@ -573,7 +560,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { match *parent_bf { None => {}, - Some(ref mut pbf) => self.insert_into_bloom_filter(pbf), + Some(ref mut pbf) => self.insert_into_bloom_filter(&mut **pbf), } for kid in self.children() { @@ -586,7 +573,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { match *parent_bf { None => {}, - Some(ref mut pbf) => self.remove_from_bloom_filter(pbf), + Some(ref mut pbf) => self.remove_from_bloom_filter(&mut **pbf), } // Construct flows. diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 835d5037b43..238ab4157dc 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -1833,8 +1833,11 @@ pub struct ChildDisplayListAccumulator { impl ChildDisplayListAccumulator { /// Creates a `ChildDisplayListAccumulator` from the `overflow` property in the given style. - fn new(style: &ComputedValues, bounds: Rect<Au>, node: OpaqueNode, - level: StackingLevel, may_need_clip: bool) + fn new(style: &ComputedValues, + bounds: Rect<Au>, + node: OpaqueNode, + level: StackingLevel, + may_need_clip: bool) -> ChildDisplayListAccumulator { ChildDisplayListAccumulator { clip_display_item: match (may_need_clip, style.get_box().overflow) { @@ -1869,9 +1872,9 @@ impl ChildDisplayListAccumulator { } } - /// Consumes this accumulator and pushes the clipping item, if any, onto the display list - /// associated with the given flow, along with the items in the given display list. - pub fn finish(self, parent: &mut Flow, mut display_list: DisplayList) { + /// Consumes this accumulator and pushes the clipping item, if any, onto the given display + /// list. + pub fn finish(self, display_list: &mut DisplayList) { let ChildDisplayListAccumulator { clip_display_item } = self; @@ -1879,6 +1882,5 @@ impl ChildDisplayListAccumulator { None => {} Some(clip_display_item) => display_list.push(ClipDisplayItemClass(clip_display_item)), } - flow::mut_base(parent).display_list = display_list } } diff --git a/components/layout/inline.rs b/components/layout/inline.rs index f6bcc0a3394..b4f1bdb386b 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -786,11 +786,13 @@ impl InlineFlow { let rel_offset = fragment.relative_position(&self.base .absolute_position_info .relative_containing_block_size); + let fragment_position = self.base + .abs_position + .add_size(&rel_offset.to_physical(self.base.writing_mode)); let mut accumulator = fragment.build_display_list(&mut self.base.display_list, - layout_context, - self.base.abs_position.add_size( - &rel_offset.to_physical(self.base.writing_mode)), - ContentLevel); + layout_context, + fragment_position, + ContentLevel); match fragment.specific { InlineBlockFragment(ref mut block_flow) => { let block_flow = block_flow.flow_ref.get_mut(); @@ -798,10 +800,9 @@ impl InlineFlow { } _ => {} } - } - // TODO(#225): Should `inline-block` elements have flows as children of the inline flow or - // should the flow be nested inside the fragment somehow? + accumulator.finish(&mut self.base.display_list); + } // For now, don't traverse the subtree rooted here. } diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index b2653496a6b..22068ae460b 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -16,6 +16,7 @@ use flow_ref::FlowRef; use layout_debug; use parallel::UnsafeFlow; use parallel; +use traversal; use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor}; use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode}; @@ -62,9 +63,7 @@ use std::cell::Cell; use std::comm::{channel, Sender, Receiver, Select}; use std::mem; use std::ptr; -use style; -use style::{TNode, AuthorOrigin, Stylesheet, Stylist}; -use style::iter_font_face_rules; +use style::{AuthorOrigin, Stylesheet, Stylist, TNode, iter_font_face_rules}; use sync::{Arc, Mutex, MutexGuard}; use url::Url; @@ -146,108 +145,6 @@ pub struct LayoutTask { pub rw_data: Arc<Mutex<LayoutTaskData>>, } -/// The flow tree verification traversal. This is only on in debug builds. -#[cfg(debug)] -struct FlowTreeVerificationTraversal; - -#[cfg(debug)] -impl PreorderFlowTraversal for FlowTreeVerificationTraversal { - #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { - let base = flow::base(flow); - if !base.flags.is_leaf() && !base.flags.is_nonleaf() { - println("flow tree verification failed: flow wasn't a leaf or a nonleaf!"); - flow.dump(); - fail!("flow tree verification failed") - } - true - } -} - -/// The bubble-inline-sizes traversal, the first part of layout computation. This computes preferred -/// and intrinsic inline-sizes and bubbles them up the tree. -pub struct BubbleISizesTraversal<'a> { - pub layout_context: &'a LayoutContext<'a>, -} - -impl<'a> PostorderFlowTraversal for BubbleISizesTraversal<'a> { - #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { - flow.bubble_inline_sizes(self.layout_context); - true - } - - // FIXME: We can't prune until we start reusing flows - /* - #[inline] - fn should_prune(&mut self, flow: &mut Flow) -> bool { - flow::mut_base(flow).restyle_damage.lacks(BubbleISizes) - } - */ -} - -/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`. -pub struct AssignISizesTraversal<'a> { - pub layout_context: &'a LayoutContext<'a>, -} - -impl<'a> PreorderFlowTraversal for AssignISizesTraversal<'a> { - #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { - flow.assign_inline_sizes(self.layout_context); - true - } -} - -/// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of layout -/// computation. Determines the final block-sizes for all layout objects, computes positions, and -/// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`. -pub struct AssignBSizesAndStoreOverflowTraversal<'a> { - pub layout_context: &'a LayoutContext<'a>, -} - -impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> { - #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { - flow.assign_block_size(self.layout_context); - // Skip store-overflow for absolutely positioned flows. That will be - // done in a separate traversal. - if !flow.is_store_overflow_delayed() { - flow.store_overflow(self.layout_context); - } - true - } - - #[inline] - fn should_process(&mut self, flow: &mut Flow) -> bool { - !flow::base(flow).flags.impacted_by_floats() - } -} - -/// The display list construction traversal. -pub struct BuildDisplayListTraversal<'a> { - layout_context: &'a LayoutContext<'a>, -} - -impl<'a> BuildDisplayListTraversal<'a> { - #[inline] - fn process(&mut self, flow: &mut Flow) { - flow.compute_absolute_position(); - - for kid in flow::mut_base(flow).child_iter() { - if !kid.is_absolutely_positioned() { - self.process(kid) - } - } - - for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() { - self.process(absolute_descendant_link) - } - - flow.build_display_list(self.layout_context) - } -} - struct LayoutImageResponder { id: PipelineId, script_chan: ScriptControlChan, @@ -617,7 +514,7 @@ impl LayoutTask { let _scope = layout_debug_scope!("solve_constraints"); if layout_context.shared.opts.bubble_inline_sizes_separately { - let mut traversal = BubbleISizesTraversal { + let mut traversal = traversal::BubbleISizes { layout_context: layout_context, }; layout_root.traverse_postorder(&mut traversal); @@ -625,14 +522,14 @@ impl LayoutTask { // FIXME(pcwalton): Prune these two passes. { - let mut traversal = AssignISizesTraversal { + let mut traversal = traversal::AssignISizes { layout_context: layout_context, }; layout_root.traverse_preorder(&mut traversal); } { - let mut traversal = AssignBSizesAndStoreOverflowTraversal { + let mut traversal = traversal::AssignBSizesAndStoreOverflow { layout_context: layout_context, }; layout_root.traverse_postorder(&mut traversal); @@ -650,7 +547,7 @@ impl LayoutTask { layout_root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) { if shared_layout_context.opts.bubble_inline_sizes_separately { - let mut traversal = BubbleISizesTraversal { + let mut traversal = traversal::BubbleISizes { layout_context: &LayoutContext::new(shared_layout_context), }; layout_root.get_mut().traverse_postorder(&mut traversal); @@ -677,7 +574,7 @@ impl LayoutTask { #[inline(never)] #[cfg(debug)] fn verify_flow_tree(&self, layout_root: &mut FlowRef) { - let mut traversal = FlowTreeVerificationTraversal; + let mut traversal = traversal::FlowTreeVerification; layout_root.traverse_preorder(&mut traversal); } @@ -748,8 +645,7 @@ impl LayoutTask { None => { let layout_ctx = LayoutContext::new(&shared_layout_ctx); let mut applicable_declarations = ApplicableDeclarations::new(); - let mut parent_bf = Some(BloomFilter::new( - style::RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE)); + let mut parent_bf = Some(box BloomFilter::new()); node.recalc_style_for_subtree(&*rw_data.stylist, &layout_ctx, &mut parent_bf, @@ -757,7 +653,7 @@ impl LayoutTask { None) } Some(ref mut traversal) => { - parallel::recalc_style_for_subtree(node, &mut shared_layout_ctx, traversal) + parallel::traverse_dom_preorder(*node, &mut shared_layout_ctx, traversal) } } @@ -807,7 +703,7 @@ impl LayoutTask { match rw_data.parallel_traversal { None => { let layout_ctx = LayoutContext::new(&shared_layout_ctx); - let mut traversal = BuildDisplayListTraversal { + let mut traversal = traversal::BuildDisplayList { layout_context: &layout_ctx, }; traversal.process(layout_root.get_mut()); diff --git a/components/layout/lib.rs b/components/layout/lib.rs index c15b2658ab4..13e11e06c54 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -62,6 +62,7 @@ pub mod table_rowgroup; pub mod table_row; pub mod table_cell; pub mod text; +pub mod traversal; pub mod util; pub mod incremental; pub mod wrapper; diff --git a/components/layout/model.rs b/components/layout/model.rs index 34cb231ba51..fca00da5994 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -307,6 +307,14 @@ impl MaybeAuto { pub fn specified_or_zero(&self) -> Au { self.specified_or_default(Au::new(0)) } + + #[inline] + pub fn map(&self, mapper: |Au| -> Au) -> MaybeAuto { + match *self { + Auto => Auto, + Specified(value) => Specified(mapper(value)), + } + } } pub fn specified_or_none(length: computed::LengthOrPercentageOrNone, containing_length: Au) -> Option<Au> { diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index 87478be9320..90e19f6db76 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -6,32 +6,24 @@ //! //! This code is highly unsafe. Keep this file small and easy to audit. -use css::node_style::StyledNode; -use css::matching::{ApplicableDeclarations, CannotShare, MatchMethods, StyleWasShared}; -use construct::FlowConstructor; use context::{LayoutContext, SharedLayoutContext}; use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; use flow; use flow_ref::FlowRef; -use incremental::RestyleDamage; -use layout_task::{AssignBSizesAndStoreOverflowTraversal, AssignISizesTraversal}; -use layout_task::{BubbleISizesTraversal}; +use traversal::{RecalcStyleForNode, ConstructFlows}; +use traversal::{AssignBSizesAndStoreOverflow, AssignISizes, BubbleISizes}; use url::Url; -use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods}; +use util::{LayoutDataAccess, LayoutDataWrapper}; use wrapper::{layout_node_to_unsafe_layout_node, layout_node_from_unsafe_layout_node, LayoutNode}; -use wrapper::{PostorderNodeMutTraversal, ThreadSafeLayoutNode, UnsafeLayoutNode}; +use wrapper::{PostorderNodeMutTraversal, UnsafeLayoutNode}; +use wrapper::{PreorderDomTraversal, PostorderDomTraversal}; -use gfx::display_list::OpaqueNode; -use servo_util::bloom::BloomFilter; -use servo_util::tid::tid; use servo_util::time::{TimeProfilerChan, profile}; use servo_util::time; use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy}; use std::mem; use std::ptr; use std::sync::atomics::{AtomicInt, Relaxed, SeqCst}; -use style; -use style::TNode; #[allow(dead_code)] fn static_assertion(node: UnsafeLayoutNode) { @@ -85,6 +77,113 @@ impl DomParallelInfo { } } +/// A parallel top-down DOM traversal. +pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { + fn run_parallel(&mut self, + node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>); + + #[inline(always)] + fn run_parallel_helper(&mut self, + unsafe_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>, + top_down_func: extern "Rust" fn(UnsafeFlow, + &mut WorkerProxy<*const SharedLayoutContext, + UnsafeLayoutNode>), + bottom_up_func: extern "Rust" fn(UnsafeFlow, + &mut WorkerProxy<*const SharedLayoutContext, + UnsafeFlow>)) { + // Get a real layout node. + let node: LayoutNode = unsafe { + layout_node_from_unsafe_layout_node(&unsafe_node) + }; + + // Perform the appropriate traversal. + self.process(node); + + // NB: O(n). + let child_count = node.children().count(); + + // Reset the count of children. + { + let mut layout_data_ref = node.mutate_layout_data(); + let layout_data = layout_data_ref.as_mut().expect("no layout data"); + layout_data.data.parallel.children_count.store(child_count as int, Relaxed); + } + + // Possibly enqueue the children. + if child_count != 0 { + for kid in node.children() { + proxy.push(WorkUnit { + fun: top_down_func, + data: layout_node_to_unsafe_layout_node(&kid), + }); + } + } else { + // If there were no more children, start walking back up. + bottom_up_func(unsafe_node, proxy) + } + } +} + +/// A parallel bottom-up DOM traversal. +trait ParallelPostorderDomTraversal : PostorderDomTraversal { + /// Process current node and potentially traverse its ancestors. + /// + /// If we are the last child that finished processing, recursively process + /// our parent. Else, stop. Also, stop at the root. + /// + /// Thus, if we start with all the leaves of a tree, we end up traversing + /// the whole tree bottom-up because each parent will be processed exactly + /// once (by the last child that finishes processing). + /// + /// The only communication between siblings is that they both + /// fetch-and-subtract the parent's children count. + fn run_parallel(&mut self, + mut unsafe_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>) { + loop { + // Get a real layout node. + let node: LayoutNode = unsafe { + layout_node_from_unsafe_layout_node(&unsafe_node) + }; + + // Perform the appropriate traversal. + self.process(node); + + let shared_layout_context = unsafe { &**proxy.user_data() }; + let layout_context = LayoutContext::new(shared_layout_context); + + let parent = + match node.layout_parent_node(layout_context.shared) { + None => break, + Some(parent) => parent, + }; + + unsafe { + let parent_layout_data = + (*parent.borrow_layout_data_unchecked()) + .as_ref() + .expect("no layout data"); + + unsafe_node = layout_node_to_unsafe_layout_node(&parent); + + let parent_layout_data: &mut LayoutDataWrapper = mem::transmute(parent_layout_data); + if parent_layout_data + .data + .parallel + .children_count + .fetch_sub(1, SeqCst) == 1 { + // We were the last child of our parent. Construct flows for our parent. + } else { + // Get out of here and find another node to work on. + break + } + } + } + } +} + /// Information that we need stored in each flow. pub struct FlowParallelInfo { /// The number of children that still need work done. @@ -131,6 +230,7 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal { self.process(flow.get_mut()); } + let base = flow::mut_base(flow.get_mut()); // Reset the count of children for the next layout traversal. @@ -204,9 +304,9 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { } } -impl<'a> ParallelPostorderFlowTraversal for BubbleISizesTraversal<'a> {} +impl<'a> ParallelPostorderFlowTraversal for BubbleISizes<'a> {} -impl<'a> ParallelPreorderFlowTraversal for AssignISizesTraversal<'a> { +impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> { fn run_parallel(&mut self, unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { @@ -217,291 +317,46 @@ impl<'a> ParallelPreorderFlowTraversal for AssignISizesTraversal<'a> { } } -impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> {} - -/// Every time we do another layout, the old bloom filters are invalid. This is -/// detected by ticking a generation number every layout. -type Generation = uint; - -/// A pair of the bloom filter used for css selector matching, and the node to -/// which it applies. This is used to efficiently do `Descendant` selector -/// matches. Thanks to the bloom filter, we can avoid walking up the tree -/// looking for ancestors that aren't there in the majority of cases. -/// -/// As we walk down the DOM tree a task-local bloom filter is built of all the -/// CSS `SimpleSelector`s which are part of a `Descendant` compound selector -/// (i.e. paired with a `Descendant` combinator, in the `next` field of a -/// `CompoundSelector`. -/// -/// Before a `Descendant` selector match is tried, it's compared against the -/// bloom filter. If the bloom filter can exclude it, the selector is quickly -/// rejected. -/// -/// When done styling a node, all selectors previously inserted into the filter -/// are removed. -/// -/// Since a work-stealing queue is used for styling, sometimes, the bloom filter -/// will no longer be the for the parent of the node we're currently on. When -/// this happens, the task local bloom filter will be thrown away and rebuilt. -local_data_key!(style_bloom: (BloomFilter, UnsafeLayoutNode, Generation)) - -/// Returns the task local bloom filter. -/// -/// If one does not exist, a new one will be made for you. If it is out of date, -/// it will be thrown out and a new one will be made for you. -fn take_task_local_bloom_filter( - parent_node: Option<LayoutNode>, - layout_context: &LayoutContext) - -> BloomFilter { - - let new_bloom = - |p: Option<LayoutNode>| -> BloomFilter { - let mut bf = BloomFilter::new(style::RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE); - p.map(|p| insert_ancestors_into_bloom_filter(&mut bf, p, layout_context)); - if p.is_none() { - debug!("[{}] No parent, but new bloom filter!", tid()); - } - bf - }; - - match (parent_node, style_bloom.replace(None)) { - // Root node. Needs new bloom filter. - (None, _ ) => new_bloom(None), - // No bloom filter for this thread yet. - (Some(p), None) => new_bloom(Some(p)), - // Found cached bloom filter. - (Some(p), Some((bf, old_node, old_generation))) => { - // Hey, the cached parent is our parent! We can reuse the bloom filter. - if old_node == layout_node_to_unsafe_layout_node(&p) && - old_generation == layout_context.shared.generation { - debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.val0()); - bf - // Oh no. the cached parent is stale. I guess we need a new one... - } else { - new_bloom(Some(p)) - } - }, - } -} +impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {} -fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode, layout_context: &LayoutContext) { - match style_bloom.replace(Some((bf, *unsafe_node, layout_context.shared.generation))) { - None => {}, - Some(_) => fail!("Putting into a never-taken task-local bloom filter"), - } -} +impl<'a> ParallelPostorderDomTraversal for ConstructFlows<'a> {} -/// "Ancestors" in this context is inclusive of ourselves. -fn insert_ancestors_into_bloom_filter( - bf: &mut BloomFilter, mut n: LayoutNode, layout_context: &LayoutContext) { - debug!("[{}] Inserting ancestors.", tid()); - let mut ancestors = 0u; - loop { - ancestors += 1; - - n.insert_into_bloom_filter(bf); - n = match n.layout_parent_node(layout_context.shared) { - None => break, - Some(p) => p, - }; +impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> { + fn run_parallel(&mut self, + unsafe_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeLayoutNode>) { + self.run_parallel_helper(unsafe_node, + proxy, + recalc_style, + construct_flows) } - debug!("[{}] Inserted {} ancestors.", tid(), ancestors); } -fn recalc_style_for_node(mut unsafe_layout_node: UnsafeLayoutNode, - proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>) { +fn recalc_style(unsafe_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeLayoutNode>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - - // Get a real layout node. - let node: LayoutNode = unsafe { - layout_node_from_unsafe_layout_node(&unsafe_layout_node) + let mut recalc_style_for_node_traversal = RecalcStyleForNode { + layout_context: &layout_context, }; - - // Initialize layout data. - // - // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML - // parser. - node.initialize_layout_data(layout_context.shared.layout_chan.clone()); - - // Get the parent node. - let parent_opt = node.layout_parent_node(layout_context.shared); - - // Get the style bloom filter. - let bf = take_task_local_bloom_filter(parent_opt, &layout_context); - - // Just needs to be wrapped in an option for `match_node`. - let some_bf = Some(bf); - - if node.is_dirty() { - // First, check to see whether we can share a style with someone. - let style_sharing_candidate_cache = layout_context.style_sharing_candidate_cache(); - let sharing_result = unsafe { - node.share_style_if_possible(style_sharing_candidate_cache, - parent_opt.clone()) - }; - // Otherwise, match and cascade selectors. - match sharing_result { - CannotShare(mut shareable) => { - let mut applicable_declarations = ApplicableDeclarations::new(); - - if node.is_element() { - // Perform the CSS selector matching. - let stylist = unsafe { &*layout_context.shared.stylist }; - node.match_node(stylist, &some_bf, &mut applicable_declarations, &mut shareable); - } - - // Perform the CSS cascade. - unsafe { - node.cascade_node(parent_opt, - &applicable_declarations, - layout_context.applicable_declarations_cache()); - } - - // Add ourselves to the LRU cache. - if shareable { - style_sharing_candidate_cache.insert_if_possible(&node); - } - } - StyleWasShared(index) => style_sharing_candidate_cache.touch(index), - } - } - - // Prepare for flow construction by counting the node's children and storing that count. - let mut child_count = 0u; - for _ in node.children() { - child_count += 1; - } - if child_count != 0 { - let mut layout_data_ref = node.mutate_layout_data(); - match &mut *layout_data_ref { - &Some(ref mut layout_data) => { - layout_data.data.parallel.children_count.store(child_count as int, Relaxed) - } - &None => fail!("no layout data"), - } - } - - // It can be `None` now. - let mut bf = some_bf; - - // Before running the children, we need to insert our nodes into the bloom - // filter. - debug!("[{}] + {:X}", tid(), unsafe_layout_node.val0()); - bf.as_mut().map(|bf| node.insert_into_bloom_filter(bf)); - - // It's *very* important that this block is in a separate scope to the block above, - // to avoid a data race that can occur (github issue #2308). The block above issues - // a borrow on the node layout data. That borrow must be dropped before the child - // nodes are actually pushed into the work queue. Otherwise, it's possible for a child - // node to get into construct_flows() and move up it's parent hierarchy, which can call - // borrow on the layout data before it is dropped from the block above. - if child_count != 0 { - // Enqueue kids. - for kid in node.children() { - proxy.push(WorkUnit { - fun: recalc_style_for_node, - data: layout_node_to_unsafe_layout_node(&kid), - }); - } - } else { - // If we got here, we're a leaf. Start construction of flows for this node. - construct_flows(&mut unsafe_layout_node, &mut bf, &layout_context); - } - - bf.map(|bf| put_task_local_bloom_filter(bf, &unsafe_layout_node, &layout_context)); + recalc_style_for_node_traversal.run_parallel(unsafe_node, proxy) } -fn construct_flows<'a>(unsafe_layout_node: &mut UnsafeLayoutNode, - parent_bf: &mut Option<BloomFilter>, - layout_context: &'a LayoutContext<'a>) { - loop { - // Get a real layout node. - let node: LayoutNode = unsafe { - layout_node_from_unsafe_layout_node(&*unsafe_layout_node) - }; - - // Construct flows for this node. - { - let node = ThreadSafeLayoutNode::new(&node); - let mut flow_constructor = FlowConstructor::new(layout_context); - flow_constructor.process(&node); - - // Reset the layout damage in this node. It's been propagated to the - // flow by the flow constructor. - node.set_restyle_damage(RestyleDamage::empty()); - } - - unsafe { - node.set_dirty(false); - node.set_dirty_descendants(false); - } - - // Reset the count of children for the next traversal. - // - // FIXME(pcwalton): Use children().len() when the implementation of that is efficient. - let mut child_count = 0u; - for _ in node.children() { - child_count += 1 - } - { - let mut layout_data_ref = node.mutate_layout_data(); - match &mut *layout_data_ref { - &Some(ref mut layout_data) => { - layout_data.data.parallel.children_count.store(child_count as int, Relaxed) - } - &None => fail!("no layout data"), - } - } - - // If this is the reflow root, we're done. - let opaque_node: OpaqueNode = OpaqueNodeMethods::from_layout_node(&node); - if layout_context.shared.reflow_root == opaque_node { - debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.val0()); - *parent_bf = None; - break; - } else { - debug!("[{}] - {:X}", tid(), unsafe_layout_node.val0()); - parent_bf.as_mut().map(|parent_bf| node.remove_from_bloom_filter(parent_bf)); - } - - // Otherwise, enqueue the parent. - match node.parent_node() { - Some(parent) => { - - // No, we're not at the root yet. Then are we the last sibling of our parent? - // If so, we can continue on with our parent; otherwise, we've gotta wait. - unsafe { - match *parent.borrow_layout_data_unchecked() { - Some(ref parent_layout_data) => { - *unsafe_layout_node = layout_node_to_unsafe_layout_node(&parent); - - let parent_layout_data: &mut LayoutDataWrapper = mem::transmute(parent_layout_data); - if parent_layout_data.data - .parallel - .children_count - .fetch_sub(1, SeqCst) == 1 { - // We were the last child of our parent. Construct flows for our - // parent. - } else { - // Get out of here and find another node to work on. - break - } - } - None => fail!("no layout data for parent?!"), - } - } - } - None => fail!("no parent and weren't at reflow root?!"), - } - } +fn construct_flows(unsafe_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeLayoutNode>) { + let shared_layout_context = unsafe { &**proxy.user_data() }; + let layout_context = LayoutContext::new(shared_layout_context); + let mut construct_flows_traversal = ConstructFlows { + layout_context: &layout_context, + }; + construct_flows_traversal.run_parallel(unsafe_node, proxy) } fn assign_inline_sizes(unsafe_flow: UnsafeFlow, - proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { + proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - let mut assign_inline_sizes_traversal = AssignISizesTraversal { + let mut assign_inline_sizes_traversal = AssignISizes { layout_context: &layout_context, }; assign_inline_sizes_traversal.run_parallel(unsafe_flow, proxy) @@ -511,7 +366,7 @@ fn assign_block_sizes_and_store_overflow(unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - let mut assign_block_sizes_traversal = AssignBSizesAndStoreOverflowTraversal { + let mut assign_block_sizes_traversal = AssignBSizesAndStoreOverflow { layout_context: &layout_context, }; assign_block_sizes_traversal.run_parallel(unsafe_flow, proxy) @@ -629,21 +484,19 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow, } } -pub fn recalc_style_for_subtree(root_node: &LayoutNode, - shared_layout_context: &SharedLayoutContext, - queue: &mut WorkQueue<*const SharedLayoutContext,UnsafeLayoutNode>) { - debug!("[{}] Style Recalc START", tid()); +pub fn traverse_dom_preorder(root: LayoutNode, + shared_layout_context: &SharedLayoutContext, + queue: &mut WorkQueue<*const SharedLayoutContext, UnsafeLayoutNode>) { queue.data = shared_layout_context as *const _; - // Enqueue the root node. queue.push(WorkUnit { - fun: recalc_style_for_node, - data: layout_node_to_unsafe_layout_node(root_node), + fun: recalc_style, + data: layout_node_to_unsafe_layout_node(&root), }); queue.run(); - queue.data = ptr::null() + queue.data = ptr::null(); } pub fn traverse_flow_tree_preorder(root: &mut FlowRef, diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs new file mode 100644 index 00000000000..d217e785321 --- /dev/null +++ b/components/layout/traversal.rs @@ -0,0 +1,337 @@ +/* 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/. */ + +//! Traversals over the DOM and flow trees, running the layout computations. + +use css::node_style::StyledNode; +use css::matching::{ApplicableDeclarations, CannotShare, MatchMethods, StyleWasShared}; +use construct::FlowConstructor; +use context::LayoutContext; +use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; +use flow; +use incremental::RestyleDamage; +use wrapper::{layout_node_to_unsafe_layout_node, LayoutNode}; +use wrapper::{PostorderNodeMutTraversal, ThreadSafeLayoutNode, UnsafeLayoutNode}; +use wrapper::{PreorderDomTraversal, PostorderDomTraversal}; + +use servo_util::bloom::BloomFilter; +use servo_util::tid::tid; +use style::TNode; + +/// Every time we do another layout, the old bloom filters are invalid. This is +/// detected by ticking a generation number every layout. +type Generation = uint; + +/// A pair of the bloom filter used for css selector matching, and the node to +/// which it applies. This is used to efficiently do `Descendant` selector +/// matches. Thanks to the bloom filter, we can avoid walking up the tree +/// looking for ancestors that aren't there in the majority of cases. +/// +/// As we walk down the DOM tree a task-local bloom filter is built of all the +/// CSS `SimpleSelector`s which are part of a `Descendant` compound selector +/// (i.e. paired with a `Descendant` combinator, in the `next` field of a +/// `CompoundSelector`. +/// +/// Before a `Descendant` selector match is tried, it's compared against the +/// bloom filter. If the bloom filter can exclude it, the selector is quickly +/// rejected. +/// +/// When done styling a node, all selectors previously inserted into the filter +/// are removed. +/// +/// Since a work-stealing queue is used for styling, sometimes, the bloom filter +/// will no longer be the for the parent of the node we're currently on. When +/// this happens, the task local bloom filter will be thrown away and rebuilt. +local_data_key!(style_bloom: (Box<BloomFilter>, UnsafeLayoutNode, Generation)) + +/// Returns the task local bloom filter. +/// +/// If one does not exist, a new one will be made for you. If it is out of date, +/// it will be thrown out and a new one will be made for you. +fn take_task_local_bloom_filter(parent_node: Option<LayoutNode>, layout_context: &LayoutContext) + -> Box<BloomFilter> { + match (parent_node, style_bloom.replace(None)) { + // Root node. Needs new bloom filter. + (None, _ ) => { + debug!("[{}] No parent, but new bloom filter!", tid()); + box BloomFilter::new() + } + // No bloom filter for this thread yet. + (Some(parent), None) => { + let mut bloom_filter = box BloomFilter::new(); + insert_ancestors_into_bloom_filter(&mut bloom_filter, parent, layout_context); + bloom_filter + } + // Found cached bloom filter. + (Some(parent), Some((mut bloom_filter, old_node, old_generation))) => { + // Hey, the cached parent is our parent! We can reuse the bloom filter. + if old_node == layout_node_to_unsafe_layout_node(&parent) && + old_generation == layout_context.shared.generation { + debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.val0()); + bloom_filter + } else { + // Oh no. the cached parent is stale. I guess we need a new one. Reuse the existing + // allocation to avoid malloc churn. + *bloom_filter = BloomFilter::new(); + insert_ancestors_into_bloom_filter(&mut bloom_filter, parent, layout_context); + bloom_filter + } + }, + } +} + +fn put_task_local_bloom_filter(bf: Box<BloomFilter>, + unsafe_node: &UnsafeLayoutNode, + layout_context: &LayoutContext) { + match style_bloom.replace(Some((bf, *unsafe_node, layout_context.shared.generation))) { + None => {}, + Some(_) => fail!("Putting into a never-taken task-local bloom filter"), + } +} + +/// "Ancestors" in this context is inclusive of ourselves. +fn insert_ancestors_into_bloom_filter(bf: &mut Box<BloomFilter>, + mut n: LayoutNode, + layout_context: &LayoutContext) { + debug!("[{}] Inserting ancestors.", tid()); + let mut ancestors = 0u; + loop { + ancestors += 1; + + n.insert_into_bloom_filter(&mut **bf); + n = match n.layout_parent_node(layout_context.shared) { + None => break, + Some(p) => p, + }; + } + debug!("[{}] Inserted {} ancestors.", tid(), ancestors); +} + +/// The recalc-style-for-node traversal, which styles each node and must run before +/// layout computation. This computes the styles applied to each node. +pub struct RecalcStyleForNode<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { + #[inline] + fn process(&self, node: LayoutNode) { + // Initialize layout data. + // + // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML + // parser. + node.initialize_layout_data(self.layout_context.shared.layout_chan.clone()); + + // Get the parent node. + let parent_opt = node.layout_parent_node(self.layout_context.shared); + + // Get the style bloom filter. + let bf = take_task_local_bloom_filter(parent_opt, self.layout_context); + + // Just needs to be wrapped in an option for `match_node`. + let some_bf = Some(bf); + + if node.is_dirty() { + // First, check to see whether we can share a style with someone. + let style_sharing_candidate_cache = + self.layout_context.style_sharing_candidate_cache(); + let sharing_result = unsafe { + node.share_style_if_possible(style_sharing_candidate_cache, + parent_opt.clone()) + }; + // Otherwise, match and cascade selectors. + match sharing_result { + CannotShare(mut shareable) => { + let mut applicable_declarations = ApplicableDeclarations::new(); + + if node.is_element() { + // Perform the CSS selector matching. + let stylist = unsafe { &*self.layout_context.shared.stylist }; + node.match_node(stylist, + &some_bf, + &mut applicable_declarations, + &mut shareable); + } + + // Perform the CSS cascade. + unsafe { + node.cascade_node(parent_opt, + &applicable_declarations, + self.layout_context.applicable_declarations_cache()); + } + + // Add ourselves to the LRU cache. + if shareable { + style_sharing_candidate_cache.insert_if_possible(&node); + } + } + StyleWasShared(index) => style_sharing_candidate_cache.touch(index), + } + } + + let mut bf = some_bf.unwrap(); + + let unsafe_layout_node = layout_node_to_unsafe_layout_node(&node); + + // Before running the children, we need to insert our nodes into the bloom + // filter. + debug!("[{}] + {:X}", tid(), unsafe_layout_node.val0()); + node.insert_into_bloom_filter(&mut *bf); + + // NB: flow construction updates the bloom filter on the way up. + put_task_local_bloom_filter(bf, &unsafe_layout_node, self.layout_context); + } +} + +/// The flow construction traversal, which builds flows for styled nodes. +pub struct ConstructFlows<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> PostorderDomTraversal for ConstructFlows<'a> { + #[inline] + fn process(&self, node: LayoutNode) { + // Construct flows for this node. + { + let node = ThreadSafeLayoutNode::new(&node); + let mut flow_constructor = FlowConstructor::new(self.layout_context); + flow_constructor.process(&node); + + // Reset the layout damage in this node. It's been propagated to the + // flow by the flow constructor. + node.set_restyle_damage(RestyleDamage::empty()); + } + + unsafe { + node.set_dirty(false); + node.set_dirty_descendants(false); + } + + let unsafe_layout_node = layout_node_to_unsafe_layout_node(&node); + + let (mut bf, old_node, old_generation) = + style_bloom + .replace(None) + .expect("The bloom filter should have been set by style recalc."); + + assert_eq!(old_node, unsafe_layout_node); + assert_eq!(old_generation, self.layout_context.shared.generation); + + match node.layout_parent_node(self.layout_context.shared) { + None => { + debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.val0()); + // If this is the reflow root, eat the task-local bloom filter. + } + Some(parent) => { + // Otherwise, put it back, but remove this node. + node.remove_from_bloom_filter(&mut *bf); + let unsafe_parent = layout_node_to_unsafe_layout_node(&parent); + put_task_local_bloom_filter(bf, &unsafe_parent, self.layout_context); + }, + }; + } +} + +/// The flow tree verification traversal. This is only on in debug builds. +#[cfg(debug)] +struct FlowTreeVerification; + +#[cfg(debug)] +impl PreorderFlow for FlowTreeVerification { + #[inline] + fn process(&mut self, flow: &mut Flow) -> bool { + let base = flow::base(flow); + if !base.flags.is_leaf() && !base.flags.is_nonleaf() { + println("flow tree verification failed: flow wasn't a leaf or a nonleaf!"); + flow.dump(); + fail!("flow tree verification failed") + } + true + } +} + +/// The bubble-inline-sizes traversal, the first part of layout computation. This computes +/// preferred and intrinsic inline-sizes and bubbles them up the tree. +pub struct BubbleISizes<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> PostorderFlowTraversal for BubbleISizes<'a> { + #[inline] + fn process(&mut self, flow: &mut Flow) -> bool { + flow.bubble_inline_sizes(self.layout_context); + true + } + + // FIXME: We can't prune until we start reusing flows + /* + #[inline] + fn should_prune(&mut self, flow: &mut Flow) -> bool { + flow::mut_base(flow).restyle_damage.lacks(BubbleISizes) + } + */ +} + +/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`. +pub struct AssignISizes<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> PreorderFlowTraversal for AssignISizes<'a> { + #[inline] + fn process(&mut self, flow: &mut Flow) -> bool { + flow.assign_inline_sizes(self.layout_context); + true + } +} + +/// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of +/// layout computation. Determines the final block-sizes for all layout objects, computes +/// positions, and computes overflow regions. In Gecko this corresponds to `Reflow` and +/// `FinishAndStoreOverflow`. +pub struct AssignBSizesAndStoreOverflow<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> { + #[inline] + fn process(&mut self, flow: &mut Flow) -> bool { + flow.assign_block_size(self.layout_context); + // Skip store-overflow for absolutely positioned flows. That will be + // done in a separate traversal. + if !flow.is_store_overflow_delayed() { + flow.store_overflow(self.layout_context); + } + true + } + + #[inline] + fn should_process(&mut self, flow: &mut Flow) -> bool { + !flow::base(flow).flags.impacted_by_floats() + } +} + +/// The display list construction traversal. +pub struct BuildDisplayList<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> BuildDisplayList<'a> { + #[inline] + pub fn process(&mut self, flow: &mut Flow) { + flow.compute_absolute_position(); + + for kid in flow::mut_base(flow).child_iter() { + if !kid.is_absolutely_positioned() { + self.process(kid) + } + } + + for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() { + self.process(absolute_descendant_link) + } + + flow.build_display_list(self.layout_context) + } +} diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 2cc58e6e7b0..7cde321f058 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -496,6 +496,20 @@ impl<'le> TElement<'le> for LayoutElement<'le> { self.element.has_class_for_layout(name) } } + + #[inline(always)] + fn each_class(self, callback: |&Atom|) { + unsafe { + match self.element.get_classes_for_layout() { + None => {} + Some(mut classes) => { + for class in classes { + callback(class) + } + } + } + } + } } fn get_content(content_list: &content::T) -> String { @@ -888,3 +902,15 @@ pub unsafe fn layout_node_from_unsafe_layout_node(node: &UnsafeLayoutNode) -> La let (node, _) = *node; mem::transmute(node) } + +/// A top-down traversal. +pub trait PreorderDomTraversal { + /// The operation to perform. Return true to continue or false to stop. + fn process(&self, node: LayoutNode); +} + +/// A bottom-up traversal, with a optional in-order pass. +pub trait PostorderDomTraversal { + /// The operation to perform. Return true to continue or false to stop. + fn process(&self, node: LayoutNode); +} diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index ce1371f74ef..ef5ec630670 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -38,6 +38,7 @@ use std::ascii::StrAsciiExt; use std::cell::RefCell; use std::default::Default; use std::mem; +use std::slice::Items; use string_cache::{Atom, Namespace}; use url::UrlParser; @@ -172,6 +173,7 @@ pub trait RawLayoutElementHelpers { unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &str) -> Vec<&'a str>; unsafe fn get_attr_atom_for_layout(&self, namespace: &Namespace, name: &str) -> Option<Atom>; unsafe fn has_class_for_layout(&self, name: &str) -> bool; + unsafe fn get_classes_for_layout<'a>(&'a self) -> Option<Items<'a,Atom>>; } impl RawLayoutElementHelpers for Element { @@ -234,6 +236,19 @@ impl RawLayoutElementHelpers for Element { (*attr).value_tokens_forever().map(|mut tokens| { tokens.any(|atom| atom.as_slice() == name) }) }.take().unwrap()) } + + #[inline] + #[allow(unrooted_must_root)] + unsafe fn get_classes_for_layout<'a>(&'a self) -> Option<Items<'a,Atom>> { + let attrs: *const Vec<JS<Attr>> = mem::transmute(&self.attrs); + (*attrs).iter().find(|attr: & &JS<Attr>| { + let attr = attr.unsafe_get(); + (*attr).local_name_atom_forever().as_slice() == "class" + }).and_then(|attr| { + let attr = attr.unsafe_get(); + (*attr).value_tokens_forever() + }) + } } pub trait LayoutElementHelpers { @@ -1052,4 +1067,19 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> { has_class(self, name) } + fn each_class(self, callback: |&Atom|) { + match self.get_attribute(ns!(""), "class").root() { + None => {} + Some(attr) => { + match attr.deref().value().tokens() { + None => {} + Some(mut tokens) => { + for token in tokens { + callback(token) + } + } + } + } + } + } } diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index baf3fba6c93..f12035d148e 100644 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -4,18 +4,19 @@ use dom::bindings::codegen::Bindings::HTMLButtonElementBinding; use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods; -use dom::bindings::codegen::InheritTypes::{HTMLElementCast, NodeCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLButtonElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; -use dom::element::{AttributeHandlers, HTMLButtonElementTypeId}; +use dom::element::{AttributeHandlers, Element, HTMLButtonElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, window_from_node}; use dom::validitystate::ValidityState; use dom::virtualmethods::VirtualMethods; +use std::ascii::OwnedStrAsciiExt; use servo_util::str::DOMString; use string_cache::Atom; @@ -56,6 +57,20 @@ impl<'a> HTMLButtonElementMethods for JSRef<'a, HTMLButtonElement> { // http://www.whatwg.org/html/#dom-fe-disabled make_bool_setter!(SetDisabled, "disabled") + + // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type + fn Type(self) -> DOMString { + let elem: JSRef<Element> = ElementCast::from_ref(self); + let ty = elem.get_string_attribute("type").into_ascii_lower(); + // https://html.spec.whatwg.org/multipage/forms.html#attr-button-type + match ty.as_slice() { + "reset" | "button" | "menu" => ty, + _ => "submit".to_string() + } + } + + // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type + make_setter!(SetType, "type") } impl<'a> VirtualMethods for JSRef<'a, HTMLButtonElement> { diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 7b2ee466bab..03bd593cb64 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -2,19 +2,32 @@ * 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::EventBinding::EventMethods; +use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::codegen::Bindings::HTMLFormElementBinding; use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods; -use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFormElementDerived}; +use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; +use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLFormElementDerived, NodeCast}; +use dom::bindings::codegen::InheritTypes::HTMLInputElementCast; +use dom::bindings::global::Window; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; -use dom::document::Document; -use dom::element::{Element, AttributeHandlers, HTMLFormElementTypeId}; +use dom::document::{Document, DocumentHelpers}; +use dom::element::{Element, AttributeHandlers, HTMLFormElementTypeId, HTMLTextAreaElementTypeId, HTMLDataListElementTypeId}; +use dom::element::{HTMLInputElementTypeId, HTMLButtonElementTypeId, HTMLObjectElementTypeId, HTMLSelectElementTypeId}; +use dom::event::Event; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; -use dom::node::{Node, ElementNodeTypeId, window_from_node}; +use dom::htmlinputelement::HTMLInputElement; +use dom::node::{Node, NodeHelpers, ElementNodeTypeId, document_from_node, window_from_node}; +use http::method::Post; +use servo_msg::constellation_msg::LoadData; use servo_util::str::DOMString; +use script_task::{ScriptChan, TriggerLoadMsg}; use std::ascii::OwnedStrAsciiExt; - +use std::str::StrSlice; +use url::UrlParser; +use url::form_urlencoded::serialize; #[jstraceable] #[must_root] @@ -52,7 +65,7 @@ impl<'a> HTMLFormElementMethods for JSRef<'a, HTMLFormElement> { // https://html.spec.whatwg.org/multipage/forms.html#dom-fs-action fn Action(self) -> DOMString { let element: JSRef<Element> = ElementCast::from_ref(self); - let url = element.get_url_attribute("src"); + let url = element.get_url_attribute("action"); match url.as_slice() { "" => { let window = window_from_node(self).root(); @@ -135,6 +148,196 @@ impl<'a> HTMLFormElementMethods for JSRef<'a, HTMLFormElement> { // https://html.spec.whatwg.org/multipage/forms.html#dom-fs-target make_setter!(SetTarget, "target") + + // https://html.spec.whatwg.org/multipage/forms.html#the-form-element:concept-form-submit + fn Submit(self) { + self.submit(true, FormElement(self)); + } +} + +pub trait HTMLFormElementHelpers { + // https://html.spec.whatwg.org/multipage/forms.html#concept-form-submit + fn submit(self, from_submit_method: bool, submitter: FormSubmitter); + // https://html.spec.whatwg.org/multipage/forms.html#constructing-the-form-data-set + fn get_form_dataset(self, submitter: Option<FormSubmitter>) -> Vec<FormDatum>; +} + +impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> { + fn submit(self, _from_submit_method: bool, submitter: FormSubmitter) { + // Step 1 + let doc = document_from_node(self).root(); + let win = window_from_node(self).root(); + let base = doc.url(); + // TODO: Handle browsing contexts + // TODO: Handle validation + let event = Event::new(&Window(*win), + "submit".to_string(), + true, true).root(); + let target: JSRef<EventTarget> = EventTargetCast::from_ref(self); + target.DispatchEvent(*event).ok(); + if event.DefaultPrevented() { + return; + } + // Step 6 + let form_data = self.get_form_dataset(Some(submitter)); + // Step 7-8 + let mut action = submitter.action(); + if action.is_empty() { + action = base.serialize(); + } + // TODO: Resolve the url relative to the submitter element + // Step 10-15 + let action_components = UrlParser::new().base_url(base).parse(action.as_slice()).unwrap_or(base.clone()); + let _action = action_components.serialize(); + let scheme = action_components.scheme.clone(); + let enctype = submitter.enctype(); + let method = submitter.method(); + let _target = submitter.target(); + // TODO: Handle browsing contexts, partially loaded documents (step 16-17) + + let parsed_data = match enctype { + UrlEncoded => serialize(form_data.iter().map(|d| (d.name.as_slice(), d.value.as_slice())), None), + _ => "".to_string() // TODO: Add serializers for the other encoding types + }; + + let mut load_data = LoadData::new(action_components); + // Step 18 + match (scheme.as_slice(), method) { + (_, FormDialog) => return, // Unimplemented + ("http", FormGet) | ("https", FormGet) => { + load_data.url.query = Some(parsed_data); + }, + ("http", FormPost) | ("https", FormPost) => { + load_data.method = Post; + load_data.data = Some(parsed_data.into_bytes()); + }, + // https://html.spec.whatwg.org/multipage/forms.html#submit-get-action + ("ftp", _) | ("javascript", _) | ("data", FormGet) => (), + _ => return // Unimplemented (data and mailto) + } + + // This is wrong. https://html.spec.whatwg.org/multipage/forms.html#planned-navigation + let ScriptChan(ref script_chan) = win.script_chan; + script_chan.send(TriggerLoadMsg(win.page.id, load_data)); + } + + fn get_form_dataset(self, _submitter: Option<FormSubmitter>) -> Vec<FormDatum> { + fn clean_crlf(s: &str) -> DOMString { + // https://html.spec.whatwg.org/multipage/forms.html#constructing-the-form-data-set + // Step 4 + let mut buf = "".to_string(); + let mut prev = ' '; + for ch in s.chars() { + match ch { + '\n' if prev != '\r' => { + buf.push_char('\r'); + buf.push_char('\n'); + }, + '\n' => { + buf.push_char('\n'); + }, + // This character isn't LF but is + // preceded by CR + _ if prev == '\r' => { + buf.push_char('\r'); + buf.push_char('\n'); + buf.push_char(ch); + }, + _ => buf.push_char(ch) + }; + prev = ch; + } + // In case the last character was CR + if prev == '\r' { + buf.push_char('\n'); + } + buf + } + + let node: JSRef<Node> = NodeCast::from_ref(self); + // TODO: This is an incorrect way of getting controls owned + // by the form, but good enough until html5ever lands + let mut data_set = node.traverse_preorder().filter_map(|child| { + if child.get_disabled_state() { + return None; + } + if child.ancestors().any(|a| a.type_id() == ElementNodeTypeId(HTMLDataListElementTypeId)) { + return None; + } + // XXXManishearth don't include it if it is a button but not the submitter + match child.type_id() { + ElementNodeTypeId(HTMLInputElementTypeId) => { + let input: JSRef<HTMLInputElement> = HTMLInputElementCast::to_ref(child).unwrap(); + let ty = input.Type(); + let name = input.Name(); + match ty.as_slice() { + "radio" | "checkbox" => { + if !input.Checked() || name.is_empty() { + return None; + } + }, + "image" => (), + _ => { + if name.is_empty() { + return None; + } + } + } + + let mut value = input.Value(); + match ty.as_slice() { + "image" => None, // Unimplemented + "radio" | "checkbox" => { + if value.is_empty() { + value = "on".to_string(); + } + Some(FormDatum { + ty: ty, + name: name, + value: value + }) + }, + "file" => None, // Unimplemented + _ => Some(FormDatum { + ty: ty, + name: name, + value: input.Value() + }) + } + } + ElementNodeTypeId(HTMLButtonElementTypeId) => { + // Unimplemented + None + } + ElementNodeTypeId(HTMLSelectElementTypeId) => { + // Unimplemented + None + } + ElementNodeTypeId(HTMLObjectElementTypeId) => { + // Unimplemented + None + } + ElementNodeTypeId(HTMLTextAreaElementTypeId) => { + // Unimplemented + None + } + _ => None + } + }); + // TODO: Handle `dirnames` (needs directionality support) + // https://html.spec.whatwg.org/multipage/dom.html#the-directionality + let mut ret: Vec<FormDatum> = data_set.collect(); + for mut datum in ret.iter_mut() { + match datum.ty.as_slice() { + "file" | "textarea" => (), + _ => { + datum.name = clean_crlf(datum.name.as_slice()); + datum.value = clean_crlf(datum.value.as_slice()); + } + } + }; + ret + } } impl Reflectable for HTMLFormElement { @@ -142,3 +345,67 @@ impl Reflectable for HTMLFormElement { self.htmlelement.reflector() } } + +// TODO: add file support +pub struct FormDatum { + pub ty: DOMString, + pub name: DOMString, + pub value: DOMString +} + +pub enum FormEncType { + TextPlainEncoded, + UrlEncoded, + FormDataEncoded +} + +pub enum FormMethod { + FormGet, + FormPost, + FormDialog +} + +pub enum FormSubmitter<'a> { + FormElement(JSRef<'a, HTMLFormElement>) + // TODO: Submit buttons, image submit, etc etc +} + +impl<'a> FormSubmitter<'a> { + fn action(&self) -> DOMString { + match *self { + FormElement(form) => form.Action() + } + } + + fn enctype(&self) -> FormEncType { + match *self { + FormElement(form) => { + match form.Enctype().as_slice() { + "multipart/form-data" => FormDataEncoded, + "text/plain" => TextPlainEncoded, + // https://html.spec.whatwg.org/multipage/forms.html#attr-fs-enctype + // urlencoded is the default + _ => UrlEncoded + } + } + } + } + + fn method(&self) -> FormMethod { + match *self { + FormElement(form) => { + match form.Method().as_slice() { + "dialog" => FormDialog, + "post" => FormPost, + _ => FormGet + } + } + } + } + + fn target(&self) -> DOMString { + match *self { + FormElement(form) => form.Target() + } + } +} diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 9908807a713..ab9818d99f0 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -24,6 +24,7 @@ use dom::virtualmethods::VirtualMethods; use servo_util::str::{DOMString, parse_unsigned_integer}; use string_cache::Atom; +use std::ascii::OwnedStrAsciiExt; use std::cell::{Cell, RefCell}; use std::mem; @@ -120,7 +121,9 @@ impl<'a> HTMLInputElementMethods for JSRef<'a, HTMLInputElement> { make_bool_setter!(SetDisabled, "disabled") // https://html.spec.whatwg.org/multipage/forms.html#dom-input-checked - make_bool_getter!(Checked) + fn Checked(self) -> bool { + self.checked.get() + } // https://html.spec.whatwg.org/multipage/forms.html#dom-input-checked make_bool_setter!(SetChecked, "checked") @@ -131,8 +134,30 @@ impl<'a> HTMLInputElementMethods for JSRef<'a, HTMLInputElement> { // https://html.spec.whatwg.org/multipage/forms.html#dom-input-size make_uint_setter!(SetSize, "size") + // https://html.spec.whatwg.org/multipage/forms.html#dom-input-type + fn Type(self) -> DOMString { + let elem: JSRef<Element> = ElementCast::from_ref(self); + let ty = elem.get_string_attribute("type").into_ascii_lower(); + // https://html.spec.whatwg.org/multipage/forms.html#attr-input-type + match ty.as_slice() { + "hidden" | "search" | "tel" | + "url" | "email" | "password" | + "datetime" | "date" | "month" | + "week" | "time" | "datetime-local" | + "number" | "range" | "color" | + "checkbox" | "radio" | "file" | + "submit" | "image" | "reset" | "button" => ty, + _ => "text".to_string() + } + } + + // https://html.spec.whatwg.org/multipage/forms.html#dom-input-type + make_setter!(SetType, "type") + // https://html.spec.whatwg.org/multipage/forms.html#dom-input-value - make_getter!(Value) + fn Value(self) -> DOMString { + self.value.borrow().clone().unwrap_or("".to_string()) + } // https://html.spec.whatwg.org/multipage/forms.html#dom-input-value make_setter!(SetValue, "value") diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index f5aadd3c956..1d39c3a07f5 100644 --- a/components/script/dom/htmlobjectelement.rs +++ b/components/script/dom/htmlobjectelement.rs @@ -86,6 +86,12 @@ impl<'a> HTMLObjectElementMethods for JSRef<'a, HTMLObjectElement> { let window = window_from_node(self).root(); ValidityState::new(*window) } + + // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-object-type + make_getter!(Type) + + // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-object-type + make_setter!(SetType, "type") } impl<'a> VirtualMethods for JSRef<'a, HTMLObjectElement> { diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 53f8ce3efff..8c86318c38c 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -5,13 +5,13 @@ use dom::bindings::codegen::Bindings::HTMLSelectElementBinding; use dom::bindings::codegen::Bindings::HTMLSelectElementBinding::HTMLSelectElementMethods; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, NodeCast}; -use dom::bindings::codegen::InheritTypes::{HTMLSelectElementDerived, HTMLFieldSetElementDerived}; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLSelectElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::codegen::UnionTypes::HTMLElementOrLong::HTMLElementOrLong; use dom::bindings::codegen::UnionTypes::HTMLOptionElementOrHTMLOptGroupElement::HTMLOptionElementOrHTMLOptGroupElement; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; -use dom::element::{AttributeHandlers, HTMLSelectElementTypeId}; +use dom::element::{AttributeHandlers, Element, HTMLSelectElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, window_from_node}; @@ -62,6 +62,16 @@ impl<'a> HTMLSelectElementMethods for JSRef<'a, HTMLSelectElement> { // http://www.whatwg.org/html/#dom-fe-disabled make_bool_setter!(SetDisabled, "disabled") + + // https://html.spec.whatwg.org/multipage/forms.html#dom-select-type + fn Type(self) -> DOMString { + let elem: JSRef<Element> = ElementCast::from_ref(self); + if elem.has_attribute("multiple") { + "select-multiple".to_string() + } else { + "select-one".to_string() + } + } } impl<'a> VirtualMethods for JSRef<'a, HTMLSelectElement> { diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 5dd688782cf..d109a26c524 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -50,6 +50,11 @@ impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> { // http://www.whatwg.org/html/#dom-fe-disabled make_bool_setter!(SetDisabled, "disabled") + + // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-type + fn Type(self) -> DOMString { + "textarea".to_string() + } } impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 9810c67a877..957abd558ec 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -51,6 +51,10 @@ impl<'a> NavigatorMethods for JSRef<'a, Navigator> { fn Platform(self) -> DOMString { NavigatorInfo::Platform() } + + fn UserAgent(self) -> DOMString { + NavigatorInfo::UserAgent() + } } impl Reflectable for Navigator { diff --git a/components/script/dom/navigatorinfo.rs b/components/script/dom/navigatorinfo.rs index 8832aca8697..d8081ef134a 100644 --- a/components/script/dom/navigatorinfo.rs +++ b/components/script/dom/navigatorinfo.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use servo_util::str::DOMString; +use servo_util::opts; pub struct NavigatorInfo; @@ -26,4 +27,11 @@ impl NavigatorInfo { pub fn Platform() -> DOMString { "".to_string() } + + pub fn UserAgent() -> DOMString { + match opts::get().user_agent { + Some(ref user_agent) => user_agent.clone(), + None => "".to_string(), + } + } } diff --git a/components/script/dom/webidls/HTMLButtonElement.webidl b/components/script/dom/webidls/HTMLButtonElement.webidl index ad21e11370f..622abbd1cf5 100644 --- a/components/script/dom/webidls/HTMLButtonElement.webidl +++ b/components/script/dom/webidls/HTMLButtonElement.webidl @@ -14,7 +14,7 @@ interface HTMLButtonElement : HTMLElement { // attribute boolean formNoValidate; // attribute DOMString formTarget; // attribute DOMString name; - // attribute DOMString type; + attribute DOMString type; // attribute DOMString value; // attribute HTMLMenuElement? menu; diff --git a/components/script/dom/webidls/HTMLFormElement.webidl b/components/script/dom/webidls/HTMLFormElement.webidl index 0878a6931a2..1971680b5be 100644 --- a/components/script/dom/webidls/HTMLFormElement.webidl +++ b/components/script/dom/webidls/HTMLFormElement.webidl @@ -21,7 +21,7 @@ interface HTMLFormElement : HTMLElement { //getter Element (unsigned long index); //getter (RadioNodeList or Element) (DOMString name); - //void submit(); + void submit(); //void reset(); //boolean checkValidity(); //boolean reportValidity(); diff --git a/components/script/dom/webidls/HTMLInputElement.webidl b/components/script/dom/webidls/HTMLInputElement.webidl index a418f50928c..f2b888dca47 100644 --- a/components/script/dom/webidls/HTMLInputElement.webidl +++ b/components/script/dom/webidls/HTMLInputElement.webidl @@ -37,7 +37,7 @@ interface HTMLInputElement : HTMLElement { attribute unsigned long size; // attribute DOMString src; // attribute DOMString step; - // attribute DOMString type; //XXXjdm need binaryName + attribute DOMString type; // attribute DOMString defaultValue; [TreatNullAs=EmptyString] attribute DOMString value; // attribute Date? valueAsDate; diff --git a/components/script/dom/webidls/HTMLObjectElement.webidl b/components/script/dom/webidls/HTMLObjectElement.webidl index 56fc290e546..e2f6aa3cb75 100644 --- a/components/script/dom/webidls/HTMLObjectElement.webidl +++ b/components/script/dom/webidls/HTMLObjectElement.webidl @@ -6,7 +6,7 @@ // http://www.whatwg.org/html/#htmlobjectelement interface HTMLObjectElement : HTMLElement { // attribute DOMString data; - // attribute DOMString type; + attribute DOMString type; // attribute boolean typeMustMatch; // attribute DOMString name; // attribute DOMString useMap; diff --git a/components/script/dom/webidls/HTMLSelectElement.webidl b/components/script/dom/webidls/HTMLSelectElement.webidl index 91d4c3b0917..6b36b65e709 100644 --- a/components/script/dom/webidls/HTMLSelectElement.webidl +++ b/components/script/dom/webidls/HTMLSelectElement.webidl @@ -13,7 +13,7 @@ interface HTMLSelectElement : HTMLElement { // attribute boolean required; // attribute unsigned long size; - //readonly attribute DOMString type; + readonly attribute DOMString type; //readonly attribute HTMLOptionsCollection options; // attribute unsigned long length; diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 534bb87a0e5..f3fb5b3cf40 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -21,7 +21,7 @@ interface HTMLTextAreaElement : HTMLElement { // attribute unsigned long rows; // attribute DOMString wrap; - //readonly attribute DOMString type; + readonly attribute DOMString type; // attribute DOMString defaultValue; //[TreatNullAs=EmptyString] attribute DOMString value; //readonly attribute unsigned long textLength; diff --git a/components/script/dom/webidls/Navigator.webidl b/components/script/dom/webidls/Navigator.webidl index 16d96d53470..0ce509f4c04 100644 --- a/components/script/dom/webidls/Navigator.webidl +++ b/components/script/dom/webidls/Navigator.webidl @@ -23,5 +23,5 @@ interface NavigatorID { readonly attribute DOMString platform; readonly attribute DOMString product; // constant "Gecko" boolean taintEnabled(); // constant false - //readonly attribute DOMString userAgent; + readonly attribute DOMString userAgent; }; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 02166f328e4..f3edfc04943 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -24,6 +24,7 @@ use script_task::{ExitWindowMsg, FireTimerMsg, ScriptChan, TriggerLoadMsg, Trigg use script_traits::ScriptControlChan; use servo_msg::compositor_msg::ScriptListener; +use servo_msg::constellation_msg::LoadData; use servo_net::image_cache_task::ImageCacheTask; use servo_util::str::{DOMString,HTML_SPACE_CHARACTERS}; use servo_util::task::{spawn_named}; @@ -432,7 +433,7 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { if href.as_slice().starts_with("#") { script_chan.send(TriggerFragmentMsg(self.page.id, url)); } else { - script_chan.send(TriggerLoadMsg(self.page.id, url)); + script_chan.send(TriggerLoadMsg(self.page.id, LoadData::new(url))); } } diff --git a/components/script/dom/workernavigator.rs b/components/script/dom/workernavigator.rs index 2265b23c6bc..2d3c496048c 100644 --- a/components/script/dom/workernavigator.rs +++ b/components/script/dom/workernavigator.rs @@ -51,6 +51,10 @@ impl<'a> WorkerNavigatorMethods for JSRef<'a, WorkerNavigator> { fn Platform(self) -> DOMString { NavigatorInfo::Platform() } + + fn UserAgent(self) -> DOMString { + NavigatorInfo::UserAgent() + } } impl Reflectable for WorkerNavigator { diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 29e1fec40ba..e62c818943c 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -81,7 +81,7 @@ pub enum ScriptMsg { TriggerFragmentMsg(PipelineId, Url), /// Begins a content-initiated load on the specified pipeline (only /// dispatched to ScriptTask). - TriggerLoadMsg(PipelineId, Url), + TriggerLoadMsg(PipelineId, LoadData), /// Instructs the script task to send a navigate message to /// the constellation (only dispatched to ScriptTask). NavigateMsg(NavigationDirection), @@ -494,7 +494,7 @@ impl ScriptTask { // TODO(tkuehn) need to handle auxiliary layouts for iframes FromConstellation(AttachLayoutMsg(_)) => fail!("should have handled AttachLayoutMsg already"), FromConstellation(LoadMsg(id, load_data)) => self.load(id, load_data), - FromScript(TriggerLoadMsg(id, url)) => self.trigger_load(id, url), + FromScript(TriggerLoadMsg(id, load_data)) => self.trigger_load(id, load_data), FromScript(TriggerFragmentMsg(id, url)) => self.trigger_fragment(id, url), FromConstellation(SendEventMsg(id, event)) => self.handle_event(id, event), FromScript(FireTimerMsg(id, timer_id)) => self.handle_fire_timer_msg(id, timer_id), @@ -1067,9 +1067,9 @@ impl ScriptTask { /// The entry point for content to notify that a new load has been requested /// for the given pipeline. - fn trigger_load(&self, pipeline_id: PipelineId, url: Url) { + fn trigger_load(&self, pipeline_id: PipelineId, load_data: LoadData) { let ConstellationChan(ref const_chan) = self.constellation_chan; - const_chan.send(LoadUrlMsg(pipeline_id, LoadData::new(url))); + const_chan.send(LoadUrlMsg(pipeline_id, load_data)); } /// The entry point for content to notify that a fragment url has been requested diff --git a/components/style/node.rs b/components/style/node.rs index 8a8930fdc81..8fc74d5738c 100644 --- a/components/style/node.rs +++ b/components/style/node.rs @@ -38,4 +38,5 @@ pub trait TElement<'a> : Copy { fn get_disabled_state(self) -> bool; fn get_enabled_state(self) -> bool; fn has_class(self, name: &str) -> bool; + fn each_class(self, callback: |&Atom|); } diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index fc37688cea0..39e0fb73e5f 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::ascii::AsciiExt; use std::collections::hashmap::HashMap; use std::hash::Hash; use std::num::div_rem; @@ -85,7 +86,7 @@ impl SelectorMap { V:VecLike<DeclarationBlock>>( &self, node: &N, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, matching_rules_list: &mut V, shareable: &mut bool) { if self.empty { @@ -153,7 +154,7 @@ impl SelectorMap { N:TNode<'a, E>, V:VecLike<DeclarationBlock>>( node: &N, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, hash: &HashMap<Atom, Vec<Rule>>, key: &Atom, matching_rules: &mut V, @@ -172,7 +173,7 @@ impl SelectorMap { N:TNode<'a, E>, V:VecLike<DeclarationBlock>>( node: &N, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, rules: &[Rule], matching_rules: &mut V, shareable: &mut bool) { @@ -279,12 +280,18 @@ impl Stylist { after_map: PerPseudoElementSelectorMap::new(), rules_source_order: 0u, }; - let ua_stylesheet = Stylesheet::from_bytes( - read_resource_file(["user-agent.css"]).unwrap().as_slice(), - Url::parse("chrome:///user-agent.css").unwrap(), - None, - None); - stylist.add_stylesheet(ua_stylesheet, UserAgentOrigin); + // FIXME: Add quirks-mode.css in quirks mode. + // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8. + // FIXME: presentational-hints.css should be at author origin with zero specificity. + // (Does it make a difference?) + for &filename in ["user-agent.css", "servo.css", "presentational-hints.css"].iter() { + let ua_stylesheet = Stylesheet::from_bytes( + read_resource_file([filename]).unwrap().as_slice(), + Url::parse(format!("chrome:///{}", filename).as_slice()).unwrap(), + None, + None); + stylist.add_stylesheet(ua_stylesheet, UserAgentOrigin); + } stylist } @@ -353,7 +360,7 @@ impl Stylist { V:VecLike<DeclarationBlock>>( &self, element: &N, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, style_attribute: Option<&PropertyDeclarationBlock>, pseudo_element: Option<PseudoElement>, applicable_declarations: &mut V) @@ -471,7 +478,12 @@ impl DeclarationBlock { } } -pub fn matches<'a, E:TElement<'a>, N:TNode<'a, E>>(selector_list: &SelectorList, element: &N, parent_bf: &Option<BloomFilter>) -> bool { +pub fn matches<'a,E,N>( + selector_list: &SelectorList, + element: &N, + parent_bf: &Option<Box<BloomFilter>>) + -> bool + where E: TElement<'a>, N: TNode<'a,E> { get_selector_list_selectors(selector_list).iter().any(|selector| selector.pseudo_element.is_none() && matches_compound_selector(&*selector.compound_selectors, element, parent_bf, &mut false)) @@ -488,7 +500,7 @@ fn matches_compound_selector<'a, N:TNode<'a, E>>( selector: &CompoundSelector, element: &N, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, shareable: &mut bool) -> bool { match matches_compound_selector_internal(selector, element, parent_bf, shareable) { @@ -549,21 +561,22 @@ enum SelectorMatchingResult { /// Quickly figures out whether or not the compound selector is worth doing more /// work on. If the simple selectors don't match, or there's a child selector /// that does not appear in the bloom parent bloom filter, we can exit early. -fn can_fast_reject<'a, E: TElement<'a>, N: TNode<'a, E>>( - mut selector: &CompoundSelector, - element: &N, - parent_bf: &Option<BloomFilter>, - shareable: &mut bool) -> Option<SelectorMatchingResult> { +fn can_fast_reject<'a,E,N>( + mut selector: &CompoundSelector, + element: &N, + parent_bf: &Option<Box<BloomFilter>>, + shareable: &mut bool) + -> Option<SelectorMatchingResult> + where E: TElement<'a>, N: TNode<'a,E> { if !selector.simple_selectors.iter().all(|simple_selector| { matches_simple_selector(simple_selector, element, shareable) }) { return Some(NotMatchedAndRestartFromClosestLaterSibling); } - let bf: &BloomFilter = - match *parent_bf { - None => return None, - Some(ref bf) => bf, - }; + let bf: &BloomFilter = match *parent_bf { + None => return None, + Some(ref bf) => &**bf, + }; // See if the bloom filter can exclude any of the descendant selectors, and // reject if we can. @@ -580,23 +593,23 @@ fn can_fast_reject<'a, E: TElement<'a>, N: TNode<'a, E>>( for ss in selector.simple_selectors.iter() { match *ss { LocalNameSelector(LocalName { ref name, ref lower_name }) => { - if bf.definitely_excludes(name) - && bf.definitely_excludes(lower_name) { + if !bf.might_contain(name) + && !bf.might_contain(lower_name) { return Some(NotMatchedGlobally); } }, NamespaceSelector(ref namespace) => { - if bf.definitely_excludes(namespace) { + if !bf.might_contain(namespace) { return Some(NotMatchedGlobally); } }, IDSelector(ref id) => { - if bf.definitely_excludes(id) { + if !bf.might_contain(id) { return Some(NotMatchedGlobally); } }, ClassSelector(ref class) => { - if bf.definitely_excludes(&class.as_slice()) { + if !bf.might_contain(class) { return Some(NotMatchedGlobally); } }, @@ -615,7 +628,7 @@ fn matches_compound_selector_internal<'a, N:TNode<'a, E>>( selector: &CompoundSelector, element: &N, - parent_bf: &Option<BloomFilter>, + parent_bf: &Option<Box<BloomFilter>>, shareable: &mut bool) -> SelectorMatchingResult { match can_fast_reject(selector, element, parent_bf, shareable) { @@ -723,14 +736,17 @@ pub fn matches_simple_selector<'a, E:TElement<'a>, *shareable = false; element.match_attr(attr, |_| true) } - AttrEqual(ref attr, ref value) => { + AttrEqual(ref attr, ref value, case_sensitivity) => { if value.as_slice() != "DIR" { // FIXME(pcwalton): Remove once we start actually supporting RTL text. This is in // here because the UA style otherwise disables all style sharing completely. *shareable = false } element.match_attr(attr, |attr_value| { - attr_value == value.as_slice() + match case_sensitivity { + CaseSensitive => attr_value == value.as_slice(), + CaseInsensitive => attr_value.eq_ignore_ascii_case(value.as_slice()), + } }) } AttrIncludes(ref attr, ref value) => { @@ -994,7 +1010,6 @@ impl<K: Eq + Hash, V> FindPush<K, V> for HashMap<K, Vec<V>> { } } - #[cfg(test)] mod tests { use sync::Arc; diff --git a/components/style/selectors.rs b/components/style/selectors.rs index 7a6f8637cda..6c783e70349 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -61,9 +61,9 @@ pub enum SimpleSelector { // Attribute selectors AttrExists(AttrSelector), // [foo] - AttrEqual(AttrSelector, String), // [foo=bar] + AttrEqual(AttrSelector, String, CaseSensitivity), // [foo=bar] AttrIncludes(AttrSelector, String), // [foo~=bar] - AttrDashMatch(AttrSelector, String, String), // [foo|=bar] Second string is the first + "-" + AttrDashMatch(AttrSelector, String, String), // [foo|=bar] Second string is the first + "-" AttrPrefixMatch(AttrSelector, String), // [foo^=bar] AttrSubstringMatch(AttrSelector, String), // [foo*=bar] AttrSuffixMatch(AttrSelector, String), // [foo$=bar] @@ -90,6 +90,14 @@ pub enum SimpleSelector { // ... } + +#[deriving(Eq, PartialEq, Clone, Hash)] +pub enum CaseSensitivity { + CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive. + CaseInsensitive, +} + + #[deriving(Eq, PartialEq, Clone, Hash)] pub struct LocalName { pub name: Atom, @@ -446,25 +454,21 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace }; skip_whitespace(iter); // TODO: deal with empty value or value containing whitespace (see spec) - macro_rules! get_value( () => {{ - skip_whitespace(iter); - match iter.next() { - Some(Ident(value)) | Some(QuotedString(value)) => value, - _ => return Err(()) - } - }};) let result = match iter.next() { None => AttrExists(attr), // [foo] - Some(Delim('=')) => AttrEqual(attr, (get_value!())), // [foo=bar] - Some(IncludeMatch) => AttrIncludes(attr, (get_value!())), // [foo~=bar] + Some(Delim('=')) => AttrEqual( + attr, try!(parse_attribute_value(iter)), + try!(parse_attribute_flags(iter))), // [foo=bar] + Some(IncludeMatch) => AttrIncludes(attr, try!(parse_attribute_value(iter))), // [foo~=bar] Some(DashMatch) => { - let value = get_value!(); + let value = try!(parse_attribute_value(iter)); let dashing_value = format!("{}-", value); AttrDashMatch(attr, value, dashing_value) // [foo|=bar] }, - Some(PrefixMatch) => AttrPrefixMatch(attr, (get_value!())), // [foo^=bar] - Some(SubstringMatch) => AttrSubstringMatch(attr, (get_value!())), // [foo*=bar] - Some(SuffixMatch) => AttrSuffixMatch(attr, (get_value!())), // [foo$=bar] + Some(PrefixMatch) => AttrPrefixMatch(attr, try!(parse_attribute_value(iter))), // [foo^=bar] + // [foo*=bar] + Some(SubstringMatch) => AttrSubstringMatch(attr, try!(parse_attribute_value(iter))), + Some(SuffixMatch) => AttrSuffixMatch(attr, try!(parse_attribute_value(iter))), // [foo$=bar] _ => return Err(()) }; skip_whitespace(iter); @@ -472,6 +476,27 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace } +fn parse_attribute_value<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) -> Result<String, ()> { + skip_whitespace(iter); + match iter.next() { + Some(Ident(value)) | Some(QuotedString(value)) => Ok(value), + _ => Err(()) + } +} + + +fn parse_attribute_flags<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) + -> Result<CaseSensitivity, ()> { + skip_whitespace(iter); + match iter.next() { + None => Ok(CaseSensitive), + Some(Ident(ref value)) if value.as_slice().eq_ignore_ascii_case("i") + => Ok(CaseInsensitive), + _ => Err(()) + } +} + + fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> { match name.to_ascii_lower().as_slice() { "any-link" => Ok(AnyLink), diff --git a/components/util/bloom.rs b/components/util/bloom.rs index 4621697fa50..6795cb889e8 100644 --- a/components/util/bloom.rs +++ b/components/util/bloom.rs @@ -4,288 +4,230 @@ //! Simple counting bloom filters. -extern crate rand; +use string_cache::{Atom, Namespace}; -use fnv::{FnvState, hash}; -use rand::Rng; -use std::hash::Hash; -use std::iter; -use std::num; -use std::uint; +static KEY_SIZE: uint = 12; +static ARRAY_SIZE: uint = 1 << KEY_SIZE; +static KEY_MASK: u32 = (1 << KEY_SIZE) - 1; +static KEY_SHIFT: uint = 16; -// Just a quick and dirty xxhash embedding. - -/// A counting bloom filter. +/// A counting Bloom filter with 8-bit counters. For now we assume +/// that having two hash functions is enough, but we may revisit that +/// decision later. +/// +/// The filter uses an array with 2**KeySize entries. +/// +/// Assuming a well-distributed hash function, a Bloom filter with +/// array size M containing N elements and +/// using k hash function has expected false positive rate exactly +/// +/// $ (1 - (1 - 1/M)^{kN})^k $ +/// +/// because each array slot has a +/// +/// $ (1 - 1/M)^{kN} $ +/// +/// chance of being 0, and the expected false positive rate is the +/// probability that all of the k hash functions will hit a nonzero +/// slot. +/// +/// For reasonable assumptions (M large, kN large, which should both +/// hold if we're worried about false positives) about M and kN this +/// becomes approximately /// -/// A bloom filter is a probabilistic data structure which allows you to add and -/// remove elements from a set, query the set for whether it may contain an -/// element or definitely exclude it, and uses much less ram than an equivalent -/// hashtable. -#[deriving(Clone)] +/// $$ (1 - \exp(-kN/M))^k $$ +/// +/// For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$, +/// or in other words +/// +/// $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$ +/// +/// where r is the false positive rate. This can be used to compute +/// the desired KeySize for a given load N and false positive rate r. +/// +/// If N/M is assumed small, then the false positive rate can +/// further be approximated as 4*N^2/M^2. So increasing KeySize by +/// 1, which doubles M, reduces the false positive rate by about a +/// factor of 4, and a false positive rate of 1% corresponds to +/// about M/N == 20. +/// +/// What this means in practice is that for a few hundred keys using a +/// KeySize of 12 gives false positive rates on the order of 0.25-4%. +/// +/// Similarly, using a KeySize of 10 would lead to a 4% false +/// positive rate for N == 100 and to quite bad false positive +/// rates for larger N. pub struct BloomFilter { - buf: Vec<uint>, - number_of_insertions: uint, -} - -// Here's where some of the magic numbers came from: -// -// m = number of elements in the filter -// n = size of the filter -// k = number of hash functions -// -// p = Pr[false positive] = 0.01 false positive rate -// -// if we have an estimation of the number of elements in the bloom filter, we -// know m. -// -// p = (1 - exp(-kn/m))^k -// k = (m/n)ln2 -// lnp = -(m/n)(ln2)^2 -// m = -nlnp/(ln2)^2 -// => n = -m(ln2)^2/lnp -// ~= 10*m -// -// k = (m/n)ln2 = 10ln2 ~= 7 - -static NUMBER_OF_HASHES: uint = 7; - -static BITS_PER_BUCKET: uint = 4; -static BUCKETS_PER_WORD: uint = uint::BITS / BITS_PER_BUCKET; - -/// Returns a tuple of (array index, lsr shift amount) to get to the bits you -/// need. Don't forget to mask with 0xF! -fn bucket_index_to_array_index(bucket_index: uint) -> (uint, uint) { - let arr_index = bucket_index / BUCKETS_PER_WORD; - let shift_amount = (bucket_index % BUCKETS_PER_WORD) * BITS_PER_BUCKET; - (arr_index, shift_amount) -} - -// Key Stretching -// ============== -// -// Siphash is expensive. Instead of running it `NUMBER_OF_HASHES`, which would -// be a pretty big hit on performance, we just use it to see a non-cryptographic -// random number generator. This stretches the hash to get us our -// `NUMBER_OF_HASHES` array indicies. -// -// A hash is a `u64` and comes from SipHash. -// A shash is a `uint` stretched hash which comes from the XorShiftRng. - -fn to_rng(hash: u64) -> rand::XorShiftRng { - let bottom = (hash & 0xFFFFFFFF) as u32; - let top = ((hash >> 32) & 0xFFFFFFFF) as u32; - rand::SeedableRng::from_seed([ 0x97830e05, 0x113ba7bb, bottom, top ]) + counters: [u8, ..ARRAY_SIZE], } -fn stretch<'a>(r: &'a mut rand::XorShiftRng) - -> iter::Take<rand::Generator<'a, uint, rand::XorShiftRng>> { - r.gen_iter().take(NUMBER_OF_HASHES) +impl Clone for BloomFilter { + #[inline] + fn clone(&self) -> BloomFilter { + BloomFilter { + counters: self.counters, + } + } } impl BloomFilter { - /// This bloom filter is tuned to have ~1% false positive rate. In exchange - /// for this guarantee, you need to have a reasonable upper bound on the - /// number of elements that will ever be inserted into it. If you guess too - /// low, your false positive rate will suffer. If you guess too high, you'll - /// use more memory than is really necessary. - pub fn new(expected_number_of_insertions: uint) -> BloomFilter { - let size_in_buckets = 10 * expected_number_of_insertions; - - let size_in_words = size_in_buckets / BUCKETS_PER_WORD; - - let nonzero_size = if size_in_words == 0 { 1 } else { size_in_words }; - - let num_words = - num::checked_next_power_of_two(nonzero_size) - .unwrap(); - + /// Creates a new bloom filter. + #[inline] + pub fn new() -> BloomFilter { BloomFilter { - buf: Vec::from_elem(num_words, 0), - number_of_insertions: 0, + counters: [0, ..ARRAY_SIZE], } } - /// Since the array length must be a power of two, this will return a - /// bitmask that can be `&`ed with a number to bring it into the range of - /// the array. - fn mask(&self) -> uint { - (self.buf.len()*BUCKETS_PER_WORD) - 1 // guaranteed to be a power of two + #[inline] + fn first_slot(&self, hash: u32) -> &u8 { + &self.counters[hash1(hash) as uint] } - /// Converts a stretched hash into a bucket index. - fn shash_to_bucket_index(&self, shash: uint) -> uint { - shash & self.mask() + #[inline] + fn first_mut_slot(&mut self, hash: u32) -> &mut u8 { + &mut self.counters[hash1(hash) as uint] } - /// Converts a stretched hash into an array and bit index. See the comment - /// on `bucket_index_to_array_index` for details about the return value. - fn shash_to_array_index(&self, shash: uint) -> (uint, uint) { - bucket_index_to_array_index(self.shash_to_bucket_index(shash)) + #[inline] + fn second_slot(&self, hash: u32) -> &u8 { + &self.counters[hash2(hash) as uint] } - /// Gets the value at a given bucket. - fn bucket_get(&self, a_idx: uint, shift_amount: uint) -> uint { - let array_val = self.buf[a_idx]; - (array_val >> shift_amount) & 0xF + #[inline] + fn second_mut_slot(&mut self, hash: u32) -> &mut u8 { + &mut self.counters[hash2(hash) as uint] } - /// Sets the value at a given bucket. This will not bounds check, but that's - /// ok because you've called `bucket_get` first, anyhow. - fn bucket_set(&mut self, a_idx: uint, shift_amount: uint, new_val: uint) { - // We can avoid bounds checking here since in order to do a bucket_set - // we have to had done a `bucket_get` at the same index for it to make - // sense. - let old_val = self.buf.as_mut_slice().get_mut(a_idx).unwrap(); - let mask = (1 << BITS_PER_BUCKET) - 1; // selects the right-most bucket - let select_in_bucket = mask << shift_amount; // selects the correct bucket - let select_out_of_bucket = !select_in_bucket; // selects everything except the correct bucket - let new_array_val = (new_val << shift_amount) // move the new_val into the right spot - | (*old_val & select_out_of_bucket); // mask out the old value, and or it with the new one - *old_val = new_array_val; + #[inline] + pub fn clear(&mut self) { + self.counters = [0, ..ARRAY_SIZE] } - /// Insert a stretched hash into the bloom filter, remembering to saturate - /// the counter instead of overflowing. - fn insert_shash(&mut self, shash: uint) { - let (a_idx, shift_amount) = self.shash_to_array_index(shash); - let b_val = self.bucket_get(a_idx, shift_amount); - - - // saturate the count. - if b_val == 0xF { - return; + #[inline] + fn insert_hash(&mut self, hash: u32) { + { + let slot1 = self.first_mut_slot(hash); + if !full(slot1) { + *slot1 += 1 + } } - - let new_val = b_val + 1; - - self.bucket_set(a_idx, shift_amount, new_val); - } - - /// Insert a hashed value into the bloom filter. - fn insert_hashed(&mut self, hash: u64) { - self.number_of_insertions += 1; - for h in stretch(&mut to_rng(hash)) { - self.insert_shash(h); + { + let slot2 = self.second_mut_slot(hash); + if !full(slot2) { + *slot2 += 1 + } } } - /// Inserts a value into the bloom filter. Note that the bloom filter isn't - /// parameterized over the values it holds. That's because it can hold - /// values of different types, as long as it can get a hash out of them. - pub fn insert<H: Hash<FnvState>>(&mut self, h: &H) { - self.insert_hashed(hash(h)) - } - - /// Removes a stretched hash from the bloom filter, taking care not to - /// decrememnt saturated counters. - /// - /// It is an error to remove never-inserted elements. - fn remove_shash(&mut self, shash: uint) { - let (a_idx, shift_amount) = self.shash_to_array_index(shash); - let b_val = self.bucket_get(a_idx, shift_amount); - assert!(b_val != 0, "Removing an element that was never inserted."); + /// Inserts an item into the bloom filter. + #[inline] + pub fn insert<T:BloomHash>(&mut self, elem: &T) { + self.insert_hash(elem.bloom_hash()) - // can't do anything if the counter saturated. - if b_val == 0xF { return; } - - self.bucket_set(a_idx, shift_amount, b_val - 1); } - /// Removes a hashed value from the bloom filter. - fn remove_hashed(&mut self, hash: u64) { - self.number_of_insertions -= 1; - for h in stretch(&mut to_rng(hash)) { - self.remove_shash(h); + #[inline] + fn remove_hash(&mut self, hash: u32) { + { + let slot1 = self.first_mut_slot(hash); + if !full(slot1) { + *slot1 -= 1 + } + } + { + let slot2 = self.second_mut_slot(hash); + if !full(slot2) { + *slot2 -= 1 + } } } - /// Removes a value from the bloom filter. - /// - /// Be careful of adding and removing lots of elements, especially for - /// long-lived bloom filters. The counters in each bucket will saturate if - /// 16 or more elements hash to it, and then stick there. This will hurt - /// your false positive rate. To fix this, you might consider refreshing the - /// bloom filter by `clear`ing it, and then reinserting elements at regular, - /// long intervals. - /// - /// It is an error to remove never-inserted elements. - pub fn remove<H: Hash<FnvState>>(&mut self, h: &H) { - self.remove_hashed(hash(h)) + /// Removes an item from the bloom filter. + #[inline] + pub fn remove<T:BloomHash>(&mut self, elem: &T) { + self.remove_hash(elem.bloom_hash()) } - /// Returns `true` if the bloom filter cannot possibly contain the given - /// stretched hash. - fn definitely_excludes_shash(&self, shash: uint) -> bool { - let (a_idx, shift_amount) = self.shash_to_array_index(shash); - self.bucket_get(a_idx, shift_amount) == 0 + #[inline] + fn might_contain_hash(&self, hash: u32) -> bool { + *self.first_slot(hash) != 0 && *self.second_slot(hash) != 0 } - /// A hash is definitely excluded iff none of the stretched hashes are in - /// the bloom filter. - fn definitely_excludes_hashed(&self, hash: u64) -> bool { - let mut ret = false; + /// Check whether the filter might contain an item. This can + /// sometimes return true even if the item is not in the filter, + /// but will never return false for items that are actually in the + /// filter. + #[inline] + pub fn might_contain<T:BloomHash>(&self, elem: &T) -> bool { + self.might_contain_hash(elem.bloom_hash()) + } +} - // Doing `.any` is slower than this branch-free version. - for shash in stretch(&mut to_rng(hash)) { - ret |= self.definitely_excludes_shash(shash); - } +pub trait BloomHash { + fn bloom_hash(&self) -> u32; +} - ret +impl BloomHash for int { + #[inline] + fn bloom_hash(&self) -> u32 { + ((*self >> 32) ^ *self) as u32 } +} - /// A bloom filter can tell you whether or not a value has definitely never - /// been inserted. Note that bloom filters can give false positives. - pub fn definitely_excludes<H: Hash<FnvState>>(&self, h: &H) -> bool { - self.definitely_excludes_hashed(hash(h)) +impl BloomHash for uint { + #[inline] + fn bloom_hash(&self) -> u32 { + ((*self >> 32) ^ *self) as u32 } +} - /// A bloom filter can tell you if an element /may/ be in it. It cannot be - /// certain. But, assuming correct usage, this query will have a low false - /// positive rate. - pub fn may_include<H: Hash<FnvState>>(&self, h: &H) -> bool { - !self.definitely_excludes(h) +impl BloomHash for Atom { + #[inline] + fn bloom_hash(&self) -> u32 { + ((self.data >> 32) ^ self.data) as u32 } +} - /// Returns the number of elements ever inserted into the bloom filter - the - /// number of elements removed. - pub fn number_of_insertions(&self) -> uint { - self.number_of_insertions +impl BloomHash for Namespace { + #[inline] + fn bloom_hash(&self) -> u32 { + let Namespace(ref atom) = *self; + atom.bloom_hash() } +} - /// Returns the number of bytes of memory the bloom filter uses. - pub fn size(&self) -> uint { - self.buf.len() * uint::BYTES - } +#[inline] +fn full(slot: &u8) -> bool { + *slot == 0xff +} - /// Removes all elements from the bloom filter. This is both more efficient - /// and has better false-positive properties than repeatedly calling `remove` - /// on every element. - pub fn clear(&mut self) { - self.number_of_insertions = 0; - for x in self.buf.as_mut_slice().iter_mut() { - *x = 0u; - } - } +#[inline] +fn hash1(hash: u32) -> u32 { + hash & KEY_MASK +} + +#[inline] +fn hash2(hash: u32) -> u32 { + (hash >> KEY_SHIFT) & KEY_MASK } #[test] fn create_and_insert_some_stuff() { use std::iter::range; - let mut bf = BloomFilter::new(1000); + let mut bf = BloomFilter::new(); for i in range(0u, 1000) { bf.insert(&i); } - assert_eq!(bf.number_of_insertions(), 1000); - for i in range(0u, 1000) { - assert!(bf.may_include(&i)); + assert!(bf.might_contain(&i)); } let false_positives = - range(1001u, 2000).filter(|i| bf.may_include(&i)).count(); + range(1001u, 2000).filter(|i| bf.might_contain(i)).count(); assert!(false_positives < 10) // 1%. @@ -293,22 +235,18 @@ fn create_and_insert_some_stuff() { bf.remove(&i); } - assert_eq!(bf.number_of_insertions(), 900); - for i in range(100u, 1000) { - assert!(bf.may_include(&i)); + assert!(bf.might_contain(&i)); } - let false_positives = range(0u, 100).filter(|i| bf.may_include(&i)).count(); + let false_positives = range(0u, 100).filter(|i| bf.might_contain(i)).count(); assert!(false_positives < 2); // 2%. bf.clear(); - assert_eq!(bf.number_of_insertions(), 0); - for i in range(0u, 2000) { - assert!(bf.definitely_excludes(&i)); + assert!(!bf.might_contain(&i)); } } @@ -323,7 +261,7 @@ mod bench { #[bench] fn create_insert_1000_remove_100_lookup_100(b: &mut test::Bencher) { b.iter(|| { - let mut bf = BloomFilter::new(1000); + let mut bf = BloomFilter::new(); for i in iter::range(0u, 1000) { bf.insert(&i); } @@ -331,14 +269,14 @@ mod bench { bf.remove(&i); } for i in iter::range(100u, 200) { - test::black_box(bf.may_include(&i)); + test::black_box(bf.might_contain(&i)); } }); } #[bench] - fn may_include(b: &mut test::Bencher) { - let mut bf = BloomFilter::new(1000); + fn might_contain(b: &mut test::Bencher) { + let mut bf = BloomFilter::new(); for i in iter::range(0u, 1000) { bf.insert(&i); @@ -348,7 +286,7 @@ mod bench { b.bench_n(1000, |b| { b.iter(|| { - test::black_box(bf.may_include(&i)); + test::black_box(bf.might_contain(&i)); i += 1; }); }); @@ -356,7 +294,7 @@ mod bench { #[bench] fn insert(b: &mut test::Bencher) { - let mut bf = BloomFilter::new(1000); + let mut bf = BloomFilter::new(); b.bench_n(1000, |b| { let mut i = 0u; @@ -370,7 +308,7 @@ mod bench { #[bench] fn remove(b: &mut test::Bencher) { - let mut bf = BloomFilter::new(1000); + let mut bf = BloomFilter::new(); for i in range(0u, 1000) { bf.insert(&i); } @@ -384,7 +322,7 @@ mod bench { }); }); - test::black_box(bf.may_include(&0u)); + test::black_box(bf.might_contain(&0u)); } #[bench] @@ -396,3 +334,4 @@ mod bench { }) } } + diff --git a/components/util/namespace.rs b/components/util/namespace.rs index 810ac7c4456..c138a29706a 100644 --- a/components/util/namespace.rs +++ b/components/util/namespace.rs @@ -11,3 +11,4 @@ pub fn from_domstring(url: Option<DOMString>) -> Namespace { Some(ref s) => Namespace(Atom::from_slice(s.as_slice())), } } + diff --git a/components/util/opts.rs b/components/util/opts.rs index de8b295d1eb..b5970a1f5c1 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -15,6 +15,7 @@ use layers::geometry::DevicePixel; use getopts; use std::cmp; use std::io; +use std::mem; use std::os; use std::rt; @@ -230,7 +231,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> { } }; - Some(Opts { + let opts = Opts { urls: urls, render_backend: render_backend, n_render_threads: n_render_threads, @@ -253,7 +254,14 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> { initial_window_size: initial_window_size, user_agent: opt_match.opt_str("u"), dump_flow_tree: opt_match.opt_present("dump-flow-tree"), - }) + }; + + unsafe { + let box_opts = box opts.clone(); + OPTIONS = mem::transmute(box_opts); + } + + Some(opts) } static mut EXPERIMENTAL_ENABLED: bool = false; @@ -269,3 +277,14 @@ pub fn experimental_enabled() -> bool { EXPERIMENTAL_ENABLED } } + +// Make Opts available globally. This saves having to clone and pass +// opts everywhere it is used, which gets particularly cumbersome +// when passing through the DOM structures. +// GWTODO: Change existing code that takes copies of opts to instead +// make use of the global copy. +static mut OPTIONS: *mut Opts = 0 as *mut Opts; + +pub fn get() -> &'static Opts { + unsafe { mem::transmute(OPTIONS) } +} diff --git a/ports/android/Makefile b/ports/android/Makefile index 6328462c60b..e23d4c8ee5e 100644 --- a/ports/android/Makefile +++ b/ports/android/Makefile @@ -1,9 +1,11 @@ +CARGO_OPTS ?= + .PHONY: all -all: +all: glut_app NDK_DEBUG=1 $(ANDROID_NDK)/ndk-build -B - find ../../target ! \( -type d -name dist -prune \) -name libmozjs.so | \ + find glut_app/target ! \( -type d -name dist -prune \) -name libmozjs.so | \ xargs -I {} cp -f {} libs/armeabi - find ../../target ! \( -type d -name dist -prune \) -name 'libservo-*.so' | \ + find glut_app/target ! \( -type d -name dist -prune \) -name 'libglut_app-*.so' | \ xargs -I {} cp -f {} libs/armeabi/libservo.so find ../../rust/lib/rustlib/arm-linux-androideabi/lib \ -name '*.so' -type f -size +1c | \ @@ -14,6 +16,11 @@ all: --path . ant debug +.PHONY: glut_app +glut_app: + cd glut_app; \ + ../../../mach cargo build --target=arm-linux-androideabi $(CARGO_OPTS) + .PHONY: install install: $(ANDROID_SDK)/platform-tools/adb install -r bin/ServoAndroid-debug.apk diff --git a/ports/android/glut_app/Cargo.lock b/ports/android/glut_app/Cargo.lock new file mode 100644 index 00000000000..345c74274e5 --- /dev/null +++ b/ports/android/glut_app/Cargo.lock @@ -0,0 +1,519 @@ +[root] +name = "glut_app" +version = "0.0.1" +dependencies = [ + "alert 0.1.0 (git+https://github.com/servo/rust-alert#fdc24f13be8d8a2d15214ec228d166b3221b809e)", + "compositing 0.0.1", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "msg 0.0.1", + "servo 0.0.1", + "util 0.0.1", +] + +[[package]] +name = "alert" +version = "0.1.0" +source = "git+https://github.com/servo/rust-alert#fdc24f13be8d8a2d15214ec228d166b3221b809e" +dependencies = [ + "cocoa 0.1.0 (git+https://github.com/servo/rust-cocoa#acb9b4efc70c3f285057c2aee774f38f81a1b98d)", + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", +] + +[[package]] +name = "azure" +version = "0.1.0" +source = "git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d" +dependencies = [ + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", + "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics#6a9919f8a912cc67571b891ba198d5325964a104)", + "core_text 0.1.0 (git+https://github.com/servo/rust-core-text#1ad11072b31657eeccaf4879c6e98723d488bd3d)", + "egl 0.1.0 (git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220)", + "freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", + "skia-sys 0.0.20130412 (git+https://github.com/servo/skia#6d696712962fd0d41120b7a414a48417da8e6a92)", + "xlib 0.1.0 (git+https://github.com/servo/rust-xlib#581d4faddec5188d3c3ae5307dbea28aab90644c)", +] + +[[package]] +name = "canvas" +version = "0.0.1" +dependencies = [ + "azure 0.1.0 (git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", +] + +[[package]] +name = "cocoa" +version = "0.1.0" +source = "git+https://github.com/servo/rust-cocoa#acb9b4efc70c3f285057c2aee774f38f81a1b98d" + +[[package]] +name = "compositing" +version = "0.0.1" +dependencies = [ + "alert 0.1.0 (git+https://github.com/servo/rust-alert#fdc24f13be8d8a2d15214ec228d166b3221b809e)", + "azure 0.1.0 (git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d)", + "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics#6a9919f8a912cc67571b891ba198d5325964a104)", + "core_text 0.1.0 (git+https://github.com/servo/rust-core-text#1ad11072b31657eeccaf4879c6e98723d488bd3d)", + "devtools 0.0.1", + "devtools_traits 0.0.1", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "gfx 0.0.1", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "layout_traits 0.0.1", + "msg 0.0.1", + "net 0.0.1", + "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", + "png 0.1.0 (git+https://github.com/servo/rust-png#74418ffbf20e94b0d3bed4a9d004062a13342c79)", + "script_traits 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "core_foundation" +version = "0.1.0" +source = "git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a" + +[[package]] +name = "core_graphics" +version = "0.1.0" +source = "git+https://github.com/servo/rust-core-graphics#6a9919f8a912cc67571b891ba198d5325964a104" +dependencies = [ + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", +] + +[[package]] +name = "core_text" +version = "0.1.0" +source = "git+https://github.com/servo/rust-core-text#1ad11072b31657eeccaf4879c6e98723d488bd3d" +dependencies = [ + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", + "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics#6a9919f8a912cc67571b891ba198d5325964a104)", +] + +[[package]] +name = "cssparser" +version = "0.1.0" +source = "git+https://github.com/servo/rust-cssparser#22146ce095cb62df39d459c3a79d1486041f96f6" +dependencies = [ + "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)", +] + +[[package]] +name = "devtools" +version = "0.0.1" +dependencies = [ + "devtools_traits 0.0.1", + "msg 0.0.1", +] + +[[package]] +name = "devtools_traits" +version = "0.0.1" +dependencies = [ + "msg 0.0.1", +] + +[[package]] +name = "egl" +version = "0.1.0" +source = "git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220" + +[[package]] +name = "encoding" +version = "0.1.0" +source = "git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265" + +[[package]] +name = "expat-sys" +version = "2.1.0" +source = "git+https://github.com/servo/libexpat#da2ddaf78cbef836b8790807bb76b357c58df3a1" + +[[package]] +name = "fontconfig" +version = "0.1.0" +source = "git+https://github.com/servo/rust-fontconfig#b16c1e12ecb74b1e4e9a9b23c2b98580a34cf201" +dependencies = [ + "fontconfig-sys 2.11.1 (git+https://github.com/servo/libfontconfig#fcc324d2c8175d2e8e8c0aab032c03a404809f6d)", +] + +[[package]] +name = "fontconfig-sys" +version = "2.11.1" +source = "git+https://github.com/servo/libfontconfig#fcc324d2c8175d2e8e8c0aab032c03a404809f6d" +dependencies = [ + "expat-sys 2.1.0 (git+https://github.com/servo/libexpat#da2ddaf78cbef836b8790807bb76b357c58df3a1)", + "freetype-sys 2.4.11 (git+https://github.com/servo/libfreetype2#5b6499164106f094937565595c7b96d07de55521)", +] + +[[package]] +name = "freetype" +version = "0.1.0" +source = "git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70" + +[[package]] +name = "freetype-sys" +version = "2.4.11" +source = "git+https://github.com/servo/libfreetype2#5b6499164106f094937565595c7b96d07de55521" + +[[package]] +name = "geom" +version = "0.1.0" +source = "git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d" + +[[package]] +name = "gfx" +version = "0.0.1" +dependencies = [ + "azure 0.1.0 (git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d)", + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", + "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics#6a9919f8a912cc67571b891ba198d5325964a104)", + "core_text 0.1.0 (git+https://github.com/servo/rust-core-text#1ad11072b31657eeccaf4879c6e98723d488bd3d)", + "fontconfig 0.1.0 (git+https://github.com/servo/rust-fontconfig#b16c1e12ecb74b1e4e9a9b23c2b98580a34cf201)", + "freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "harfbuzz 0.1.0 (git+https://github.com/servo/rust-harfbuzz#ad520942cc17232e1a40cdd8a99c2905623d35f6)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "msg 0.0.1", + "net 0.0.1", + "plugins 0.0.1", + "png 0.1.0 (git+https://github.com/servo/rust-png#74418ffbf20e94b0d3bed4a9d004062a13342c79)", + "stb_image 0.1.0 (git+https://github.com/servo/rust-stb-image#f5022de4ad6bb474a03493d1f274dde9b0f1af0c)", + "style 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "glfw" +version = "0.0.1" +source = "git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b" +dependencies = [ + "glfw-sys 3.0.4 (git+https://github.com/servo/glfw?ref=cargo-3.0.4#65a2b4721276589d9de24f6a9999a2db37286cae)", + "semver 0.0.1 (git+https://github.com/rust-lang/semver#d04583a173395b76c1eaa15cc630a5f6f8f0ae10)", +] + +[[package]] +name = "glfw-sys" +version = "3.0.4" +source = "git+https://github.com/servo/glfw?ref=cargo-3.0.4#65a2b4721276589d9de24f6a9999a2db37286cae" + +[[package]] +name = "glut" +version = "0.0.1" +source = "git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949" +dependencies = [ + "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", +] + +[[package]] +name = "harfbuzz" +version = "0.1.0" +source = "git+https://github.com/servo/rust-harfbuzz#ad520942cc17232e1a40cdd8a99c2905623d35f6" + +[[package]] +name = "http" +version = "0.1.0-pre" +source = "git+https://github.com/servo/rust-http?ref=servo#92019011b0cdf1bffc8c584830de1bf330d79d0d" +dependencies = [ + "openssl 0.0.0 (git+https://github.com/sfackler/rust-openssl.git#a495465b75ffb18ff2303c5a11a103e00a15a13d)", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", +] + +[[package]] +name = "hubbub" +version = "0.1.0" +source = "git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b" +dependencies = [ + "hubbub-sys 0.1.2 (git+https://github.com/servo/libhubbub#6d09893991dedc616b264058442a304c03842213)", +] + +[[package]] +name = "hubbub-sys" +version = "0.1.2" +source = "git+https://github.com/servo/libhubbub#6d09893991dedc616b264058442a304c03842213" +dependencies = [ + "parserutils-sys 0.1.1 (git+https://github.com/servo/libparserutils#651b636ba1214bceeb0907adb1eab60efe0d4598)", +] + +[[package]] +name = "io_surface" +version = "0.1.0" +source = "git+https://github.com/servo/rust-io-surface#7038341220bd7e86e21118fac2cbc6bd50890e47" +dependencies = [ + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", +] + +[[package]] +name = "js" +version = "0.1.0" +source = "git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04" +dependencies = [ + "mozjs-sys 0.0.0 (git+https://github.com/servo/mozjs#47cd6a4e60c75642ba182f0df9a42b71ec7c2c88)", +] + +[[package]] +name = "layers" +version = "0.1.0" +source = "git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8" +dependencies = [ + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", + "egl 0.1.0 (git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface#7038341220bd7e86e21118fac2cbc6bd50890e47)", + "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", + "xlib 0.1.0 (git+https://github.com/servo/rust-xlib#581d4faddec5188d3c3ae5307dbea28aab90644c)", +] + +[[package]] +name = "layout" +version = "0.0.1" +dependencies = [ + "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "gfx 0.0.1", + "layout_traits 0.0.1", + "net 0.0.1", + "plugins 0.0.1", + "script 0.0.1", + "script_traits 0.0.1", + "string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "style 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "layout_traits" +version = "0.0.1" +dependencies = [ + "gfx 0.0.1", + "msg 0.0.1", + "net 0.0.1", + "script_traits 0.0.1", + "util 0.0.1", +] + +[[package]] +name = "lazy_static" +version = "0.1.0" +source = "git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb9381d819edff80e360" + +[[package]] +name = "mozjs-sys" +version = "0.0.0" +source = "git+https://github.com/servo/mozjs#47cd6a4e60c75642ba182f0df9a42b71ec7c2c88" + +[[package]] +name = "msg" +version = "0.0.1" +dependencies = [ + "azure 0.1.0 (git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d)", + "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface#7038341220bd7e86e21118fac2cbc6bd50890e47)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "net" +version = "0.0.1" +dependencies = [ + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo#92019011b0cdf1bffc8c584830de1bf330d79d0d)", + "png 0.1.0 (git+https://github.com/servo/rust-png#74418ffbf20e94b0d3bed4a9d004062a13342c79)", + "stb_image 0.1.0 (git+https://github.com/servo/rust-stb-image#f5022de4ad6bb474a03493d1f274dde9b0f1af0c)", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "opengles" +version = "0.1.0" +source = "git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc" + +[[package]] +name = "openssl" +version = "0.0.0" +source = "git+https://github.com/sfackler/rust-openssl.git#a495465b75ffb18ff2303c5a11a103e00a15a13d" + +[[package]] +name = "parserutils-sys" +version = "0.1.1" +source = "git+https://github.com/servo/libparserutils#651b636ba1214bceeb0907adb1eab60efe0d4598" + +[[package]] +name = "phf" +version = "0.0.0" +source = "git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0" + +[[package]] +name = "phf_mac" +version = "0.0.0" +source = "git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0" + +[[package]] +name = "plugins" +version = "0.0.1" + +[[package]] +name = "png" +version = "0.1.0" +source = "git+https://github.com/servo/rust-png#74418ffbf20e94b0d3bed4a9d004062a13342c79" +dependencies = [ + "png-sys 1.6.3 (git+https://github.com/servo/libpng?ref=servo#d01f32b4eb86904695efe7fc02b574f902e21a98)", +] + +[[package]] +name = "png-sys" +version = "1.6.3" +source = "git+https://github.com/servo/libpng?ref=servo#d01f32b4eb86904695efe7fc02b574f902e21a98" + +[[package]] +name = "script" +version = "0.0.1" +dependencies = [ + "canvas 0.0.1", + "cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser#22146ce095cb62df39d459c3a79d1486041f96f6)", + "devtools_traits 0.0.1", + "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "gfx 0.0.1", + "http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo#92019011b0cdf1bffc8c584830de1bf330d79d0d)", + "hubbub 0.1.0 (git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)", + "msg 0.0.1", + "net 0.0.1", + "plugins 0.0.1", + "script_traits 0.0.1", + "string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "style 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", + "uuid 0.0.1 (git+https://github.com/rust-lang/uuid#c3041068f413a5e46d795d21a346072794593839)", +] + +[[package]] +name = "script_traits" +version = "0.0.1" +dependencies = [ + "devtools_traits 0.0.1", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "msg 0.0.1", + "net 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "semver" +version = "0.0.1" +source = "git+https://github.com/rust-lang/semver#d04583a173395b76c1eaa15cc630a5f6f8f0ae10" + +[[package]] +name = "servo" +version = "0.0.1" +dependencies = [ + "compositing 0.0.1", + "gfx 0.0.1", + "layout 0.0.1", + "msg 0.0.1", + "net 0.0.1", + "script 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "skia-sys" +version = "0.0.20130412" +source = "git+https://github.com/servo/skia#6d696712962fd0d41120b7a414a48417da8e6a92" +dependencies = [ + "expat-sys 2.1.0 (git+https://github.com/servo/libexpat#da2ddaf78cbef836b8790807bb76b357c58df3a1)", + "freetype-sys 2.4.11 (git+https://github.com/servo/libfreetype2#5b6499164106f094937565595c7b96d07de55521)", +] + +[[package]] +name = "stb_image" +version = "0.1.0" +source = "git+https://github.com/servo/rust-stb-image#f5022de4ad6bb474a03493d1f274dde9b0f1af0c" + +[[package]] +name = "string_cache" +version = "0.0.0" +source = "git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98" +dependencies = [ + "phf 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)", + "phf_mac 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)", + "string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", +] + +[[package]] +name = "string_cache_macros" +version = "0.0.0" +source = "git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98" +dependencies = [ + "lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb9381d819edff80e360)", +] + +[[package]] +name = "style" +version = "0.0.1" +dependencies = [ + "cssparser 0.1.0 (git+https://github.com/servo/rust-cssparser#22146ce095cb62df39d459c3a79d1486041f96f6)", + "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb9381d819edff80e360)", + "plugins 0.0.1", + "string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", +] + +[[package]] +name = "task_info" +version = "0.0.1" + +[[package]] +name = "url" +version = "0.1.0" +source = "git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243" +dependencies = [ + "encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)", +] + +[[package]] +name = "util" +version = "0.0.1" +dependencies = [ + "azure 0.1.0 (git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d)", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)", + "task_info 0.0.1", + "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", +] + +[[package]] +name = "uuid" +version = "0.0.1" +source = "git+https://github.com/rust-lang/uuid#c3041068f413a5e46d795d21a346072794593839" + +[[package]] +name = "xlib" +version = "0.1.0" +source = "git+https://github.com/servo/rust-xlib#581d4faddec5188d3c3ae5307dbea28aab90644c" + diff --git a/ports/android/glut_app/Cargo.toml b/ports/android/glut_app/Cargo.toml new file mode 100644 index 00000000000..a4372c4a910 --- /dev/null +++ b/ports/android/glut_app/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "glut_app" +version = "0.0.1" +authors = ["The Servo Project Developers"] + +[lib] +name = "glut_app" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies.alert] +git = "https://github.com/servo/rust-alert" + +[dependencies.compositing] +path = "../../../components/compositing" + +[dependencies.geom] +git = "https://github.com/servo/rust-geom" + +[dependencies.glut] +git = "https://github.com/servo/rust-glut" + +[dependencies.layers] +git = "https://github.com/servo/rust-layers" + +[dependencies.msg] +path = "../../../components/msg" + +[dependencies.servo] +path = "../../.." +default-features = false + +[dependencies.util] +path = "../../../components/util" diff --git a/ports/android/glut_app/lib.rs b/ports/android/glut_app/lib.rs new file mode 100644 index 00000000000..90269e91c5b --- /dev/null +++ b/ports/android/glut_app/lib.rs @@ -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/. */ + +//! A simple application that uses GLUT to open a window for Servo to display in. + +#![license = "MPL"] +#![feature(macro_rules, phase)] +#![deny(unused_imports, unused_variable)] + +extern crate alert; +extern crate compositing; +extern crate geom; +extern crate glut; +extern crate layers; +extern crate libc; +#[phase(plugin, link)] extern crate log; +extern crate msg; +extern crate native; +extern crate servo; +#[phase(plugin, link)] extern crate util; + +use geom::scale_factor::ScaleFactor; +use std::rc::Rc; +use std::string; +use util::opts; +use window::Window; + +use glut::glut::{init, init_display_mode, DOUBLE}; + +mod window; + +pub fn create_window(opts: &opts::Opts) -> Rc<Window> { + // Initialize GLUT. + init(); + init_display_mode(DOUBLE); + + // Read command-line options. + let scale_factor = opts.device_pixels_per_px.unwrap_or(ScaleFactor(1.0)); + let size = opts.initial_window_size.as_f32() * scale_factor; + + // Open a window. + Window::new(size.as_uint()) +} + +#[no_mangle] +#[allow(dead_code)] +pub extern "C" fn android_start(argc: int, argv: *const *const u8) -> int { + native::start(argc, argv, proc() { + let mut args: Vec<String> = vec!(); + for i in range(0u, argc as uint) { + unsafe { + args.push(string::raw::from_buf(*argv.offset(i as int) as *const u8)); + } + } + + opts::from_cmdline_args(args.as_slice()).map(|mut opts| { + // Always use CPU rendering on android. + opts.cpu_painting = true; + let window = Some(create_window(&opts)); + servo::run(opts, window); + }); + }) +} diff --git a/components/compositing/platform/common/glut_windowing.rs b/ports/android/glut_app/window.rs index 00d5cc889e8..a9e06af2ccb 100644 --- a/components/compositing/platform/common/glut_windowing.rs +++ b/ports/android/glut_app/window.rs @@ -4,11 +4,11 @@ //! A windowing implementation using GLUT. -use windowing::{ApplicationMethods, WindowEvent, WindowMethods}; -use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass}; -use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; -use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; -use windowing::{Forward, Back}; +use compositing::windowing::{WindowEvent, WindowMethods}; +use compositing::windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass}; +use compositing::windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; +use compositing::windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; +use compositing::windowing::{Forward, Back}; use alert::{Alert, AlertMethods}; use libc::{c_int, c_uchar}; @@ -18,33 +18,16 @@ use geom::point::{Point2D, TypedPoint2D}; use geom::scale_factor::ScaleFactor; use geom::size::TypedSize2D; use layers::geometry::DevicePixel; -use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; -use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState}; -use servo_util::geometry::ScreenPx; +use msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; +use msg::compositor_msg::{FinishedLoading, Blank, ReadyState}; +use util::geometry::ScreenPx; -use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight}; +use glut::glut::{ACTIVE_SHIFT, WindowHeight}; use glut::glut::WindowWidth; use glut::glut; // static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ]; -/// A structure responsible for setting up and tearing down the entire windowing system. -pub struct Application; - -impl ApplicationMethods for Application { - fn new() -> Application { - glut::init(); - glut::init_display_mode(DOUBLE); - Application - } -} - -impl Drop for Application { - fn drop(&mut self) { - drop_local_window(); - } -} - /// The type of a window. pub struct Window { pub glut_window: glut::Window, @@ -61,9 +44,9 @@ pub struct Window { pub throbber_frame: Cell<u8>, } -impl WindowMethods<Application> for Window { +impl Window { /// Creates a new window. - fn new(_: &Application, _: bool, size: TypedSize2D<DevicePixel, uint>) -> Rc<Window> { + pub fn new(size: TypedSize2D<DevicePixel, uint>) -> Rc<Window> { // Create the GLUT window. let window_size = size.to_untyped(); glut::init_window_size(window_size.width, window_size.height); @@ -145,7 +128,15 @@ impl WindowMethods<Application> for Window { wrapped_window } +} + +impl Drop for Window { + fn drop(&mut self) { + drop_local_window(); + } +} +impl WindowMethods for Window { /// Returns the size of the window in hardware pixels. fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, uint> { TypedSize2D(glut::get(WindowWidth) as uint, glut::get(WindowHeight) as uint) diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index fb5a1d2faaf..212487a0cd5 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -8,8 +8,8 @@ dependencies = [ "devtools 0.0.1", "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", "gfx 0.0.1", - "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)", - "glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)", + "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b)", + "glfw_app 0.0.1", "js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)", "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", "msg 0.0.1", @@ -44,7 +44,7 @@ dependencies = [ "egl 0.1.0 (git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220)", "freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)", "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", - "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)", + "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b)", "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", "skia-sys 0.0.20130412 (git+https://github.com/servo/skia#6d696712962fd0d41120b7a414a48417da8e6a92)", @@ -76,8 +76,6 @@ dependencies = [ "devtools_traits 0.0.1", "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", "gfx 0.0.1", - "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)", - "glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)", "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", "layout_traits 0.0.1", "msg 0.0.1", @@ -207,7 +205,7 @@ dependencies = [ [[package]] name = "glfw" version = "0.0.1" -source = "git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e" +source = "git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b" dependencies = [ "glfw-sys 3.0.4 (git+https://github.com/servo/glfw?ref=cargo-3.0.4#65a2b4721276589d9de24f6a9999a2db37286cae)", "semver 0.0.1 (git+https://github.com/rust-lang/semver#d04583a173395b76c1eaa15cc630a5f6f8f0ae10)", @@ -219,11 +217,16 @@ version = "3.0.4" source = "git+https://github.com/servo/glfw?ref=cargo-3.0.4#65a2b4721276589d9de24f6a9999a2db37286cae" [[package]] -name = "glut" +name = "glfw_app" version = "0.0.1" -source = "git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949" dependencies = [ - "opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)", + "alert 0.1.0 (git+https://github.com/servo/rust-alert#fdc24f13be8d8a2d15214ec228d166b3221b809e)", + "compositing 0.0.1", + "geom 0.1.0 (git+https://github.com/servo/rust-geom#90add8d65273c8a46aa16d73959e29a51d0c282d)", + "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#a15c2d04b8969aea653841d1d79e5fdf68de664b)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers#180d3ff2f28d239e32d01982c76be5c97d5763a8)", + "msg 0.0.1", + "util 0.0.1", ] [[package]] @@ -428,6 +431,7 @@ dependencies = [ "msg 0.0.1", "net 0.0.1", "url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)", + "util 0.0.1", ] [[package]] @@ -441,6 +445,7 @@ version = "0.0.1" dependencies = [ "compositing 0.0.1", "gfx 0.0.1", + "glfw_app 0.0.1", "layout 0.0.1", "msg 0.0.1", "net 0.0.1", diff --git a/ports/cef/Cargo.toml b/ports/cef/Cargo.toml index 95ffcf73cef..a0de421b970 100644 --- a/ports/cef/Cargo.toml +++ b/ports/cef/Cargo.toml @@ -11,6 +11,9 @@ crate-type = ["dylib"] [dependencies.servo] path = "../.." +[dependencies.glfw_app] +path = "../glfw" + [dependencies.plugins] path = "../../components/plugins" @@ -45,9 +48,6 @@ git = "https://github.com/servo/rust-geom" git = "https://github.com/servo/glfw-rs" branch = "servo" -[dependencies.glut] -git = "https://github.com/servo/rust-glut" - [dependencies.js] git = "https://github.com/servo/rust-mozjs" diff --git a/ports/cef/core.rs b/ports/cef/core.rs index d425252f3a2..f1b6549c2cc 100644 --- a/ports/cef/core.rs +++ b/ports/cef/core.rs @@ -7,6 +7,7 @@ use azure; use command_line::command_line_init; use eutil::fptr_is_null; use geom::size::TypedSize2D; +use glfw_app; use libc::{c_int, c_void}; use native; use servo; @@ -74,7 +75,8 @@ pub extern "C" fn cef_run_message_loop() { dump_flow_tree: false, }; native::start(0, 0 as *const *const u8, proc() { - servo::run(opts); + let window = Some(glfw_app::create_window(&opts)); + servo::run(opts, window); }); } diff --git a/ports/cef/lib.rs b/ports/cef/lib.rs index e486644aa89..bf7aeec80e6 100644 --- a/ports/cef/lib.rs +++ b/ports/cef/lib.rs @@ -18,10 +18,8 @@ extern crate servo; extern crate azure; extern crate geom; extern crate gfx; -#[cfg(not(target_os="android"))] extern crate glfw; -#[cfg(target_os="android")] -extern crate glut; +extern crate glfw_app; extern crate js; extern crate layers; extern crate opengles; diff --git a/ports/glfw/Cargo.toml b/ports/glfw/Cargo.toml new file mode 100644 index 00000000000..3212bd428ac --- /dev/null +++ b/ports/glfw/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "glfw_app" +version = "0.0.1" +authors = ["The Servo Project Developers"] + +[lib] +name = "glfw_app" +path = "lib.rs" + +[dependencies.alert] +git = "https://github.com/servo/rust-alert" + +[dependencies.compositing] +path = "../../components/compositing" + +[dependencies.geom] +git = "https://github.com/servo/rust-geom" + +[dependencies.glfw] +git = "https://github.com/servo/glfw-rs" +branch = "servo" + +[dependencies.layers] +git = "https://github.com/servo/rust-layers" + +[dependencies.msg] +path = "../../components/msg" + +[dependencies.util] +path = "../../components/util" diff --git a/ports/glfw/lib.rs b/ports/glfw/lib.rs new file mode 100644 index 00000000000..d0f96f950eb --- /dev/null +++ b/ports/glfw/lib.rs @@ -0,0 +1,43 @@ +/* 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/. */ + +//! A simple application that uses GLFW to open a window for Servo to display in. + +#![license = "MPL"] +#![feature(macro_rules)] +#![deny(unused_imports, unused_variable)] + +extern crate alert; +extern crate compositing; +extern crate geom; +extern crate glfw; +extern crate layers; +extern crate libc; +extern crate msg; +extern crate time; +extern crate util; + +use geom::scale_factor::ScaleFactor; +use std::rc::Rc; +use window::Window; + +mod window; + +pub fn create_window(opts: &util::opts::Opts) -> Rc<Window> { + // Initialize GLFW. + let glfw = glfw::init(glfw::LOG_ERRORS).unwrap_or_else(|_| { + // handles things like inability to connect to X + // cannot simply fail, since the runtime isn't up yet (causes a nasty abort) + println!("GLFW initialization failed"); + unsafe { libc::exit(1); } + }); + + // Read command-line options. + let foreground = opts.output_file.is_none(); + let scale_factor = opts.device_pixels_per_px.unwrap_or(ScaleFactor(1.0)); + let size = opts.initial_window_size.as_f32() * scale_factor; + + // Open a window. + Window::new(glfw, foreground, size.as_uint()) +} diff --git a/components/compositing/platform/common/glfw_windowing.rs b/ports/glfw/window.rs index dfe200bf8d8..50be31f05db 100644 --- a/components/compositing/platform/common/glfw_windowing.rs +++ b/ports/glfw/window.rs @@ -4,15 +4,15 @@ //! A windowing implementation using GLFW. -use windowing::{ApplicationMethods, WindowEvent, WindowMethods}; -use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass, MouseWindowMoveEventClass}; -use windowing::{ScrollWindowEvent, ZoomWindowEvent, PinchZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; -use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; -use windowing::RefreshWindowEvent; -use windowing::{Forward, Back}; +use compositing::windowing::{WindowEvent, WindowMethods}; +use compositing::windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass, MouseWindowMoveEventClass}; +use compositing::windowing::{ScrollWindowEvent, ZoomWindowEvent, PinchZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; +use compositing::windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; +use compositing::windowing::RefreshWindowEvent; +use compositing::windowing::{Forward, Back}; use alert::{Alert, AlertMethods}; -use libc::{exit, c_int}; +use libc::c_int; use time; use time::Timespec; use std::cell::{Cell, RefCell}; @@ -23,35 +23,14 @@ use geom::point::{Point2D, TypedPoint2D}; use geom::scale_factor::ScaleFactor; use geom::size::TypedSize2D; use layers::geometry::DevicePixel; -use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; -use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState}; -use servo_util::geometry::ScreenPx; +use msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; +use msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState}; +use util::geometry::ScreenPx; use glfw; use glfw::Context; /// A structure responsible for setting up and tearing down the entire windowing system. -pub struct Application { - pub glfw: glfw::Glfw, -} - -impl ApplicationMethods for Application { - fn new() -> Application { - let app = glfw::init(glfw::LOG_ERRORS); - match app { - Err(_) => { - // handles things like inability to connect to X - // cannot simply fail, since the runtime isn't up yet (causes a nasty abort) - println!("GLFW initialization failed"); - unsafe { exit(1); } - } - Ok(app) => { - Application { glfw: app } - } - } - } -} - macro_rules! glfw_callback( ( $callback:path ($($arg:ident: $arg_ty:ty),*) $block:expr @@ -102,21 +81,22 @@ pub struct Window { last_title_set_time: Cell<Timespec>, } -impl WindowMethods<Application> for Window { +impl Window { /// Creates a new window. - fn new(app: &Application, is_foreground: bool, size: TypedSize2D<DevicePixel, uint>) -> Rc<Window> { + pub fn new(glfw: glfw::Glfw, is_foreground: bool, size: TypedSize2D<DevicePixel, uint>) + -> Rc<Window> { // Create the GLFW window. let window_size = size.to_untyped(); - app.glfw.window_hint(glfw::Visible(is_foreground)); - let (glfw_window, events) = app.glfw.create_window(window_size.width as u32, - window_size.height as u32, - "Servo", glfw::Windowed) + glfw.window_hint(glfw::Visible(is_foreground)); + let (glfw_window, events) = glfw.create_window(window_size.width as u32, + window_size.height as u32, + "Servo", glfw::Windowed) .expect("Failed to create GLFW window"); glfw_window.make_current(); // Create our window object. let window = Window { - glfw: app.glfw, + glfw: glfw, glfw_window: glfw_window, events: events, @@ -144,7 +124,9 @@ impl WindowMethods<Application> for Window { wrapped_window } +} +impl WindowMethods for Window { /// Returns the size of the window in hardware pixels. fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, uint> { let (width, height) = self.glfw_window.get_framebuffer_size(); diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 2d67fdb8c75..5a7316a9b97 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -46,20 +46,22 @@ class MachCommands(CommandBase): opts += ["--release"] if target: opts += ["--target", target] - elif android: - opts += ["--target", "arm-linux-androideabi"] if jobs is not None: opts += ["-j", jobs] if verbose: opts += ["-v"] build_start = time() - status = subprocess.call( - ["cargo", "build"] + opts, - env=self.build_env()) if android: - status = status or subprocess.call( - ["make", "-C", "ports/android"], + make_opts = [] + if opts: + make_opts += ["CARGO_OPTS=" + " ".join(opts)] + status = subprocess.call( + ["make", "-C", "ports/android"] + make_opts, + env=self.build_env()) + else: + status = subprocess.call( + ["cargo", "build"] + opts, env=self.build_env()) elapsed = time() - build_start diff --git a/resources/iso-8859-8.css b/resources/iso-8859-8.css new file mode 100644 index 00000000000..fd97ef5807f --- /dev/null +++ b/resources/iso-8859-8.css @@ -0,0 +1,23 @@ +/* + +https://html.spec.whatwg.org/multipage/rendering.html#bidi-rendering + +> When the document's character encoding is ISO-8859-8, +> the following rules are additionally expected to apply, following [user-agent.css] + +*/ + +@namespace url(http://www.w3.org/1999/xhtml); + + +address, blockquote, center, div, figure, figcaption, footer, form, header, hr, +legend, listing, main, p, plaintext, pre, summary, xmp, article, aside, h1, h2, +h3, h4, h5, h6, hgroup, nav, section, table, caption, colgroup, col, thead, +tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, [dir=ltr i], +[dir=rtl i], [dir=auto i], *|* { + unicode-bidi: bidi-override; +} +input:not([type=submit i]):not([type=reset i]):not([type=button i]), +textarea, keygen { + unicode-bidi: normal; +} diff --git a/resources/presentational-hints.css b/resources/presentational-hints.css new file mode 100644 index 00000000000..dcccbf9a64b --- /dev/null +++ b/resources/presentational-hints.css @@ -0,0 +1,261 @@ +/* +https://html.spec.whatwg.org/multipage/rendering.html#presentational-hints +*/ + +@namespace url(http://www.w3.org/1999/xhtml); + + +pre[wrap] { white-space: pre-wrap; } + +/* +FIXME: also "align descendants" +https://html.spec.whatwg.org/multipage/rendering.html#align-descendants +*/ +center, div[align=center i], div[align=middle i] { text-align: center; } +div[align=left i] { text-align: left; } +div[align=right i] { text-align: right; } +div[align=justify i] { text-align: justify; } + + +br[clear=left i] { clear: left; } +br[clear=right i] { clear: right; } +br[clear=all i], br[clear=both i] { clear: both; } + + +ol[type=1], li[type=1] { list-style-type: decimal; } +ol[type=a], li[type=a] { list-style-type: lower-alpha; } +ol[type=A], li[type=A] { list-style-type: upper-alpha; } +ol[type=i], li[type=i] { list-style-type: lower-roman; } +ol[type=I], li[type=I] { list-style-type: upper-roman; } +ul[type=none i], li[type=none i] { list-style-type: none; } +ul[type=disc i], li[type=disc i] { list-style-type: disc; } +ul[type=circle i], li[type=circle i] { list-style-type: circle; } +ul[type=square i], li[type=square i] { list-style-type: square; } + + +table[align=left i] { float: left; } +table[align=right i] { float: right; } +table[align=center i] { margin-left: auto; margin-right: auto; } +:matches(thead, tbody, tfoot, tr, td, th)[align=absmiddle i] { + text-align: center; +} + +caption[align=bottom i] { caption-side: bottom; } +:matches(p, h1, h2, h3, h4, h5, h6)[align=left i] { text-align: left; } +:matches(p, h1, h2, h3, h4, h5, h6)[align=right i] { text-align: right; } +:matches(p, h1, h2, h3, h4, h5, h6)[align=center i] { text-align: center; } +:matches(p, h1, h2, h3, h4, h5, h6)[align=justify i] { text-align: justify; } +:matches(thead, tbody, tfoot, tr, td, th)[valign=top i] { vertical-align: top; } +:matches(thead, tbody, tfoot, tr, td, th)[valign=middle i] { vertical-align: middle; } +:matches(thead, tbody, tfoot, tr, td, th)[valign=bottom i] { vertical-align: bottom; } +:matches(thead, tbody, tfoot, tr, td, th)[valign=baseline i] { vertical-align: baseline; } + +td[nowrap], th[nowrap] { white-space: nowrap; } + +table:matches([rules=none i], [rules=groups i], [rules=rows i], [rules=cols i], [rules=all i]) { + border-style: hidden; + border-collapse: collapse; +} + +table[border] { + border-style: outset; + /* + FIXME: only if border is not equivalent to zero + https://html.spec.whatwg.org/multipage/rendering.html#magic-border-selector + */ +} +table[frame=void i] { border-style: hidden; } +table[frame=above i] { border-style: outset hidden hidden hidden; } +table[frame=below i] { border-style: hidden hidden outset hidden; } +table[frame=hsides i] { border-style: outset hidden outset hidden; } +table[frame=lhs i] { border-style: hidden hidden hidden outset; } +table[frame=rhs i] { border-style: hidden outset hidden hidden; } +table[frame=vsides i] { border-style: hidden outset; } +table[frame=box i], table[frame=border i] { border-style: outset; } + + +table[border] > tr > :matches(td, th), +table[border] > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { + /* + FIXME: only if border is not equivalent to zero + https://html.spec.whatwg.org/multipage/rendering.html#magic-border-selector + */ + border-width: 1px; + border-style: inset; +} + +table:matches([rules=none i], [rules=groups i], [rules=rows i]) > tr > :matches(td, th), +table:matches([rules=none i], [rules=groups i], [rules=rows i]) > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { + border-width: 1px; + border-style: none; +} +table[rules=cols i] > tr > :matches(td, th), +table[rules=cols i] > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { + border-width: 1px; + border-style: none solid; +} +table[rules=all i] > tr > :matches(td, th), +table[rules=all i] > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { + border-width: 1px; + border-style: solid; +} + +table[rules=groups i] > colgroup { + border-left-width: 1px; + border-left-style: solid; + border-right-width: 1px; + border-right-style: solid; +} +table[rules=groups i] > :matches(thead, tbody, tfoot) { + border-top-width: 1px; + border-top-style: solid; + border-bottom-width: 1px; + border-bottom-style: solid; +} +table[rules=rows i] > tr, +table[rules=rows i] > :matches(thead, tbody, tfoot) > tr { + border-top-width: 1px; + border-top-style: solid; + border-bottom-width: 1px; + border-bottom-style: solid; +} + + +hr[align=left] { margin-left: 0; margin-right: auto; } +hr[align=right] { margin-left: auto; margin-right: 0; } +hr[align=center] { margin-left: auto; margin-right: auto; } +hr[color], hr[noshade] { border-style: solid; } + + + +iframe[frameborder=0], iframe[frameborder=no i] { border: none; } + +:matches(applet, embed, iframe, img, input[type=image i], object)[align=left i] { + float: left; +} +:matches(applet, embed, iframe, img, input[type=image i], object)[align=right i] { + float: right; +} +:matches(applet, embed, iframe, img, input[type=image i], object)[align=top i] { + vertical-align: top; +} +:matches(applet, embed, iframe, img, input[type=image i], object)[align=baseline i] { + vertical-align: baseline; +} +:matches(applet, embed, iframe, img, input[type=image i], object)[align=texttop i] { + vertical-align: text-top; +} +:matches(applet, embed, iframe, img, input[type=image i], object):matches([align=absmiddle i], [align=abscenter i]) { + vertical-align: middle; +} +:matches(applet, embed, iframe, img, input[type=image i], object)[align=bottom i] { + vertical-align: bottom; +} +/* +FIXME: +:matches(applet, embed, iframe, img, input[type=image i], object):matches([align=center i], [align=middle i]) { + vertical-align: "aligns the vertical middle of the element with the parent element's baseline." +} +*/ + +/* + +Presentational attributes which can not currently be expressed in CSS. +FIXME: Deal with them with attr(foo dimension) and the like? + +body + marginheight + marginwidth + topmargin + rightmargin + bottommargin + leftmargin + background + bgcolor + text + link + vlink + alink + +frame, iframe + marginheight + marginwidth + +font + face + color + size + +table + cellspacing + cellpadding + hspace + vspace + height + width + bordercolor + border + +col + width + +tr + height + +td, th + width + height + +caption, thead, tbody, tfoot, tr, td, and th + align + +table, thead, tbody, tfoot, tr, td, or th + background + bgcolor + +(quirks mode) th, td + nowrap + +hr + color + noshade + size + width + +legend + align + +applet, embed, iframe, img, input[type=image i], object + hspace + vspace + +img, input[type=image i], object + border + +applet, embed, iframe, img, input[type=image i], object, video + width + height + +*/ + +/* + +Extra + ol > li + https://html.spec.whatwg.org/multipage/semantics.html#ordinal-value + col + span + colgroup (if not col child) + span + td, th + colspan + rowspan + + :computed-value(text-align is initial) > th { + text-align: center; + } + + https://html.spec.whatwg.org/multipage/rendering.html#rendered-legend + +*/ + diff --git a/resources/quirks-mode.css b/resources/quirks-mode.css new file mode 100644 index 00000000000..4ba71bb6392 --- /dev/null +++ b/resources/quirks-mode.css @@ -0,0 +1,33 @@ +/* + +https://html.spec.whatwg.org/multipage/rendering.html#flow-content-3 + +> In quirks mode, the following rules are also expected to apply: + +*/ + +@namespace url(http://www.w3.org/1999/xhtml); + + +form { margin-bottom: 1em; } + + +table { + font-weight: initial; + font-style: initial; + font-variant: initial; + font-size: initial; + line-height: initial; + white-space: initial; + text-align: initial; +} + + +/* FIXME: https://html.spec.whatwg.org/multipage/rendering.html#margin-collapsing-quirks */ + + +input:not([type=image]), textarea { box-sizing: border-box; } + + +img[align=left i] { margin-right: 3px; } +img[align=right i] { margin-left: 3px; } diff --git a/resources/quotes.css b/resources/quotes.css new file mode 100644 index 00000000000..2b1b7470b16 --- /dev/null +++ b/resources/quotes.css @@ -0,0 +1,190 @@ +/* + +https://html.spec.whatwg.org/multipage/rendering.html#quotes + +> This block is automatically generated from the Unicode Common Locale Data Repository. +> http://cldr.unicode.org/ +> +> User agents are expected to use either the block [from the spec] +> (which will be regularly updated) +> or to automatically generate their own copy directly from the source material. +> The language codes are derived from the CLDR file names. +> The quotes are derived from the delimiter blocks, +> with fallback handled as specified in the CLDR documentation. + +*/ + +@namespace url(http://www.w3.org/1999/xhtml); + + +:root { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(af), :not(:lang(af)) > :lang(af) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(agq), :not(:lang(agq)) > :lang(agq) { quotes: '\201e' '\201d' '\201a' '\2019' } /* „ ” ‚ ’ */ +:root:lang(ak), :not(:lang(ak)) > :lang(ak) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(am), :not(:lang(am)) > :lang(am) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(ar), :not(:lang(ar)) > :lang(ar) { quotes: '\201d' '\201c' '\2019' '\2018' } /* ” “ ’ ‘ */ +:root:lang(asa), :not(:lang(asa)) > :lang(asa) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ast), :not(:lang(ast)) > :lang(ast) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(az), :not(:lang(az)) > :lang(az) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(az-Cyrl), :not(:lang(az-Cyrl)) > :lang(az-Cyrl) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(bas), :not(:lang(bas)) > :lang(bas) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */ +:root:lang(bem), :not(:lang(bem)) > :lang(bem) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(bez), :not(:lang(bez)) > :lang(bez) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(bg), :not(:lang(bg)) > :lang(bg) { quotes: '\201e' '\201c' '\201e' '\201c' } /* „ “ „ “ */ +:root:lang(bm), :not(:lang(bm)) > :lang(bm) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(bn), :not(:lang(bn)) > :lang(bn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(br), :not(:lang(br)) > :lang(br) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(brx), :not(:lang(brx)) > :lang(brx) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(bs), :not(:lang(bs)) > :lang(bs) { quotes: '\201e' '\201c' '\2018' '\2019' } /* „ “ ‘ ’ */ +:root:lang(bs-Cyrl), :not(:lang(bs-Cyrl)) > :lang(bs-Cyrl) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(ca), :not(:lang(ca)) > :lang(ca) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(cgg), :not(:lang(cgg)) > :lang(cgg) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(chr), :not(:lang(chr)) > :lang(chr) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(cs), :not(:lang(cs)) > :lang(cs) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(cy), :not(:lang(cy)) > :lang(cy) { quotes: '\2018' '\2019' '\201c' '\201d' } /* ‘ ’ “ ” */ +:root:lang(da), :not(:lang(da)) > :lang(da) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(dav), :not(:lang(dav)) > :lang(dav) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(de), :not(:lang(de)) > :lang(de) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(de-CH), :not(:lang(de-CH)) > :lang(de-CH) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(dje), :not(:lang(dje)) > :lang(dje) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(dsb), :not(:lang(dsb)) > :lang(dsb) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(dua), :not(:lang(dua)) > :lang(dua) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » ‘ ’ */ +:root:lang(dyo), :not(:lang(dyo)) > :lang(dyo) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(dz), :not(:lang(dz)) > :lang(dz) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ebu), :not(:lang(ebu)) > :lang(ebu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ee), :not(:lang(ee)) > :lang(ee) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(el), :not(:lang(el)) > :lang(el) { quotes: '\00ab' '\00bb' '\0022' '\0022' } /* « » " " */ +:root:lang(en), :not(:lang(en)) > :lang(en) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(es), :not(:lang(es)) > :lang(es) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(et), :not(:lang(et)) > :lang(et) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(eu), :not(:lang(eu)) > :lang(eu) { quotes: '\0022' '\0022' '\0022' '\0022' } /* " " " " */ +:root:lang(ewo), :not(:lang(ewo)) > :lang(ewo) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(fa), :not(:lang(fa)) > :lang(fa) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(ff), :not(:lang(ff)) > :lang(ff) { quotes: '\201e' '\201d' '\201a' '\2019' } /* „ ” ‚ ’ */ +:root:lang(fi), :not(:lang(fi)) > :lang(fi) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” ’ ’ */ +:root:lang(fil), :not(:lang(fil)) > :lang(fil) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(fr), :not(:lang(fr)) > :lang(fr) { quotes: '\00ab' '\00bb' '\00ab' '\00bb' } /* « » « » */ +:root:lang(fr-CA), :not(:lang(fr-CA)) > :lang(fr-CA) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(fr-CH), :not(:lang(fr-CH)) > :lang(fr-CH) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(ga), :not(:lang(ga)) > :lang(ga) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(gd), :not(:lang(gd)) > :lang(gd) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(gl), :not(:lang(gl)) > :lang(gl) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(gsw), :not(:lang(gsw)) > :lang(gsw) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(gu), :not(:lang(gu)) > :lang(gu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(guz), :not(:lang(guz)) > :lang(guz) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ha), :not(:lang(ha)) > :lang(ha) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(he), :not(:lang(he)) > :lang(he) { quotes: '\05f4' '\05f4' '\05f3' '\05f3' } /* ״ ״ ׳ ׳ */ +:root:lang(hi), :not(:lang(hi)) > :lang(hi) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(hr), :not(:lang(hr)) > :lang(hr) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(hsb), :not(:lang(hsb)) > :lang(hsb) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(hu), :not(:lang(hu)) > :lang(hu) { quotes: '\201e' '\201d' '\00bb' '\00ab' } /* „ ” » « */ +:root:lang(hy), :not(:lang(hy)) > :lang(hy) { quotes: '\00ab' '\00bb' '\00ab' '\00bb' } /* « » « » */ +:root:lang(id), :not(:lang(id)) > :lang(id) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ig), :not(:lang(ig)) > :lang(ig) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(is), :not(:lang(is)) > :lang(is) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(it), :not(:lang(it)) > :lang(it) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(ja), :not(:lang(ja)) > :lang(ja) { quotes: '\300c' '\300d' '\300e' '\300f' } /* 「 」 『 』 */ +:root:lang(jgo), :not(:lang(jgo)) > :lang(jgo) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(jmc), :not(:lang(jmc)) > :lang(jmc) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ka), :not(:lang(ka)) > :lang(ka) { quotes: '\201e' '\201c' '\00ab' '\00bb' } /* „ “ « » */ +:root:lang(kab), :not(:lang(kab)) > :lang(kab) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(kam), :not(:lang(kam)) > :lang(kam) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(kde), :not(:lang(kde)) > :lang(kde) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(kea), :not(:lang(kea)) > :lang(kea) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(khq), :not(:lang(khq)) > :lang(khq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ki), :not(:lang(ki)) > :lang(ki) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(kk), :not(:lang(kk)) > :lang(kk) { quotes: '\201c' '\0022' '\2018' '\2019' } /* “ " ‘ ’ */ +:root:lang(kkj), :not(:lang(kkj)) > :lang(kkj) { quotes: '\00ab' '\00bb' '\2039' '\203a' } /* « » ‹ › */ +:root:lang(kln), :not(:lang(kln)) > :lang(kln) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(km), :not(:lang(km)) > :lang(km) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(kn), :not(:lang(kn)) > :lang(kn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ko), :not(:lang(ko)) > :lang(ko) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ksb), :not(:lang(ksb)) > :lang(ksb) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ksf), :not(:lang(ksf)) > :lang(ksf) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » ‘ ’ */ +:root:lang(ky), :not(:lang(ky)) > :lang(ky) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */ +:root:lang(lag), :not(:lang(lag)) > :lang(lag) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” ’ ’ */ +:root:lang(lb), :not(:lang(lb)) > :lang(lb) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(lg), :not(:lang(lg)) > :lang(lg) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ln), :not(:lang(ln)) > :lang(ln) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(lo), :not(:lang(lo)) > :lang(lo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(lt), :not(:lang(lt)) > :lang(lt) { quotes: '\201e' '\201c' '\201e' '\201c' } /* „ “ „ “ */ +:root:lang(lu), :not(:lang(lu)) > :lang(lu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(luo), :not(:lang(luo)) > :lang(luo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(luy), :not(:lang(luy)) > :lang(luy) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(lv), :not(:lang(lv)) > :lang(lv) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mas), :not(:lang(mas)) > :lang(mas) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mer), :not(:lang(mer)) > :lang(mer) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mfe), :not(:lang(mfe)) > :lang(mfe) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mg), :not(:lang(mg)) > :lang(mg) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(mgo), :not(:lang(mgo)) > :lang(mgo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mk), :not(:lang(mk)) > :lang(mk) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(ml), :not(:lang(ml)) > :lang(ml) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mn), :not(:lang(mn)) > :lang(mn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mr), :not(:lang(mr)) > :lang(mr) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ms), :not(:lang(ms)) > :lang(ms) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mt), :not(:lang(mt)) > :lang(mt) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(mua), :not(:lang(mua)) > :lang(mua) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(my), :not(:lang(my)) > :lang(my) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(naq), :not(:lang(naq)) > :lang(naq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(nb), :not(:lang(nb)) > :lang(nb) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » ‘ ’ */ +:root:lang(nd), :not(:lang(nd)) > :lang(nd) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ne), :not(:lang(ne)) > :lang(ne) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(nl), :not(:lang(nl)) > :lang(nl) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(nmg), :not(:lang(nmg)) > :lang(nmg) { quotes: '\201e' '\201d' '\00ab' '\00bb' } /* „ ” « » */ +:root:lang(nn), :not(:lang(nn)) > :lang(nn) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » ‘ ’ */ +:root:lang(nnh), :not(:lang(nnh)) > :lang(nnh) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(nus), :not(:lang(nus)) > :lang(nus) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(nyn), :not(:lang(nyn)) > :lang(nyn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(pa), :not(:lang(pa)) > :lang(pa) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(pl), :not(:lang(pl)) > :lang(pl) { quotes: '\201e' '\201d' '\00ab' '\00bb' } /* „ ” « » */ +:root:lang(pt), :not(:lang(pt)) > :lang(pt) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(pt-PT), :not(:lang(pt-PT)) > :lang(pt-PT) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(rn), :not(:lang(rn)) > :lang(rn) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” ’ ’ */ +:root:lang(ro), :not(:lang(ro)) > :lang(ro) { quotes: '\201c' '\201d' '\00ab' '\00bb' } /* “ ” « » */ +:root:lang(rof), :not(:lang(rof)) > :lang(rof) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ru), :not(:lang(ru)) > :lang(ru) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */ +:root:lang(rw), :not(:lang(rw)) > :lang(rw) { quotes: '\00ab' '\00bb' '\2018' '\2019' } /* « » ‘ ’ */ +:root:lang(rwk), :not(:lang(rwk)) > :lang(rwk) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(saq), :not(:lang(saq)) > :lang(saq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(sbp), :not(:lang(sbp)) > :lang(sbp) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(seh), :not(:lang(seh)) > :lang(seh) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ses), :not(:lang(ses)) > :lang(ses) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(sg), :not(:lang(sg)) > :lang(sg) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(shi), :not(:lang(shi)) > :lang(shi) { quotes: '\00ab' '\00bb' '\201e' '\201d' } /* « » „ ” */ +:root:lang(shi-Latn), :not(:lang(shi-Latn)) > :lang(shi-Latn) { quotes: '\00ab' '\00bb' '\201e' '\201d' } /* « » „ ” */ +:root:lang(si), :not(:lang(si)) > :lang(si) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(sk), :not(:lang(sk)) > :lang(sk) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(sl), :not(:lang(sl)) > :lang(sl) { quotes: '\201e' '\201c' '\201a' '\2018' } /* „ “ ‚ ‘ */ +:root:lang(sn), :not(:lang(sn)) > :lang(sn) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” ’ ’ */ +:root:lang(so), :not(:lang(so)) > :lang(so) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(sq), :not(:lang(sq)) > :lang(sq) { quotes: '\00ab' '\00bb' '\201c' '\201d' } /* « » “ ” */ +:root:lang(sr), :not(:lang(sr)) > :lang(sr) { quotes: '\201e' '\201c' '\2018' '\2018' } /* „ “ ‘ ‘ */ +:root:lang(sr-Latn), :not(:lang(sr-Latn)) > :lang(sr-Latn) { quotes: '\201e' '\201c' '\2018' '\2018' } /* „ “ ‘ ‘ */ +:root:lang(sv), :not(:lang(sv)) > :lang(sv) { quotes: '\201d' '\201d' '\2019' '\2019' } /* ” ” ’ ’ */ +:root:lang(sw), :not(:lang(sw)) > :lang(sw) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(swc), :not(:lang(swc)) > :lang(swc) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ta), :not(:lang(ta)) > :lang(ta) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(te), :not(:lang(te)) > :lang(te) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(teo), :not(:lang(teo)) > :lang(teo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(th), :not(:lang(th)) > :lang(th) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(ti-ER), :not(:lang(ti-ER)) > :lang(ti-ER) { quotes: '\2018' '\2019' '\201c' '\201d' } /* ‘ ’ “ ” */ +:root:lang(to), :not(:lang(to)) > :lang(to) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(tr), :not(:lang(tr)) > :lang(tr) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(twq), :not(:lang(twq)) > :lang(twq) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(tzm), :not(:lang(tzm)) > :lang(tzm) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(uk), :not(:lang(uk)) > :lang(uk) { quotes: '\00ab' '\00bb' '\201e' '\201c' } /* « » „ “ */ +:root:lang(ur), :not(:lang(ur)) > :lang(ur) { quotes: '\201d' '\201c' '\2019' '\2018' } /* ” “ ’ ‘ */ +:root:lang(ur-IN), :not(:lang(ur-IN)) > :lang(ur-IN) { quotes: '\0022' '\0022' '\0027' '\0027' } /* " " ' ' */ +:root:lang(uz), :not(:lang(uz)) > :lang(uz) { quotes: '\0022' '\0022' '\0027' '\0027' } /* " " ' ' */ +:root:lang(uz-Cyrl), :not(:lang(uz-Cyrl)) > :lang(uz-Cyrl) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(vai), :not(:lang(vai)) > :lang(vai) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(vai-Latn), :not(:lang(vai-Latn)) > :lang(vai-Latn) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(vi), :not(:lang(vi)) > :lang(vi) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(vun), :not(:lang(vun)) > :lang(vun) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(xog), :not(:lang(xog)) > :lang(xog) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(yav), :not(:lang(yav)) > :lang(yav) { quotes: '\00ab' '\00bb' '\00ab' '\00bb' } /* « » « » */ +:root:lang(yo), :not(:lang(yo)) > :lang(yo) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(zgh), :not(:lang(zgh)) > :lang(zgh) { quotes: '\00ab' '\00bb' '\201e' '\201d' } /* « » „ ” */ +:root:lang(zh), :not(:lang(zh)) > :lang(zh) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ +:root:lang(zh-Hant), :not(:lang(zh-Hant)) > :lang(zh-Hant) { quotes: '\300c' '\300d' '\300e' '\300f' } /* 「 」 『 』 */ +:root:lang(zu), :not(:lang(zu)) > :lang(zu) { quotes: '\201c' '\201d' '\2018' '\2019' } /* “ ” ‘ ’ */ diff --git a/resources/servo.css b/resources/servo.css new file mode 100644 index 00000000000..77d05782725 --- /dev/null +++ b/resources/servo.css @@ -0,0 +1,13 @@ +input, select { display: inline-block; } +input { background: white; min-height: 1.0em; padding: 0em; padding-left: 0.25em; padding-right: 0.25em; border: solid lightgrey 1px; color: black; white-space: nowrap; } +input[type="button"], +input[type="submit"], +input[type="reset"] { background: lightgrey; border-top: solid 1px #EEEEEE; border-left: solid 1px #CCCCCC; border-right: solid 1px #999999; border-bottom: solid 1px #999999; text-align: center; vertical-align: middle; color: black; } +input[type="hidden"] { display: none !important } +input[type="checkbox"], +input[type="radio"] { font-family: monospace !important; border: none !important; background: transparent; } + +input[type="checkbox"]::before { content: "[ ]"; padding: 0; } +input[type="checkbox"][checked]::before { content: "[✓]"; } +input[type="radio"]::before { content: "( )"; padding: 0; } +input[type="radio"][checked]::before { content: "(●)"; } diff --git a/resources/user-agent.css b/resources/user-agent.css index 209bafa4c2e..8ae8f5a5960 100644 --- a/resources/user-agent.css +++ b/resources/user-agent.css @@ -1,130 +1,276 @@ -html, address, -blockquote, -body, div, -dt, fieldset, form, -frame, frameset, -h1, h2, h3, h4, -h5, h6, noframes, -center, dir, -hr, menu, pre { display: block; unicode-bidi: embed } - head, noscript { display: none } - table { display: table } - tr { display: table-row } - thead { display: table-header-group } - tbody { display: table-row-group } - tfoot { display: table-footer-group } - col { display: table-column } - colgroup { display: table-column-group } - td, th { display: table-cell } - caption { display: table-caption } - th { font-weight: bolder; text-align: center } - caption { text-align: center } - body { margin: 8px } - h1 { font-size: 2em; margin: .67em 0 } - h2 { font-size: 1.5em; margin: .75em 0 } - h3 { font-size: 1.17em; margin: .83em 0 } -h4, -blockquote, -fieldset, dir, -menu { margin: 1.12em 0 } - h5 { font-size: .83em; margin: 1.5em 0 } - h6 { font-size: .75em; margin: 1.67em 0 } -h1, h2, h3, h4, -h5, h6, b, - strong { font-weight: bolder } - blockquote { margin-left: 40px; margin-right: 40px } -i, cite, em, - var, address { font-style: italic } -pre, tt, code, - kbd, samp { font-family: monospace } - pre { white-space: pre } -button, textarea, - input, select { display: inline-block } - big { font-size: 1.17em } - small, sub, sup { font-size: .83em } - sub { vertical-align: sub } - sup { vertical-align: super } - table { border-spacing: 2px; } -thead, tbody, - tfoot { vertical-align: middle } - td, th, tr { vertical-align: inherit } - s, strike, del { text-decoration: line-through } - hr { border: 1px inset } - -/* lists */ -dd { display: block; margin-left: 40px } -p, dl, multicol { display: block; margin: 1em 0 } -ul { display: block; list-style-type: disc; - margin: 1em 0; padding-left: 40px } - -ol { display: block; list-style-type: decimal; - margin: 1em 0; padding-left: 40px } - -li { display: list-item } - -/* nested lists have no top/bottom margins */ -ul ul, ul ol, ul dl, -ol ul, ol ol, ol dl, -dl ul, dl ol, dl dl { margin-top: 0; margin-bottom: 0 } - -/* 2 deep unordered lists use a circle */ -ol ul, ul ul { list-style-type: circle; } - -/* 3 deep (or more) unordered lists use a square */ -ol ol ul, ol ul ul, -ul ol ul, ul ul ul { list-style-type: square; } - -/* The type attribute on ol and ul elements */ -ul[type="disc"] { list-style-type: disc; } -ul[type="circle"] { list-style-type: circle; } -ul[type="square"] { list-style-type: square; } -ol[type="1"] { list-style-type: decimal; } -ol[type="a"] { list-style-type: lower-alpha; } -ol[type="A"] { list-style-type: upper-alpha; } -ol[type="i"] { list-style-type: lower-roman; } -ol[type="I"] { list-style-type: upper-roman; } - -u, ins { text-decoration: underline } -br:before { content: "\A"; white-space: pre } - -center { text-align: center } -a:link, -a:visited, -area:link, -area:visited, -link:link, -link:visited { text-decoration: underline } -:focus { outline: thin dotted invert } - -/* Begin bidirectionality settings (do not change) */ -BDO[DIR="ltr"] { direction: ltr; unicode-bidi: bidi-override } -BDO[DIR="rtl"] { direction: rtl; unicode-bidi: bidi-override } - -*[DIR="ltr"] { direction: ltr; unicode-bidi: embed } -*[DIR="rtl"] { direction: rtl; unicode-bidi: embed } - -@media print { -h1 { page-break-before: always } -h1, h2, h3, -h4, h5, h6 { page-break-after: avoid } -ul, ol, dl { page-break-before: avoid } -} - -/* Servo additions */ -a:link, -area:link, -link:link { color: blue } -script { display: none } -style { display: none } -input { background: white; min-height: 1.0em; padding: 0em; padding-left: 0.25em; padding-right: 0.25em; border: solid lightgrey 1px; color: black; white-space: nowrap; } -input[type="button"], -input[type="submit"], -input[type="reset"] { background: lightgrey; border-top: solid 1px #EEEEEE; border-left: solid 1px #CCCCCC; border-right: solid 1px #999999; border-bottom: solid 1px #999999; text-align: center; vertical-align: middle; color: black; } -input[type="hidden"] { display: none !important } -input[type="checkbox"], -input[type="radio"] { font-family: monospace !important; border: none !important; background: transparent; } - -input[type="checkbox"]::before { content: "[ ]"; padding: 0; } -input[type="checkbox"][checked]::before { content: "[✓]"; } -input[type="radio"]::before { content: "( )"; padding: 0; } -input[type="radio"][checked]::before { content: "(●)"; } +/* +https://html.spec.whatwg.org/multipage/rendering.html#form-controls +*/ + +@namespace url(http://www.w3.org/1999/xhtml); + +/* +FIXME: Uncomment this when :lang() is supported, or do something equivalent. +@import url(quotes.css); +*/ + +[hidden], area, base, basefont, datalist, head, link, menu[type=popup i], meta, +noembed, noframes, param, rp, script, source, style, template, track, title { + display: none; +} + +embed[hidden] { display: inline; height: 0; width: 0; } + +/* FIXME: only if scripting is enabled */ +noscript { display: none !important; } + +input[type=hidden i] { display: none !important; } + + +html, body { display: block; } + +body { margin: 8px; } + + +address, blockquote, center, div, figure, figcaption, footer, form, header, hr, +legend, listing, main, p, plaintext, pre, summary, xmp { + display: block; +} + +blockquote, figure, listing, p, plaintext, pre, xmp { + margin-top: 1em; margin-bottom: 1em; +} + +blockquote, figure { margin-left: 40px; margin-right: 40px; } + +address { font-style: italic; } +listing, plaintext, pre, xmp { + font-family: monospace; white-space: pre; +} + +dialog:not([open]) { display: none; } +dialog { + position: absolute; + left: 0; right: 0; + /* FIXME: support fit-content */ + width: fit-content; + height: fit-content; + margin: auto; + border: solid; + padding: 1em; + background: white; + color: black; +} +/* FIXME: support ::backdrop */ +dialog::backdrop { + position: fixed; + top: 0; right: 0; bottom: 0; left: 0; + background: rgba(0,0,0,0.1); +} + +/* for small devices, modal dialogs go full-screen */ +@media screen and (max-width: 540px) { + /* FIXME: support :modal */ + dialog:modal { + top: 0; + width: auto; + margin: 1em; + } +} + + +cite, dfn, em, i, var { font-style: italic; } +b, strong { font-weight: bolder; } +code, kbd, samp, tt { font-family: monospace; } +big { font-size: larger; } +small { font-size: smaller; } + +sub { vertical-align: sub; } +sup { vertical-align: super; } +sub, sup { line-height: normal; font-size: smaller; } + +ruby { display: ruby; } +rt { display: ruby-text; } + +:link { color: #0000EE; } +:visited { color: #551A8B; } +:link, :visited { text-decoration: underline; } +a:link[rel~=help], a:visited[rel~=help], +area:link[rel~=help], area:visited[rel~=help] { cursor: help; } + +:focus { outline: thin dotted; } /* FIXME: 'outline: auto' ? */ + +mark { background: yellow; color: black; } + +abbr[title], acronym[title] { text-decoration: dotted underline; } +ins, u { text-decoration: underline; } +del, s, strike { text-decoration: line-through; } +blink { text-decoration: blink; } + +q::before { content: open-quote; } +q::after { content: close-quote; } + +/*br { display-outside: newline; } /* this also has bidi implications */ +br::before { content: "\A"; white-space: pre } + +nobr { white-space: nowrap; } +wbr { display-outside: break-opportunity; } /* this also has bidi implications */ +nobr wbr { white-space: normal; } + + +[dir]:dir(ltr), bdi:dir(ltr), input[type=tel]:dir(ltr) { direction: ltr; } +[dir]:dir(rtl), bdi:dir(rtl) { direction: rtl; } + +address, blockquote, center, div, figure, figcaption, footer, form, header, hr, +legend, listing, main, p, plaintext, pre, summary, xmp, article, aside, h1, h2, +h3, h4, h5, h6, hgroup, nav, section, table, caption, colgroup, col, thead, +tbody, tfoot, tr, td, th, dir, dd, dl, dt, menu, ol, ul, li, bdi, output, +[dir=ltr i], [dir=rtl i], [dir=auto i] { + unicode-bidi: isolate; +} + +bdo, bdo[dir] { unicode-bidi: isolate-override; } + +textarea[dir=auto i], pre[dir=auto i] { unicode-bidi: plaintext; } + + +article, aside, h1, h2, h3, h4, h5, h6, hgroup, nav, section { + display: block; +} + +h1 { margin-top: 0.67em; margin-bottom: 0.67em; font-size: 2.00em; font-weight: bold; } +h2 { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; font-weight: bold; } +h3 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; font-weight: bold; } +h4 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; font-weight: bold; } +h5 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; font-weight: bold; } +h6 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; font-weight: bold; } + +:matches(article, aside, nav, section) h1 { margin-top: 0.83em; margin-bottom: 0.83em; font-size: 1.50em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) h1 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; } + +:matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.00em; margin-bottom: 1.00em; font-size: 1.17em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h2 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; } + +:matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 1.33em; margin-bottom: 1.33em; font-size: 1.00em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h3 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; } + +:matches(article, aside, nav, section) hgroup > h1 ~ h4 { margin-top: 1.67em; margin-bottom: 1.67em; font-size: 0.83em; } +:matches(article, aside, nav, section) :matches(article, aside, nav, section) hgroup > h1 ~ h4 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; } + +:matches(article, aside, nav, section) hgroup > h1 ~ h5 { margin-top: 2.33em; margin-bottom: 2.33em; font-size: 0.67em; } + + +dir, dd, dl, dt, menu, ol, ul { display: block; } +li { display: list-item; } + +dir, dl, menu, ol, ul { margin-top: 1em; margin-bottom: 1em; } + +:matches(dir, dl, menu, ol, ul) :matches(dir, dl, menu, ol, ul) { + margin-top: 0; margin-bottom: 0; +} + +dd { margin-left: 40px; } /* FIXME: use margin-inline-start when supported */ +dir, menu, ol, ul { padding-left: 40px; } /* FIXME: use padding-inline-start when supported */ + +ol { list-style-type: decimal; } + +dir, menu, ul { list-style-type: disc; } + +:matches(dir, menu, ol, ul) :matches(dir, menu, ul) { + list-style-type: circle; +} + +:matches(dir, menu, ol, ul) :matches(dir, menu, ol, ul) :matches(dir, menu, ul) { + list-style-type: square; +} + + +table { display: table; } +caption { display: table-caption; } +colgroup, colgroup[hidden] { display: table-column-group; } +col, col[hidden] { display: table-column; } +thead, thead[hidden] { display: table-header-group; } +tbody, tbody[hidden] { display: table-row-group; } +tfoot, tfoot[hidden] { display: table-footer-group; } +tr, tr[hidden] { display: table-row; } +td, th, td[hidden], th[hidden] { display: table-cell; } + +colgroup[hidden], col[hidden], thead[hidden], tbody[hidden], +tfoot[hidden], tr[hidden], td[hidden], th[hidden] { + visibility: collapse; +} + +table { + box-sizing: border-box; + border-spacing: 2px; + border-collapse: separate; + text-indent: initial; +} +td, th { padding: 1px; } +th { font-weight: bold; } + +thead, tbody, tfoot, table > tr { vertical-align: middle; } +tr, td, th { vertical-align: inherit; } + + +table, td, th { border-color: gray; } +thead, tbody, tfoot, tr { border-color: inherit; } +table:matches( + [rules=none i], [rules=groups i], [rules=rows i], + [rules=cols i], [rules=all i], + [frame=void i], [frame=above i], [frame=below i], + [frame=hsides i], [frame=lhs i], [frame=rhs i], + [frame=vsides i], [frame=box i], [frame=border i] +), +table:matches( + [rules=none i], [rules=groups i], [rules=rows i], + [rules=cols i], [rules=all i] +) > tr > :matches(td, th), +table:matches( + [rules=none i], [rules=groups i], [rules=rows i], + [rules=cols i], [rules=all i] +) > :matches(thead, tbody, tfoot) > tr > :matches(td, th) { + border-color: black; +} + + +:matches(table, thead, tbody, tfoot, tr) > form { + display: none !important; +} + + +input, select, option, optgroup, button, textarea, keygen { + text-indent: initial; +} + +textarea { white-space: pre-wrap; } + +input[type="radio"], input[type="checkbox"], input[type="reset"], input[type="button"], +input[type="submit"], select, button { + box-sizing: border-box; +} + + +hr { color: gray; border-style: inset; border-width: 1px; margin: 0.5em auto; } + + +fieldset { + display: block; /* https://www.w3.org/Bugs/Public/show_bug.cgi?id=27018 */ + margin-left: 2px; margin-right: 2px; + border: groove 2px; + border-color: ThreeDFace; /* FIXME: system color */ + padding: 0.35em 0.625em 0.75em; + min-width: min-content; +} + +legend { + padding-left: 2px; padding-right: 2px; +} + +iframe:not([seamless]) { border: 2px inset; } +iframe[seamless] { display: block; } +video { object-fit: contain; } + + +textarea { white-space: pre-wrap; } diff --git a/src/lib.rs b/src/lib.rs index 79ace45134c..132d0314558 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,8 @@ extern crate url; #[cfg(not(test))] use compositing::{CompositorChan, CompositorTask, Constellation}; #[cfg(not(test))] +use compositing::windowing::WindowMethods; +#[cfg(not(test))] use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg}; #[cfg(not(test))] use script::dom::bindings::codegen::RegisterBindings; @@ -55,36 +57,12 @@ use green::GreenTaskBuilder; #[cfg(not(test))] use std::os; #[cfg(not(test))] +use std::rc::Rc; +#[cfg(not(test))] use std::task::TaskBuilder; -#[cfg(not(test), target_os="android")] -use std::string; - -#[cfg(not(test), target_os="android")] -#[no_mangle] -#[allow(dead_code)] -pub extern "C" fn android_start(argc: int, argv: *const *const u8) -> int { - native::start(argc, argv, proc() { - let mut args: Vec<String> = vec!(); - for i in range(0u, argc as uint) { - unsafe { - args.push(string::raw::from_buf(*argv.offset(i as int) as *const u8)); - } - } - - let opts = opts::from_cmdline_args(args.as_slice()); - match opts { - Some(mut o) => { - // Always use CPU rendering on android. - o.cpu_painting = true; - run(o); - }, - None => {} - } - }) -} #[cfg(not(test))] -pub fn run(opts: opts::Opts) { +pub fn run<Window: WindowMethods>(opts: opts::Opts, window: Option<Rc<Window>>) { ::servo_util::opts::set_experimental_enabled(opts.enable_experimental); RegisterBindings::RegisterProxyHandlers(); @@ -149,7 +127,8 @@ pub fn run(opts: opts::Opts) { let constellation_chan = result_port.recv(); debug!("preparing to enter main loop"); - CompositorTask::create(opts, + CompositorTask::create(window, + opts, compositor_port, constellation_chan, time_profiler_chan, diff --git a/src/main.rs b/src/main.rs index a1ced51d823..9d78c0967c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,9 @@ extern crate native; extern crate "util" as servo_util; #[cfg(not(test),not(target_os="android"))] +extern crate glfw_app; + +#[cfg(not(test),not(target_os="android"))] use servo_util::opts; #[cfg(not(test),not(target_os="android"))] @@ -20,13 +23,19 @@ use servo::run; #[cfg(not(test),not(target_os="android"))] use std::os; -#[cfg(not(test), target_os="linux")] -#[cfg(not(test), target_os="macos")] +#[cfg(not(test), not(target_os="android"))] #[start] #[allow(dead_code)] fn start(argc: int, argv: *const *const u8) -> int { native::start(argc, argv, proc() { - opts::from_cmdline_args(os::args().as_slice()).map(run); + opts::from_cmdline_args(os::args().as_slice()).map(|opts| { + let window = if opts.headless { + None + } else { + Some(glfw_app::create_window(&opts)) + }; + run(opts, window); + }); }) } diff --git a/tests/html/form_submission_handsfree.html b/tests/html/form_submission_handsfree.html new file mode 100644 index 00000000000..cc729d2ea79 --- /dev/null +++ b/tests/html/form_submission_handsfree.html @@ -0,0 +1,16 @@ +<html> +<head></head> +<body> +<!-- Run with nc -l 8000 --> +<form action="http://localhost:8000" method=get id="foo"> +<input name=bar type=checkbox checked> +<input name=baz value="baz1" type=radio checked> +<input name=baz value="baz2" type=radio> +<input type=text name=bye value="hi!"> +</form> +<script> +// setTimeout because https://github.com/servo/servo/issues/3628 +setTimeout(function(){document.getElementById("foo").submit()},5000) +</script> +</body> +</html> diff --git a/tests/ref/attr_selector_case_sensitivity.html b/tests/ref/attr_selector_case_sensitivity.html new file mode 100644 index 00000000000..c4d36db7918 --- /dev/null +++ b/tests/ref/attr_selector_case_sensitivity.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute selector case-sensitivity: [foo=bar] and [foo=bar i]</title> + <style> + p[data-foo=Bar] { color: green } + p[data-foo=bar] { color: red } + p[data-foo=baz i] { color: green } + p[data-foo=baz] { color: red } + </style> + </head> + <body> + <p data-foo="Bar">This text should be green.</p> + <p data-foo="Baz">This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/tests/ref/attr_selector_case_sensitivity_ref.html b/tests/ref/attr_selector_case_sensitivity_ref.html new file mode 100644 index 00000000000..9e9be12d13e --- /dev/null +++ b/tests/ref/attr_selector_case_sensitivity_ref.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute selector case-sensitivity: [foo=bar] and [foo=bar i]</title> + <style> + p[data-foo=Bar] { color: green } + p[data-foo=bar] { color: red } + p[data-foo=baz i] { color: green } + p[data-foo=baz] { color: red } + </style> + </head> + <body> + <p style="color: green">This text should be green.</p> + <p style="color: green">This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 247f4d38d81..18b09f45bfe 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -30,6 +30,7 @@ # inline_border_a.html inline_border_b.html == anon_block_inherit_a.html anon_block_inherit_b.html == attr_exists_selector.html attr_exists_selector_ref.html +== attr_selector_case_sensitivity.html attr_selector_case_sensitivity_ref.html != noteq_attr_exists_selector.html attr_exists_selector_ref.html == data_img_a.html data_img_b.html == background_style_attr.html background_ref.html @@ -62,6 +63,7 @@ == position_fixed_overflow_a.html position_fixed_overflow_b.html == position_fixed_tile_edge.html position_fixed_tile_edge_ref.html == position_fixed_tile_edge_2.html position_fixed_tile_edge_ref.html +== position_fixed_tile_edge_3.html position_fixed_tile_edge_ref.html == position_relative_a.html position_relative_b.html == position_relative_top_percentage_a.html position_relative_top_percentage_b.html == background_none_a.html background_none_b.html @@ -133,7 +135,8 @@ fragment=top != ../html/acid2.html acid2_ref.html == float_table_a.html float_table_ref.html == table_containing_block_a.html table_containing_block_ref.html == link_style_order.html link_style_order_ref.html -== link_style_dynamic_addition.html link_style_dynamic_addition_ref.html +# Fails intermittently (#3636) +# == link_style_dynamic_addition.html link_style_dynamic_addition_ref.html == percent_height.html percent_height_ref.html == inline_block_with_margin_a.html inline_block_with_margin_ref.html == table_padding_a.html table_padding_ref.html @@ -168,3 +171,5 @@ fragment=top != ../html/acid2.html acid2_ref.html != input_height_a.html input_height_ref.html == pre_ignorable_whitespace_a.html pre_ignorable_whitespace_ref.html == many_brs_a.html many_brs_ref.html +== box_sizing_sanity_check_a.html box_sizing_sanity_check_ref.html +== inline_block_overflow_hidden_a.html inline_block_overflow_hidden_ref.html diff --git a/tests/ref/box_sizing_sanity_check_a.html b/tests/ref/box_sizing_sanity_check_a.html new file mode 100644 index 00000000000..9f4adbe3cba --- /dev/null +++ b/tests/ref/box_sizing_sanity_check_a.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<html> +<body> +<div style="box-sizing: border-box; float: left; background: yellow;">Heeheehee</div> +</body> +</html> + diff --git a/tests/ref/box_sizing_sanity_check_ref.html b/tests/ref/box_sizing_sanity_check_ref.html new file mode 100644 index 00000000000..1925994c911 --- /dev/null +++ b/tests/ref/box_sizing_sanity_check_ref.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<html> +<body> +<div style="float: left; background: yellow;">Heeheehee</div> +</body> +</html> + diff --git a/tests/ref/iframe/multiple_external.html b/tests/ref/iframe/multiple_external.html index 870bef5ba2d..7daac996435 100644 --- a/tests/ref/iframe/multiple_external.html +++ b/tests/ref/iframe/multiple_external.html @@ -7,6 +7,7 @@ float: left; width: 300px; height: 300px; + border: none; } </style> </head> diff --git a/tests/ref/iframe/overflow.html b/tests/ref/iframe/overflow.html index 64456f1b418..405ee9fa8e6 100644 --- a/tests/ref/iframe/overflow.html +++ b/tests/ref/iframe/overflow.html @@ -1,7 +1,7 @@ <html> <body> <iframe src="data:text/html,%3Cdiv%20style%3D%22background%3Agreen%3B%20width%3A%20200px%3B%20height%3A%20200px%3B%22%3E%3C%2Fdiv%3E" - style="display: block; width: 108px; height: 108px;"> + style="display: block; width: 108px; height: 108px; border: none"> </iframe> </div> </body> diff --git a/tests/ref/inline_block_overflow_hidden_a.html b/tests/ref/inline_block_overflow_hidden_a.html new file mode 100644 index 00000000000..088d536e4e0 --- /dev/null +++ b/tests/ref/inline_block_overflow_hidden_a.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<html> +<body> +<div style="display: inline-block; overflow: hidden">This should be visible</div> +</body> +</html> + diff --git a/tests/ref/inline_block_overflow_hidden_ref.html b/tests/ref/inline_block_overflow_hidden_ref.html new file mode 100644 index 00000000000..93047704cac --- /dev/null +++ b/tests/ref/inline_block_overflow_hidden_ref.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<body> +<div style="display: inline-block">This should be visible</div> +</body> +</html> + + diff --git a/tests/ref/position_fixed_tile_edge_3.html b/tests/ref/position_fixed_tile_edge_3.html new file mode 100644 index 00000000000..dcf2341c170 --- /dev/null +++ b/tests/ref/position_fixed_tile_edge_3.html @@ -0,0 +1,11 @@ +<html> + <body> + <div style="position: absolute; top: 0px; left: 0px;"> + <div style="position: absolute; background: green; margin-left: 512px; width: 20px; height: 20px;"></div> + + <!-- This position:fixed sibling should force its sibling to be layerized. --> + <div style="position: fixed;"></div> + </div> + </body> +</html> + diff --git a/tests/ref/table_auto_width.html b/tests/ref/table_auto_width.html index 39396bbb799..62f0def0086 100644 --- a/tests/ref/table_auto_width.html +++ b/tests/ref/table_auto_width.html @@ -6,7 +6,7 @@ <table> <tbody> <tr> - <td> + <td style="padding: 0"> <span>12345<span>67890</span></span> </td> </tr> diff --git a/tests/ref/table_auto_width_ref.html b/tests/ref/table_auto_width_ref.html index 1a90aab518e..0cb28c3ef1e 100644 --- a/tests/ref/table_auto_width_ref.html +++ b/tests/ref/table_auto_width_ref.html @@ -6,7 +6,7 @@ <table> <tbody> <tr> - <td> + <td style="padding: 0"> <span>1234567890</span> </td> </tr> diff --git a/tests/ref/table_containing_block_a.html b/tests/ref/table_containing_block_a.html index 1b33586f70c..6c3a4e02a4a 100644 --- a/tests/ref/table_containing_block_a.html +++ b/tests/ref/table_containing_block_a.html @@ -14,7 +14,7 @@ <table class="rel"> <tbody> <tr class="abs"> - <td>Don't crash!</td> + <td style="padding: 0">Don't crash!</td> </tr> </tbody> </table> diff --git a/tests/ref/table_containing_block_ref.html b/tests/ref/table_containing_block_ref.html index b4377f5e761..d59322ab8ec 100644 --- a/tests/ref/table_containing_block_ref.html +++ b/tests/ref/table_containing_block_ref.html @@ -6,7 +6,7 @@ <table> <tbody> <tr> - <td>Don't crash!</td> + <td style="padding: 0">Don't crash!</td> </tr> </tbody> </table> diff --git a/tests/ref/table_padding_a.html b/tests/ref/table_padding_a.html index a95ac820bff..5170b6d12b2 100644 --- a/tests/ref/table_padding_a.html +++ b/tests/ref/table_padding_a.html @@ -15,9 +15,11 @@ table { background:green; padding: 150px; + box-sizing: content-box; } th { color: yellow; + padding: 0; } </style> </head> diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 1ec90dd8049..bfc351e5eab 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -1546,6 +1546,62 @@ "url": "/custom-elements/testcommon.js" }, { + "path": "docs/configuration.md", + "url": "/docs/configuration.md" + }, + { + "path": "docs/css-metadata.md", + "url": "/docs/css-metadata.md" + }, + { + "path": "docs/css-naming.md", + "url": "/docs/css-naming.md" + }, + { + "path": "docs/css-user-styles.md", + "url": "/docs/css-user-styles.md" + }, + { + "path": "docs/github-101.md", + "url": "/docs/github-101.md" + }, + { + "path": "docs/manual-test.md", + "url": "/docs/manual-test.md" + }, + { + "path": "docs/reftests.md", + "url": "/docs/reftests.md" + }, + { + "path": "docs/review-checklist.md", + "url": "/docs/review-checklist.md" + }, + { + "path": "docs/review-process.md", + "url": "/docs/review-process.md" + }, + { + "path": "docs/running_tests.md", + "url": "/docs/running_tests.md" + }, + { + "path": "docs/submission-process.md", + "url": "/docs/submission-process.md" + }, + { + "path": "docs/test-format-guidelines.md", + "url": "/docs/test-format-guidelines.md" + }, + { + "path": "docs/test-style-guidelines.md", + "url": "/docs/test-style-guidelines.md" + }, + { + "path": "docs/test-templates.md", + "url": "/docs/test-templates.md" + }, + { "path": "dom/common.js", "url": "/dom/common.js" }, @@ -1690,6 +1746,10 @@ "url": "/dom/nodes/getElementsByClassName-11.xml" }, { + "path": "dom/nodes/mutationobservers.js", + "url": "/dom/nodes/mutationobservers.js" + }, + { "path": "dom/nodes/productions.js", "url": "/dom/nodes/productions.js" }, @@ -6452,6 +6512,10 @@ "url": "/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html" }, { + "path": "pointerevents/pointerevent_touch-action-button-test_touch-manual.html", + "url": "/pointerevents/pointerevent_touch-action-button-test_touch-manual.html" + }, + { "path": "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html", "url": "/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html" }, @@ -6504,10 +6568,18 @@ "url": "/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html" }, { + "path": "pointerevents/pointerevent_touch-action-span-test_touch-manual.html", + "url": "/pointerevents/pointerevent_touch-action-span-test_touch-manual.html" + }, + { "path": "pointerevents/pointerevent_touch-action-svg-test_touch-manual.html", "url": "/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html" }, { + "path": "pointerevents/pointerevent_touch-action-table-test_touch-manual.html", + "url": "/pointerevents/pointerevent_touch-action-table-test_touch-manual.html" + }, + { "path": "touch-events/multi-touch-interactions-manual.html", "url": "/touch-events/multi-touch-interactions-manual.html" }, @@ -12485,6 +12557,18 @@ "url": "/IndexedDB/idbindex_get4.htm" }, { + "path": "IndexedDB/idbindex_get5.htm", + "url": "/IndexedDB/idbindex_get5.htm" + }, + { + "path": "IndexedDB/idbindex_get6.htm", + "url": "/IndexedDB/idbindex_get6.htm" + }, + { + "path": "IndexedDB/idbindex_get7.htm", + "url": "/IndexedDB/idbindex_get7.htm" + }, + { "path": "IndexedDB/idbindex_getKey.htm", "url": "/IndexedDB/idbindex_getKey.htm" }, @@ -14382,6 +14466,34 @@ "url": "/dom/nodes/Element-tagName.html" }, { + "path": "dom/nodes/MutationObserver-attributes.html", + "url": "/dom/nodes/MutationObserver-attributes.html" + }, + { + "path": "dom/nodes/MutationObserver-characterData.html", + "url": "/dom/nodes/MutationObserver-characterData.html" + }, + { + "path": "dom/nodes/MutationObserver-childList.html", + "url": "/dom/nodes/MutationObserver-childList.html" + }, + { + "path": "dom/nodes/MutationObserver-disconnect.html", + "url": "/dom/nodes/MutationObserver-disconnect.html" + }, + { + "path": "dom/nodes/MutationObserver-document.html", + "url": "/dom/nodes/MutationObserver-document.html" + }, + { + "path": "dom/nodes/MutationObserver-inner-outer.html", + "url": "/dom/nodes/MutationObserver-inner-outer.html" + }, + { + "path": "dom/nodes/MutationObserver-takeRecords.html", + "url": "/dom/nodes/MutationObserver-takeRecords.html" + }, + { "path": "dom/nodes/Node-appendChild.html", "url": "/dom/nodes/Node-appendChild.html" }, @@ -15967,6 +16079,7 @@ }, { "path": "html/dom/interfaces.html", + "timeout": "long", "url": "/html/dom/interfaces.html" }, { @@ -19958,6 +20071,10 @@ "url": "/pointerevents/pointerevent_touch-action-illegal.html" }, { + "path": "pointerevents/pointerevent_touch-action-verification.html", + "url": "/pointerevents/pointerevent_touch-action-verification.html" + }, + { "path": "pointerlock/constructor.html", "url": "/pointerlock/constructor.html" }, @@ -22853,5 +22970,5 @@ ] }, "local_changes": [], - "rev": "746cc5a50a947ed0eafd4d38b82a99554b47697b" + "rev": "b621c0b3a3eb5f865ec3cc72372e5c75610337e2" }
\ No newline at end of file diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini new file mode 100644 index 00000000000..66e97c704e6 --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini @@ -0,0 +1,128 @@ +[MutationObserver-attributes.html] + type: testharness + [attributes Element.id: update, no oldValue, mutation] + expected: FAIL + + [attributes Element.id: update mutation] + expected: FAIL + + [attributes Element.id: empty string update mutation] + expected: FAIL + + [attributes Element.id: same value mutation] + expected: FAIL + + [attributes Element.unknown: IDL attribute no mutation] + expected: FAIL + + [attributes HTMLInputElement.type: type update mutation] + expected: FAIL + + [attributes Element.className: new value mutation] + expected: FAIL + + [attributes Element.className: empty string update mutation] + expected: FAIL + + [attributes Element.className: same value mutation] + expected: FAIL + + [attributes Element.className: same multiple values mutation] + expected: FAIL + + [attributes Element.classList.add: single token addition mutation] + expected: FAIL + + [attributes Element.classList.add: multiple tokens addition mutation] + expected: FAIL + + [attributes Element.classList.add: syntax err/no mutation] + expected: FAIL + + [attributes Element.classList.add: invalid character/no mutation] + expected: FAIL + + [attributes Element.classList.add: same value mutation] + expected: FAIL + + [attributes Element.classList.remove: single token removal mutation] + expected: FAIL + + [attributes Element.classList.remove: multiple tokens removal mutation] + expected: FAIL + + [attributes Element.classList.remove: missing token removal mutation] + expected: FAIL + + [attributes Element.classList.toggle: token removal mutation] + expected: FAIL + + [attributes Element.classList.toggle: token addition mutation] + expected: FAIL + + [attributes Element.classList.toggle: forced token removal mutation] + expected: FAIL + + [attributes Element.classList.toggle: forced missing token removal no mutation] + expected: FAIL + + [attributes Element.classList.toggle: forced existing token addition no mutation] + expected: FAIL + + [attributes Element.classList.toggle: forced token addition mutation] + expected: FAIL + + [attributes Element.attributes.value: update mutation] + expected: FAIL + + [attributes Element.attributes.value: same id mutation] + expected: FAIL + + [attributes Element.setAttribute: id mutation] + expected: FAIL + + [attributes Element.setAttribute: same class mutation] + expected: FAIL + + [attributes Element.setAttribute: classname mutation] + expected: FAIL + + [attributes Element.removeAttribute: removal mutation] + expected: FAIL + + [attributes Element.removeAttribute: removal no mutation] + expected: FAIL + + [childList HTMLInputElement.removeAttribute: type removal mutation] + expected: FAIL + + [attributes Element.setAttributeNS: creation mutation] + expected: FAIL + + [attributes Element.setAttributeNS: prefixed attribute creation mutation] + expected: FAIL + + [attributes Element.removeAttributeNS: removal mutation] + expected: FAIL + + [attributes Element.removeAttributeNS: removal no mutation] + expected: FAIL + + [attributes Element.removeAttributeNS: prefixed attribute removal no mutation] + expected: FAIL + + [attributes/attributeFilter Element.id/Element.className: update mutation] + expected: FAIL + + [attributes/attributeFilter Element.id/Element.className: multiple filter update mutation] + expected: FAIL + + [attributeOldValue alone Element.id: update mutation] + expected: FAIL + + [attributeFilter alone Element.id/Element.className: multiple filter update mutation] + expected: FAIL + + [childList false: no childList mutation] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini new file mode 100644 index 00000000000..0aa1edd7502 --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini @@ -0,0 +1,71 @@ +[MutationObserver-characterData.html] + type: testharness + [characterData Text.data: simple mutation without oldValue] + expected: FAIL + + [characterData Text.data: simple mutation] + expected: FAIL + + [characterData Text.appendData: simple mutation] + expected: FAIL + + [characterData Text.appendData: empty string mutation] + expected: FAIL + + [characterData Text.appendData: null string mutation] + expected: FAIL + + [characterData Text.insertData: simple mutation] + expected: FAIL + + [characterData Text.insertData: empty string mutation] + expected: FAIL + + [characterData Text.insertData: null string mutation] + expected: FAIL + + [characterData Text.deleteData: simple mutation] + expected: FAIL + + [characterData Text.deleteData: empty mutation] + expected: FAIL + + [characterData Text.replaceData: simple mutation] + expected: FAIL + + [characterData Text.replaceData: empty mutation] + expected: FAIL + + [characterData ProcessingInstruction: data mutations] + expected: FAIL + + [characterData Comment: data mutations] + expected: FAIL + + [Range (r70) is created] + expected: FAIL + + [characterData Range.deleteContents: child and data removal mutation] + expected: FAIL + + [Range (r71) is created] + expected: FAIL + + [characterData Range.deleteContents: child and data removal mutation (2)] + expected: FAIL + + [Range (r80) is created] + expected: FAIL + + [characterData Range.extractContents: child and data removal mutation] + expected: FAIL + + [Range (r81) is created] + expected: FAIL + + [characterData Range.extractContents: child and data removal mutation (2)] + expected: FAIL + + [characterData/characterDataOldValue alone Text.data: simple mutation] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini new file mode 100644 index 00000000000..1c9646a9700 --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini @@ -0,0 +1,113 @@ +[MutationObserver-childList.html] + type: testharness + [childList Node.nodeValue: no mutation] + expected: FAIL + + [childList Node.textContent: replace content mutation] + expected: FAIL + + [childList Node.textContent: no previous content mutation] + expected: FAIL + + [childList Node.textContent: textContent no mutation] + expected: FAIL + + [childList Node.textContent: empty string mutation] + expected: FAIL + + [childList Node.normalize mutation] + expected: FAIL + + [childList Node.normalize mutations] + expected: FAIL + + [childList Node.insertBefore: addition mutation] + expected: FAIL + + [childList Node.insertBefore: removal mutation] + expected: FAIL + + [childList Node.insertBefore: removal and addition mutations] + expected: FAIL + + [childList Node.insertBefore: fragment addition mutations] + expected: FAIL + + [childList Node.insertBefore: fragment removal mutations] + expected: FAIL + + [childList Node.insertBefore: last child addition mutation] + expected: FAIL + + [childList Node.appendChild: addition mutation] + expected: FAIL + + [childList Node.appendChild: removal mutation] + expected: FAIL + + [childList Node.appendChild: removal and addition mutations] + expected: FAIL + + [childList Node.appendChild: fragment addition mutations] + expected: FAIL + + [childList Node.appendChild: fragment removal mutations] + expected: FAIL + + [childList Node.appendChild: addition outside document tree mutation] + expected: FAIL + + [childList Node.replaceChild: replacement mutation] + expected: FAIL + + [childList Node.replaceChild: removal mutation] + expected: FAIL + + [childList Node.replaceChild: internal replacement mutation] + expected: FAIL + + [childList Node.removeChild: removal mutation] + expected: FAIL + + [Range (r70) is created] + expected: FAIL + + [childList Range.deleteContents: child removal mutation] + expected: FAIL + + [Range (r71) is created] + expected: FAIL + + [childList Range.deleteContents: child and data removal mutation] + expected: FAIL + + [Range (r80) is created] + expected: FAIL + + [childList Range.extractContents: child removal mutation] + expected: FAIL + + [Range (r81) is created] + expected: FAIL + + [childList Range.extractContents: child and data removal mutation] + expected: FAIL + + [Range (r90) is created] + expected: FAIL + + [childList Range.insertNode: child insertion mutation] + expected: FAIL + + [Range (r91) is created] + expected: FAIL + + [childList Range.insertNode: children insertion mutation] + expected: FAIL + + [Range (r100) is created] + expected: FAIL + + [childList Range.surroundContents: children removal and addition mutation] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-disconnect.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-disconnect.html.ini new file mode 100644 index 00000000000..7dae7d464b4 --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-disconnect.html.ini @@ -0,0 +1,3 @@ +[MutationObserver-disconnect.html] + type: testharness + expected: TIMEOUT diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-document.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-document.html.ini new file mode 100644 index 00000000000..86213c4b71a --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-document.html.ini @@ -0,0 +1,14 @@ +[MutationObserver-document.html] + type: testharness + [setup test] + expected: FAIL + + [parser insertion mutations] + expected: FAIL + + [parser script insertion mutation] + expected: FAIL + + [removal of parent during parsing] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini new file mode 100644 index 00000000000..cc46ef272e3 --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini @@ -0,0 +1,11 @@ +[MutationObserver-inner-outer.html] + type: testharness + [innerHTML mutation] + expected: FAIL + + [innerHTML with 2 children mutation] + expected: FAIL + + [outerHTML mutation] + expected: FAIL + diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini new file mode 100644 index 00000000000..be8b8f2cc8a --- /dev/null +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini @@ -0,0 +1,11 @@ +[MutationObserver-takeRecords.html] + type: testharness + [unreachabled test] + expected: FAIL + + [All records present] + expected: FAIL + + [No more records present] + expected: FAIL + diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index 2f50c0d40be..2b46a216624 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -3123,9 +3123,6 @@ [HTMLObjectElement interface: attribute data] expected: FAIL - [HTMLObjectElement interface: attribute type] - expected: FAIL - [HTMLObjectElement interface: attribute typeMustMatch] expected: FAIL @@ -5403,9 +5400,6 @@ [HTMLFormElement interface: attribute length] expected: FAIL - [HTMLFormElement interface: operation submit()] - expected: FAIL - [HTMLFormElement interface: operation reset()] expected: FAIL @@ -5424,9 +5418,6 @@ [HTMLFormElement interface: document.createElement("form") must inherit property "length" with the proper type (10)] expected: FAIL - [HTMLFormElement interface: document.createElement("form") must inherit property "submit" with the proper type (13)] - expected: FAIL - [HTMLFormElement interface: document.createElement("form") must inherit property "reset" with the proper type (14)] expected: FAIL @@ -5541,9 +5532,6 @@ [HTMLInputElement interface: attribute step] expected: FAIL - [HTMLInputElement interface: attribute type] - expected: FAIL - [HTMLInputElement interface: attribute defaultValue] expected: FAIL @@ -5700,9 +5688,6 @@ [HTMLInputElement interface: document.createElement("input") must inherit property "step" with the proper type (31)] expected: FAIL - [HTMLInputElement interface: document.createElement("input") must inherit property "type" with the proper type (32)] - expected: FAIL - [HTMLInputElement interface: document.createElement("input") must inherit property "defaultValue" with the proper type (33)] expected: FAIL @@ -5817,9 +5802,6 @@ [HTMLButtonElement interface: attribute name] expected: FAIL - [HTMLButtonElement interface: attribute type] - expected: FAIL - [HTMLButtonElement interface: attribute value] expected: FAIL @@ -5868,9 +5850,6 @@ [HTMLButtonElement interface: document.createElement("button") must inherit property "name" with the proper type (8)] expected: FAIL - [HTMLButtonElement interface: document.createElement("button") must inherit property "type" with the proper type (9)] - expected: FAIL - [HTMLButtonElement interface: document.createElement("button") must inherit property "value" with the proper type (10)] expected: FAIL @@ -5919,9 +5898,6 @@ [HTMLSelectElement interface: attribute size] expected: FAIL - [HTMLSelectElement interface: attribute type] - expected: FAIL - [HTMLSelectElement interface: attribute options] expected: FAIL @@ -5991,9 +5967,6 @@ [HTMLSelectElement interface: document.createElement("select") must inherit property "size" with the proper type (7)] expected: FAIL - [HTMLSelectElement interface: document.createElement("select") must inherit property "type" with the proper type (8)] - expected: FAIL - [HTMLSelectElement interface: document.createElement("select") must inherit property "options" with the proper type (9)] expected: FAIL @@ -6129,9 +6102,6 @@ [HTMLTextAreaElement interface: attribute wrap] expected: FAIL - [HTMLTextAreaElement interface: attribute type] - expected: FAIL - [HTMLTextAreaElement interface: attribute defaultValue] expected: FAIL @@ -6225,9 +6195,6 @@ [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "wrap" with the proper type (14)] expected: FAIL - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "type" with the proper type (15)] - expected: FAIL - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "defaultValue" with the proper type (16)] expected: FAIL @@ -8835,9 +8802,6 @@ [Navigator interface: attribute appVersion] expected: FAIL - [Navigator interface: attribute userAgent] - expected: FAIL - [Navigator interface: attribute language] expected: FAIL @@ -8883,9 +8847,6 @@ [Navigator interface: window.navigator must inherit property "appVersion" with the proper type (2)] expected: FAIL - [Navigator interface: window.navigator must inherit property "userAgent" with the proper type (6)] - expected: FAIL - [Navigator interface: window.navigator must inherit property "language" with the proper type (7)] expected: FAIL @@ -9438,9 +9399,6 @@ [WorkerNavigator interface: attribute appVersion] expected: FAIL - [WorkerNavigator interface: attribute userAgent] - expected: FAIL - [WorkerNavigator interface: attribute language] expected: FAIL diff --git a/tests/wpt/metadata/html/dom/reflection-embedded.html.ini b/tests/wpt/metadata/html/dom/reflection-embedded.html.ini index 114f4de8aa9..77ef21a33a1 100644 --- a/tests/wpt/metadata/html/dom/reflection-embedded.html.ini +++ b/tests/wpt/metadata/html/dom/reflection-embedded.html.ini @@ -7494,135 +7494,6 @@ [object.data: IDL set to object "test-valueOf" followed by IDL get] expected: FAIL - [object.type: typeof IDL attribute] - expected: FAIL - - [object.type: IDL get with DOM attribute unset] - expected: FAIL - - [object.type: setAttribute() to "" followed by IDL get] - expected: FAIL - - [object.type: 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 - - [object.type: setAttribute() to undefined followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to 7 followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to 1.5 followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to true followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to false followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to object "[object Object\]" followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to NaN followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to Infinity followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to -Infinity followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to "\\0" followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to null followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to object "test-toString" followed by IDL get] - expected: FAIL - - [object.type: setAttribute() to object "test-valueOf" followed by IDL get] - expected: FAIL - - [object.type: IDL set to "" followed by getAttribute()] - expected: FAIL - - [object.type: IDL set 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 getAttribute()] - expected: FAIL - - [object.type: IDL set to undefined followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to undefined followed by IDL get] - expected: FAIL - - [object.type: IDL set to 7 followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to 7 followed by IDL get] - expected: FAIL - - [object.type: IDL set to 1.5 followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to 1.5 followed by IDL get] - expected: FAIL - - [object.type: IDL set to true followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to true followed by IDL get] - expected: FAIL - - [object.type: IDL set to false followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to false followed by IDL get] - expected: FAIL - - [object.type: IDL set to object "[object Object\]" followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to object "[object Object\]" followed by IDL get] - expected: FAIL - - [object.type: IDL set to NaN followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to NaN followed by IDL get] - expected: FAIL - - [object.type: IDL set to Infinity followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to Infinity followed by IDL get] - expected: FAIL - - [object.type: IDL set to -Infinity followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to -Infinity followed by IDL get] - expected: FAIL - - [object.type: IDL set to "\\0" followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to null followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to null followed by IDL get] - expected: FAIL - - [object.type: IDL set to object "test-toString" followed by getAttribute()] - expected: FAIL - - [object.type: IDL set to object "test-toString" followed by IDL get] - expected: FAIL - - [object.type: IDL set to object "test-valueOf" followed by IDL get] - expected: FAIL - [object.typeMustMatch: typeof IDL attribute] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/select-an-image-source.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/select-an-image-source.html.ini index 73c44b2aafe..2bd003bb1c9 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/select-an-image-source.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/select-an-image-source.html.ini @@ -27,9 +27,6 @@ ["data:,a , data:,b"] expected: FAIL - ["data:,a foo, data:,b bar"] - expected: FAIL - ["data:,a 1w, data:,b 1x" sizes="1px"] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini index d4e30764fff..cb88126c193 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini @@ -1,8 +1,5 @@ [date.html] type: testharness - [date type support on input element] - expected: FAIL - [The value attribute, if specified and not empty, must have a value that is a valid date string.] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime.html.ini index 3df255b1df9..2636975bd2a 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/datetime.html.ini @@ -1,8 +1,5 @@ [datetime.html] type: testharness - [date type support on input element] - expected: FAIL - [[date\] The min attribute must have a value that is a valid global date and time string] expected: FAIL @@ -18,9 +15,6 @@ [[date\] stepDown method support on input \'date\' element] expected: FAIL - [[time\] time type support on input element] - expected: FAIL - [[time\] The min attribute must have a value that is a valid global date and time string] expected: FAIL @@ -36,9 +30,6 @@ [[time\] stepDown method support on input \'time\' element] expected: FAIL - [datetime type support on input element] - expected: FAIL - [[datetime\] The min attribute must have a value that is a valid global date and time string] expected: FAIL @@ -54,9 +45,6 @@ [[datetime\] stepDown method support on input \'datetime\' element] expected: FAIL - [month type support on input element] - expected: FAIL - [[month\] The min attribute must have a value that is a valid global date and time string] expected: FAIL @@ -72,9 +60,6 @@ [[month\] stepDown method support on input \'month\' element] expected: FAIL - [week type support on input element] - expected: FAIL - [[week\] The min attribute must have a value that is a valid global date and time string] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini index d705c5eff0c..5bf6d677388 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini @@ -1,8 +1,5 @@ [month.html] type: testharness - [month type support on input element] - expected: FAIL - [The value attribute, if specified and not empty, must have a value that is a valid month string] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini index 0f5a9775cab..828547f72bd 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini @@ -3,9 +3,6 @@ [range input value set to \'\'] expected: FAIL - [range input value set to an integer] - expected: FAIL - [range input value equals 50] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini index 1e65929716f..5b161f4a92e 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini @@ -1,8 +1,5 @@ [range.html] type: testharness - [range type support on input element] - expected: FAIL - [min attribute support on input element] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/search_input.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/search_input.html.ini index c0e39d628e7..49b9be48239 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/search_input.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/search_input.html.ini @@ -1,8 +1,5 @@ [search_input.html] type: testharness - [search type support on input element] - expected: FAIL - [placeholder attribute support on input element] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/telephone.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/telephone.html.ini index 2cae9ba8c66..0d7fa2f7654 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/telephone.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/telephone.html.ini @@ -1,8 +1,5 @@ [telephone.html] type: testharness - [tel type supported on input element] - expected: FAIL - [User agents must not allow users to insert "LF" (U+000A)] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini index c4cbe43fee8..b2368ef46ea 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini @@ -9,9 +9,6 @@ [min attribute on default value check] expected: FAIL - [type attribute support on input element] - expected: FAIL - [max attribute support on input element] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini index 1999c699e92..69b2a129c40 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini @@ -1,905 +1,3 @@ [type-change-state.html] type: testharness - [change state from hidden to text] - expected: FAIL - - [change state from hidden to search] - expected: FAIL - - [change state from hidden to tel] - expected: FAIL - - [change state from hidden to url] - expected: FAIL - - [change state from hidden to email] - expected: FAIL - - [change state from hidden to password] - expected: FAIL - - [change state from hidden to datetime] - expected: FAIL - - [change state from hidden to date] - expected: FAIL - - [change state from hidden to month] - expected: FAIL - - [change state from hidden to week] - expected: FAIL - - [change state from hidden to time] - expected: FAIL - - [change state from hidden to number] - expected: FAIL - - [change state from hidden to range] - expected: FAIL - - [change state from hidden to color] - expected: FAIL - - [change state from text to search] - expected: FAIL - - [change state from text to tel] - expected: FAIL - - [change state from text to url] - expected: FAIL - - [change state from text to email] - expected: FAIL - - [change state from text to password] - expected: FAIL - - [change state from text to datetime] - expected: FAIL - - [change state from text to date] - expected: FAIL - - [change state from text to month] - expected: FAIL - - [change state from text to week] - expected: FAIL - - [change state from text to time] - expected: FAIL - - [change state from text to number] - expected: FAIL - - [change state from text to range] - expected: FAIL - - [change state from text to color] - expected: FAIL - - [change state from search to text] - expected: FAIL - - [change state from search to tel] - expected: FAIL - - [change state from search to url] - expected: FAIL - - [change state from search to email] - expected: FAIL - - [change state from search to password] - expected: FAIL - - [change state from search to datetime] - expected: FAIL - - [change state from search to date] - expected: FAIL - - [change state from search to month] - expected: FAIL - - [change state from search to week] - expected: FAIL - - [change state from search to time] - expected: FAIL - - [change state from search to number] - expected: FAIL - - [change state from search to range] - expected: FAIL - - [change state from search to color] - expected: FAIL - - [change state from tel to text] - expected: FAIL - - [change state from tel to search] - expected: FAIL - - [change state from tel to url] - expected: FAIL - - [change state from tel to email] - expected: FAIL - - [change state from tel to password] - expected: FAIL - - [change state from tel to datetime] - expected: FAIL - - [change state from tel to date] - expected: FAIL - - [change state from tel to month] - expected: FAIL - - [change state from tel to week] - expected: FAIL - - [change state from tel to time] - expected: FAIL - - [change state from tel to number] - expected: FAIL - - [change state from tel to range] - expected: FAIL - - [change state from tel to color] - expected: FAIL - - [change state from url to text] - expected: FAIL - - [change state from url to search] - expected: FAIL - - [change state from url to tel] - expected: FAIL - - [change state from url to email] - expected: FAIL - - [change state from url to password] - expected: FAIL - - [change state from url to datetime] - expected: FAIL - - [change state from url to date] - expected: FAIL - - [change state from url to month] - expected: FAIL - - [change state from url to week] - expected: FAIL - - [change state from url to time] - expected: FAIL - - [change state from url to number] - expected: FAIL - - [change state from url to range] - expected: FAIL - - [change state from url to color] - expected: FAIL - - [change state from email to text] - expected: FAIL - - [change state from email to search] - expected: FAIL - - [change state from email to tel] - expected: FAIL - - [change state from email to url] - expected: FAIL - - [change state from email to password] - expected: FAIL - - [change state from email to datetime] - expected: FAIL - - [change state from email to date] - expected: FAIL - - [change state from email to month] - expected: FAIL - - [change state from email to week] - expected: FAIL - - [change state from email to time] - expected: FAIL - - [change state from email to number] - expected: FAIL - - [change state from email to range] - expected: FAIL - - [change state from email to color] - expected: FAIL - - [change state from password to text] - expected: FAIL - - [change state from password to search] - expected: FAIL - - [change state from password to tel] - expected: FAIL - - [change state from password to url] - expected: FAIL - - [change state from password to email] - expected: FAIL - - [change state from password to datetime] - expected: FAIL - - [change state from password to date] - expected: FAIL - - [change state from password to month] - expected: FAIL - - [change state from password to week] - expected: FAIL - - [change state from password to time] - expected: FAIL - - [change state from password to number] - expected: FAIL - - [change state from password to range] - expected: FAIL - - [change state from password to color] - expected: FAIL - - [change state from datetime to text] - expected: FAIL - - [change state from datetime to search] - expected: FAIL - - [change state from datetime to tel] - expected: FAIL - - [change state from datetime to url] - expected: FAIL - - [change state from datetime to email] - expected: FAIL - - [change state from datetime to password] - expected: FAIL - - [change state from datetime to date] - expected: FAIL - - [change state from datetime to month] - expected: FAIL - - [change state from datetime to week] - expected: FAIL - - [change state from datetime to time] - expected: FAIL - - [change state from datetime to number] - expected: FAIL - - [change state from datetime to range] - expected: FAIL - - [change state from datetime to color] - expected: FAIL - - [change state from date to text] - expected: FAIL - - [change state from date to search] - expected: FAIL - - [change state from date to tel] - expected: FAIL - - [change state from date to url] - expected: FAIL - - [change state from date to email] - expected: FAIL - - [change state from date to password] - expected: FAIL - - [change state from date to datetime] - expected: FAIL - - [change state from date to month] - expected: FAIL - - [change state from date to week] - expected: FAIL - - [change state from date to time] - expected: FAIL - - [change state from date to number] - expected: FAIL - - [change state from date to range] - expected: FAIL - - [change state from date to color] - expected: FAIL - - [change state from month to text] - expected: FAIL - - [change state from month to search] - expected: FAIL - - [change state from month to tel] - expected: FAIL - - [change state from month to url] - expected: FAIL - - [change state from month to email] - expected: FAIL - - [change state from month to password] - expected: FAIL - - [change state from month to datetime] - expected: FAIL - - [change state from month to date] - expected: FAIL - - [change state from month to week] - expected: FAIL - - [change state from month to time] - expected: FAIL - - [change state from month to number] - expected: FAIL - - [change state from month to range] - expected: FAIL - - [change state from month to color] - expected: FAIL - - [change state from week to text] - expected: FAIL - - [change state from week to search] - expected: FAIL - - [change state from week to tel] - expected: FAIL - - [change state from week to url] - expected: FAIL - - [change state from week to email] - expected: FAIL - - [change state from week to password] - expected: FAIL - - [change state from week to datetime] - expected: FAIL - - [change state from week to date] - expected: FAIL - - [change state from week to month] - expected: FAIL - - [change state from week to time] - expected: FAIL - - [change state from week to number] - expected: FAIL - - [change state from week to range] - expected: FAIL - - [change state from week to color] - expected: FAIL - - [change state from time to text] - expected: FAIL - - [change state from time to search] - expected: FAIL - - [change state from time to tel] - expected: FAIL - - [change state from time to url] - expected: FAIL - - [change state from time to email] - expected: FAIL - - [change state from time to password] - expected: FAIL - - [change state from time to datetime] - expected: FAIL - - [change state from time to date] - expected: FAIL - - [change state from time to month] - expected: FAIL - - [change state from time to week] - expected: FAIL - - [change state from time to number] - expected: FAIL - - [change state from time to range] - expected: FAIL - - [change state from time to color] - expected: FAIL - - [change state from number to text] - expected: FAIL - - [change state from number to search] - expected: FAIL - - [change state from number to tel] - expected: FAIL - - [change state from number to url] - expected: FAIL - - [change state from number to email] - expected: FAIL - - [change state from number to password] - expected: FAIL - - [change state from number to datetime] - expected: FAIL - - [change state from number to date] - expected: FAIL - - [change state from number to month] - expected: FAIL - - [change state from number to week] - expected: FAIL - - [change state from number to time] - expected: FAIL - - [change state from number to range] - expected: FAIL - - [change state from number to color] - expected: FAIL - - [change state from range to text] - expected: FAIL - - [change state from range to search] - expected: FAIL - - [change state from range to tel] - expected: FAIL - - [change state from range to url] - expected: FAIL - - [change state from range to email] - expected: FAIL - - [change state from range to password] - expected: FAIL - - [change state from range to datetime] - expected: FAIL - - [change state from range to date] - expected: FAIL - - [change state from range to month] - expected: FAIL - - [change state from range to week] - expected: FAIL - - [change state from range to time] - expected: FAIL - - [change state from range to number] - expected: FAIL - - [change state from range to color] - expected: FAIL - - [change state from color to text] - expected: FAIL - - [change state from color to search] - expected: FAIL - - [change state from color to tel] - expected: FAIL - - [change state from color to url] - expected: FAIL - - [change state from color to email] - expected: FAIL - - [change state from color to password] - expected: FAIL - - [change state from color to datetime] - expected: FAIL - - [change state from color to date] - expected: FAIL - - [change state from color to month] - expected: FAIL - - [change state from color to week] - expected: FAIL - - [change state from color to time] - expected: FAIL - - [change state from color to number] - expected: FAIL - - [change state from color to range] - expected: FAIL - - [change state from checkbox to text] - expected: FAIL - - [change state from checkbox to search] - expected: FAIL - - [change state from checkbox to tel] - expected: FAIL - - [change state from checkbox to url] - expected: FAIL - - [change state from checkbox to email] - expected: FAIL - - [change state from checkbox to password] - expected: FAIL - - [change state from checkbox to datetime] - expected: FAIL - - [change state from checkbox to date] - expected: FAIL - - [change state from checkbox to month] - expected: FAIL - - [change state from checkbox to week] - expected: FAIL - - [change state from checkbox to time] - expected: FAIL - - [change state from checkbox to number] - expected: FAIL - - [change state from checkbox to range] - expected: FAIL - - [change state from checkbox to color] - expected: FAIL - - [change state from radio to text] - expected: FAIL - - [change state from radio to search] - expected: FAIL - - [change state from radio to tel] - expected: FAIL - - [change state from radio to url] - expected: FAIL - - [change state from radio to email] - expected: FAIL - - [change state from radio to password] - expected: FAIL - - [change state from radio to datetime] - expected: FAIL - - [change state from radio to date] - expected: FAIL - - [change state from radio to month] - expected: FAIL - - [change state from radio to week] - expected: FAIL - - [change state from radio to time] - expected: FAIL - - [change state from radio to number] - expected: FAIL - - [change state from radio to range] - expected: FAIL - - [change state from radio to color] - expected: FAIL - - [change state from file to hidden] - expected: FAIL - - [change state from file to text] - expected: FAIL - - [change state from file to search] - expected: FAIL - - [change state from file to tel] - expected: FAIL - - [change state from file to url] - expected: FAIL - - [change state from file to email] - expected: FAIL - - [change state from file to password] - expected: FAIL - - [change state from file to datetime] - expected: FAIL - - [change state from file to date] - expected: FAIL - - [change state from file to month] - expected: FAIL - - [change state from file to week] - expected: FAIL - - [change state from file to time] - expected: FAIL - - [change state from file to number] - expected: FAIL - - [change state from file to range] - expected: FAIL - - [change state from file to color] - expected: FAIL - - [change state from file to checkbox] - expected: FAIL - - [change state from file to radio] - expected: FAIL - - [change state from file to submit] - expected: FAIL - - [change state from file to image] - expected: FAIL - - [change state from file to reset] - expected: FAIL - - [change state from file to button] - expected: FAIL - - [change state from submit to text] - expected: FAIL - - [change state from submit to search] - expected: FAIL - - [change state from submit to tel] - expected: FAIL - - [change state from submit to url] - expected: FAIL - - [change state from submit to email] - expected: FAIL - - [change state from submit to password] - expected: FAIL - - [change state from submit to datetime] - expected: FAIL - - [change state from submit to date] - expected: FAIL - - [change state from submit to month] - expected: FAIL - - [change state from submit to week] - expected: FAIL - - [change state from submit to time] - expected: FAIL - - [change state from submit to number] - expected: FAIL - - [change state from submit to range] - expected: FAIL - - [change state from submit to color] - expected: FAIL - - [change state from image to text] - expected: FAIL - - [change state from image to search] - expected: FAIL - - [change state from image to tel] - expected: FAIL - - [change state from image to url] - expected: FAIL - - [change state from image to email] - expected: FAIL - - [change state from image to password] - expected: FAIL - - [change state from image to datetime] - expected: FAIL - - [change state from image to date] - expected: FAIL - - [change state from image to month] - expected: FAIL - - [change state from image to week] - expected: FAIL - - [change state from image to time] - expected: FAIL - - [change state from image to number] - expected: FAIL - - [change state from image to range] - expected: FAIL - - [change state from image to color] - expected: FAIL - - [change state from reset to text] - expected: FAIL - - [change state from reset to search] - expected: FAIL - - [change state from reset to tel] - expected: FAIL - - [change state from reset to url] - expected: FAIL - - [change state from reset to email] - expected: FAIL - - [change state from reset to password] - expected: FAIL - - [change state from reset to datetime] - expected: FAIL - - [change state from reset to date] - expected: FAIL - - [change state from reset to month] - expected: FAIL - - [change state from reset to week] - expected: FAIL - - [change state from reset to time] - expected: FAIL - - [change state from reset to number] - expected: FAIL - - [change state from reset to range] - expected: FAIL - - [change state from reset to color] - expected: FAIL - - [change state from button to text] - expected: FAIL - - [change state from button to search] - expected: FAIL - - [change state from button to tel] - expected: FAIL - - [change state from button to url] - expected: FAIL - - [change state from button to email] - expected: FAIL - - [change state from button to password] - expected: FAIL - - [change state from button to datetime] - expected: FAIL - - [change state from button to date] - expected: FAIL - - [change state from button to month] - expected: FAIL - - [change state from button to week] - expected: FAIL - - [change state from button to time] - expected: FAIL - - [change state from button to number] - expected: FAIL - - [change state from button to range] - expected: FAIL - - [change state from button to color] - expected: FAIL - + disabled: intermittent failures
\ No newline at end of file diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/url.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/url.html.ini index e756878e339..5dc56d7e1e3 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/url.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/url.html.ini @@ -1,8 +1,5 @@ [url.html] type: testharness - [url type supported on input element] - expected: FAIL - [The value must not be set with "LF" (U+000A) or "CR" (U+000D)] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-textarea-element/textarea-type.html.ini b/tests/wpt/metadata/html/semantics/forms/the-textarea-element/textarea-type.html.ini deleted file mode 100644 index 62c14c198bb..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/the-textarea-element/textarea-type.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[textarea-type.html] - type: testharness - [Textarea\'s type attribute should return \'textarea\'] - expected: FAIL - diff --git a/tests/wpt/web-platform-tests b/tests/wpt/web-platform-tests -Subproject 746cc5a50a947ed0eafd4d38b82a99554b47697 +Subproject b621c0b3a3eb5f865ec3cc72372e5c75610337e |