aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock18
-rw-r--r--Cargo.toml8
-rw-r--r--README.md3
-rw-r--r--components/compositing/Cargo.toml8
-rw-r--r--components/compositing/compositor.rs30
-rw-r--r--components/compositing/compositor_task.rs39
-rw-r--r--components/compositing/lib.rs9
-rw-r--r--components/compositing/windowing.rs10
-rw-r--r--components/layout/block.rs126
-rw-r--r--components/layout/css/matching.rs29
-rw-r--r--components/layout/fragment.rs14
-rw-r--r--components/layout/inline.rs15
-rw-r--r--components/layout/layout_task.rs124
-rw-r--r--components/layout/lib.rs1
-rw-r--r--components/layout/model.rs8
-rw-r--r--components/layout/parallel.rs441
-rw-r--r--components/layout/traversal.rs337
-rw-r--r--components/layout/wrapper.rs26
-rw-r--r--components/script/dom/element.rs30
-rw-r--r--components/script/dom/htmlbuttonelement.rs19
-rw-r--r--components/script/dom/htmlformelement.rs279
-rw-r--r--components/script/dom/htmlinputelement.rs29
-rw-r--r--components/script/dom/htmlobjectelement.rs6
-rw-r--r--components/script/dom/htmlselectelement.rs14
-rw-r--r--components/script/dom/htmltextareaelement.rs5
-rw-r--r--components/script/dom/navigator.rs4
-rw-r--r--components/script/dom/navigatorinfo.rs8
-rw-r--r--components/script/dom/webidls/HTMLButtonElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLFormElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLInputElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLObjectElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLSelectElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLTextAreaElement.webidl2
-rw-r--r--components/script/dom/webidls/Navigator.webidl2
-rw-r--r--components/script/dom/window.rs3
-rw-r--r--components/script/dom/workernavigator.rs4
-rw-r--r--components/script/script_task.rs8
-rw-r--r--components/style/node.rs1
-rw-r--r--components/style/selector_matching.rs77
-rw-r--r--components/style/selectors.rs55
-rw-r--r--components/util/bloom.rs407
-rw-r--r--components/util/namespace.rs1
-rw-r--r--components/util/opts.rs23
-rw-r--r--ports/android/Makefile13
-rw-r--r--ports/android/glut_app/Cargo.lock519
-rw-r--r--ports/android/glut_app/Cargo.toml34
-rw-r--r--ports/android/glut_app/lib.rs64
-rw-r--r--ports/android/glut_app/window.rs (renamed from components/compositing/platform/common/glut_windowing.rs)47
-rw-r--r--ports/cef/Cargo.lock23
-rw-r--r--ports/cef/Cargo.toml6
-rw-r--r--ports/cef/core.rs4
-rw-r--r--ports/cef/lib.rs4
-rw-r--r--ports/glfw/Cargo.toml30
-rw-r--r--ports/glfw/lib.rs43
-rw-r--r--ports/glfw/window.rs (renamed from components/compositing/platform/common/glfw_windowing.rs)58
-rw-r--r--python/servo/build_commands.py16
-rw-r--r--resources/iso-8859-8.css23
-rw-r--r--resources/presentational-hints.css261
-rw-r--r--resources/quirks-mode.css33
-rw-r--r--resources/quotes.css190
-rw-r--r--resources/servo.css13
-rw-r--r--resources/user-agent.css406
-rw-r--r--src/lib.rs35
-rw-r--r--src/main.rs15
-rw-r--r--tests/html/form_submission_handsfree.html16
-rw-r--r--tests/ref/attr_selector_case_sensitivity.html17
-rw-r--r--tests/ref/attr_selector_case_sensitivity_ref.html17
-rw-r--r--tests/ref/basic.list7
-rw-r--r--tests/ref/box_sizing_sanity_check_a.html7
-rw-r--r--tests/ref/box_sizing_sanity_check_ref.html7
-rw-r--r--tests/ref/iframe/multiple_external.html1
-rw-r--r--tests/ref/iframe/overflow.html2
-rw-r--r--tests/ref/inline_block_overflow_hidden_a.html7
-rw-r--r--tests/ref/inline_block_overflow_hidden_ref.html8
-rw-r--r--tests/ref/position_fixed_tile_edge_3.html11
-rw-r--r--tests/ref/table_auto_width.html2
-rw-r--r--tests/ref/table_auto_width_ref.html2
-rw-r--r--tests/ref/table_containing_block_a.html2
-rw-r--r--tests/ref/table_containing_block_ref.html2
-rw-r--r--tests/ref/table_padding_a.html2
-rw-r--r--tests/wpt/metadata/MANIFEST.json119
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini128
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini71
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini113
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-disconnect.html.ini3
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-document.html.ini14
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini11
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini11
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.html.ini42
-rw-r--r--tests/wpt/metadata/html/dom/reflection-embedded.html.ini129
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-img-element/srcset/select-an-image-source.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/date.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/datetime.html.ini15
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/month.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/range-2.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/range.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/search_input.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/telephone.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini904
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/url.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-textarea-element/textarea-type.html.ini5
m---------tests/wpt/web-platform-tests0
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