Update servo to 9d2b98e6f82fe601672dbf435a920ccceffe78dc.
authorCameron McCormack <cam@mcc.id.au>
Sat, 17 Dec 2016 10:23:15 +0800
changeset 450609 edce57705f6b63e95f322267c39a8afacdea6cc8
parent 450608 bd87878b7799ddee5d65be616ed4f0e111639cf9
child 450610 59cc2f45d402b7b9a01dc38cf0e954fcf62de76f
push id38922
push userbmo:emilio+bugs@crisal.io
push dateSat, 17 Dec 2016 10:01:32 +0000
milestone53.0a1
Update servo to 9d2b98e6f82fe601672dbf435a920ccceffe78dc.
servo/Cargo.lock
servo/cargo-commit-hash
servo/components/bluetooth/Cargo.toml
servo/components/bluetooth/lib.rs
servo/components/bluetooth_traits/Cargo.toml
servo/components/bluetooth_traits/blocklist.rs
servo/components/bluetooth_traits/lib.rs
servo/components/canvas/Cargo.toml
servo/components/canvas/canvas_paint_thread.rs
servo/components/canvas/lib.rs
servo/components/canvas/webgl_paint_thread.rs
servo/components/compositing/Cargo.toml
servo/components/compositing/compositor.rs
servo/components/compositing/lib.rs
servo/components/compositing/windowing.rs
servo/components/config/Cargo.toml
servo/components/config/basedir.rs
servo/components/config/lib.rs
servo/components/config/opts.rs
servo/components/config/prefs.rs
servo/components/config/resource_files.rs
servo/components/constellation/Cargo.toml
servo/components/constellation/constellation.rs
servo/components/constellation/event_loop.rs
servo/components/constellation/lib.rs
servo/components/constellation/pipeline.rs
servo/components/constellation/sandboxing.rs
servo/components/debugger/Cargo.toml
servo/components/debugger/lib.rs
servo/components/devtools/Cargo.toml
servo/components/devtools/actors/timeline.rs
servo/components/devtools/lib.rs
servo/components/geometry/Cargo.toml
servo/components/geometry/lib.rs
servo/components/gfx/Cargo.toml
servo/components/gfx/display_list/mod.rs
servo/components/gfx/font_cache_thread.rs
servo/components/gfx/lib.rs
servo/components/layout/Cargo.toml
servo/components/layout/block.rs
servo/components/layout/construct.rs
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/flex.rs
servo/components/layout/inline.rs
servo/components/layout/lib.rs
servo/components/layout/multicol.rs
servo/components/layout/parallel.rs
servo/components/layout/query.rs
servo/components/layout/sequential.rs
servo/components/layout/traversal.rs
servo/components/layout/webrender_helpers.rs
servo/components/layout_thread/Cargo.toml
servo/components/layout_thread/lib.rs
servo/components/net/Cargo.toml
servo/components/net/chrome_loader.rs
servo/components/net/connector.rs
servo/components/net/content_blocker.rs
servo/components/net/fetch/methods.rs
servo/components/net/filemanager_thread.rs
servo/components/net/hsts.rs
servo/components/net/http_loader.rs
servo/components/net/image_cache_thread.rs
servo/components/net/lib.rs
servo/components/net/resource_thread.rs
servo/components/net/storage_thread.rs
servo/components/net/websocket_loader.rs
servo/components/net_traits/Cargo.toml
servo/components/net_traits/lib.rs
servo/components/net_traits/pub_domains.rs
servo/components/profile/Cargo.toml
servo/components/profile/heartbeats.rs
servo/components/profile/lib.rs
servo/components/profile/mem.rs
servo/components/profile/time.rs
servo/components/profile_traits/Cargo.toml
servo/components/profile_traits/lib.rs
servo/components/profile_traits/time.rs
servo/components/remutex/Cargo.toml
servo/components/remutex/lib.rs
servo/components/script/Cargo.toml
servo/components/script/dom/bindings/codegen/CodegenRust.py
servo/components/script/dom/bindings/conversions.rs
servo/components/script/dom/bindings/guard.rs
servo/components/script/dom/bindings/trace.rs
servo/components/script/dom/bluetooth.rs
servo/components/script/dom/bluetoothadvertisingdata.rs
servo/components/script/dom/bluetoothadvertisingevent.rs
servo/components/script/dom/bluetoothdevice.rs
servo/components/script/dom/bluetoothremotegattcharacteristic.rs
servo/components/script/dom/bluetoothremotegattdescriptor.rs
servo/components/script/dom/bluetoothremotegattserver.rs
servo/components/script/dom/bluetoothremotegattservice.rs
servo/components/script/dom/characterdata.rs
servo/components/script/dom/create.rs
servo/components/script/dom/cssimportrule.rs
servo/components/script/dom/csskeyframesrule.rs
servo/components/script/dom/cssrule.rs
servo/components/script/dom/dedicatedworkerglobalscope.rs
servo/components/script/dom/document.rs
servo/components/script/dom/element.rs
servo/components/script/dom/filereader.rs
servo/components/script/dom/htmlanchorelement.rs
servo/components/script/dom/htmliframeelement.rs
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmetaelement.rs
servo/components/script/dom/htmlscriptelement.rs
servo/components/script/dom/htmlstyleelement.rs
servo/components/script/dom/htmltextareaelement.rs
servo/components/script/dom/htmltitleelement.rs
servo/components/script/dom/mod.rs
servo/components/script/dom/mouseevent.rs
servo/components/script/dom/navigatorinfo.rs
servo/components/script/dom/node.rs
servo/components/script/dom/serviceworkerglobalscope.rs
servo/components/script/dom/servoparser/mod.rs
servo/components/script/dom/testbinding.rs
servo/components/script/dom/userscripts.rs
servo/components/script/dom/webidls/BluetoothAdvertisingData.webidl
servo/components/script/dom/webidls/BluetoothAdvertisingEvent.webidl
servo/components/script/dom/webidls/BluetoothDevice.webidl
servo/components/script/dom/webidls/CSSImportRule.webidl
servo/components/script/dom/webidls/CSSKeyframesRule.webidl
servo/components/script/dom/webidls/CSSStyleDeclaration.webidl
servo/components/script/dom/websocket.rs
servo/components/script/dom/window.rs
servo/components/script/dom/xmlhttprequest.rs
servo/components/script/lib.rs
servo/components/script/script_runtime.rs
servo/components/script/script_thread.rs
servo/components/script/serviceworker_manager.rs
servo/components/script/stylesheet_loader.rs
servo/components/script/timers.rs
servo/components/script/webdriver_handlers.rs
servo/components/servo/Cargo.toml
servo/components/servo/lib.rs
servo/components/style/Cargo.toml
servo/components/style/binding_tools/regen_atoms.py
servo/components/style/build_gecko.rs
servo/components/style/context.rs
servo/components/style/dom.rs
servo/components/style/gecko/context.rs
servo/components/style/gecko/conversions.rs
servo/components/style/gecko/traversal.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/gecko_bindings/structs_debug.rs
servo/components/style/gecko_bindings/structs_release.rs
servo/components/style/keyframes.rs
servo/components/style/lib.rs
servo/components/style/matching.rs
servo/components/style/media_queries.rs
servo/components/style/parallel.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/properties/longhand/background.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/effects.mako.rs
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/properties/longhand/position.mako.rs
servo/components/style/properties/longhand/svg.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/properties/shorthand/background.mako.rs
servo/components/style/refcell.rs
servo/components/style/sequential.rs
servo/components/style/servo/restyle_damage.rs
servo/components/style/stylesheets.rs
servo/components/style/stylist.rs
servo/components/style/traversal.rs
servo/components/style/values/computed/image.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/computed/position.rs
servo/components/style/values/specified/basic_shape.rs
servo/components/style/values/specified/grid.rs
servo/components/style/values/specified/image.rs
servo/components/style/values/specified/mod.rs
servo/components/style/values/specified/position.rs
servo/components/style/values/specified/url.rs
servo/components/url/Cargo.toml
servo/components/util/Cargo.toml
servo/components/util/basedir.rs
servo/components/util/geometry.rs
servo/components/util/lib.rs
servo/components/util/opts.rs
servo/components/util/prefs.rs
servo/components/util/remutex.rs
servo/components/util/resource_files.rs
servo/components/util/thread.rs
servo/components/webdriver_server/Cargo.toml
servo/components/webdriver_server/lib.rs
servo/etc/ci/check_dynamic_symbols.py
servo/ports/cef/Cargo.toml
servo/ports/cef/browser.rs
servo/ports/cef/core.rs
servo/ports/cef/lib.rs
servo/ports/cef/window.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/lib.rs
servo/ports/geckolib/stylesheet_loader.rs
servo/ports/glutin/Cargo.toml
servo/ports/glutin/lib.rs
servo/ports/glutin/window.rs
servo/ports/servo/Cargo.toml
servo/ports/servo/main.rs
servo/python/servo/build_commands.py
servo/python/servo/command_base.py
servo/python/servo/testing_commands.py
servo/python/tidy/servo_tidy/tidy.py
servo/python/tidy/servo_tidy_tests/script_thread.rs
servo/python/tidy/servo_tidy_tests/test_tidy.py
servo/servo-tidy.toml
servo/servobuild.example
servo/tests/unit/net/Cargo.toml
servo/tests/unit/net/data_loader.rs
servo/tests/unit/net/fetch.rs
servo/tests/unit/net/http_loader.rs
servo/tests/unit/net/lib.rs
servo/tests/unit/servo_config/Cargo.toml
servo/tests/unit/servo_config/lib.rs
servo/tests/unit/servo_config/opts.rs
servo/tests/unit/servo_config/prefs.rs
servo/tests/unit/servo_remutex/Cargo.toml
servo/tests/unit/servo_remutex/lib.rs
servo/tests/unit/style/Cargo.toml
servo/tests/unit/style/lib.rs
servo/tests/unit/style/media_queries.rs
servo/tests/unit/style/parsing/background.rs
servo/tests/unit/style/parsing/image.rs
servo/tests/unit/style/parsing/position.rs
servo/tests/unit/style/properties/serialization.rs
servo/tests/unit/style/stylesheets.rs
servo/tests/unit/style/viewport.rs
servo/tests/unit/stylo/lib.rs
servo/tests/unit/util/Cargo.toml
servo/tests/unit/util/lib.rs
servo/tests/unit/util/opts.rs
servo/tests/unit/util/prefs.rs
servo/tests/unit/util/remutex.rs
servo/tests/unit/util/thread.rs
servo/tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-331.htm.ini
servo/tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-333.htm.ini
servo/tests/wpt/metadata-css/css-transitions-1_dev/html/changing-while-transition.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/abspos-019.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/abspos-020.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-001.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-007.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-008.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-009.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-012.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-014.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-015.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-016.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-019.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-020.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-021.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-024.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-025.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-026.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-027.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-028.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-029.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-030.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-040.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-041.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-042.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-043.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-044.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-045.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-046.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-047.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-048.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-053.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-charset-060.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-import-002.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-import-003.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-import-005.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-import-006.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-import-007.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-keywords-000.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-rule-005.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/at-rule-010.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/c11-import-000.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/cascade-012.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/core-syntax-009.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/eof-005.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/eof-006.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/media-dependency-002.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/media-dependency-004.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/media-dependency-005.htm.ini
servo/tests/wpt/metadata-css/css21_dev/html4/uri-001.htm.ini
servo/tests/wpt/metadata-css/cssom-1_dev/html/cssimportrule.htm.ini
servo/tests/wpt/metadata-css/cssom-1_dev/html/index-003.htm.ini
servo/tests/wpt/metadata-css/cssom-1_dev/html/interfaces.htm.ini
servo/tests/wpt/metadata/fetch/nosniff/stylesheet.html.ini
servo/tests/wpt/metadata/html/semantics/document-metadata/the-link-element/link-style-error-01.html.ini
servo/tests/wpt/metadata/html/semantics/document-metadata/the-style-element/style_events.html.ini
servo/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/106-import.html.ini
servo/tests/wpt/metadata/webgl/conformance-1.0.3/conformance/reading/read-pixels-test.html.ini
servo/tests/wpt/mozilla/meta/MANIFEST.json
servo/tests/wpt/mozilla/meta/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html.ini
servo/tests/wpt/mozilla/meta/mozilla/bluetooth/connect/device-goes-out-of-range.html.ini
servo/tests/wpt/mozilla/meta/mozilla/bluetooth/stopNotifications/disconnect-called-before.html.ini
servo/tests/wpt/mozilla/meta/mozilla/bluetooth/stopNotifications/disconnect-called-during.html.ini
servo/tests/wpt/mozilla/tests/css/import_serialization.html
servo/tests/wpt/mozilla/tests/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html
servo/tests/wpt/mozilla/tests/mozilla/bluetooth/stopNotifications/disconnect-called-before.html
servo/tests/wpt/mozilla/tests/mozilla/bluetooth/stopNotifications/disconnect-called-during.html
servo/tests/wpt/mozilla/tests/mozilla/interfaces.html
servo/tests/wpt/mozilla/tests/mozilla/keyframe-infinite-percentage.html
servo/tests/wpt/mozilla/tests/mozilla/textarea_placeholder.html
servo/tests/wpt/mozilla/tests/mozilla/textarea_placeholder_ref.html
third_party/rust/serde/.cargo-checksum.json
third_party/rust/serde/Cargo.toml
third_party/rust/serde/src/de/impls.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1,27 +1,27 @@
 [root]
 name = "webdriver_server"
 version = "0.0.1"
 dependencies = [
  "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webdriver 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "aho-corasick"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -35,16 +35,21 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "android_glue"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "android_injected_glue"
+version = "0.2.1"
+source = "git+https://github.com/mmatyas/android-rs-injected-glue#d3223d1273d0dafcf06d6a6405fedfffbf257300"
+
+[[package]]
 name = "angle"
 version = "0.1.2"
 source = "git+https://github.com/servo/angle?branch=servo#99128001400771ee9c8a74dcf54cf6fe11b1e532"
 dependencies = [
  "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -90,17 +95,17 @@ dependencies = [
 name = "azure"
 version = "0.9.1"
 source = "git+https://github.com/servo/rust-azure#d817e7e1b1af6896f778d0cc0693e0a1573f3a48"
 dependencies = [
  "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.1.2 (git+https://github.com/servo/rust-freetype)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -175,29 +180,28 @@ name = "bluetooth"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
  "device 0.0.1 (git+https://github.com/servo/devices)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
- "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "bluetooth_traits"
 version = "0.0.1"
 dependencies = [
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
+ "servo_config 0.0.1",
 ]
 
 [[package]]
 name = "blurdroid"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -248,34 +252,34 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "canvas"
 version = "0.0.1"
 dependencies = [
  "azure 0.9.1 (git+https://github.com/servo/rust-azure)",
  "canvas_traits 0.0.1",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
- "util 0.0.1",
+ "servo_config 0.0.1",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "canvas_traits"
 version = "0.0.1"
 dependencies = [
  "azure 0.9.1 (git+https://github.com/servo/rust-azure)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
@@ -302,17 +306,17 @@ name = "cfg-if"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cgl"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "clang-sys"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -375,67 +379,69 @@ dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "compositing"
 version = "0.0.1"
 dependencies = [
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "webrender 0.11.0 (git+https://github.com/servo/webrender)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "constellation"
 version = "0.0.1"
 dependencies = [
  "backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
  "canvas 0.0.1",
  "canvas_traits 0.0.1",
  "compositing 0.0.1",
  "debugger 0.0.1",
  "devtools_traits 0.0.1",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gaol 0.0.1 (git+https://github.com/servo/gaol)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout_traits 0.0.1",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
+ "servo_remutex 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
- "util 0.0.1",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "content-blocker"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -534,17 +540,16 @@ dependencies = [
  "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "debugger"
 version = "0.0.1"
 dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "ws 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "deque"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -572,17 +577,16 @@ dependencies = [
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "plugins 0.0.1",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "devtools_traits"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -635,31 +639,32 @@ dependencies = [
 
 [[package]]
 name = "embedding"
 version = "0.0.1"
 dependencies = [
  "cocoa 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
  "devtools 0.0.1",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin_app 0.0.1",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "libservo 0.0.1",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "script_traits 0.0.1",
+ "servo_config 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
- "util 0.0.1",
  "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "encoding"
 version = "0.2.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -770,17 +775,17 @@ version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "euclid"
-version = "0.10.2"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -880,17 +885,17 @@ dependencies = [
 
 [[package]]
 name = "geckoservo"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
  "style 0.0.1",
@@ -909,17 +914,17 @@ version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
  "freetype 0.1.2 (git+https://github.com/servo/rust-freetype)",
  "gfx_traits 0.0.1",
  "harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -931,24 +936,24 @@ dependencies = [
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "range 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "simd 0.1.1 (git+https://github.com/huonw/simd)",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
  "xi-unicode 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gfx_tests"
 version = "0.0.1"
 dependencies = [
@@ -986,17 +991,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gleam"
-version = "0.2.24"
+version = "0.2.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glob"
@@ -1004,32 +1009,33 @@ version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "glutin_app"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "osmesa-src 12.0.1 (git+https://github.com/servo/osmesa-src)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-glutin 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glx"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1205,17 +1211,17 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "io-surface"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "ipc-channel"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1287,17 +1293,17 @@ source = "registry+https://github.com/ru
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1312,39 +1318,39 @@ dependencies = [
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "layout_tests"
 version = "0.0.1"
 dependencies = [
  "layout 0.0.1",
 ]
 
 [[package]]
 name = "layout_thread"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout 0.0.1",
  "layout_traits 0.0.1",
@@ -1357,19 +1363,20 @@ dependencies = [
  "profile_traits 0.0.1",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
- "util 0.0.1",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "layout_traits"
 version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
@@ -1461,39 +1468,39 @@ dependencies = [
  "canvas 0.0.1",
  "canvas_traits 0.0.1",
  "compositing 0.0.1",
  "constellation 0.0.1",
  "debugger 0.0.1",
  "devtools 0.0.1",
  "devtools_traits 0.0.1",
  "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gaol 0.0.1 (git+https://github.com/servo/gaol)",
  "gfx 0.0.1",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "layout 0.0.1",
  "layout_thread 0.0.1",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile 0.0.1",
  "profile_traits 0.0.1",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "webdriver_server 0.0.1",
  "webrender 0.11.0 (git+https://github.com/servo/webrender)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "libz-sys"
 version = "1.0.6"
@@ -1666,23 +1673,23 @@ dependencies = [
  "net_traits 0.0.1",
  "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
  "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "net2"
 version = "0.2.26"
@@ -1706,21 +1713,21 @@ dependencies = [
  "hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper_serde 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "net_traits"
 version = "0.0.1"
 dependencies = [
  "bluetooth_traits 0.0.1",
  "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1731,19 +1738,19 @@ dependencies = [
  "image 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "net_traits_tests"
 version = "0.0.1"
@@ -1854,20 +1861,20 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "offscreen_gl_context"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2078,19 +2085,19 @@ dependencies = [
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
  "task_info 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "profile_tests"
 version = "0.0.1"
 dependencies = [
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile 0.0.1",
@@ -2103,19 +2110,19 @@ version = "0.0.1"
 dependencies = [
  "energy-monitor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "energymon 0.2.0 (git+https://github.com/energymon/energymon-rust.git)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_config 0.0.1",
  "signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "quasi"
 version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "syntex_errors 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2244,17 +2251,17 @@ dependencies = [
  "bluetooth_traits 0.0.1",
  "canvas_traits 0.0.1",
  "caseless 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "devtools_traits 0.0.1",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper_serde 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2282,39 +2289,40 @@ dependencies = [
  "ref_slice 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_config 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml5ever 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "script_layout_interface"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
@@ -2343,17 +2351,17 @@ dependencies = [
 name = "script_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
  "canvas_traits 0.0.1",
  "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "devtools_traits 0.0.1",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper_serde 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
@@ -2438,34 +2446,36 @@ dependencies = [
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "servo"
 version = "0.0.1"
 dependencies = [
  "android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "android_injected_glue 0.2.1 (git+https://github.com/mmatyas/android-rs-injected-glue)",
  "backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "browserhtml 0.1.17 (git+https://github.com/browserhtml/browserhtml?branch=crate)",
  "compiletest_helper 0.0.1",
  "gfx_tests 0.0.1",
  "glutin_app 0.0.1",
  "layout_tests 0.0.1",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "libservo 0.0.1",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "net_tests 0.0.1",
  "net_traits_tests 0.0.1",
  "phf_macros 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugin_compiletest 0.0.1",
  "profile_tests 0.0.1",
  "script_tests 0.0.1",
+ "servo_config_tests 0.0.1",
+ "servo_remutex_tests 0.0.1",
  "sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_tests 0.0.1",
- "util_tests 0.0.1",
 ]
 
 [[package]]
 name = "servo-egl"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2530,19 +2540,19 @@ dependencies = [
 
 [[package]]
 name = "servo-skia"
 version = "0.20130412.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "io-surface 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig-sys 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-glutin 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2552,16 +2562,68 @@ dependencies = [
 name = "servo_atoms"
 version = "0.0.1"
 dependencies = [
  "string_cache 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_codegen 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "servo_config"
+version = "0.0.1"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "plugins 0.0.1",
+ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo_geometry 0.0.1",
+ "servo_url 0.0.1",
+ "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "servo_config_tests"
+version = "0.0.1"
+dependencies = [
+ "servo_config 0.0.1",
+]
+
+[[package]]
+name = "servo_geometry"
+version = "0.0.1"
+dependencies = [
+ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "servo_remutex"
+version = "0.0.1"
+dependencies = [
+ "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "servo_remutex_tests"
+version = "0.0.1"
+dependencies = [
+ "servo_remutex 0.0.1",
+]
+
+[[package]]
 name = "servo_url"
 version = "0.0.1"
 dependencies = [
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2655,17 +2717,17 @@ source = "registry+https://github.com/ru
 name = "style"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libbindgen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2684,67 +2746,67 @@ dependencies = [
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "walkdir 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "style_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
+ "servo_config 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "stylo_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
@@ -3008,45 +3070,16 @@ dependencies = [
 ]
 
 [[package]]
 name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "util"
-version = "0.0.1"
-dependencies = [
- "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "plugins 0.0.1",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo_url 0.0.1",
- "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "util_tests"
-version = "0.0.1"
-dependencies = [
- "util 0.0.1",
-]
-
-[[package]]
 name = "uuid"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -3127,50 +3160,50 @@ dependencies = [
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender"
 version = "0.11.0"
-source = "git+https://github.com/servo/webrender#c4a0c01f7a249a5786a5f32922574feb56b370b2"
+source = "git+https://github.com/servo/webrender#b2e02df28a6150433d299bac8435b5812d7bba15"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.11.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "webrender_traits"
 version = "0.11.0"
-source = "git+https://github.com/servo/webrender#c4a0c01f7a249a5786a5f32922574feb56b370b2"
+source = "git+https://github.com/servo/webrender#b2e02df28a6150433d299bac8435b5812d7bba15"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -3272,16 +3305,17 @@ dependencies = [
  "tendril 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [metadata]
 "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
 "checksum alloc-no-stdlib 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b21f6ad9c9957eb5d70c3dee16d31c092b3cab339628f821766b05e6833d72b8"
 "checksum android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e2b80445d331077679dfc6f3014f3e9ab7083e588423d35041d3fc017198189"
+"checksum android_injected_glue 0.2.1 (git+https://github.com/mmatyas/android-rs-injected-glue)" = "<none>"
 "checksum angle 0.1.2 (git+https://github.com/servo/angle?branch=servo)" = "<none>"
 "checksum app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "636ee56f12e31dbc11dc0a1ac6004f08b04e6e6595963716fc8130e90d4e04cf"
 "checksum arrayvec 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "80a137392e2e92ce7387c063d98a11f0d47115426c5f8759657af3c7b385c860"
 "checksum aster 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88bb8ecdf6a7eaddb7bfd872ebf5e085d343ca42ce98c582dba8046e3450b524"
 "checksum audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "03da2550cb89fe3faf218c179261c26cf7891c4234707c15f5d09ebb32ae2400"
 "checksum azure 0.9.1 (git+https://github.com/servo/rust-azure)" = "<none>"
 "checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f"
 "checksum backtrace-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ff73785ae8e06bb4a7b09e09f06d7434f9748b86d2f67bdf334b603354497e08"
@@ -3334,32 +3368,32 @@ dependencies = [
 "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
 "checksum energy-monitor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe872d0664f1cc60db36349af245d892ee67d3c8f78055df0ebc43271fd4e05c"
 "checksum energymon 0.2.0 (git+https://github.com/energymon/energymon-rust.git)" = "<none>"
 "checksum energymon-builder 0.2.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum energymon-default-sys 0.2.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum energymon-sys 0.2.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f79eff5be92a4d7d5bddf7daa7d650717ea71628634efe6ca7bcda85b2183c23"
 "checksum env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82dcb9ceed3868a03b335657b85a159736c961900f7e7747d3b0b97b9ccb5ccb"
-"checksum euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "44ef2a3e4a621518e488db36820a12b49a9d5004764b8daf1458bbe5d7c9b626"
+"checksum euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c274f13773ec277a48408d0c7a8dc935ad4bfe190f4cfccd0126d203afc3c83"
 "checksum expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cef36cd1a8a02d28b91d97347c63247b9e4cb8a8e36df36f8201dc87a1c0859c"
 "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum fontsan 0.3.2 (git+https://github.com/servo/fontsan)" = "<none>"
 "checksum freetype 0.1.2 (git+https://github.com/servo/rust-freetype)" = "<none>"
 "checksum freetype 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a89563eaf185762cf495c56cb16277549d2aaa7b1240d93338e8429fa33acd1"
 "checksum fs2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bcd414e5a1a979b931bb92f41b7a54106d3f6d2e6c253e9ce943b7cd468251ef"
 "checksum futf 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7a9689380a2553b51c564b3d9178075c68ebd0b397972c783acfd28b46c28ad"
 "checksum gaol 0.0.1 (git+https://github.com/servo/gaol)" = "<none>"
 "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
 "checksum gif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01c7c19a035de94bd7afbaa62c241aadfbdf1a70f560b348d2312eafa566ca16"
 "checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55"
-"checksum gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b04d6c8a1df841e48dfe99ed67829c9d1d17b1bb3e44c5f3283992010e20359b"
+"checksum gleam 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b83402229bde9d923f0b92811be017f9df5946ee86f8647367b1e02bcf5c293"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b280007fa9c7442cfd1e0b1addb8d1a59240267110e8705f8f7e2c7bfb7e2f72"
 "checksum harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6b76113246f5c089dcf272cf89c3f61168a4d77b50ec5b2c1fab8c628c9ea762"
 "checksum heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8c80e194758495a9109566134dc06e42ea0423987d6ceca016edaa90381b3549"
 "checksum heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b6876925b6c3de6f9073f016f425de0076ab68cf30522107fa586ae6524abfe"
 "checksum heartbeats-simple 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "78c0810722eacd0bdd3f1f691524bd9900bf8fed1947f6b883c10ddecd2560b1"
 "checksum heartbeats-simple-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53c4b67617665d7f4172f381f9843c1bec6a4fccc9a9226529e5b1be40dc1301"
 "checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
--- a/servo/cargo-commit-hash
+++ b/servo/cargo-commit-hash
@@ -1,1 +1,1 @@
-5e3221eac240f1e2c719524ea3c15fde9329dec2
+16f38c1102bddc8e6b6a4322ae41489b769884dc
--- a/servo/components/bluetooth/Cargo.toml
+++ b/servo/components/bluetooth/Cargo.toml
@@ -10,13 +10,12 @@ name = "bluetooth"
 path = "lib.rs"
 
 [dependencies]
 bitflags = "0.7"
 bluetooth_traits = {path = "../bluetooth_traits"}
 device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]}
 ipc-channel = "0.5"
 rand = "0.3"
-util = {path = "../util"}
 uuid = {version = "0.3.1", features = ["v4"]}
 
 [target.'cfg(target_os = "linux")'.dependencies]
 tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"}
--- a/servo/components/bluetooth/lib.rs
+++ b/servo/components/bluetooth/lib.rs
@@ -5,36 +5,34 @@
 #[macro_use]
 extern crate bitflags;
 extern crate bluetooth_traits;
 extern crate device;
 extern crate ipc_channel;
 extern crate rand;
 #[cfg(target_os = "linux")]
 extern crate tinyfiledialogs;
-extern crate util;
 extern crate uuid;
 
 pub mod test;
 
 use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg, BluetoothServiceMsg};
-use bluetooth_traits::{BluetoothDeviceMsg, BluetoothRequest, BluetoothResponse};
+use bluetooth_traits::{BluetoothDeviceMsg, BluetoothRequest, BluetoothResponse, GATTType};
 use bluetooth_traits::{BluetoothError, BluetoothResponseResult, BluetoothResult};
 use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist};
 use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions};
 use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic};
 use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService};
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use rand::Rng;
 use std::borrow::ToOwned;
 use std::collections::{HashMap, HashSet};
 use std::string::String;
 use std::thread;
 use std::time::Duration;
-use util::thread::spawn_named;
 
 // A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed.
 // https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 480)
 const MAXIMUM_TRANSACTION_TIME: u8 = 30;
 const CONNECTION_TIMEOUT_MS: u64 = 1000;
 // The discovery session needs some time to find any nearby devices
 const DISCOVERY_TIMEOUT_MS: u64 = 1500;
 #[cfg(target_os = "linux")]
@@ -61,41 +59,27 @@ bitflags! {
 macro_rules! return_if_cached(
     ($cache:expr, $key:expr) => (
         if $cache.contains_key($key) {
             return $cache.get($key);
         }
     );
 );
 
-macro_rules! get_adapter_or_return_error(
-    ($bl_manager:expr, $sender:expr) => (
-        match $bl_manager.get_or_create_adapter() {
-            Some(adapter) => {
-                if !adapter.is_powered().unwrap_or(false) {
-                    return drop($sender.send(Err(BluetoothError::NotFound)))
-                }
-                adapter
-            },
-            None => return drop($sender.send(Err(BluetoothError::NotFound))),
-        }
-    );
-);
-
 pub trait BluetoothThreadFactory {
     fn new() -> Self;
 }
 
 impl BluetoothThreadFactory for IpcSender<BluetoothRequest> {
     fn new() -> IpcSender<BluetoothRequest> {
         let (sender, receiver) = ipc::channel().unwrap();
         let adapter = BluetoothAdapter::init().ok();
-        spawn_named("BluetoothThread".to_owned(), move || {
+        thread::Builder::new().name("BluetoothThread".to_owned()).spawn(move || {
             BluetoothManager::new(receiver, adapter).start();
-        });
+        }).expect("Thread spawning failed");
         sender
     }
 }
 
 // https://webbluetoothcg.github.io/web-bluetooth/#matches-a-filter
 fn matches_filter(device: &BluetoothDevice, filter: &BluetoothScanfilter) -> bool {
     if filter.is_empty_or_invalid() {
         return false;
@@ -232,87 +216,65 @@ impl BluetoothManager {
             allowed_services: HashMap::new(),
         }
     }
 
     fn start(&mut self) {
         while let Ok(msg) = self.receiver.recv() {
             match msg {
                 BluetoothRequest::RequestDevice(options, sender) => {
-                    self.request_device(options, sender)
+                    let _ = sender.send(self.request_device(options));
                 },
                 BluetoothRequest::GATTServerConnect(device_id, sender) => {
-                    self.gatt_server_connect(device_id, sender)
+                    let _ = sender.send(self.gatt_server_connect(device_id));
                 },
                 BluetoothRequest::GATTServerDisconnect(device_id, sender) => {
-                    self.gatt_server_disconnect(device_id, sender)
-                },
-                BluetoothRequest::GetPrimaryService(device_id, uuid, sender) => {
-                    self.get_primary_service(device_id, uuid, sender)
-                },
-                BluetoothRequest::GetPrimaryServices(device_id, uuid, sender) => {
-                    self.get_primary_services(device_id, uuid, sender)
-                },
-                BluetoothRequest::GetIncludedService(service_id, uuid, sender) => {
-                    self.get_included_service(service_id, uuid, sender)
+                    let _ = sender.send(self.gatt_server_disconnect(device_id));
                 },
-                BluetoothRequest::GetIncludedServices(service_id, uuid, sender) => {
-                    self.get_included_services(service_id, uuid, sender)
-                },
-                BluetoothRequest::GetCharacteristic(service_id, uuid, sender) => {
-                    self.get_characteristic(service_id, uuid, sender)
-                },
-                BluetoothRequest::GetCharacteristics(service_id, uuid, sender) => {
-                    self.get_characteristics(service_id, uuid, sender)
-                },
-                BluetoothRequest::GetDescriptor(characteristic_id, uuid, sender) => {
-                    self.get_descriptor(characteristic_id, uuid, sender)
-                },
-                BluetoothRequest::GetDescriptors(characteristic_id, uuid, sender) => {
-                    self.get_descriptors(characteristic_id, uuid, sender)
+                BluetoothRequest::GetGATTChildren(id, uuid, single, child_type, sender) => {
+                    let _ = sender.send(self.get_gatt_children(id, uuid, single, child_type));
                 },
                 BluetoothRequest::ReadValue(id, sender) => {
-                    self.read_value(id, sender)
+                    let _ = sender.send(self.read_value(id));
                 },
                 BluetoothRequest::WriteValue(id, value, sender) => {
-                    self.write_value(id, value, sender)
+                    let _ = sender.send(self.write_value(id, value));
                 },
                 BluetoothRequest::EnableNotification(id, enable, sender) => {
-                    self.enable_notification(id, enable, sender)
+                    let _ = sender.send(self.enable_notification(id, enable));
+                },
+                BluetoothRequest::WatchAdvertisements(id, sender) => {
+                    let _ = sender.send(self.watch_advertisements(id));
                 },
                 BluetoothRequest::Test(data_set_name, sender) => {
-                    self.test(data_set_name, sender)
+                    let _ = sender.send(self.test(data_set_name));
                 }
                 BluetoothRequest::Exit => {
                     break
                 },
             }
         }
     }
 
     // Test
 
-    fn test(&mut self, data_set_name: String, sender: IpcSender<BluetoothResult<()>>) {
+    fn test(&mut self, data_set_name: String) -> BluetoothResult<()> {
         self.address_to_id.clear();
         self.service_to_device.clear();
         self.characteristic_to_service.clear();
         self.descriptor_to_characteristic.clear();
         self.cached_devices.clear();
         self.cached_services.clear();
         self.cached_characteristics.clear();
         self.cached_descriptors.clear();
         self.allowed_services.clear();
         self.adapter = BluetoothAdapter::init_mock().ok();
         match test::test(self, data_set_name) {
-            Ok(_) => {
-                let _ = sender.send(Ok(()));
-            },
-            Err(error) => {
-                let _ = sender.send(Err(BluetoothError::Type(error.description().to_owned())));
-            },
+            Ok(_) => return Ok(()),
+            Err(error) => Err(BluetoothError::Type(error.description().to_owned())),
         }
     }
 
     // Adapter
 
     pub fn get_or_create_adapter(&mut self) -> Option<BluetoothAdapter> {
         let adapter_valid = self.adapter.as_ref().map_or(false, |a| a.get_address().is_ok());
         if !adapter_valid {
@@ -326,16 +288,28 @@ impl BluetoothManager {
 
         if is_mock_adapter(adapter) && !adapter.is_present().unwrap_or(false) {
             return None;
         }
 
         self.adapter.clone()
     }
 
+    fn get_adapter(&mut self) -> BluetoothResult<BluetoothAdapter> {
+        match self.get_or_create_adapter() {
+            Some(adapter) => {
+                if !adapter.is_powered().unwrap_or(false) {
+                    return Err(BluetoothError::NotFound);
+                }
+                return Ok(adapter);
+            },
+            None => return Err(BluetoothError::NotFound),
+        }
+    }
+
     // Device
 
     fn get_and_cache_devices(&mut self, adapter: &mut BluetoothAdapter) -> Vec<BluetoothDevice> {
         let devices = adapter.get_devices().unwrap_or(vec!());
         for device in &devices {
             if let Ok(address) = device.get_address() {
                 if !self.address_to_id.contains_key(&address) {
                     let generated_id = self.generate_device_id();
@@ -413,16 +387,20 @@ impl BluetoothManager {
             None => return None,
         };
         match self.cached_devices.get(device_id) {
             Some(d) => Some(d.clone()),
             None => None,
         }
     }
 
+    fn device_is_cached(&self, device_id: &str) -> bool {
+        self.cached_devices.contains_key(device_id) && self.address_to_id.values().any(|v| v == device_id)
+    }
+
     // Service
 
     fn get_and_cache_gatt_services(&mut self,
                                    adapter: &mut BluetoothAdapter,
                                    device_id: &str)
                                    -> Vec<BluetoothGATTService> {
         let mut services = match self.get_device(adapter, device_id) {
             Some(d) => d.get_gatt_services().unwrap_or(vec!()),
@@ -446,23 +424,18 @@ impl BluetoothManager {
             Some(d) => d.clone(),
             None => return None,
         };
         self.get_and_cache_gatt_services(adapter, &device_id);
         return_if_cached!(self.cached_services, service_id);
         None
     }
 
-    fn get_gatt_services_by_uuid(&mut self,
-                                 adapter: &mut BluetoothAdapter,
-                                 device_id: &str,
-                                 service_uuid: &str)
-                                 -> Vec<BluetoothGATTService> {
-        let services = self.get_and_cache_gatt_services(adapter, device_id);
-        services.into_iter().filter(|s| s.get_uuid().ok() == Some(service_uuid.to_string())).collect()
+    fn service_is_cached(&self, service_id: &str) -> bool {
+        self.cached_services.contains_key(service_id) && self.service_to_device.contains_key(service_id)
     }
 
     // Characteristic
 
     fn get_and_cache_gatt_characteristics(&mut self,
                                           adapter: &mut BluetoothAdapter,
                                           service_id: &str)
                                           -> Vec<BluetoothGATTCharacteristic> {
@@ -488,27 +461,16 @@ impl BluetoothManager {
             Some(s) => s.clone(),
             None => return None,
         };
         self.get_and_cache_gatt_characteristics(adapter, &service_id);
         return_if_cached!(self.cached_characteristics, characteristic_id);
         None
     }
 
-    fn get_gatt_characteristics_by_uuid(&mut self,
-                                        adapter: &mut BluetoothAdapter,
-                                        service_id: &str,
-                                        characteristic_uuid: &str)
-                                        -> Vec<BluetoothGATTCharacteristic> {
-        let characteristics = self.get_and_cache_gatt_characteristics(adapter, service_id);
-        characteristics.into_iter()
-                       .filter(|c| c.get_uuid().ok() == Some(characteristic_uuid.to_string()))
-                       .collect()
-    }
-
     fn get_characteristic_properties(&self, characteristic: &BluetoothGATTCharacteristic) -> Flags {
         let mut props: Flags = Flags::empty();
         let flags = characteristic.get_flags().unwrap_or(vec!());
         for flag in flags {
             match flag.as_ref() {
                 "broadcast" => props.insert(BROADCAST),
                 "read" => props.insert(READ),
                 "write-without-response" => props.insert(WRITE_WITHOUT_RESPONSE),
@@ -519,16 +481,21 @@ impl BluetoothManager {
                 "reliable-write" => props.insert(RELIABLE_WRITE),
                 "writable-auxiliaries" => props.insert(WRITABLE_AUXILIARIES),
                 _ => (),
             }
         }
         props
     }
 
+    fn characteristic_is_cached(&self, characteristic_id: &str) -> bool {
+        self.cached_characteristics.contains_key(characteristic_id) &&
+        self.characteristic_to_service.contains_key(characteristic_id)
+    }
+
     // Descriptor
 
     fn get_and_cache_gatt_descriptors(&mut self,
                                       adapter: &mut BluetoothAdapter,
                                       characteristic_id: &str)
                                       -> Vec<BluetoothGATTDescriptor> {
         let mut descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) {
             Some(c) => c.get_gatt_descriptors().unwrap_or(vec!()),
@@ -552,35 +519,24 @@ impl BluetoothManager {
             Some(c) => c.clone(),
             None => return None,
         };
         self.get_and_cache_gatt_descriptors(adapter, &characteristic_id);
         return_if_cached!(self.cached_descriptors, descriptor_id);
         None
     }
 
-    fn get_gatt_descriptors_by_uuid(&mut self,
-                                    adapter: &mut BluetoothAdapter,
-                                    characteristic_id: &str,
-                                    descriptor_uuid: &str)
-                                    -> Vec<BluetoothGATTDescriptor> {
-        let descriptors = self.get_and_cache_gatt_descriptors(adapter, characteristic_id);
-        descriptors.into_iter()
-                   .filter(|d| d.get_uuid().ok() == Some(descriptor_uuid.to_string()))
-                   .collect()
-    }
-
     // Methods
 
     // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
     fn request_device(&mut self,
-                      options: RequestDeviceoptions,
-                      sender: IpcSender<BluetoothResponseResult>) {
+                      options: RequestDeviceoptions)
+                      -> BluetoothResponseResult {
         // Step 6.
-        let mut adapter = get_adapter_or_return_error!(self, sender);
+        let mut adapter = try!(self.get_adapter());
         if let Ok(ref session) = adapter.create_discovery_session() {
             if session.start_discovery().is_ok() {
                 if !is_mock_adapter(&adapter) {
                     thread::sleep(Duration::from_millis(DISCOVERY_TIMEOUT_MS));
                 }
             }
             let _ = session.stop_discovery();
         }
@@ -597,417 +553,253 @@ impl BluetoothManager {
         }
 
         // Step 9.
         // TODO: After the permission API implementation
         //       https://w3c.github.io/permissions/#prompt-the-user-to-choose
         if let Some(address) = self.select_device(matched_devices, &adapter) {
             let device_id = match self.address_to_id.get(&address) {
                 Some(id) => id.clone(),
-                None => return drop(sender.send(Err(BluetoothError::NotFound))),
+                None => return Err(BluetoothError::NotFound),
             };
             let mut services = options.get_services_set();
             if let Some(services_set) = self.allowed_services.get(&device_id) {
                 services = services_set | &services;
             }
             self.allowed_services.insert(device_id.clone(), services);
             if let Some(device) = self.get_device(&mut adapter, &device_id) {
                 let message = BluetoothDeviceMsg {
                     id: device_id,
                     name: device.get_name().ok(),
-                    appearance: device.get_appearance().ok(),
-                    tx_power: device.get_tx_power().ok().map(|p| p as i8),
-                    rssi: device.get_rssi().ok().map(|p| p as i8),
                 };
-                return drop(sender.send(Ok(BluetoothResponse::RequestDevice(message))));
+                return Ok(BluetoothResponse::RequestDevice(message));
             }
         }
         // TODO: Step 10 - 11: Implement the permission API.
-        return drop(sender.send(Err(BluetoothError::NotFound)));
+        return Err(BluetoothError::NotFound);
         // Step 12: Missing, because it is optional.
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
-    fn gatt_server_connect(&mut self, device_id: String, sender: IpcSender<BluetoothResponseResult>) {
-        let mut adapter = get_adapter_or_return_error!(self, sender);
+    fn gatt_server_connect(&mut self, device_id: String) -> BluetoothResponseResult {
+        // Step 2.
+        if !self.device_is_cached(&device_id) {
+            return Err(BluetoothError::Network);
+        }
+        let mut adapter = try!(self.get_adapter());
 
         // Step 5.1.1.
         match self.get_device(&mut adapter, &device_id) {
             Some(d) => {
                 if d.is_connected().unwrap_or(false) {
-                    return drop(sender.send(Ok(BluetoothResponse::GATTServerConnect(true))));
+                    return Ok(BluetoothResponse::GATTServerConnect(true));
                 }
                 let _ = d.connect();
                 for _ in 0..MAXIMUM_TRANSACTION_TIME {
                     match d.is_connected().unwrap_or(false) {
-                        true => return drop(sender.send(Ok(BluetoothResponse::GATTServerConnect(true)))),
+                        true => return Ok(BluetoothResponse::GATTServerConnect(true)),
                         false => {
                             if is_mock_adapter(&adapter) {
                                 break;
                             }
                             thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS));
                         },
                     }
                 // TODO: Step 5.1.4: Use the exchange MTU procedure.
                 }
                 // Step 5.1.3.
-                return drop(sender.send(Err(BluetoothError::Network)));
+                return Err(BluetoothError::Network);
             },
-            None => return drop(sender.send(Err(BluetoothError::NotFound))),
+            None => return Err(BluetoothError::NotFound),
         }
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
-    fn gatt_server_disconnect(&mut self, device_id: String, sender: IpcSender<BluetoothResult<bool>>) {
-        let mut adapter = get_adapter_or_return_error!(self, sender);
+    fn gatt_server_disconnect(&mut self, device_id: String) -> BluetoothResult<bool> {
+        let mut adapter = try!(self.get_adapter());
 
         match self.get_device(&mut adapter, &device_id) {
             Some(d) => {
                 // Step 2.
                 if !d.is_connected().unwrap_or(true) {
-                    return drop(sender.send(Ok(false)));
+                    return Ok(false);
                 }
                 let _ = d.disconnect();
                 for _ in 0..MAXIMUM_TRANSACTION_TIME {
                     match d.is_connected().unwrap_or(true) {
                         true => thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS)),
-                        false => return drop(sender.send(Ok(false))),
+                        false => return Ok(false),
                     }
                 }
-                return drop(sender.send(Err(BluetoothError::Network)));
+                return Err(BluetoothError::Network);
             },
-            None => return drop(sender.send(Err(BluetoothError::NotFound))),
+            None => return Err(BluetoothError::NotFound),
         }
     }
 
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
     // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_primary_service(&mut self,
-                           device_id: String,
-                           uuid: String,
-                           sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_devices.contains_key(&device_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        if !self.allowed_services.get(&device_id).map_or(false, |s| s.contains(&uuid)) {
-            return drop(sender.send(Err(BluetoothError::Security)));
-        }
-        let services = self.get_gatt_services_by_uuid(&mut adapter, &device_id, &uuid);
+    fn get_gatt_children(&mut self,
+                         id: String,
+                         uuid: Option<String>,
+                         single: bool,
+                         child_type: GATTType)
+                         -> BluetoothResponseResult {
+        let mut adapter = try!(self.get_adapter());
+        match child_type {
+            GATTType::PrimaryService => {
+                // Step 5.
+                if !self.device_is_cached(&id) {
+                    return Err(BluetoothError::InvalidState);
+                }
+                // Step 6.
+                if let Some(ref uuid) = uuid {
+                    if !self.allowed_services.get(&id).map_or(false, |s| s.contains(uuid)) {
+                        return Err(BluetoothError::Security);
+                    }
+                }
+                let mut services = self.get_and_cache_gatt_services(&mut adapter, &id);
+                if let Some(uuid) = uuid {
+                    services.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
+                }
+                let mut services_vec = vec!();
+                for service in services {
+                    if service.is_primary().unwrap_or(false) {
+                        if let Ok(uuid) = service.get_uuid() {
+                            services_vec.push(
+                                BluetoothServiceMsg {
+                                    uuid: uuid,
+                                    is_primary: true,
+                                    instance_id: service.get_id(),
+                                }
+                            );
+                        }
+                    }
+                }
+                // Step 7.
+                if services_vec.is_empty() {
+                    return Err(BluetoothError::NotFound);
+                }
 
-        // Step 6.
-        for service in services {
-            if service.is_primary().unwrap_or(false) {
-                if let Ok(uuid) = service.get_uuid() {
-                    return drop(sender.send(
-                        Ok(BluetoothResponse::GetPrimaryService(
-                            BluetoothServiceMsg {
-                                uuid: uuid,
-                                is_primary: true,
-                                instance_id: service.get_id(),
-                            }
-                        ))
-                    ));
-                }
-            }
-        }
-        // Step 7.
-        return drop(sender.send(Err(BluetoothError::NotFound)));
-    }
-
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_primary_services(&mut self,
-                            device_id: String,
-                            uuid: Option<String>,
-                            sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_devices.contains_key(&device_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let services = match uuid {
-            Some(ref id) => {
-                if !self.allowed_services.get(&device_id).map_or(false, |s| s.contains(id)) {
-                    return drop(sender.send(Err(BluetoothError::Security)))
-                }
-                self.get_gatt_services_by_uuid(&mut adapter, &device_id, id)
+                return Ok(BluetoothResponse::GetPrimaryServices(services_vec, single));
             },
-            None => self.get_and_cache_gatt_services(&mut adapter, &device_id),
-        };
-
-        // Step 6.
-        let mut services_vec = vec!();
-        for service in services {
-            if service.is_primary().unwrap_or(false) {
-                if let Ok(uuid) = service.get_uuid() {
-                    services_vec.push(
-                        BluetoothServiceMsg {
-                            uuid: uuid,
-                            is_primary: true,
-                            instance_id: service.get_id(),
-                        }
-                    );
+            GATTType::Characteristic => {
+                // Step 5.
+                if !self.service_is_cached(&id) {
+                    return Err(BluetoothError::InvalidState);
+                }
+                // Step 6.
+                let mut characteristics = self.get_and_cache_gatt_characteristics(&mut adapter, &id);
+                if let Some(uuid) = uuid {
+                    characteristics.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
                 }
-            }
-        }
-
-        // Step 7.
-        if services_vec.is_empty() {
-            return drop(sender.send(Err(BluetoothError::NotFound)));
-        }
-
-        return drop(sender.send(Ok(BluetoothResponse::GetPrimaryServices(services_vec))));
-    }
+                let mut characteristics_vec = vec!();
+                for characteristic in characteristics {
+                    if let Ok(uuid) = characteristic.get_uuid() {
+                        let properties = self.get_characteristic_properties(&characteristic);
+                        characteristics_vec.push(
+                            BluetoothCharacteristicMsg {
+                                uuid: uuid,
+                                instance_id: characteristic.get_id(),
+                                broadcast: properties.contains(BROADCAST),
+                                read: properties.contains(READ),
+                                write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
+                                write: properties.contains(WRITE),
+                                notify: properties.contains(NOTIFY),
+                                indicate: properties.contains(INDICATE),
+                                authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
+                                reliable_write: properties.contains(RELIABLE_WRITE),
+                                writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
+                            }
+                        );
+                    }
+                }
 
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_included_service(&mut self,
-                            service_id: String,
-                            uuid: String,
-                            sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_services.contains_key(&service_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let device = match self.device_from_service_id(&service_id) {
-            Some(device) => device,
-            None => return drop(sender.send(Err(BluetoothError::NotFound))),
-        };
-        let primary_service = match self.get_gatt_service(&mut adapter, &service_id) {
-            Some(s) => s,
-            None => return drop(sender.send(Err(BluetoothError::NotFound))),
-        };
-        let services = primary_service.get_includes(device).unwrap_or(vec!());
+                // Step 7.
+                if characteristics_vec.is_empty() {
+                    return Err(BluetoothError::NotFound);
+                }
 
-        // Step 6.
-        for service in services {
-            if let Ok(service_uuid) = service.get_uuid() {
-                if uuid == service_uuid {
-                    return drop(sender.send(
-                        Ok(BluetoothResponse::GetIncludedService(
+                return Ok(BluetoothResponse::GetCharacteristics(characteristics_vec, single));
+            },
+            GATTType::IncludedService => {
+                // Step 5.
+                if !self.service_is_cached(&id) {
+                    return Err(BluetoothError::InvalidState);
+                }
+                // Step 6.
+                let device = match self.device_from_service_id(&id) {
+                    Some(device) => device,
+                    None => return Err(BluetoothError::NotFound),
+                };
+                let primary_service = match self.get_gatt_service(&mut adapter, &id) {
+                    Some(s) => s,
+                    None => return Err(BluetoothError::NotFound),
+                };
+                let services = primary_service.get_includes(device).unwrap_or(vec!());
+                let mut services_vec = vec!();
+                for service in services {
+                    if let Ok(service_uuid) = service.get_uuid() {
+                        services_vec.push(
                             BluetoothServiceMsg {
-                                uuid: uuid,
+                                uuid: service_uuid,
                                 is_primary: service.is_primary().unwrap_or(false),
                                 instance_id: service.get_id(),
-                           }
-                       ))
-                    ));
-                }
-            }
-        }
-        // Step 7.
-        return drop(sender.send(Err(BluetoothError::NotFound)));
-    }
-
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_included_services(&mut self,
-                             service_id: String,
-                             uuid: Option<String>,
-                             sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_services.contains_key(&service_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let device = match self.device_from_service_id(&service_id) {
-            Some(device) => device,
-            None => return drop(sender.send(Err(BluetoothError::NotFound))),
-        };
-        let primary_service = match self.get_gatt_service(&mut adapter, &service_id) {
-            Some(s) => s,
-            None => return drop(sender.send(Err(BluetoothError::NotFound))),
-        };
-        let services = primary_service.get_includes(device).unwrap_or(vec!());
-
-        // Step 6.
-        let mut services_vec = vec!();
-        for service in services {
-            if let Ok(service_uuid) = service.get_uuid() {
-                services_vec.push(
-                    BluetoothServiceMsg {
-                        uuid: service_uuid,
-                        is_primary: service.is_primary().unwrap_or(false),
-                        instance_id: service.get_id(),
+                            }
+                        );
                     }
-                );
-            }
-        }
-        if let Some(uuid) = uuid {
-            services_vec.retain(|ref s| s.uuid == uuid);
-        }
-        services_vec.retain(|s| !uuid_is_blocklisted(&s.uuid, Blocklist::All));
-
-        // Step 7.
-        if services_vec.is_empty() {
-            return drop(sender.send(Err(BluetoothError::NotFound)));
-        }
-
-        return drop(sender.send(Ok(BluetoothResponse::GetIncludedServices(services_vec))));
-    }
+                }
+                if let Some(uuid) = uuid {
+                    services_vec.retain(|ref s| s.uuid == uuid);
+                }
+                services_vec.retain(|s| !uuid_is_blocklisted(&s.uuid, Blocklist::All));
 
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_characteristic(&mut self,
-                          service_id: String,
-                          uuid: String,
-                          sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_services.contains_key(&service_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let characteristics = self.get_gatt_characteristics_by_uuid(&mut adapter, &service_id, &uuid);
-
-        // Step 6.
-        for characteristic in characteristics {
-            if let Ok(uuid) = characteristic.get_uuid() {
-                let properties = self.get_characteristic_properties(&characteristic);
-                let message = BluetoothCharacteristicMsg {
-                    uuid: uuid,
-                    instance_id: characteristic.get_id(),
-                    broadcast: properties.contains(BROADCAST),
-                    read: properties.contains(READ),
-                    write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
-                    write: properties.contains(WRITE),
-                    notify: properties.contains(NOTIFY),
-                    indicate: properties.contains(INDICATE),
-                    authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
-                    reliable_write: properties.contains(RELIABLE_WRITE),
-                    writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
-                };
-                return drop(sender.send(Ok(BluetoothResponse::GetCharacteristic(message))));
-            }
-        }
-        // Step 7.
-        return drop(sender.send(Err(BluetoothError::NotFound)));
-    }
+                // Step 7.
+                if services_vec.is_empty() {
+                    return Err(BluetoothError::NotFound);
+                }
 
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_characteristics(&mut self,
-                           service_id: String,
-                           uuid: Option<String>,
-                           sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_services.contains_key(&service_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let characteristics = match uuid {
-            Some(id) => self.get_gatt_characteristics_by_uuid(&mut adapter, &service_id, &id),
-            None => self.get_and_cache_gatt_characteristics(&mut adapter, &service_id),
-        };
-
-        // Step 6.
-        let mut characteristics_vec = vec!();
-        for characteristic in characteristics {
-            if let Ok(uuid) = characteristic.get_uuid() {
-                let properties = self.get_characteristic_properties(&characteristic);
-                characteristics_vec.push(
-                    BluetoothCharacteristicMsg {
-                        uuid: uuid,
-                        instance_id: characteristic.get_id(),
-                        broadcast: properties.contains(BROADCAST),
-                        read: properties.contains(READ),
-                        write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
-                        write: properties.contains(WRITE),
-                        notify: properties.contains(NOTIFY),
-                        indicate: properties.contains(INDICATE),
-                        authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
-                        reliable_write: properties.contains(RELIABLE_WRITE),
-                        writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
+                return Ok(BluetoothResponse::GetIncludedServices(services_vec, single));
+            },
+            GATTType::Descriptor => {
+                // Step 5.
+                if !self.characteristic_is_cached(&id) {
+                    return Err(BluetoothError::InvalidState);
+                }
+                // Step 6.
+                let mut descriptors = self.get_and_cache_gatt_descriptors(&mut adapter, &id);
+                if let Some(uuid) = uuid {
+                    descriptors.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
+                }
+                let mut descriptors_vec = vec!();
+                for descriptor in descriptors {
+                    if let Ok(uuid) = descriptor.get_uuid() {
+                        descriptors_vec.push(
+                            BluetoothDescriptorMsg {
+                                uuid: uuid,
+                                instance_id: descriptor.get_id(),
+                            }
+                        );
                     }
-                );
-            }
-        }
-
-        // Step 7.
-        if characteristics_vec.is_empty() {
-            return drop(sender.send(Err(BluetoothError::NotFound)));
-        }
-
-        return drop(sender.send(Ok(BluetoothResponse::GetCharacteristics(characteristics_vec))));
-    }
+                }
 
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_descriptor(&mut self,
-                      characteristic_id: String,
-                      uuid: String,
-                      sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_characteristics.contains_key(&characteristic_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let descriptors = self.get_gatt_descriptors_by_uuid(&mut adapter, &characteristic_id, &uuid);
-
-        // Step 6.
-        for descriptor in descriptors {
-            if let Ok(uuid) = descriptor.get_uuid() {
-                return drop(sender.send(
-                    Ok(BluetoothResponse::GetDescriptor(
-                        BluetoothDescriptorMsg {
-                            uuid: uuid,
-                            instance_id: descriptor.get_id(),
-                        }
-                    ))
-                ));
-            }
+                // Step 7.
+                if descriptors_vec.is_empty() {
+                    return Err(BluetoothError::NotFound);
+                }
+                return Ok(BluetoothResponse::GetDescriptors(descriptors_vec, single));
+            },
         }
-        // Step 7.
-        return drop(sender.send(Err(BluetoothError::NotFound)));
-    }
-
-    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
-    // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
-    fn get_descriptors(&mut self,
-                       characteristic_id: String,
-                       uuid: Option<String>,
-                       sender: IpcSender<BluetoothResponseResult>) {
-        // Step 5.
-        if !self.cached_characteristics.contains_key(&characteristic_id) {
-            return drop(sender.send(Err(BluetoothError::InvalidState)));
-        }
-        let mut adapter = get_adapter_or_return_error!(self, sender);
-        let descriptors = match uuid {
-            Some(id) => self.get_gatt_descriptors_by_uuid(&mut adapter, &characteristic_id, &id),
-            None => self.get_and_cache_gatt_descriptors(&mut adapter, &characteristic_id),
-        };
-
-        // Step 6.
-        let mut descriptors_vec = vec!();
-        for descriptor in descriptors {
-            if let Ok(uuid) = descriptor.get_uuid() {
-                descriptors_vec.push(
-                    BluetoothDescriptorMsg {
-                        uuid: uuid,
-                        instance_id: descriptor.get_id(),
-                    }
-                );
-            }
-        }
-
-        // Step 7.
-        if descriptors_vec.is_empty() {
-            return drop(sender.send(Err(BluetoothError::NotFound)));
-        }
-        return drop(sender.send(Ok(BluetoothResponse::GetDescriptors(descriptors_vec))));
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
-    fn read_value(&mut self, id: String, sender: IpcSender<BluetoothResponseResult>) {
+    fn read_value(&mut self, id: String) -> BluetoothResponseResult {
         // (Characteristic) Step 5.2: Missing because it is optional.
         // (Descriptor)     Step 5.1: Missing because it is optional.
-        let mut adapter = get_adapter_or_return_error!(self, sender);
+        let mut adapter = try!(self.get_adapter());
 
         // (Characteristic) Step 5.3.
         let mut value = self.get_gatt_characteristic(&mut adapter, &id)
                             .map(|c| c.read_value().unwrap_or(vec![]));
 
         // (Characteristic) TODO: Step 5.4: Handle all the errors returned from the read_value call.
 
         // (Descriptor) Step 5.2.
@@ -1016,30 +808,30 @@ impl BluetoothManager {
                         .map(|d| d.read_value().unwrap_or(vec![]));
         }
 
         // (Descriptor) TODO: Step 5.3: Handle all the errors returned from the read_value call.
 
         match value {
             // (Characteristic) Step 5.5.4.
             // (Descriptor)     Step 5.4.3.
-            Some(v) => return drop(sender.send(Ok(BluetoothResponse::ReadValue(v)))),
+            Some(v) => return Ok(BluetoothResponse::ReadValue(v)),
 
             // (Characteristic) Step 4.
             // (Descriptor)     Step 4.
-            None => return drop(sender.send(Err(BluetoothError::InvalidState))),
+            None => return Err(BluetoothError::InvalidState),
         }
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
-    fn write_value(&mut self, id: String, value: Vec<u8>, sender: IpcSender<BluetoothResponseResult>) {
+    fn write_value(&mut self, id: String, value: Vec<u8>) -> BluetoothResponseResult {
         // (Characteristic) Step 7.2: Missing because it is optional.
         // (Descriptor)     Step 7.1: Missing because it is optional.
-        let mut adapter = get_adapter_or_return_error!(self, sender);
+        let mut adapter = try!(self.get_adapter());
 
         // (Characteristic) Step 7.3.
         let mut result = self.get_gatt_characteristic(&mut adapter, &id)
                              .map(|c| c.write_value(value.clone()));
 
         // (Characteristic) TODO: Step 7.4: Handle all the errors returned from the write_value call.
 
         // (Descriptor) Step 7.2.
@@ -1049,49 +841,62 @@ impl BluetoothManager {
         }
 
         // (Descriptor) TODO: Step 7.3: Handle all the errors returned from the write_value call.
 
         match result {
             Some(v) => match v {
                 // (Characteristic) Step 7.5.3.
                 // (Descriptor) Step 7.4.3.
-                Ok(_) => return drop(sender.send(Ok(BluetoothResponse::WriteValue(value)))),
+                Ok(_) => return Ok(BluetoothResponse::WriteValue(value)),
 
                 // (Characteristic) Step 7.1.
-                Err(_) => return drop(sender.send(Err(BluetoothError::NotSupported))),
+                Err(_) => return Err(BluetoothError::NotSupported),
             },
 
             // (Characteristic) Step 6.
             // (Descriptor)     Step 6.
-            None => return drop(sender.send(Err(BluetoothError::InvalidState))),
+            None => return Err(BluetoothError::InvalidState),
         }
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-stopnotifications
-    fn enable_notification(&mut self, id: String, enable: bool, sender: IpcSender<BluetoothResponseResult>) {
+    fn enable_notification(&mut self, id: String, enable: bool) -> BluetoothResponseResult {
+        // (StartNotifications) Step 2 - 3.
+        // (StopNotifications) Step 1 - 2.
+        if !self.characteristic_is_cached(&id) {
+            return Err(BluetoothError::InvalidState);
+        }
+
         // (StartNotification) TODO: Step 7: Missing because it is optional.
-        let mut adapter = get_adapter_or_return_error!(self, sender);
+        let mut adapter = try!(self.get_adapter());
         match self.get_gatt_characteristic(&mut adapter, &id) {
             Some(c) => {
                 let result = match enable {
                     // (StartNotification) Step 8.
                     // TODO: Handle all the errors returned from the start_notify call.
                     true => c.start_notify(),
 
                     // (StopNotification) Step 4.
                     false => c.stop_notify(),
                 };
                 match result {
                     // (StartNotification) Step 11.
                     // (StopNotification)  Step 5.
-                    Ok(_) => return drop(sender.send(Ok(BluetoothResponse::EnableNotification(())))),
+                    Ok(_) => return Ok(BluetoothResponse::EnableNotification(())),
 
                     // (StartNotification) Step 4.
-                    Err(_) => return drop(sender.send(Err(BluetoothError::NotSupported))),
+                    Err(_) => return Err(BluetoothError::NotSupported),
                 }
             },
             // (StartNotification) Step 3.
-            None => return drop(sender.send(Err(BluetoothError::InvalidState))),
+            None => return Err(BluetoothError::InvalidState),
         }
     }
+
+    // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements
+    fn watch_advertisements(&mut self, _device_id: String) -> BluetoothResponseResult {
+        // Step 2.
+        // TODO: Implement this when supported in lower level
+        return Err(BluetoothError::NotSupported);
+    }
 }
--- a/servo/components/bluetooth_traits/Cargo.toml
+++ b/servo/components/bluetooth_traits/Cargo.toml
@@ -9,9 +9,9 @@ publish = false
 name = "bluetooth_traits"
 path = "lib.rs"
 
 [dependencies]
 ipc-channel = "0.5"
 regex = "0.1.43"
 serde = "0.8"
 serde_derive = "0.8"
-util = {path = "../util"}
+servo_config = {path = "../config"}
--- a/servo/components/bluetooth_traits/blocklist.rs
+++ b/servo/components/bluetooth_traits/blocklist.rs
@@ -1,18 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use regex::Regex;
+use servo_config::resource_files::read_resource_file;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::io::BufRead;
 use std::string::String;
-use util::resource_files::read_resource_file;
 
 const BLOCKLIST_FILE: &'static str = "gatt_blocklist.txt";
 const BLOCKLIST_FILE_NOT_FOUND: &'static str = "Could not find gatt_blocklist.txt file";
 const EXCLUDE_READS: &'static str = "exclude-reads";
 const EXCLUDE_WRITES: &'static str = "exclude-writes";
 const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
 
 thread_local!(pub static BLUETOOTH_BLOCKLIST: RefCell<BluetoothBlocklist> =
--- a/servo/components/bluetooth_traits/lib.rs
+++ b/servo/components/bluetooth_traits/lib.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![feature(proc_macro)]
 
 extern crate ipc_channel;
 extern crate regex;
 #[macro_use]
 extern crate serde_derive;
-extern crate util;
+extern crate servo_config;
 
 pub mod blocklist;
 pub mod scanfilter;
 
 use ipc_channel::ipc::IpcSender;
 use scanfilter::RequestDeviceoptions;
 
 #[derive(Deserialize, Serialize)]
@@ -22,24 +22,28 @@ pub enum BluetoothError {
     Network,
     NotFound,
     NotSupported,
     Security,
     InvalidState,
 }
 
 #[derive(Deserialize, Serialize)]
+pub enum GATTType {
+    PrimaryService,
+    Characteristic,
+    IncludedService,
+    Descriptor,
+}
+
+#[derive(Deserialize, Serialize)]
 pub struct BluetoothDeviceMsg {
     // Bluetooth Device properties
     pub id: String,
     pub name: Option<String>,
-    // Advertising Data properties
-    pub appearance: Option<u16>,
-    pub tx_power: Option<i8>,
-    pub rssi: Option<i8>,
 }
 
 #[derive(Deserialize, Serialize)]
 pub struct BluetoothServiceMsg {
     pub uuid: String,
     pub is_primary: bool,
     pub instance_id: String,
 }
@@ -77,43 +81,34 @@ pub type BluetoothResult<T> = Result<T, 
 
 pub type BluetoothResponseResult = Result<BluetoothResponse, BluetoothError>;
 
 #[derive(Deserialize, Serialize)]
 pub enum BluetoothRequest {
     RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResponseResult>),
     GATTServerConnect(String, IpcSender<BluetoothResponseResult>),
     GATTServerDisconnect(String, IpcSender<BluetoothResult<bool>>),
-    GetPrimaryService(String, String, IpcSender<BluetoothResponseResult>),
-    GetPrimaryServices(String, Option<String>, IpcSender<BluetoothResponseResult>),
-    GetIncludedService(String, String, IpcSender<BluetoothResponseResult>),
-    GetIncludedServices(String, Option<String>, IpcSender<BluetoothResponseResult>),
-    GetCharacteristic(String, String, IpcSender<BluetoothResponseResult>),
-    GetCharacteristics(String, Option<String>, IpcSender<BluetoothResponseResult>),
-    GetDescriptor(String, String, IpcSender<BluetoothResponseResult>),
-    GetDescriptors(String, Option<String>, IpcSender<BluetoothResponseResult>),
+    GetGATTChildren(String, Option<String>, bool, GATTType, IpcSender<BluetoothResponseResult>),
     ReadValue(String, IpcSender<BluetoothResponseResult>),
     WriteValue(String, Vec<u8>, IpcSender<BluetoothResponseResult>),
     EnableNotification(String, bool, IpcSender<BluetoothResponseResult>),
+    WatchAdvertisements(String, IpcSender<BluetoothResponseResult>),
     Test(String, IpcSender<BluetoothResult<()>>),
     Exit,
 }
 
 #[derive(Deserialize, Serialize)]
 pub enum BluetoothResponse {
     RequestDevice(BluetoothDeviceMsg),
     GATTServerConnect(bool),
-    GetPrimaryService(BluetoothServiceMsg),
-    GetPrimaryServices(BluetoothServicesMsg),
-    GetIncludedService(BluetoothServiceMsg),
-    GetIncludedServices(BluetoothServicesMsg),
-    GetCharacteristic(BluetoothCharacteristicMsg),
-    GetCharacteristics(BluetoothCharacteristicsMsg),
-    GetDescriptor(BluetoothDescriptorMsg),
-    GetDescriptors(BluetoothDescriptorsMsg),
+    GetPrimaryServices(BluetoothServicesMsg, bool),
+    GetIncludedServices(BluetoothServicesMsg, bool),
+    GetCharacteristics(BluetoothCharacteristicsMsg, bool),
+    GetDescriptors(BluetoothDescriptorsMsg, bool),
     ReadValue(Vec<u8>),
     WriteValue(Vec<u8>),
     EnableNotification(()),
+    WatchAdvertisements(()),
 }
 
 pub trait BluetoothResponseListener {
     fn response(&mut self, response: BluetoothResponseResult);
 }
--- a/servo/components/canvas/Cargo.toml
+++ b/servo/components/canvas/Cargo.toml
@@ -14,14 +14,14 @@ azure = {git = "https://github.com/servo
 canvas_traits = {path = "../canvas_traits"}
 euclid = "0.10.1"
 gleam = "0.2.8"
 ipc-channel = "0.5"
 log = "0.3.5"
 num-traits = "0.1.32"
 offscreen_gl_context = "0.5.0"
 plugins = {path = "../plugins"}
-util = {path = "../util"}
+servo_config = {path = "../config"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
--- a/servo/components/canvas/canvas_paint_thread.rs
+++ b/servo/components/canvas/canvas_paint_thread.rs
@@ -10,17 +10,17 @@ use canvas_traits::*;
 use euclid::matrix2d::Matrix2D;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::size::Size2D;
 use ipc_channel::ipc::{self, IpcSender};
 use num_traits::ToPrimitive;
 use std::borrow::ToOwned;
 use std::mem;
-use util::thread::spawn_named;
+use std::thread;
 use webrender_traits;
 
 impl<'a> CanvasPaintThread<'a> {
     /// It reads image data from the canvas
     /// canvas_size: The size of the canvas we're reading from
     /// read_rect: The area of the canvas we want to read from
     fn read_pixels(&self, read_rect: Rect<i32>, canvas_size: Size2D<f64>) -> Vec<u8>{
         let canvas_size = canvas_size.to_i32();
@@ -116,17 +116,17 @@ impl<'a> CanvasPaintThread<'a> {
 
     /// Creates a new `CanvasPaintThread` and returns an `IpcSender` to
     /// communicate with it.
     pub fn start(size: Size2D<i32>,
                  webrender_api_sender: webrender_traits::RenderApiSender,
                  antialias: bool)
                  -> IpcSender<CanvasMsg> {
         let (sender, receiver) = ipc::channel::<CanvasMsg>().unwrap();
-        spawn_named("CanvasThread".to_owned(), move || {
+        thread::Builder::new().name("CanvasThread".to_owned()).spawn(move || {
             let mut painter = CanvasPaintThread::new(size, webrender_api_sender, antialias);
             loop {
                 let msg = receiver.recv();
                 match msg.unwrap() {
                     CanvasMsg::Canvas2d(message) => {
                         match message {
                             Canvas2dMsg::FillRect(ref rect) => painter.fill_rect(rect),
                             Canvas2dMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
@@ -206,17 +206,17 @@ impl<'a> CanvasPaintThread<'a> {
                             FromLayoutMsg::SendData(chan) => {
                                 painter.send_data(chan)
                             }
                         }
                     }
                     CanvasMsg::WebGL(_) => panic!("Wrong message sent to Canvas2D thread"),
                 }
             }
-        });
+        }).expect("Thread spawning failed");
 
         sender
     }
 
     fn save_context_state(&mut self) {
         self.saved_states.push(self.state.clone());
     }
 
--- a/servo/components/canvas/lib.rs
+++ b/servo/components/canvas/lib.rs
@@ -12,13 +12,13 @@ extern crate canvas_traits;
 extern crate core;
 extern crate euclid;
 extern crate gleam;
 extern crate ipc_channel;
 #[macro_use]
 extern crate log;
 extern crate num_traits;
 extern crate offscreen_gl_context;
-extern crate util;
+extern crate servo_config;
 extern crate webrender_traits;
 
 pub mod canvas_paint_thread;
 pub mod webgl_paint_thread;
--- a/servo/components/canvas/webgl_paint_thread.rs
+++ b/servo/components/canvas/webgl_paint_thread.rs
@@ -4,20 +4,20 @@
 
 use canvas_traits::{CanvasCommonMsg, CanvasData, CanvasMsg, CanvasImageData};
 use canvas_traits::{FromLayoutMsg, FromScriptMsg, byte_swap};
 use euclid::size::Size2D;
 use gleam::gl;
 use ipc_channel::ipc::{self, IpcSender};
 use offscreen_gl_context::{ColorAttachmentType, GLContext, GLLimits};
 use offscreen_gl_context::{GLContextAttributes, NativeGLContext, OSMesaContext};
+use servo_config::opts;
 use std::borrow::ToOwned;
 use std::sync::mpsc::channel;
-use util::opts;
-use util::thread::spawn_named;
+use std::thread;
 use webrender_traits;
 
 enum GLContextWrapper {
     Native(GLContext<NativeGLContext>),
     OSMesa(GLContext<OSMesaContext>),
 }
 
 impl GLContextWrapper {
@@ -111,17 +111,18 @@ fn create_readback_painter(size: Size2D<
 }
 
 impl WebGLPaintThread {
     fn new(size: Size2D<i32>,
            attrs: GLContextAttributes,
            webrender_api_sender: webrender_traits::RenderApiSender)
         -> Result<(WebGLPaintThread, GLLimits), String> {
         let wr_api = webrender_api_sender.create_api();
-        match wr_api.request_webgl_context(&size, attrs) {
+        let device_size = webrender_traits::DeviceIntSize::from_untyped(&size);
+        match wr_api.request_webgl_context(&device_size, attrs) {
             Ok((id, limits)) => {
                 let painter = WebGLPaintThread {
                     data: WebGLPaintTaskData::WebRender(wr_api, id),
                     size: size
                 };
                 Ok((painter, limits))
             },
             Err(msg) => {
@@ -146,17 +147,17 @@ impl WebGLPaintThread {
     /// Creates a new `WebGLPaintThread` and returns an `IpcSender` to
     /// communicate with it.
     pub fn start(size: Size2D<i32>,
                  attrs: GLContextAttributes,
                  webrender_api_sender: webrender_traits::RenderApiSender)
                  -> Result<(IpcSender<CanvasMsg>, GLLimits), String> {
         let (sender, receiver) = ipc::channel::<CanvasMsg>().unwrap();
         let (result_chan, result_port) = channel();
-        spawn_named("WebGLThread".to_owned(), move || {
+        thread::Builder::new().name("WebGLThread".to_owned()).spawn(move || {
             let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender) {
                 Ok((thread, limits)) => {
                     result_chan.send(Ok(limits)).unwrap();
                     thread
                 },
                 Err(e) => {
                     result_chan.send(Err(e)).unwrap();
                     return
@@ -186,17 +187,17 @@ impl WebGLPaintThread {
                         match message {
                             FromLayoutMsg::SendData(chan) =>
                                 painter.send_data(chan),
                         }
                     }
                     CanvasMsg::Canvas2d(_) => panic!("Wrong message sent to WebGLThread"),
                 }
             }
-        });
+        }).expect("Thread spawning failed");
 
         result_port.recv().unwrap().map(|limits| (sender, limits))
     }
 
     fn send_data(&mut self, chan: IpcSender<CanvasData>) {
         match self.data {
             WebGLPaintTaskData::Readback(_, ref webrender_api, image_key) => {
                 let width = self.size.width as usize;
@@ -247,17 +248,18 @@ impl WebGLPaintThread {
                    size.height > self.size.height {
                     self.size = try!(context.resize(size));
                 } else {
                     self.size = size;
                     unsafe { gl::Scissor(0, 0, size.width, size.height); }
                 }
             }
             WebGLPaintTaskData::WebRender(ref api, id) => {
-                api.resize_webgl_context(id, &size);
+                let device_size = webrender_traits::DeviceIntSize::from_untyped(&size);
+                api.resize_webgl_context(id, &device_size);
             }
         }
 
         Ok(())
     }
 
     fn init(&mut self) {
         if let WebGLPaintTaskData::Readback(ref context, _, _) = self.data {
--- a/servo/components/compositing/Cargo.toml
+++ b/servo/components/compositing/Cargo.toml
@@ -18,20 +18,21 @@ ipc-channel = "0.5"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 script_traits = {path = "../script_traits"}
 serde = "0.8"
 serde_derive = "0.8"
+servo_config = {path = "../config", features = ["servo"]}
+servo_geometry = {path = "../geometry", features = ["servo"]}
 servo_url = {path = "../url", features = ["servo"]}
 style_traits = {path = "../style_traits"}
 time = "0.1.17"
-util = {path = "../util"}
 
 [dependencies.webrender]
 git = "https://github.com/servo/webrender"
 default-features = false
 features = ["serde_derive"]
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use CompositionPipeline;
 use SendableFrameTree;
 use compositor_thread::{CompositorProxy, CompositorReceiver};
 use compositor_thread::{InitialCompositorState, Msg, RenderListener};
 use delayed_composition::DelayedCompositionTimerProxy;
-use euclid::{Point2D, Size2D};
+use euclid::Point2D;
 use euclid::point::TypedPoint2D;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use gfx_traits::{DevicePixel, LayerPixel, ScrollRootId};
 use gfx_traits::{Epoch, FrameTreeId, FragmentType};
 use gleam::gl;
 use gleam::gl::types::{GLint, GLsizei};
 use image::{DynamicImage, ImageFormat, RgbImage};
@@ -21,31 +21,31 @@ use msg::constellation_msg::{Key, KeyMod
 use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId, TraversalDirection};
 use net_traits::image::base::{Image, PixelFormat};
 use profile_traits::time::{self, ProfilerCategory, profile};
 use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
 use script_traits::{ConstellationMsg, LayoutControlMsg, LoadData, MouseButton};
 use script_traits::{MouseEventType, StackingContextScrollState};
 use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType};
 use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent};
+use servo_config::opts;
+use servo_config::prefs::PREFS;
+use servo_geometry::ScreenPx;
 use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::fs::File;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use std::time::{Duration, Instant};
 use style_traits::{PagePx, ViewportPx};
 use style_traits::viewport::ViewportConstraints;
 use time::{precise_time_ns, precise_time_s};
 use touch::{TouchHandler, TouchAction};
-use util::geometry::ScreenPx;
-use util::opts;
-use util::prefs::PREFS;
 use webrender;
-use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId};
+use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint};
 use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
 
 #[derive(Debug, PartialEq)]
 enum UnableToComposite {
     WindowUnprepared,
     NotReadyToPaintImage(NotReadyToPaint),
 }
 
@@ -331,21 +331,21 @@ impl webrender_traits::RenderNotifier fo
     }
 
     fn new_scroll_frame_ready(&mut self, composite_needed: bool) {
         self.compositor_proxy.send(Msg::NewScrollFrameReady(composite_needed));
     }
 
     fn pipeline_size_changed(&mut self,
                              pipeline_id: webrender_traits::PipelineId,
-                             size: Option<Size2D<f32>>) {
+                             size: Option<webrender_traits::LayoutSize>) {
         let pipeline_id = pipeline_id.from_webrender();
 
         if let Some(size) = size {
-            let msg = ConstellationMsg::FrameSize(pipeline_id, size);
+            let msg = ConstellationMsg::FrameSize(pipeline_id, size.to_untyped());
             if let Err(e) = self.constellation_chan.send(msg) {
                 warn!("Compositor resize to constellation failed ({}).", e);
             }
         }
     }
 }
 
 // Used to dispatch functions from webrender to the main thread's event loop.
@@ -768,17 +768,17 @@ impl<Window: WindowMethods> IOCompositor
         self.composition_request = CompositionRequest::DelayedComposite(timestamp);
     }
 
     fn scroll_fragment_to_point(&mut self,
                                 pipeline_id: PipelineId,
                                 scroll_root_id: ScrollRootId,
                                 point: Point2D<f32>) {
         self.webrender_api.scroll_layers_with_scroll_root_id(
-            point,
+            LayoutPoint::from_untyped(&point),
             pipeline_id.to_webrender(),
             ServoScrollRootId(scroll_root_id.0));
     }
 
     fn handle_window_message(&mut self, event: WindowEvent) {
         match event {
             WindowEvent::Idle => {}
 
@@ -1076,16 +1076,17 @@ impl<Window: WindowMethods> IOCompositor
         self.dispatch_mouse_window_event_class(MouseWindowEvent::MouseUp(button, p));
         self.dispatch_mouse_window_event_class(MouseWindowEvent::Click(button, p));
     }
 
     fn on_scroll_window_event(&mut self,
                               delta: TypedPoint2D<f32, DevicePixel>,
                               cursor: TypedPoint2D<i32, DevicePixel>) {
         let event_phase = match (self.scroll_in_progress, self.in_scroll_transaction) {
+            (false, None) => ScrollEventPhase::Start,
             (false, Some(last_scroll)) if last_scroll.elapsed() > Duration::from_millis(80) =>
                 ScrollEventPhase::Start,
             (_, _) => ScrollEventPhase::Move(self.scroll_in_progress),
         };
         self.in_scroll_transaction = Some(Instant::now());
         self.pending_scroll_zoom_events.push(ScrollZoomEvent {
             magnification: 1.0,
             delta: delta,
@@ -1129,17 +1130,20 @@ impl<Window: WindowMethods> IOCompositor
         for scroll_event in self.pending_scroll_zoom_events.drain(..) {
             let this_delta = scroll_event.delta;
             let this_cursor = scroll_event.cursor;
             if let Some(combined_event) = last_combined_event {
                 if combined_event.phase != scroll_event.phase {
                     let delta = (combined_event.delta / self.scale).to_untyped();
                     let cursor =
                         (combined_event.cursor.to_f32() / self.scale).to_untyped();
-                    self.webrender_api.scroll(delta, cursor, combined_event.phase);
+                    let delta = webrender_traits::LayerPoint::from_untyped(&delta);
+                    let location = webrender_traits::ScrollLocation::Delta(delta);
+                    let cursor = webrender_traits::WorldPoint::from_untyped(&cursor);
+                    self.webrender_api.scroll(location, cursor, combined_event.phase);
                     last_combined_event = None
                 }
             }
 
             match (&mut last_combined_event, scroll_event.phase) {
                 (last_combined_event @ &mut None, _) => {
                     *last_combined_event = Some(ScrollZoomEvent {
                         magnification: scroll_event.magnification,
@@ -1169,18 +1173,21 @@ impl<Window: WindowMethods> IOCompositor
                     last_combined_event.event_count += 1
                 }
             }
         }
 
         // TODO(gw): Support zoom (WR issue #28).
         if let Some(combined_event) = last_combined_event {
             let delta = (combined_event.delta / self.scale).to_untyped();
+            let delta = webrender_traits::LayoutPoint::from_untyped(&delta);
             let cursor = (combined_event.cursor.to_f32() / self.scale).to_untyped();
-            self.webrender_api.scroll(delta, cursor, combined_event.phase);
+            let location = webrender_traits::ScrollLocation::Delta(delta);
+            let cursor = webrender_traits::WorldPoint::from_untyped(&cursor);
+            self.webrender_api.scroll(location, cursor, combined_event.phase);
             self.waiting_for_results_of_scroll = true
         }
 
         if had_events {
             self.send_viewport_rects();
         }
     }
 
@@ -1311,17 +1318,17 @@ impl<Window: WindowMethods> IOCompositor
         }
     }
 
     fn send_viewport_rects(&self) {
         let mut stacking_context_scroll_states_per_pipeline = HashMap::new();
         for scroll_layer_state in self.webrender_api.get_scroll_layer_state() {
             let stacking_context_scroll_state = StackingContextScrollState {
                 scroll_root_id: scroll_layer_state.scroll_root_id.from_webrender(),
-                scroll_offset: scroll_layer_state.scroll_offset,
+                scroll_offset: scroll_layer_state.scroll_offset.to_untyped(),
             };
             let pipeline_id = scroll_layer_state.pipeline_id;
             stacking_context_scroll_states_per_pipeline
                 .entry(pipeline_id)
                 .or_insert(vec![])
                 .push(stacking_context_scroll_state);
         }
 
@@ -1459,17 +1466,18 @@ impl<Window: WindowMethods> IOCompositor
             CompositeTarget::Window => RenderTargetInfo::empty(),
             _ => initialize_png(width, height)
         };
 
         profile(ProfilerCategory::Compositing, None, self.time_profiler_chan.clone(), || {
             debug!("compositor: compositing");
 
             // Paint the scene.
-            self.webrender.render(self.window_size.to_untyped());
+            let size = webrender_traits::DeviceUintSize::from_untyped(&self.window_size.to_untyped());
+            self.webrender.render(size);
         });
 
         let rv = match target {
             CompositeTarget::Window => None,
             CompositeTarget::WindowAndPng => {
                 let img = self.draw_img(render_target_info,
                                         width,
                                         height);
--- a/servo/components/compositing/lib.rs
+++ b/servo/components/compositing/lib.rs
@@ -18,21 +18,21 @@ extern crate ipc_channel;
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 #[macro_use]
 extern crate profile_traits;
 extern crate script_traits;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_config;
+extern crate servo_geometry;
 extern crate servo_url;
 extern crate style_traits;
 extern crate time;
-#[macro_use]
-extern crate util;
 extern crate webrender;
 extern crate webrender_traits;
 
 pub use compositor_thread::CompositorProxy;
 pub use compositor::IOCompositor;
 use euclid::size::TypedSize2D;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
--- a/servo/components/compositing/windowing.rs
+++ b/servo/components/compositing/windowing.rs
@@ -8,20 +8,20 @@ use compositor_thread::{CompositorProxy,
 use euclid::{Point2D, Size2D};
 use euclid::point::TypedPoint2D;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use gfx_traits::DevicePixel;
 use msg::constellation_msg::{Key, KeyModifiers, KeyState};
 use net_traits::net_error_list::NetError;
 use script_traits::{MouseButton, TouchEventType, TouchId, TouchpadPressurePhase};
+use servo_geometry::ScreenPx;
 use servo_url::ServoUrl;
 use std::fmt::{Debug, Error, Formatter};
 use style_traits::cursor::Cursor;
-use util::geometry::ScreenPx;
 
 #[derive(Clone)]
 pub enum MouseWindowEvent {
     Click(MouseButton, TypedPoint2D<f32, DevicePixel>),
     MouseDown(MouseButton, TypedPoint2D<f32, DevicePixel>),
     MouseUp(MouseButton, TypedPoint2D<f32, DevicePixel>),
 }
 
new file mode 100644
--- /dev/null
+++ b/servo/components/config/Cargo.toml
@@ -0,0 +1,35 @@
+[package]
+name = "servo_config"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+publish = false
+
+[lib]
+name = "servo_config"
+path = "lib.rs"
+
+[features]
+# servo as opposed to geckolib
+servo = ["serde", "serde_derive", "url/heap_size", "url/serde", "plugins"]
+
+[dependencies]
+bitflags = "0.7"
+euclid = "0.10.1"
+getopts = "0.2.11"
+lazy_static = "0.2"
+log = "0.3.5"
+num_cpus = "1.1.0"
+rustc-serialize = "0.3"
+serde = {version = "0.8", optional = true}
+serde_derive = {version = "0.8", optional = true}
+servo_geometry = {path = "../geometry"}
+servo_url = {path = "../url"}
+plugins = {path = "../plugins", optional = true}
+url = "1.2"
+
+[dev-dependencies]
+env_logger = "0.3"
+
+[target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))'.dependencies]
+xdg = "2.0"
rename from servo/components/util/basedir.rs
rename to servo/components/config/basedir.rs
new file mode 100644
--- /dev/null
+++ b/servo/components/config/lib.rs
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#![cfg_attr(feature = "servo", feature(plugin))]
+#![cfg_attr(feature = "servo", feature(proc_macro))]
+#![cfg_attr(feature = "servo", plugin(plugins))]
+
+#![deny(unsafe_code)]
+
+#[allow(unused_extern_crates)] #[macro_use] extern crate bitflags;
+extern crate core;
+extern crate euclid;
+extern crate getopts;
+#[allow(unused_extern_crates)] #[macro_use] extern crate lazy_static;
+#[macro_use] extern crate log;
+extern crate num_cpus;
+extern crate rustc_serialize;
+#[cfg(feature = "servo")] extern crate serde;
+#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
+extern crate servo_geometry;
+extern crate servo_url;
+extern crate url;
+#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
+extern crate xdg;
+
+pub mod basedir;
+#[allow(unsafe_code)] pub mod opts;
+pub mod prefs;
+pub mod resource_files;
+
+pub fn servo_version() -> String {
+    let cargo_version = env!("CARGO_PKG_VERSION");
+    let git_info = option_env!("GIT_INFO");
+    match git_info {
+        Some(info) => format!("Servo {}{}", cargo_version, info),
+        None => format!("Servo {}", cargo_version),
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/config/opts.rs
@@ -0,0 +1,958 @@
+/* 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/. */
+
+//! Configuration options for a single run of the servo application. Created
+//! from command line arguments.
+
+use euclid::size::TypedSize2D;
+use getopts::Options;
+use num_cpus;
+use prefs::{self, PrefValue, PREFS};
+use resource_files::set_resources_path;
+use servo_geometry::ScreenPx;
+use servo_url::ServoUrl;
+use std::borrow::Cow;
+use std::cmp;
+use std::default::Default;
+use std::env;
+use std::fs::{self, File};
+use std::io::{self, Read, Write};
+use std::path::{Path, PathBuf};
+use std::process;
+use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+use url::{self, Url};
+
+
+/// Global flags for Servo, currently set on the command line.
+#[derive(Clone)]
+#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
+pub struct Opts {
+    pub is_running_problem_test: bool,
+
+    /// The initial URL to load.
+    pub url: Option<ServoUrl>,
+
+    /// How many threads to use for CPU painting (`-t`).
+    ///
+    /// Note that painting is sequentialized when using GPU painting.
+    pub paint_threads: usize,
+
+    /// The maximum size of each tile in pixels (`-s`).
+    pub tile_size: usize,
+
+    /// The ratio of device pixels per px at the default scale. If unspecified, will use the
+    /// platform default setting.
+    pub device_pixels_per_px: Option<f32>,
+
+    /// `None` to disable the time profiler or `Some` with an interval in seconds to enable it and
+    /// cause it to produce output on that interval (`-p`).
+    pub time_profiling: Option<OutputOptions>,
+
+    /// When the profiler is enabled, this is an optional path to dump a self-contained HTML file
+    /// visualizing the traces as a timeline.
+    pub time_profiler_trace_path: Option<String>,
+
+    /// `None` to disable the memory profiler or `Some` with an interval in seconds to enable it
+    /// and cause it to produce output on that interval (`-m`).
+    pub mem_profiler_period: Option<f64>,
+
+    pub nonincremental_layout: bool,
+
+    /// Where to load userscripts from, if any. An empty string will load from
+    /// the resources/user-agent-js directory, and if the option isn't passed userscripts
+    /// won't be loaded
+    pub userscripts: Option<String>,
+
+    pub user_stylesheets: Vec<(Vec<u8>, ServoUrl)>,
+
+    pub output_file: Option<String>,
+
+    /// Replace unpaires surrogates in DOM strings with U+FFFD.
+    /// See https://github.com/servo/servo/issues/6564
+    pub replace_surrogates: bool,
+
+    /// Log GC passes and their durations.
+    pub gc_profile: bool,
+
+    /// Load web fonts synchronously to avoid non-deterministic network-driven reflows.
+    pub load_webfonts_synchronously: bool,
+
+    pub headless: bool,
+    pub hard_fail: bool,
+
+    /// True if we should bubble intrinsic widths sequentially (`-b`). If this is true, then
+    /// intrinsic widths are computed as a separate pass instead of during flow construction. You
+    /// may wish to turn this flag on in order to benchmark style recalculation against other
+    /// browser engines.
+    pub bubble_inline_sizes_separately: bool,
+
+    /// True if we should show borders on all layers and tiles for
+    /// debugging purposes (`--show-debug-borders`).
+    pub show_debug_borders: bool,
+
+    /// True if we should show borders on all fragments for debugging purposes
+    /// (`--show-debug-fragment-borders`).
+    pub show_debug_fragment_borders: bool,
+
+    /// True if we should paint tiles with overlays based on which thread painted them.
+    pub show_debug_parallel_paint: bool,
+
+    /// True if we should paint borders around flows based on which thread painted them.
+    pub show_debug_parallel_layout: bool,
+
+    /// True if we should paint tiles a random color whenever they're repainted. Useful for
+    /// debugging invalidation.
+    pub paint_flashing: bool,
+
+    /// If set with --disable-text-aa, disable antialiasing on fonts. This is primarily useful for reftests
+    /// where pixel perfect results are required when using fonts such as the Ahem
+    /// font for layout tests.
+    pub enable_text_antialiasing: bool,
+
+    /// If set with --enable-subpixel, use subpixel antialiasing for glyphs. In the future
+    /// this will likely become the default, but for now it's opt-in while we work
+    /// out any bugs and improve the implementation.
+    pub enable_subpixel_text_antialiasing: bool,
+
+    /// If set with --disable-canvas-aa, disable antialiasing on the HTML canvas element.
+    /// Like --disable-text-aa, this is useful for reftests where pixel perfect results are required.
+    pub enable_canvas_antialiasing: bool,
+
+    /// True if each step of layout is traced to an external JSON file
+    /// for debugging purposes. Settings this implies sequential layout
+    /// and paint.
+    pub trace_layout: bool,
+
+    /// Periodically print out on which events script threads spend their processing time.
+    pub profile_script_events: bool,
+
+    /// Enable all heartbeats for profiling.
+    pub profile_heartbeats: bool,
+
+    /// `None` to disable debugger or `Some` with a port number to start a server to listen to
+    /// remote Firefox debugger connections.
+    pub debugger_port: Option<u16>,
+
+    /// `None` to disable devtools or `Some` with a port number to start a server to listen to
+    /// remote Firefox devtools connections.
+    pub devtools_port: Option<u16>,
+
+    /// `None` to disable WebDriver or `Some` with a port number to start a server to listen to
+    /// remote WebDriver commands.
+    pub webdriver_port: Option<u16>,
+
+    /// The initial requested size of the window.
+    pub initial_window_size: TypedSize2D<u32, ScreenPx>,
+
+    /// An optional string allowing the user agent to be set for testing.
+    pub user_agent: Cow<'static, str>,
+
+    /// Whether we're running in multiprocess mode.
+    pub multiprocess: bool,
+
+    /// Whether we're running inside the sandbox.
+    pub sandbox: bool,
+
+    /// Probability of randomly closing a pipeline,
+    /// used for testing the hardening of the constellation.
+    pub random_pipeline_closure_probability: Option<f32>,
+
+    /// The seed for the RNG used to randomly close pipelines,
+    /// used for testing the hardening of the constellation.
+    pub random_pipeline_closure_seed: Option<usize>,
+
+    /// Dumps the DOM after restyle.
+    pub dump_style_tree: bool,
+
+    /// Dumps the rule tree.
+    pub dump_rule_tree: bool,
+
+    /// Dumps the flow tree after a layout.
+    pub dump_flow_tree: bool,
+
+    /// Dumps the display list after a layout.
+    pub dump_display_list: bool,
+
+    /// Dumps the display list in JSON form after a layout.
+    pub dump_display_list_json: bool,
+
+    /// Dumps the layer tree when it changes.
+    pub dump_layer_tree: bool,
+
+    /// Emits notifications when there is a relayout.
+    pub relayout_event: bool,
+
+    /// Whether Style Sharing Cache is used
+    pub disable_share_style_cache: bool,
+
+    /// Whether to show in stdout style sharing cache stats after a restyle.
+    pub style_sharing_stats: bool,
+
+    /// Translate mouse input into touch events.
+    pub convert_mouse_to_touch: bool,
+
+    /// True to exit after the page load (`-x`).
+    pub exit_after_load: bool,
+
+    /// Do not use native titlebar
+    pub no_native_titlebar: bool,
+
+    /// Enable vsync in the compositor
+    pub enable_vsync: bool,
+
+    /// True to show webrender profiling stats on screen.
+    pub webrender_stats: bool,
+
+    /// True to show webrender debug on screen.
+    pub webrender_debug: bool,
+
+    /// True if webrender recording should be enabled.
+    pub webrender_record: bool,
+
+    /// True to compile all webrender shaders at init time. This is mostly
+    /// useful when modifying the shaders, to ensure they all compile
+    /// after each change is made.
+    pub precache_shaders: bool,
+
+    /// True if WebRender should use multisample antialiasing.
+    pub use_msaa: bool,
+
+    /// Directory for a default config directory
+    pub config_dir: Option<PathBuf>,
+
+    // don't skip any backtraces on panic
+    pub full_backtraces: bool,
+
+    /// True to use OS native signposting facilities. This makes profiling events (script activity,
+    /// reflow, compositing, etc.) appear in Instruments.app on macOS.
+    pub signpost: bool,
+
+    /// Print the version and exit.
+    pub is_printing_version: bool,
+}
+
+fn print_usage(app: &str, opts: &Options) {
+    let message = format!("Usage: {} [ options ... ] [URL]\n\twhere options include", app);
+    println!("{}", opts.usage(&message));
+}
+
+
+/// Debug options for Servo, currently set on the command line with -Z
+#[derive(Default)]
+pub struct DebugOptions {
+    /// List all the debug options.
+    pub help: bool,
+
+    /// Bubble intrinsic widths separately like other engines.
+    pub bubble_widths: bool,
+
+    /// Disable antialiasing of rendered text.
+    pub disable_text_aa: bool,
+
+    /// Enable subpixel antialiasing of rendered text.
+    pub enable_subpixel_aa: bool,
+
+    /// Disable antialiasing of rendered text on the HTML canvas element.
+    pub disable_canvas_aa: bool,
+
+    /// Print the DOM after each restyle.
+    pub dump_style_tree: bool,
+
+    /// Dumps the rule tree.
+    pub dump_rule_tree: bool,
+
+    /// Print the flow tree after each layout.
+    pub dump_flow_tree: bool,
+
+    /// Print the display list after each layout.
+    pub dump_display_list: bool,
+
+    /// Print the display list in JSON form.
+    pub dump_display_list_json: bool,
+
+    /// Print the layer tree whenever it changes.
+    pub dump_layer_tree: bool,
+
+    /// Print notifications when there is a relayout.
+    pub relayout_event: bool,
+
+    /// Profile which events script threads spend their time on.
+    pub profile_script_events: bool,
+
+    /// Enable all heartbeats for profiling.
+    pub profile_heartbeats: bool,
+
+    /// Paint borders along layer and tile boundaries.
+    pub show_compositor_borders: bool,
+
+    /// Paint borders along fragment boundaries.
+    pub show_fragment_borders: bool,
+
+    /// Overlay tiles with colors showing which thread painted them.
+    pub show_parallel_paint: bool,
+
+    /// Mark which thread laid each flow out with colors.
+    pub show_parallel_layout: bool,
+
+    /// Overlay repainted areas with a random color.
+    pub paint_flashing: bool,
+
+    /// Write layout trace to an external file for debugging.
+    pub trace_layout: bool,
+
+    /// Disable the style sharing cache.
+    pub disable_share_style_cache: bool,
+
+    /// Whether to show in stdout style sharing cache stats after a restyle.
+    pub style_sharing_stats: bool,
+
+    /// Translate mouse input into touch events.
+    pub convert_mouse_to_touch: bool,
+
+    /// Replace unpaires surrogates in DOM strings with U+FFFD.
+    /// See https://github.com/servo/servo/issues/6564
+    pub replace_surrogates: bool,
+
+    /// Log GC passes and their durations.
+    pub gc_profile: bool,
+
+    /// Load web fonts synchronously to avoid non-deterministic network-driven reflows.
+    pub load_webfonts_synchronously: bool,
+
+    /// Disable vsync in the compositor
+    pub disable_vsync: bool,
+
+    /// Show webrender profiling stats on screen.
+    pub webrender_stats: bool,
+
+    /// Show webrender debug on screen.
+    pub webrender_debug: bool,
+
+    /// Enable webrender recording.
+    pub webrender_record: bool,
+
+    /// Use multisample antialiasing in WebRender.
+    pub use_msaa: bool,
+
+    // don't skip any backtraces on panic
+    pub full_backtraces: bool,
+
+    /// True to compile all webrender shaders at init time. This is mostly
+    /// useful when modifying the shaders, to ensure they all compile
+    /// after each change is made.
+    pub precache_shaders: bool,
+
+    /// True to use OS native signposting facilities. This makes profiling events (script activity,
+    /// reflow, compositing, etc.) appear in Instruments.app on macOS.
+    pub signpost: bool,
+}
+
+
+impl DebugOptions {
+    pub fn extend(&mut self, debug_string: String) -> Result<(), String> {
+        for option in debug_string.split(',') {
+            match option {
+                "help" => self.help = true,
+                "bubble-widths" => self.bubble_widths = true,
+                "disable-text-aa" => self.disable_text_aa = true,
+                "enable-subpixel-aa" => self.enable_subpixel_aa = true,
+                "disable-canvas-aa" => self.disable_text_aa = true,
+                "dump-style-tree" => self.dump_style_tree = true,
+                "dump-rule-tree" => self.dump_rule_tree = true,
+                "dump-flow-tree" => self.dump_flow_tree = true,
+                "dump-display-list" => self.dump_display_list = true,
+                "dump-display-list-json" => self.dump_display_list_json = true,
+                "dump-layer-tree" => self.dump_layer_tree = true,
+                "relayout-event" => self.relayout_event = true,
+                "profile-script-events" => self.profile_script_events = true,
+                "profile-heartbeats" => self.profile_heartbeats = true,
+                "show-compositor-borders" => self.show_compositor_borders = true,
+                "show-fragment-borders" => self.show_fragment_borders = true,
+                "show-parallel-paint" => self.show_parallel_paint = true,
+                "show-parallel-layout" => self.show_parallel_layout = true,
+                "paint-flashing" => self.paint_flashing = true,
+                "trace-layout" => self.trace_layout = true,
+                "disable-share-style-cache" => self.disable_share_style_cache = true,
+                "style-sharing-stats" => self.style_sharing_stats = true,
+                "convert-mouse-to-touch" => self.convert_mouse_to_touch = true,
+                "replace-surrogates" => self.replace_surrogates = true,
+                "gc-profile" => self.gc_profile = true,
+                "load-webfonts-synchronously" => self.load_webfonts_synchronously = true,
+                "disable-vsync" => self.disable_vsync = true,
+                "wr-stats" => self.webrender_stats = true,
+                "wr-debug" => self.webrender_debug = true,
+                "wr-record" => self.webrender_record = true,
+                "msaa" => self.use_msaa = true,
+                "full-backtraces" => self.full_backtraces = true,
+                "precache-shaders" => self.precache_shaders = true,
+                "signpost" => self.signpost = true,
+                "" => {},
+                _ => return Err(String::from(option)),
+            };
+        };
+        Ok(())
+    }
+}
+
+
+fn print_debug_usage(app: &str) -> ! {
+    fn print_option(name: &str, description: &str) {
+        println!("\t{:<35} {}", name, description);
+    }
+
+    println!("Usage: {} debug option,[options,...]\n\twhere options include\n\nOptions:", app);
+
+    print_option("bubble-widths", "Bubble intrinsic widths separately like other engines.");
+    print_option("disable-text-aa", "Disable antialiasing of rendered text.");
+    print_option("disable-canvas-aa", "Disable antialiasing on the HTML canvas element.");
+    print_option("dump-style-tree", "Print the DOM with computed styles after each restyle.");
+    print_option("dump-flow-tree", "Print the flow tree after each layout.");
+    print_option("dump-display-list", "Print the display list after each layout.");
+    print_option("dump-display-list-json", "Print the display list in JSON form.");
+    print_option("dump-layer-tree", "Print the layer tree whenever it changes.");
+    print_option("relayout-event", "Print notifications when there is a relayout.");
+    print_option("profile-script-events", "Enable profiling of script-related events.");
+    print_option("profile-heartbeats", "Enable heartbeats for all thread categories.");
+    print_option("show-compositor-borders", "Paint borders along layer and tile boundaries.");
+    print_option("show-fragment-borders", "Paint borders along fragment boundaries.");
+    print_option("show-parallel-paint", "Overlay tiles with colors showing which thread painted them.");
+    print_option("show-parallel-layout", "Mark which thread laid each flow out with colors.");
+    print_option("paint-flashing", "Overlay repainted areas with a random color.");
+    print_option("trace-layout", "Write layout trace to an external file for debugging.");
+    print_option("disable-share-style-cache",
+                 "Disable the style sharing cache.");
+    print_option("parallel-display-list-building", "Build display lists in parallel.");
+    print_option("convert-mouse-to-touch", "Send touch events instead of mouse events");
+    print_option("replace-surrogates", "Replace unpaires surrogates in DOM strings with U+FFFD. \
+                                        See https://github.com/servo/servo/issues/6564");
+    print_option("gc-profile", "Log GC passes and their durations.");
+    print_option("load-webfonts-synchronously",
+                 "Load web fonts synchronously to avoid non-deterministic network-driven reflows");
+    print_option("disable-vsync",
+                 "Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate");
+    print_option("wr-stats", "Show WebRender profiler on screen.");
+    print_option("msaa", "Use multisample antialiasing in WebRender.");
+    print_option("full-backtraces", "Print full backtraces for all errors");
+    print_option("wr-debug", "Display webrender tile borders. Must be used with -w option.");
+    print_option("precache-shaders", "Compile all shaders during init. Must be used with -w option.");
+    print_option("signpost", "Emit native OS signposts for profile events (currently macOS only)");
+
+    println!("");
+
+    process::exit(0)
+}
+
+#[derive(Clone)]
+#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
+pub enum OutputOptions {
+    FileName(String),
+    Stdout(f64)
+}
+
+fn args_fail(msg: &str) -> ! {
+    writeln!(io::stderr(), "{}", msg).unwrap();
+    process::exit(1)
+}
+
+static MULTIPROCESS: AtomicBool = ATOMIC_BOOL_INIT;
+
+#[inline]
+pub fn multiprocess() -> bool {
+    MULTIPROCESS.load(Ordering::Relaxed)
+}
+
+enum UserAgent {
+    Desktop,
+    Android,
+}
+
+fn default_user_agent_string(agent: UserAgent) -> &'static str {
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    const DESKTOP_UA_STRING: &'static str =
+        "Mozilla/5.0 (X11; Linux x86_64; rv:37.0) Servo/1.0 Firefox/37.0";
+    #[cfg(all(target_os = "linux", not(target_arch = "x86_64")))]
+    const DESKTOP_UA_STRING: &'static str =
+        "Mozilla/5.0 (X11; Linux i686; rv:37.0) Servo/1.0 Firefox/37.0";
+
+    #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
+    const DESKTOP_UA_STRING: &'static str =
+        "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:37.0) Servo/1.0 Firefox/37.0";
+    #[cfg(all(target_os = "windows", not(target_arch = "x86_64")))]
+    const DESKTOP_UA_STRING: &'static str =
+        "Mozilla/5.0 (Windows NT 6.1; rv:37.0) Servo/1.0 Firefox/37.0";
+
+    #[cfg(not(any(target_os = "linux", target_os = "windows")))]
+    // Neither Linux nor Windows, so maybe OS X, and if not then OS X is an okay fallback.
+    const DESKTOP_UA_STRING: &'static str =
+        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:37.0) Servo/1.0 Firefox/37.0";
+
+
+    match agent {
+        UserAgent::Desktop => {
+            DESKTOP_UA_STRING
+        }
+        UserAgent::Android => {
+            "Mozilla/5.0 (Android; Mobile; rv:37.0) Servo/1.0 Firefox/37.0"
+        }
+    }
+}
+
+#[cfg(target_os = "android")]
+const DEFAULT_USER_AGENT: UserAgent = UserAgent::Android;
+
+#[cfg(not(target_os = "android"))]
+const DEFAULT_USER_AGENT: UserAgent = UserAgent::Desktop;
+
+pub fn default_opts() -> Opts {
+    Opts {
+        is_running_problem_test: false,
+        url: Some(ServoUrl::parse("about:blank").unwrap()),
+        paint_threads: 1,
+        tile_size: 512,
+        device_pixels_per_px: None,
+        time_profiling: None,
+        time_profiler_trace_path: None,
+        mem_profiler_period: None,
+        nonincremental_layout: false,
+        userscripts: None,
+        user_stylesheets: Vec::new(),
+        output_file: None,
+        replace_surrogates: false,
+        gc_profile: false,
+        load_webfonts_synchronously: false,
+        headless: true,
+        hard_fail: true,
+        bubble_inline_sizes_separately: false,
+        show_debug_borders: false,
+        show_debug_fragment_borders: false,
+        show_debug_parallel_paint: false,
+        show_debug_parallel_layout: false,
+        paint_flashing: false,
+        enable_text_antialiasing: false,
+        enable_subpixel_text_antialiasing: false,
+        enable_canvas_antialiasing: false,
+        trace_layout: false,
+        debugger_port: None,
+        devtools_port: None,
+        webdriver_port: None,
+        initial_window_size: TypedSize2D::new(1024, 740),
+        user_agent: default_user_agent_string(DEFAULT_USER_AGENT).into(),
+        multiprocess: false,
+        random_pipeline_closure_probability: None,
+        random_pipeline_closure_seed: None,
+        sandbox: false,
+        dump_style_tree: false,
+        dump_rule_tree: false,
+        dump_flow_tree: false,
+        dump_display_list: false,
+        dump_display_list_json: false,
+        dump_layer_tree: false,
+        relayout_event: false,
+        profile_script_events: false,
+        profile_heartbeats: false,
+        disable_share_style_cache: false,
+        style_sharing_stats: false,
+        convert_mouse_to_touch: false,
+        exit_after_load: false,
+        no_native_titlebar: false,
+        enable_vsync: true,
+        webrender_stats: false,
+        use_msaa: false,
+        config_dir: None,
+        full_backtraces: false,
+        is_printing_version: false,
+        webrender_debug: false,
+        webrender_record: false,
+        precache_shaders: false,
+        signpost: false,
+    }
+}
+
+pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
+    let (app_name, args) = args.split_first().unwrap();
+
+    let mut opts = Options::new();
+    opts.optflag("c", "cpu", "CPU painting");
+    opts.optflag("g", "gpu", "GPU painting");
+    opts.optopt("o", "output", "Output file", "output.png");
+    opts.optopt("s", "size", "Size of tiles", "512");
+    opts.optopt("", "device-pixel-ratio", "Device pixels per px", "");
+    opts.optopt("t", "threads", "Number of paint threads", "1");
+    opts.optflagopt("p", "profile", "Time profiler flag and either a TSV output filename \
+        OR an interval for output to Stdout (blank for Stdout with interval of 5s)", "10 \
+        OR time.tsv");
+    opts.optflagopt("", "profiler-trace-path",
+                    "Path to dump a self-contained HTML timeline of profiler traces",
+                    "");
+    opts.optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10");
+    opts.optflag("x", "exit", "Exit after load flag");
+    opts.optopt("y", "layout-threads", "Number of threads to use for layout", "1");
+    opts.optflag("i", "nonincremental-layout", "Enable to turn off incremental layout.");
+    opts.optflagopt("", "userscripts",
+                    "Uses userscripts in resources/user-agent-js, or a specified full path", "");
+    opts.optmulti("", "user-stylesheet",
+                  "A user stylesheet to be added to every document", "file.css");
+    opts.optflag("z", "headless", "Headless mode");
+    opts.optflag("f", "hard-fail", "Exit on thread failure instead of displaying about:failure");
+    opts.optflag("F", "soft-fail", "Display about:failure on thread failure instead of exiting");
+    opts.optflagopt("", "remote-debugging-port", "Start remote debugger server on port", "2794");
+    opts.optflagopt("", "devtools", "Start remote devtools server on port", "6000");
+    opts.optflagopt("", "webdriver", "Start remote WebDriver server on port", "7000");
+    opts.optopt("", "resolution", "Set window resolution.", "1024x740");
+    opts.optopt("u",
+                "user-agent",
+                "Set custom user agent string (or android / desktop for platform default)",
+                "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)");
+    opts.optflag("M", "multiprocess", "Run in multiprocess mode");
+    opts.optflag("S", "sandbox", "Run in a sandbox if multiprocess");
+    opts.optopt("",
+                "random-pipeline-closure-probability",
+                "Probability of randomly closing a pipeline (for testing constellation hardening).",
+                "0.0");
+    opts.optopt("", "random-pipeline-closure-seed", "A fixed seed for repeatbility of random pipeline closure.", "");
+    opts.optmulti("Z", "debug",
+                  "A comma-separated string of debug options. Pass help to show available options.", "");
+    opts.optflag("h", "help", "Print this message");
+    opts.optopt("", "resources-path", "Path to find static resources", "/home/servo/resources");
+    opts.optopt("", "content-process" , "Run as a content process and connect to the given pipe",
+                "servo-ipc-channel.abcdefg");
+    opts.optmulti("", "pref",
+                  "A preference to set to enable", "dom.mozbrowser.enabled");
+    opts.optflag("b", "no-native-titlebar", "Do not use native titlebar");
+    opts.optflag("w", "webrender", "Use webrender backend");
+    opts.optopt("G", "graphics", "Select graphics backend (gl or es2)", "gl");
+    opts.optopt("", "config-dir",
+                    "config directory following xdg spec on linux platform", "");
+    opts.optflag("v", "version", "Display servo version information");
+
+    let opt_match = match opts.parse(args) {
+        Ok(m) => m,
+        Err(f) => args_fail(&f.to_string()),
+    };
+
+    set_resources_path(opt_match.opt_str("resources-path"));
+
+    if opt_match.opt_present("h") || opt_match.opt_present("help") {
+        print_usage(app_name, &opts);
+        process::exit(0);
+    };
+
+    // If this is the content process, we'll receive the real options over IPC. So just fill in
+    // some dummy options for now.
+    if let Some(content_process) = opt_match.opt_str("content-process") {
+        MULTIPROCESS.store(true, Ordering::SeqCst);
+        return ArgumentParsingResult::ContentProcess(content_process);
+    }
+
+    let mut debug_options = DebugOptions::default();
+
+    for debug_string in opt_match.opt_strs("Z") {
+        if let Err(e) = debug_options.extend(debug_string) {
+            args_fail(&format!("error: unrecognized debug option: {}", e));
+        }
+    }
+
+    if debug_options.help {
+        print_debug_usage(app_name)
+    }
+
+    let cwd = env::current_dir().unwrap();
+    let homepage_pref = PREFS.get("shell.homepage");
+    let url_opt = if !opt_match.free.is_empty() {
+        Some(&opt_match.free[0][..])
+    } else {
+        homepage_pref.as_string()
+    };
+    let is_running_problem_test =
+        url_opt
+        .as_ref()
+        .map_or(false, |url|
+             url.starts_with("http://web-platform.test:8000/2dcontext/drawing-images-to-the-canvas/") ||
+             url.starts_with("http://web-platform.test:8000/_mozilla/mozilla/canvas/") ||
+             url.starts_with("http://web-platform.test:8000/_mozilla/css/canvas_over_area.html"));
+
+    let url = match url_opt {
+        Some(url_string) => {
+            parse_url_or_filename(&cwd, url_string)
+                .unwrap_or_else(|()| args_fail("URL parsing failed"))
+        },
+        None => {
+            print_usage(app_name, &opts);
+            args_fail("servo asks that you provide a URL")
+        }
+    };
+
+    let tile_size: usize = match opt_match.opt_str("s") {
+        Some(tile_size_str) => tile_size_str.parse()
+            .unwrap_or_else(|err| args_fail(&format!("Error parsing option: -s ({})", err))),
+        None => 512,
+    };
+
+    let device_pixels_per_px = opt_match.opt_str("device-pixel-ratio").map(|dppx_str|
+        dppx_str.parse()
+            .unwrap_or_else(|err| args_fail(&format!("Error parsing option: --device-pixel-ratio ({})", err)))
+    );
+
+    let mut paint_threads: usize = match opt_match.opt_str("t") {
+        Some(paint_threads_str) => paint_threads_str.parse()
+            .unwrap_or_else(|err| args_fail(&format!("Error parsing option: -t ({})", err))),
+        None => cmp::max(num_cpus::get() * 3 / 4, 1),
+    };
+
+    // If only the flag is present, default to a 5 second period for both profilers
+    let time_profiling = if opt_match.opt_present("p") {
+        match opt_match.opt_str("p") {
+            Some(argument) => match argument.parse::<f64>() {
+                Ok(interval) => Some(OutputOptions::Stdout(interval)) ,
+                Err(_) => Some(OutputOptions::FileName(argument)),
+            },
+            None => Some(OutputOptions::Stdout(5.0 as f64)),
+        }
+    } else {
+        // if the p option doesn't exist:
+        None
+    };
+
+    if let Some(ref time_profiler_trace_path) = opt_match.opt_str("profiler-trace-path") {
+        let mut path = PathBuf::from(time_profiler_trace_path);
+        path.pop();
+        if let Err(why) = fs::create_dir_all(&path) {
+            error!("Couldn't create/open {:?}: {:?}",
+                Path::new(time_profiler_trace_path).to_string_lossy(), why);
+        }
+    }
+
+    let mem_profiler_period = opt_match.opt_default("m", "5").map(|period| {
+        period.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: -m ({})", err)))
+    });
+
+    let mut layout_threads: Option<usize> = opt_match.opt_str("y")
+        .map(|layout_threads_str| {
+            layout_threads_str.parse()
+                .unwrap_or_else(|err| args_fail(&format!("Error parsing option: -y ({})", err)))
+        });
+
+    let nonincremental_layout = opt_match.opt_present("i");
+
+    let random_pipeline_closure_probability = opt_match.opt_str("random-pipeline-closure-probability").map(|prob|
+        prob.parse().unwrap_or_else(|err| {
+            args_fail(&format!("Error parsing option: --random-pipeline-closure-probability ({})", err))
+        })
+    );
+
+    let random_pipeline_closure_seed = opt_match.opt_str("random-pipeline-closure-seed").map(|seed|
+        seed.parse().unwrap_or_else(|err| {
+            args_fail(&format!("Error parsing option: --random-pipeline-closure-seed ({})", err))
+        })
+    );
+
+    let mut bubble_inline_sizes_separately = debug_options.bubble_widths;
+    if debug_options.trace_layout {
+        paint_threads = 1;
+        layout_threads = Some(1);
+        bubble_inline_sizes_separately = true;
+    }
+
+    let debugger_port = opt_match.opt_default("remote-debugging-port", "2794").map(|port| {
+        port.parse()
+            .unwrap_or_else(|err| args_fail(&format!("Error parsing option: --remote-debugging-port ({})", err)))
+    });
+
+    let devtools_port = opt_match.opt_default("devtools", "6000").map(|port| {
+        port.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --devtools ({})", err)))
+    });
+
+    let webdriver_port = opt_match.opt_default("webdriver", "7000").map(|port| {
+        port.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --webdriver ({})", err)))
+    });
+
+    let initial_window_size = match opt_match.opt_str("resolution") {
+        Some(res_string) => {
+            let res: Vec<u32> = res_string.split('x').map(|r| {
+                r.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --resolution ({})", err)))
+            }).collect();
+            TypedSize2D::new(res[0], res[1])
+        }
+        None => {
+            TypedSize2D::new(1024, 740)
+        }
+    };
+
+    if opt_match.opt_present("M") {
+        MULTIPROCESS.store(true, Ordering::SeqCst)
+    }
+
+    let user_agent = match opt_match.opt_str("u") {
+        Some(ref ua) if ua == "android" => default_user_agent_string(UserAgent::Android).into(),
+        Some(ref ua) if ua == "desktop" => default_user_agent_string(UserAgent::Desktop).into(),
+        Some(ua) => ua.into(),
+        None => default_user_agent_string(DEFAULT_USER_AGENT).into(),
+    };
+
+    let user_stylesheets = opt_match.opt_strs("user-stylesheet").iter().map(|filename| {
+        let path = cwd.join(filename);
+        let url = ServoUrl::from_url(Url::from_file_path(&path).unwrap());
+        let mut contents = Vec::new();
+        File::open(path)
+            .unwrap_or_else(|err| args_fail(&format!("Couldn't open {}: {}", filename, err)))
+            .read_to_end(&mut contents)
+            .unwrap_or_else(|err| args_fail(&format!("Couldn't read {}: {}", filename, err)));
+        (contents, url)
+    }).collect();
+
+    let do_not_use_native_titlebar =
+        opt_match.opt_present("b") ||
+        !PREFS.get("shell.native-titlebar.enabled").as_boolean().unwrap();
+
+    let is_printing_version = opt_match.opt_present("v") || opt_match.opt_present("version");
+
+    let opts = Opts {
+        is_running_problem_test: is_running_problem_test,
+        url: Some(url),
+        paint_threads: paint_threads,
+        tile_size: tile_size,
+        device_pixels_per_px: device_pixels_per_px,
+        time_profiling: time_profiling,
+        time_profiler_trace_path: opt_match.opt_str("profiler-trace-path"),
+        mem_profiler_period: mem_profiler_period,
+        nonincremental_layout: nonincremental_layout,
+        userscripts: opt_match.opt_default("userscripts", ""),
+        user_stylesheets: user_stylesheets,
+        output_file: opt_match.opt_str("o"),
+        replace_surrogates: debug_options.replace_surrogates,
+        gc_profile: debug_options.gc_profile,
+        load_webfonts_synchronously: debug_options.load_webfonts_synchronously,
+        headless: opt_match.opt_present("z"),
+        hard_fail: opt_match.opt_present("f") && !opt_match.opt_present("F"),
+        bubble_inline_sizes_separately: bubble_inline_sizes_separately,
+        profile_script_events: debug_options.profile_script_events,
+        profile_heartbeats: debug_options.profile_heartbeats,
+        trace_layout: debug_options.trace_layout,
+        debugger_port: debugger_port,
+        devtools_port: devtools_port,
+        webdriver_port: webdriver_port,
+        initial_window_size: initial_window_size,
+        user_agent: user_agent,
+        multiprocess: opt_match.opt_present("M"),
+        sandbox: opt_match.opt_present("S"),
+        random_pipeline_closure_probability: random_pipeline_closure_probability,
+        random_pipeline_closure_seed: random_pipeline_closure_seed,
+        show_debug_borders: debug_options.show_compositor_borders,
+        show_debug_fragment_borders: debug_options.show_fragment_borders,
+        show_debug_parallel_paint: debug_options.show_parallel_paint,
+        show_debug_parallel_layout: debug_options.show_parallel_layout,
+        paint_flashing: debug_options.paint_flashing,
+        enable_text_antialiasing: !debug_options.disable_text_aa,
+        enable_subpixel_text_antialiasing: debug_options.enable_subpixel_aa,
+        enable_canvas_antialiasing: !debug_options.disable_canvas_aa,
+        dump_style_tree: debug_options.dump_style_tree,
+        dump_rule_tree: debug_options.dump_rule_tree,
+        dump_flow_tree: debug_options.dump_flow_tree,
+        dump_display_list: debug_options.dump_display_list,
+        dump_display_list_json: debug_options.dump_display_list_json,
+        dump_layer_tree: debug_options.dump_layer_tree,
+        relayout_event: debug_options.relayout_event,
+        disable_share_style_cache: debug_options.disable_share_style_cache,
+        style_sharing_stats: debug_options.style_sharing_stats,
+        convert_mouse_to_touch: debug_options.convert_mouse_to_touch,
+        exit_after_load: opt_match.opt_present("x"),
+        no_native_titlebar: do_not_use_native_titlebar,
+        enable_vsync: !debug_options.disable_vsync,
+        webrender_stats: debug_options.webrender_stats,
+        use_msaa: debug_options.use_msaa,
+        config_dir: opt_match.opt_str("config-dir").map(Into::into),
+        full_backtraces: debug_options.full_backtraces,
+        is_printing_version: is_printing_version,
+        webrender_debug: debug_options.webrender_debug,
+        webrender_record: debug_options.webrender_record,
+        precache_shaders: debug_options.precache_shaders,
+        signpost: debug_options.signpost,
+    };
+
+    set_defaults(opts);
+
+    // These must happen after setting the default options, since the prefs rely on
+    // on the resource path.
+    // Note that command line preferences have the highest precedence
+
+    prefs::add_user_prefs();
+
+    for pref in opt_match.opt_strs("pref").iter() {
+        let split: Vec<&str> = pref.splitn(2, '=').collect();
+        let pref_name = split[0];
+        let value = split.get(1);
+        match value {
+            Some(&"false") => PREFS.set(pref_name, PrefValue::Boolean(false)),
+            Some(&"true") | None => PREFS.set(pref_name, PrefValue::Boolean(true)),
+            _ => PREFS.set(pref_name, PrefValue::String(value.unwrap().to_string()))
+        };
+    }
+
+    if let Some(layout_threads) = layout_threads {
+        PREFS.set("layout.threads", PrefValue::Number(layout_threads as f64));
+    } else if let Some(layout_threads) = PREFS.get("layout.threads").as_string() {
+        PREFS.set("layout.threads", PrefValue::Number(layout_threads.parse::<f64>().unwrap()));
+    } else if *PREFS.get("layout.threads") == PrefValue::Missing {
+        let layout_threads = cmp::max(num_cpus::get() * 3 / 4, 1);
+        PREFS.set("layout.threads", PrefValue::Number(layout_threads as f64));
+    }
+
+    ArgumentParsingResult::ChromeProcess
+}
+
+pub enum ArgumentParsingResult {
+    ChromeProcess,
+    ContentProcess(String),
+}
+
+// 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.
+static mut DEFAULT_OPTIONS: *mut Opts = 0 as *mut Opts;
+const INVALID_OPTIONS: *mut Opts = 0x01 as *mut Opts;
+
+lazy_static! {
+    static ref OPTIONS: Opts = {
+        unsafe {
+            let initial = if !DEFAULT_OPTIONS.is_null() {
+                let opts = Box::from_raw(DEFAULT_OPTIONS);
+                *opts
+            } else {
+                default_opts()
+            };
+            DEFAULT_OPTIONS = INVALID_OPTIONS;
+            initial
+        }
+    };
+}
+
+pub fn set_defaults(opts: Opts) {
+    unsafe {
+        assert!(DEFAULT_OPTIONS.is_null());
+        assert!(DEFAULT_OPTIONS != INVALID_OPTIONS);
+        let box_opts = Box::new(opts);
+        DEFAULT_OPTIONS = Box::into_raw(box_opts);
+    }
+}
+
+#[inline]
+pub fn get() -> &'static Opts {
+    &OPTIONS
+}
+
+pub fn parse_url_or_filename(cwd: &Path, input: &str) -> Result<ServoUrl, ()> {
+    match ServoUrl::parse(input) {
+        Ok(url) => Ok(url),
+        Err(url::ParseError::RelativeUrlWithoutBase) => {
+            Url::from_file_path(&*cwd.join(input)).map(ServoUrl::from_url)
+        }
+        Err(_) => Err(()),
+    }
+}
+
+impl Opts {
+    pub fn should_use_osmesa(&self) -> bool {
+        self.headless
+    }
+}
rename from servo/components/util/prefs.rs
rename to servo/components/config/prefs.rs
rename from servo/components/util/resource_files.rs
rename to servo/components/config/resource_files.rs
--- a/servo/components/constellation/Cargo.toml
+++ b/servo/components/constellation/Cargo.toml
@@ -28,18 +28,19 @@ net_traits = {path = "../net_traits"}
 offscreen_gl_context = "0.5.0"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rand = "0.3"
 script_traits = {path = "../script_traits"}
 serde = "0.8"
 serde_derive = "0.8"
 style_traits = {path = "../style_traits"}
+servo_config = {path = "../config", features = ["servo"]}
+servo_remutex = {path = "../remutex"}
 servo_url = {path = "../url", features = ["servo"]}
-util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive", "ipc"]
 
 [target.'cfg(not(target_os = "windows"))'.dependencies]
 gaol = {git = "https://github.com/servo/gaol"}
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -16,42 +16,46 @@ use canvas::webgl_paint_thread::WebGLPai
 use canvas_traits::CanvasMsg;
 use compositing::SendableFrameTree;
 use compositing::compositor_thread::CompositorProxy;
 use compositing::compositor_thread::Msg as ToCompositorMsg;
 use debugger;
 use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::{Size2D, TypedSize2D};
+use event_loop::EventLoop;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx_traits::Epoch;
 use ipc_channel::ipc::{self, IpcSender};
 use ipc_channel::router::ROUTER;
 use layout_traits::LayoutThreadFactory;
 use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
 use msg::constellation_msg::{FrameId, FrameType, PipelineId};
 use msg::constellation_msg::{Key, KeyModifiers, KeyState};
 use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
 use net_traits::{self, IpcSend, ResourceThreads};
 use net_traits::image_cache_thread::ImageCacheThread;
 use net_traits::pub_domains::reg_suffix;
 use net_traits::storage_thread::{StorageThreadMsg, StorageType};
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
-use pipeline::{ChildProcess, InitialPipelineState, Pipeline};
+use pipeline::{InitialPipelineState, Pipeline};
 use profile_traits::mem;
 use profile_traits::time;
 use rand::{Rng, SeedableRng, StdRng, random};
 use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
 use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg};
 use script_traits::{DocumentState, LayoutControlMsg, LoadData};
 use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
 use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
 use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
 use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData};
 use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType};
+use servo_config::opts;
+use servo_config::prefs::PREFS;
+use servo_remutex::ReentrantMutex;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::{HashMap, VecDeque};
 use std::io::Error as IOError;
 use std::iter::once;
 use std::marker::PhantomData;
 use std::mem::replace;
 use std::process;
@@ -59,20 +63,16 @@ use std::rc::{Rc, Weak};
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::thread;
 use std::time::Instant;
 use style_traits::PagePx;
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
 use timer_scheduler::TimerScheduler;
-use util::opts;
-use util::prefs::PREFS;
-use util::remutex::ReentrantMutex;
-use util::thread::spawn_named;
 use webrender_traits;
 
 #[derive(Debug, PartialEq)]
 enum ReadyToSave {
     NoRootFrame,
     PendingFrames,
     WebFontNotLoaded,
     DocumentLoading,
@@ -129,20 +129,20 @@ pub struct Constellation<Message, LTF, S
     swmanager_chan: Option<IpcSender<ServiceWorkerMsg>>,
 
     /// to send messages to this object
     swmanager_sender: IpcSender<SWManagerMsg>,
 
     /// to receive sw manager message
     swmanager_receiver: Receiver<SWManagerMsg>,
 
-    /// A map from top-level frame id and registered domain name to script channels.
-    /// This double indirection ensures that separate tabs do not share script threads,
+    /// A map from top-level frame id and registered domain name to event loops.
+    /// This double indirection ensures that separate tabs do not share event loops,
     /// even if the same domain is loaded in each.
-    script_channels: HashMap<FrameId, HashMap<String, Weak<ScriptChan>>>,
+    event_loops: HashMap<FrameId, HashMap<String, Weak<EventLoop>>>,
 
     /// A list of all the pipelines. (See the `pipeline` module for more details.)
     pipelines: HashMap<PipelineId, Pipeline>,
 
     /// A list of all the frames
     frames: HashMap<FrameId, Frame>,
 
     /// A channel through which messages can be sent to the font cache.
@@ -170,20 +170,16 @@ pub struct Constellation<Message, LTF, S
 
     window_size: WindowSizeData,
 
     /// Bits of state used to interact with the webdriver implementation
     webdriver: WebDriverData,
 
     scheduler_chan: IpcSender<TimerEventRequest>,
 
-    /// A list of child content processes.
-    #[cfg_attr(target_os = "windows", allow(dead_code))]
-    child_processes: Vec<ChildProcess>,
-
     /// Document states for loaded pipelines (used only when writing screenshots).
     document_states: HashMap<PipelineId, DocumentState>,
 
     // Webrender interface.
     webrender_api_sender: webrender_traits::RenderApiSender,
 
     /// Are we shutting down?
     shutting_down: bool,
@@ -367,40 +363,16 @@ impl WebDriverData {
 }
 
 #[derive(Clone, Copy)]
 enum ExitPipelineMode {
     Normal,
     Force,
 }
 
-/// A script channel, that closes the script thread down when it is dropped
-pub struct ScriptChan {
-    chan: IpcSender<ConstellationControlMsg>,
-    dont_send_or_sync: PhantomData<Rc<()>>,
-}
-
-impl Drop for ScriptChan {
-    fn drop(&mut self) {
-        let _ = self.chan.send(ConstellationControlMsg::ExitScriptThread);
-    }
-}
-
-impl ScriptChan {
-    pub fn send(&self, msg: ConstellationControlMsg) -> Result<(), IOError> {
-        self.chan.send(msg)
-    }
-    pub fn new(chan: IpcSender<ConstellationControlMsg>) -> Rc<ScriptChan> {
-        Rc::new(ScriptChan { chan: chan, dont_send_or_sync: PhantomData })
-    }
-    pub fn sender(&self) -> IpcSender<ConstellationControlMsg> {
-        self.chan.clone()
-    }
-}
-
 /// A logger directed at the constellation from content processes
 #[derive(Clone)]
 pub struct FromScriptLogger {
     /// A channel to the constellation
     pub constellation_chan: Arc<ReentrantMutex<IpcSender<FromScriptMsg>>>,
 }
 
 impl FromScriptLogger {
@@ -504,17 +476,17 @@ impl<Message, LTF, STF> Constellation<Me
 {
     pub fn start(state: InitialConstellationState) -> (Sender<FromCompositorMsg>, IpcSender<SWManagerMsg>) {
         let (compositor_sender, compositor_receiver) = channel();
 
         // service worker manager to communicate with constellation
         let (swmanager_sender, swmanager_receiver) = ipc::channel().expect("ipc channel failure");
         let sw_mgr_clone = swmanager_sender.clone();
 
-        spawn_named("Constellation".to_owned(), move || {
+        thread::Builder::new().name("Constellation".to_owned()).spawn(move || {
             let (ipc_script_sender, ipc_script_receiver) = ipc::channel().expect("ipc channel failure");
             let script_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_script_receiver);
 
             let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure");
             let layout_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_layout_receiver);
 
             let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver);
 
@@ -532,17 +504,17 @@ impl<Message, LTF, STF> Constellation<Me
                 bluetooth_thread: state.bluetooth_thread,
                 public_resource_threads: state.public_resource_threads,
                 private_resource_threads: state.private_resource_threads,
                 image_cache_thread: state.image_cache_thread,
                 font_cache_thread: state.font_cache_thread,
                 swmanager_chan: None,
                 swmanager_receiver: swmanager_receiver,
                 swmanager_sender: sw_mgr_clone,
-                script_channels: HashMap::new(),
+                event_loops: HashMap::new(),
                 pipelines: HashMap::new(),
                 frames: HashMap::new(),
                 pending_frames: vec!(),
                 // We initialize the namespace at 1, since we reserved namespace 0 for the constellation
                 next_pipeline_namespace_id: PipelineNamespaceId(1),
                 root_frame_id: FrameId::new(),
                 focus_pipeline_id: None,
                 time_profiler_chan: state.time_profiler_chan,
@@ -553,32 +525,32 @@ impl<Message, LTF, STF> Constellation<Me
                     initial_viewport: opts::get().initial_window_size.to_f32() *
                         ScaleFactor::new(1.0),
                     device_pixel_ratio:
                         ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)),
                 },
                 phantom: PhantomData,
                 webdriver: WebDriverData::new(),
                 scheduler_chan: TimerScheduler::start(),
-                child_processes: Vec::new(),
                 document_states: HashMap::new(),
                 webrender_api_sender: state.webrender_api_sender,
                 shutting_down: false,
                 handled_warnings: VecDeque::new(),
                 random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| {
                     let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random);
                     let rng = StdRng::from_seed(&[seed]);
                     warn!("Randomly closing pipelines.");
                     info!("Using seed {} for random pipeline closure.", seed);
                     (rng, prob)
                 }),
             };
 
             constellation.run();
-        });
+        }).expect("Thread spawning failed");
+
         (compositor_sender, swmanager_sender)
     }
 
     fn run(&mut self) {
         while !self.shutting_down || !self.pipelines.is_empty() {
             // Randomly close a pipeline if --random-pipeline-closure-probability is set
             // This is for testing the hardening of the constellation.
             self.maybe_close_random_pipeline();
@@ -608,27 +580,27 @@ impl<Message, LTF, STF> Constellation<Me
         // TODO: can we get a case where the child pipeline is created
         // before the parent is part of the frame tree?
         let top_level_frame_id = match parent_info {
             Some((_, FrameType::MozBrowserIFrame)) => frame_id,
             Some((parent_id, _)) => self.get_top_level_frame_for_pipeline(parent_id),
             None => self.root_frame_id,
         };
 
-        let (script_channel, host) = match sandbox {
+        let (event_loop, host) = match sandbox {
             IFrameSandboxState::IFrameSandboxed => (None, None),
             IFrameSandboxState::IFrameUnsandboxed => match reg_host(&load_data.url) {
                 None => (None, None),
                 Some(host) => {
-                    let script_channel = self.script_channels.get(&top_level_frame_id)
+                    let event_loop = self.event_loops.get(&top_level_frame_id)
                         .and_then(|map| map.get(host))
                         .and_then(|weak| weak.upgrade());
-                    match script_channel {
+                    match event_loop {
                         None => (None, Some(String::from(host))),
-                        Some(script_channel) => (Some(script_channel.clone()), None),
+                        Some(event_loop) => (Some(event_loop.clone()), None),
                     }
                 },
             },
         };
 
         let resource_threads = if is_private {
             self.private_resource_threads.clone()
         } else {
@@ -665,38 +637,34 @@ impl<Message, LTF, STF> Constellation<Me
             bluetooth_thread: self.bluetooth_thread.clone(),
             swmanager_thread: self.swmanager_sender.clone(),
             image_cache_thread: self.image_cache_thread.clone(),
             font_cache_thread: self.font_cache_thread.clone(),
             resource_threads: resource_threads,
             time_profiler_chan: self.time_profiler_chan.clone(),
             mem_profiler_chan: self.mem_profiler_chan.clone(),
             window_size: initial_window_size,
-            script_chan: script_channel,
+            event_loop: event_loop,
             load_data: load_data,
             device_pixel_ratio: self.window_size.device_pixel_ratio,
             pipeline_namespace_id: self.next_pipeline_namespace_id(),
             prev_visibility: prev_visibility,
             webrender_api_sender: self.webrender_api_sender.clone(),
             is_private: is_private,
         });
 
-        let (pipeline, child_process) = match result {
+        let pipeline = match result {
             Ok(result) => result,
             Err(e) => return self.handle_send_error(pipeline_id, e),
         };
 
-        if let Some(child_process) = child_process {
-            self.child_processes.push(child_process);
-        }
-
         if let Some(host) = host {
-            self.script_channels.entry(top_level_frame_id)
+            self.event_loops.entry(top_level_frame_id)
                 .or_insert_with(HashMap::new)
-                .insert(host, Rc::downgrade(&pipeline.script_chan));
+                .insert(host, Rc::downgrade(&pipeline.event_loop));
         }
 
         assert!(!self.pipelines.contains_key(&pipeline_id));
         self.pipelines.insert(pipeline_id, pipeline);
     }
 
     // Get an iterator for the current frame tree. Specify self.root_frame_id to
     // iterate the entire tree, or a specific frame id to iterate only that sub-tree.
@@ -974,17 +942,17 @@ impl<Message, LTF, STF> Constellation<Me
             FromScriptMsg::Focus(pipeline_id) => {
                 debug!("constellation got focus message");
                 self.handle_focus_msg(pipeline_id);
             }
             FromScriptMsg::ForwardEvent(pipeline_id, event) => {
                 let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
                 let result = match self.pipelines.get(&pipeline_id) {
                     None => { debug!("Pipeline {:?} got event after closure.", pipeline_id); return; }
-                    Some(pipeline) => pipeline.script_chan.send(msg),
+                    Some(pipeline) => pipeline.event_loop.send(msg),
                 };
                 if let Err(e) = result {
                     self.handle_send_error(pipeline_id, e);
                 }
             }
             FromScriptMsg::GetClipboardContents(sender) => {
                 if let Err(e) = sender.send("".to_owned()) {
                     warn!("Failed to send clipboard ({})", e);
@@ -1122,17 +1090,17 @@ impl<Message, LTF, STF> Constellation<Me
     fn handle_broadcast_storage_event(&self, pipeline_id: PipelineId, storage: StorageType, url: ServoUrl,
                                       key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
         let origin = url.origin();
         for pipeline in self.pipelines.values() {
             if (pipeline.id != pipeline_id) && (pipeline.url.origin() == origin) {
                 let msg = ConstellationControlMsg::DispatchStorageEvent(
                     pipeline.id, storage, url.clone(), key.clone(), old_value.clone(), new_value.clone()
                 );
-                if let Err(err) = pipeline.script_chan.send(msg) {
+                if let Err(err) = pipeline.event_loop.send(msg) {
                     warn!("Failed to broadcast storage event to pipeline {} ({:?}).", pipeline.id, err);
                 }
             }
         }
     }
 
     fn handle_exit(&mut self) {
         // TODO: add a timer, which forces shutdown if threads aren't responsive.
@@ -1331,17 +1299,17 @@ impl<Message, LTF, STF> Constellation<Me
         // Store the new rect inside the pipeline
         let result = {
             // Find the pipeline that corresponds to this rectangle. It's possible that this
             // pipeline may have already exited before we process this message, so just
             // early exit if that occurs.
             match self.pipelines.get_mut(&pipeline_id) {
                 Some(pipeline) => {
                     pipeline.size = Some(*size);
-                    pipeline.script_chan.send(msg)
+                    pipeline.event_loop.send(msg)
                 }
                 None => return,
             }
         };
 
         if let Err(e) = result {
             self.handle_send_error(pipeline_id, e);
         }
@@ -1356,17 +1324,17 @@ impl<Message, LTF, STF> Constellation<Me
             None => return warn!("Pipeline {} loaded after closure.", pipeline_id),
         };
         let msg = ConstellationControlMsg::DispatchFrameLoadEvent {
             target: frame_id,
             parent: parent_id,
             child: pipeline_id,
         };
         let result = match self.pipelines.get(&parent_id) {
-            Some(parent) => parent.script_chan.send(msg),
+            Some(parent) => parent.event_loop.send(msg),
             None => return warn!("Parent {} frame loaded after closure.", parent_id),
         };
         if let Err(e) = result {
             self.handle_send_error(parent_id, e);
         }
     }
 
     // The script thread associated with pipeline_id has loaded a URL in an iframe via script. This
@@ -1436,17 +1404,17 @@ impl<Message, LTF, STF> Constellation<Me
         } = load_info;
 
         let pipeline = {
             let parent_pipeline = match self.pipelines.get(&parent_pipeline_id) {
                 Some(parent_pipeline) => parent_pipeline,
                 None => return warn!("Script loaded url in closed iframe {}.", parent_pipeline_id),
             };
 
-            let script_sender = parent_pipeline.script_chan.clone();
+            let script_sender = parent_pipeline.event_loop.clone();
 
             let url = ServoUrl::parse("about:blank").expect("infallible");
             Pipeline::new(new_pipeline_id,
                           frame_id,
                           Some((parent_pipeline_id, frame_type)),
                           script_sender,
                           layout_sender,
                           self.compositor_proxy.clone_compositor_proxy(),
@@ -1479,17 +1447,17 @@ impl<Message, LTF, STF> Constellation<Me
                                                                                animation_state))
     }
 
     fn handle_tick_animation(&mut self, pipeline_id: PipelineId, tick_type: AnimationTickType) {
         let result = match tick_type {
             AnimationTickType::Script => {
                 let msg = ConstellationControlMsg::TickAllAnimations(pipeline_id);
                 match self.pipelines.get(&pipeline_id) {
-                    Some(pipeline) => pipeline.script_chan.send(msg),
+                    Some(pipeline) => pipeline.event_loop.send(msg),
                     None => return warn!("Pipeline {:?} got script tick after closure.", pipeline_id),
                 }
             }
             AnimationTickType::Layout => {
                 let msg = LayoutControlMsg::TickAnimations;
                 match self.pipelines.get(&pipeline_id) {
                     Some(pipeline) => pipeline.layout_chan.send(msg),
                     None => return warn!("Pipeline {:?} got layout tick after closure.", pipeline_id),
@@ -1552,17 +1520,17 @@ impl<Message, LTF, STF> Constellation<Me
         };
         match parent_info {
             Some((parent_pipeline_id, _)) => {
                 self.handle_load_start_msg(source_id);
                 // Message the constellation to find the script thread for this iframe
                 // and issue an iframe load through there.
                 let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, frame_id, load_data, replace);
                 let result = match self.pipelines.get(&parent_pipeline_id) {
-                    Some(parent_pipeline) => parent_pipeline.script_chan.send(msg),
+                    Some(parent_pipeline) => parent_pipeline.event_loop.send(msg),
                     None => {
                         warn!("Pipeline {:?} child loaded after closure", parent_pipeline_id);
                         return None;
                     },
                 };
                 if let Err(e) = result {
                     self.handle_send_error(parent_pipeline_id, e);
                 }
@@ -1698,17 +1666,17 @@ impl<Message, LTF, STF> Constellation<Me
             .map(|root_frame| root_frame.current.pipeline_id);
         let pipeline_id = self.focus_pipeline_id.or(root_pipeline_id);
 
         match pipeline_id {
             Some(pipeline_id) => {
                 let event = CompositorEvent::KeyEvent(ch, key, state, mods);
                 let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
                 let result = match self.pipelines.get(&pipeline_id) {
-                    Some(pipeline) => pipeline.script_chan.send(msg),
+                    Some(pipeline) => pipeline.event_loop.send(msg),
                     None => return debug!("Pipeline {:?} got key event after closure.", pipeline_id),
                 };
                 if let Err(e) = result {
                     self.handle_send_error(pipeline_id, e);
                 }
             },
             None => {
                 let event = ToCompositorMsg::KeyEvent(ch, key, state, mods);
@@ -1720,29 +1688,29 @@ impl<Message, LTF, STF> Constellation<Me
     fn handle_reload_msg(&mut self) {
         // Send Reload constellation msg to root script channel.
         let root_pipeline_id = self.frames.get(&self.root_frame_id)
             .map(|root_frame| root_frame.current.pipeline_id);
 
         if let Some(pipeline_id) = root_pipeline_id {
             let msg = ConstellationControlMsg::Reload(pipeline_id);
             let result = match self.pipelines.get(&pipeline_id) {
-                Some(pipeline) => pipeline.script_chan.send(msg),
+                Some(pipeline) => pipeline.event_loop.send(msg),
                 None => return debug!("Pipeline {:?} got reload event after closure.", pipeline_id),
             };
             if let Err(e) = result {
                 self.handle_send_error(pipeline_id, e);
             }
         }
     }
 
     fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) {
         let result = match self.pipelines.get(&pipeline_id) {
             None => return self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(pipeline_id, None)),
-            Some(pipeline) => pipeline.script_chan.send(ConstellationControlMsg::GetTitle(pipeline_id)),
+            Some(pipeline) => pipeline.event_loop.send(ConstellationControlMsg::GetTitle(pipeline_id)),
         };
         if let Err(e) = result {
             self.handle_send_error(pipeline_id, e);
         }
     }
 
     fn handle_mozbrowser_event_msg(&mut self,
                                    parent_pipeline_id: PipelineId,
@@ -1795,17 +1763,17 @@ impl<Message, LTF, STF> Constellation<Me
             Some(info) => info,
             None => return debug!("Pipeline {:?} focus has no parent.", pipeline_id),
         };
 
         // Send a message to the parent of the provided pipeline (if it exists)
         // telling it to mark the iframe element as focused.
         let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id);
         let result = match self.pipelines.get(&parent_pipeline_id) {
-            Some(pipeline) => pipeline.script_chan.send(msg),
+            Some(pipeline) => pipeline.event_loop.send(msg),
             None => return warn!("Pipeline {:?} focus after closure.", parent_pipeline_id),
         };
         if let Err(e) = result {
             self.handle_send_error(parent_pipeline_id, e);
         }
         self.focus_parent_pipeline(parent_pipeline_id);
     }
 
@@ -1857,17 +1825,17 @@ impl<Message, LTF, STF> Constellation<Me
             Some(pipeline) => (pipeline.frame_id, pipeline.parent_info),
         };
         if let Some((parent_pipeline_id, _)) = parent_pipeline_info {
             let visibility_msg = ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id,
                                                                                  frame_id,
                                                                                  visibility);
             let  result = match self.pipelines.get(&parent_pipeline_id) {
                 None => return warn!("Parent pipeline {:?} closed", parent_pipeline_id),
-                Some(parent_pipeline) => parent_pipeline.script_chan.send(visibility_msg),
+                Some(parent_pipeline) => parent_pipeline.event_loop.send(visibility_msg),
             };
 
             if let Err(e) = result {
                 self.handle_send_error(parent_pipeline_id, e);
             }
         }
     }
 
@@ -1915,32 +1883,32 @@ impl<Message, LTF, STF> Constellation<Me
                     Some(pipeline) => LoadData::new(pipeline.url.clone(), None, None),
                     None => return warn!("Pipeline {:?} Refresh after closure.", pipeline_id),
                 };
                 self.load_url_for_webdriver(pipeline_id, load_data, reply, true);
             }
             WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd) => {
                 let control_msg = ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, cmd);
                 let result = match self.pipelines.get(&pipeline_id) {
-                    Some(pipeline) => pipeline.script_chan.send(control_msg),
+                    Some(pipeline) => pipeline.event_loop.send(control_msg),
                     None => return warn!("Pipeline {:?} ScriptCommand after closure.", pipeline_id),
                 };
                 if let Err(e) = result {
                     self.handle_send_error(pipeline_id, e);
                 }
             },
             WebDriverCommandMsg::SendKeys(pipeline_id, cmd) => {
-                let script_channel = match self.pipelines.get(&pipeline_id) {
-                    Some(pipeline) => pipeline.script_chan.clone(),
+                let event_loop = match self.pipelines.get(&pipeline_id) {
+                    Some(pipeline) => pipeline.event_loop.clone(),
                     None => return warn!("Pipeline {:?} SendKeys after closure.", pipeline_id),
                 };
                 for (key, mods, state) in cmd {
                     let event = CompositorEvent::KeyEvent(None, key, state, mods);
                     let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
-                    if let Err(e) = script_channel.send(control_msg) {
+                    if let Err(e) = event_loop.send(control_msg) {
                         return self.handle_send_error(pipeline_id, e);
                     }
                 }
             },
             WebDriverCommandMsg::TakeScreenshot(pipeline_id, reply) => {
                 let current_pipeline_id = self.frames.get(&self.root_frame_id)
                     .map(|root_frame| root_frame.current.pipeline_id);
                 if Some(pipeline_id) == current_pipeline_id {
@@ -2019,17 +1987,17 @@ impl<Message, LTF, STF> Constellation<Me
         // Update the owning iframe to point to the new pipeline id.
         // This makes things like contentDocument work correctly.
         if let Some((parent_pipeline_id, _)) = pipeline_info {
             let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id,
                                                                 frame_id,
                                                                 next_pipeline_id);
             let result = match self.pipelines.get(&parent_pipeline_id) {
                 None => return warn!("Pipeline {:?} child traversed after closure.", parent_pipeline_id),
-                Some(pipeline) => pipeline.script_chan.send(msg),
+                Some(pipeline) => pipeline.event_loop.send(msg),
             };
             if let Err(e) = result {
                 self.handle_send_error(parent_pipeline_id, e);
             }
 
             // If this is an iframe, send a mozbrowser location change event.
             // This is the result of a back/forward traversal.
             self.trigger_mozbrowserlocationchange(next_pipeline_id);
@@ -2116,17 +2084,17 @@ impl<Message, LTF, STF> Constellation<Me
     fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) {
         debug!("Document ready to activate {:?}", pipeline_id);
 
         // Notify the parent (if there is one).
         if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
             if let Some((parent_pipeline_id, _)) = pipeline.parent_info {
                 if let Some(parent_pipeline) = self.pipelines.get(&parent_pipeline_id) {
                     let msg = ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, pipeline.frame_id);
-                    let _ = parent_pipeline.script_chan.send(msg);
+                    let _ = parent_pipeline.event_loop.send(msg);
                 }
             }
         }
 
         // Find the pending frame change whose new pipeline id is pipeline_id.
         let pending_index = self.pending_frames.iter().rposition(|frame_change| {
             frame_change.new_pipeline_id == pipeline_id
         });
@@ -2147,45 +2115,45 @@ impl<Message, LTF, STF> Constellation<Me
         if let Some(frame) = self.frames.get(&self.root_frame_id) {
             // Send Resize (or ResizeInactive) messages to each
             // pipeline in the frame tree.
             let pipeline_id = frame.current.pipeline_id;
             let pipeline = match self.pipelines.get(&pipeline_id) {
                 None => return warn!("Pipeline {:?} resized after closing.", pipeline_id),
                 Some(pipeline) => pipeline,
             };
-            let _ = pipeline.script_chan.send(ConstellationControlMsg::Resize(
+            let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize(
                 pipeline.id,
                 new_size,
                 size_type
             ));
             for entry in frame.prev.iter().chain(&frame.next) {
                 let pipeline = match self.pipelines.get(&entry.pipeline_id) {
                     None => {
                         warn!("Inactive pipeline {:?} resized after closing.", pipeline_id);
                         continue;
                     },
                     Some(pipeline) => pipeline,
                 };
-                let _ = pipeline.script_chan.send(ConstellationControlMsg::ResizeInactive(
+                let _ = pipeline.event_loop.send(ConstellationControlMsg::ResizeInactive(
                     pipeline.id,
                     new_size
                 ));
             }
         }
 
         // Send resize message to any pending pipelines that aren't loaded yet.
         for pending_frame in &self.pending_frames {
             let pipeline_id = pending_frame.new_pipeline_id;
             let pipeline = match self.pipelines.get(&pipeline_id) {
                 None => { warn!("Pending pipeline {:?} is closed", pipeline_id); continue; }
                 Some(pipeline) => pipeline,
             };
             if pipeline.parent_info.is_none() {
-                let _ = pipeline.script_chan.send(ConstellationControlMsg::Resize(
+                let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize(
                     pipeline.id,
                     new_size,
                     size_type
                 ));
             }
         }
 
         if let Some(resize_channel) = self.webdriver.resize_channel.take() {
@@ -2344,17 +2312,17 @@ impl<Message, LTF, STF> Constellation<Me
     fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
         debug!("Closing frame {}.", frame_id);
         let parent_info = self.frames.get(&frame_id)
             .and_then(|frame| self.pipelines.get(&frame.current.pipeline_id))
             .and_then(|pipeline| pipeline.parent_info);
 
         self.close_frame_children(frame_id, exit_mode);
 
-        self.script_channels.remove(&frame_id);
+        self.event_loops.remove(&frame_id);
         if self.frames.remove(&frame_id).is_none() {
             warn!("Closing frame {:?} twice.", frame_id);
         }
 
         if let Some((parent_pipeline_id, _)) = parent_info {
             let parent_pipeline = match self.pipelines.get_mut(&parent_pipeline_id) {
                 None => return warn!("Pipeline {:?} child closed after parent.", parent_pipeline_id),
                 Some(parent_pipeline) => parent_pipeline,
new file mode 100644
--- /dev/null
+++ b/servo/components/constellation/event_loop.rs
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! This module contains the `EventLoop` type, which is the constellation's
+//! view of a script thread. When an `EventLoop` is dropped, an `ExitScriptThread`
+//! message is sent to the script thread, asking it to shut down.
+
+use ipc_channel::ipc::IpcSender;
+use script_traits::ConstellationControlMsg;
+use std::io::Error as IOError;
+use std::marker::PhantomData;
+use std::rc::Rc;
+
+/// https://html.spec.whatwg.org/multipage/#event-loop
+pub struct EventLoop {
+    script_chan: IpcSender<ConstellationControlMsg>,
+    dont_send_or_sync: PhantomData<Rc<()>>,
+}
+
+impl Drop for EventLoop {
+    fn drop(&mut self) {
+        let _ = self.script_chan.send(ConstellationControlMsg::ExitScriptThread);
+    }
+}
+
+impl EventLoop {
+    /// Create a new event loop from the channel to its script thread.
+    pub fn new(script_chan: IpcSender<ConstellationControlMsg>) -> Rc<EventLoop> {
+        Rc::new(EventLoop {
+            script_chan: script_chan,
+            dont_send_or_sync: PhantomData,
+        })
+    }
+
+    /// Send a message to the event loop.
+    pub fn send(&self, msg: ConstellationControlMsg) -> Result<(), IOError> {
+        self.script_chan.send(msg)
+    }
+
+    /// The underlying channel to the script thread.
+    pub fn sender(&self) -> IpcSender<ConstellationControlMsg> {
+        self.script_chan.clone()
+    }
+}
+
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -31,23 +31,24 @@ extern crate net_traits;
 extern crate offscreen_gl_context;
 #[macro_use]
 extern crate profile_traits;
 extern crate rand;
 extern crate script_traits;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_config;
+extern crate servo_remutex;
 extern crate servo_url;
 extern crate style_traits;
-#[macro_use]
-extern crate util;
 extern crate webrender_traits;
 
 mod constellation;
+mod event_loop;
 mod pipeline;
 #[cfg(not(target_os = "windows"))]
 mod sandboxing;
 mod timer_scheduler;
 
 pub use constellation::{Constellation, FromCompositorLogger, FromScriptLogger, InitialConstellationState};
 pub use pipeline::UnprivilegedPipelineContent;
 #[cfg(not(target_os = "windows"))]
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -1,63 +1,54 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use bluetooth_traits::BluetoothRequest;
 use compositing::CompositionPipeline;
 use compositing::CompositorProxy;
 use compositing::compositor_thread::Msg as CompositorMsg;
-use constellation::ScriptChan;
 use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
-#[cfg(not(target_os = "windows"))]
-use gaol;
+use event_loop::EventLoop;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx_traits::DevicePixel;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use layout_traits::LayoutThreadFactory;
 use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespaceId};
 use net_traits::{IpcSend, ResourceThreads};
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::mem as profile_mem;
 use profile_traits::time;
 use script_traits::{ConstellationControlMsg, InitialScriptState};
 use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent};
 use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
 use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
+use servo_config::opts::{self, Opts};
+use servo_config::prefs::{PREFS, Pref};
 use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::env;
 use std::ffi::OsStr;
 use std::io::Error as IOError;
 use std::process;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use style_traits::{PagePx, ViewportPx};
-use util::opts::{self, Opts};
-use util::prefs::{PREFS, Pref};
 use webrender_traits;
 
-pub enum ChildProcess {
-    #[cfg(not(target_os = "windows"))]
-    Sandboxed(gaol::platform::process::Process),
-    #[cfg(not(target_os = "windows"))]
-    Unsandboxed(process::Child),
-}
-
 /// A uniquely-identifiable pipeline of script thread, layout thread, and paint thread.
 pub struct Pipeline {
     pub id: PipelineId,
     /// The ID of the frame that contains this Pipeline.
     pub frame_id: FrameId,
     pub parent_info: Option<(PipelineId, FrameType)>,
-    pub script_chan: Rc<ScriptChan>,
+    pub event_loop: Rc<EventLoop>,
     /// A channel to layout, for performing reflows and shutdown.
     pub layout_chan: IpcSender<LayoutControlMsg>,
     /// A channel to the compositor.
     pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
     /// URL corresponding to the most recently-loaded page.
     pub url: ServoUrl,
     /// The title of the most recently-loaded page.
     pub title: Option<String>,
@@ -110,58 +101,56 @@ pub struct InitialPipelineState {
     /// A channel to the time profiler thread.
     pub time_profiler_chan: time::ProfilerChan,
     /// A channel to the memory profiler thread.
     pub mem_profiler_chan: profile_mem::ProfilerChan,
     /// Information about the initial window size.
     pub window_size: Option<TypedSize2D<f32, PagePx>>,
     /// Information about the device pixel ratio.
     pub device_pixel_ratio: ScaleFactor<f32, ViewportPx, DevicePixel>,
-    /// A channel to the script thread, if applicable.
-    /// If this is `None`, create a new script thread.
-    /// If this is `Some`, then reuse an existing script thread.
-    pub script_chan: Option<Rc<ScriptChan>>,
+    /// The event loop to run in, if applicable. If this is `Some`,
+    /// then `parent_info` must also be `Some`.
+    pub event_loop: Option<Rc<EventLoop>>,
     /// Information about the page to load.
     pub load_data: LoadData,
     /// The ID of the pipeline namespace for this script thread.
     pub pipeline_namespace_id: PipelineNamespaceId,
     /// Pipeline visibility to be inherited
     pub prev_visibility: Option<bool>,
     /// Webrender api.
     pub webrender_api_sender: webrender_traits::RenderApiSender,
     /// Whether this pipeline is considered private.
     pub is_private: bool,
 }
 
 impl Pipeline {
     /// Starts a paint thread, layout thread, and possibly a script thread, in
     /// a new process if requested.
-    pub fn spawn<Message, LTF, STF>(state: InitialPipelineState)
-                                    -> Result<(Pipeline, Option<ChildProcess>), IOError>
+    pub fn spawn<Message, LTF, STF>(state: InitialPipelineState) -> Result<Pipeline, IOError>
         where LTF: LayoutThreadFactory<Message=Message>,
               STF: ScriptThreadFactory<Message=Message>
     {
         // Note: we allow channel creation to panic, since recovering from this
         // probably requires a general low-memory strategy.
         let (pipeline_chan, pipeline_port) = ipc::channel()
-            .expect("Pipeline main chan");;
+            .expect("Pipeline main chan");
 
         let (layout_content_process_shutdown_chan, layout_content_process_shutdown_port) =
             ipc::channel().expect("Pipeline layout content shutdown chan");
 
         let device_pixel_ratio = state.device_pixel_ratio;
         let window_size = state.window_size.map(|size| {
             WindowSizeData {
                 visible_viewport: size,
                 initial_viewport: size * ScaleFactor::new(1.0),
                 device_pixel_ratio: device_pixel_ratio,
             }
         });
 
-        let (script_chan, content_ports) = match state.script_chan {
+        let (script_chan, content_ports) = match state.event_loop {
             Some(script_chan) => {
                 let new_layout_info = NewLayoutInfo {
                     parent_info: state.parent_info,
                     new_pipeline_id: state.id,
                     frame_id: state.frame_id,
                     load_data: state.load_data.clone(),
                     window_size: window_size,
                     pipeline_port: pipeline_port,
@@ -171,21 +160,20 @@ impl Pipeline {
 
                 if let Err(e) = script_chan.send(ConstellationControlMsg::AttachLayout(new_layout_info)) {
                     warn!("Sending to script during pipeline creation failed ({})", e);
                 }
                 (script_chan, None)
             }
             None => {
                 let (script_chan, script_port) = ipc::channel().expect("Pipeline script chan");
-                (ScriptChan::new(script_chan), Some((script_port, pipeline_port)))
+                (EventLoop::new(script_chan), Some((script_port, pipeline_port)))
             }
         };
 
-        let mut child_process = None;
         if let Some((script_port, pipeline_port)) = content_ports {
             // Route messages coming from content to devtools as appropriate.
             let script_to_devtools_chan = state.devtools_chan.as_ref().map(|devtools_chan| {
                 let (script_to_devtools_chan, script_to_devtools_port) = ipc::channel()
                     .expect("Pipeline script to devtools chan");
                 let devtools_chan = (*devtools_chan).clone();
                 ROUTER.add_route(script_to_devtools_port.to_opaque(), box move |message| {
                     match message.to::<ScriptToDevtoolsControlMsg>() {
@@ -231,54 +219,52 @@ impl Pipeline {
                 script_content_process_shutdown_port: script_content_process_shutdown_port,
                 webrender_api_sender: state.webrender_api_sender,
             };
 
             // Spawn the child process.
             //
             // Yes, that's all there is to it!
             if opts::multiprocess() {
-                child_process = Some(try!(unprivileged_pipeline_content.spawn_multiprocess()));
+                let _ = try!(unprivileged_pipeline_content.spawn_multiprocess());
             } else {
                 unprivileged_pipeline_content.start_all::<Message, LTF, STF>(false);
             }
         }
 
-        let pipeline = Pipeline::new(state.id,
-                                     state.frame_id,
-                                     state.parent_info,
-                                     script_chan,
-                                     pipeline_chan,
-                                     state.compositor_proxy,
-                                     state.is_private,
-                                     state.load_data.url,
-                                     state.window_size,
-                                     state.prev_visibility.unwrap_or(true));
-
-        Ok((pipeline, child_process))
+        Ok(Pipeline::new(state.id,
+                         state.frame_id,
+                         state.parent_info,
+                         script_chan,
+                         pipeline_chan,
+                         state.compositor_proxy,
+                         state.is_private,
+                         state.load_data.url,
+                         state.window_size,
+                         state.prev_visibility.unwrap_or(true)))
     }
 
     /// Creates a new `Pipeline`, after the script and layout threads have been
     /// spawned.
     pub fn new(id: PipelineId,
                frame_id: FrameId,
                parent_info: Option<(PipelineId, FrameType)>,
-               script_chan: Rc<ScriptChan>,
+               event_loop: Rc<EventLoop>,
                layout_chan: IpcSender<LayoutControlMsg>,
                compositor_proxy: Box<CompositorProxy + 'static + Send>,
                is_private: bool,
                url: ServoUrl,
                size: Option<TypedSize2D<f32, PagePx>>,
                visible: bool)
                -> Pipeline {
         let pipeline = Pipeline {
             id: id,
             frame_id: frame_id,
             parent_info: parent_info,
-            script_chan: script_chan,
+            event_loop: event_loop,
             layout_chan: layout_chan,
             compositor_proxy: compositor_proxy,
             url: url,
             title: None,
             children: vec!(),
             size: size,
             running_animations: false,
             visible: visible,
@@ -302,46 +288,46 @@ impl Pipeline {
             self.compositor_proxy.send(CompositorMsg::PipelineExited(self.id, sender));
             if let Err(e) = receiver.recv() {
                 warn!("Sending exit message failed ({}).", e);
             }
         }
 
         // Script thread handles shutting down layout, and layout handles shutting down the painter.
         // For now, if the script thread has failed, we give up on clean shutdown.
-        if let Err(e) = self.script_chan.send(ConstellationControlMsg::ExitPipeline(self.id)) {
+        if let Err(e) = self.event_loop.send(ConstellationControlMsg::ExitPipeline(self.id)) {
             warn!("Sending script exit message failed ({}).", e);
         }
     }
 
     pub fn freeze(&self) {
-        if let Err(e) = self.script_chan.send(ConstellationControlMsg::Freeze(self.id)) {
+        if let Err(e) = self.event_loop.send(ConstellationControlMsg::Freeze(self.id)) {
             warn!("Sending freeze message failed ({}).", e);
         }
     }
 
     pub fn thaw(&self) {
-        if let Err(e) = self.script_chan.send(ConstellationControlMsg::Thaw(self.id)) {
+        if let Err(e) = self.event_loop.send(ConstellationControlMsg::Thaw(self.id)) {
             warn!("Sending freeze message failed ({}).", e);
         }
     }
 
     pub fn force_exit(&self) {
-        if let Err(e) = self.script_chan.send(ConstellationControlMsg::ExitPipeline(self.id)) {
+        if let Err(e) = self.event_loop.send(ConstellationControlMsg::ExitPipeline(self.id)) {
             warn!("Sending script exit message failed ({}).", e);
         }
         if let Err(e) = self.layout_chan.send(LayoutControlMsg::ExitNow) {
             warn!("Sending layout exit message failed ({}).", e);
         }
     }
 
     pub fn to_sendable(&self) -> CompositionPipeline {
         CompositionPipeline {
             id: self.id.clone(),
-            script_chan: self.script_chan.sender(),
+            script_chan: self.event_loop.sender(),
             layout_chan: self.layout_chan.clone(),
         }
     }
 
     pub fn add_child(&mut self, frame_id: FrameId) {
         self.children.push(frame_id);
     }
 
@@ -355,26 +341,26 @@ impl Pipeline {
     pub fn trigger_mozbrowser_event(&self,
                                      child_id: Option<FrameId>,
                                      event: MozBrowserEvent) {
         assert!(PREFS.is_mozbrowser_enabled());
 
         let event = ConstellationControlMsg::MozBrowserEvent(self.id,
                                                              child_id,
                                                              event);
-        if let Err(e) = self.script_chan.send(event) {
+        if let Err(e) = self.event_loop.send(event) {
             warn!("Sending mozbrowser event to script failed ({}).", e);
         }
     }
 
     fn notify_visibility(&self) {
-        self.script_chan.send(ConstellationControlMsg::ChangeFrameVisibilityStatus(self.id, self.visible))
-                        .expect("Pipeline script chan");
-
-        self.compositor_proxy.send(CompositorMsg::PipelineVisibilityChanged(self.id, self.visible));
+        let script_msg = ConstellationControlMsg::ChangeFrameVisibilityStatus(self.id, self.visible);
+        let compositor_msg = CompositorMsg::PipelineVisibilityChanged(self.id, self.visible);
+        self.event_loop.send(script_msg).expect("Pipeline script chan");
+        self.compositor_proxy.send(compositor_msg);
     }
 
     pub fn change_visibility(&mut self, visible: bool) {
         if visible == self.visible {
             return;
         }
         self.visible = visible;
         self.notify_visibility();
@@ -459,17 +445,17 @@ impl UnprivilegedPipelineContent {
 
         if wait_for_completion {
             let _ = self.script_content_process_shutdown_port.recv();
             let _ = self.layout_content_process_shutdown_port.recv();
         }
     }
 
     #[cfg(not(target_os = "windows"))]
-    pub fn spawn_multiprocess(self) -> Result<ChildProcess, IOError> {
+    pub fn spawn_multiprocess(self) -> Result<(), IOError> {
         use gaol::sandbox::{self, Sandbox, SandboxMethods};
         use ipc_channel::ipc::IpcOneShotServer;
         use sandboxing::content_process_sandbox_profile;
 
         impl CommandMethods for sandbox::Command {
             fn arg<T>(&mut self, arg: T)
                 where T: AsRef<OsStr> {
                 self.arg(arg);
@@ -484,41 +470,40 @@ impl UnprivilegedPipelineContent {
         // Note that this function can panic, due to process creation,
         // avoiding this panic would require a mechanism for dealing
         // with low-resource scenarios.
         let (server, token) =
             IpcOneShotServer::<IpcSender<UnprivilegedPipelineContent>>::new()
             .expect("Failed to create IPC one-shot server.");
 
         // If there is a sandbox, use the `gaol` API to create the child process.
-        let child_process = if opts::get().sandbox {
+        if opts::get().sandbox {
             let mut command = sandbox::Command::me().expect("Failed to get current sandbox.");
             self.setup_common(&mut command, token);
 
             let profile = content_process_sandbox_profile();
-            ChildProcess::Sandboxed(Sandbox::new(profile).start(&mut command)
-                                    .expect("Failed to start sandboxed child process!"))
+            let _ = Sandbox::new(profile)
+                .start(&mut command)
+                .expect("Failed to start sandboxed child process!");
         } else {
             let path_to_self = env::current_exe()
                 .expect("Failed to get current executor.");
             let mut child_process = process::Command::new(path_to_self);
             self.setup_common(&mut child_process, token);
-
-            ChildProcess::Unsandboxed(child_process.spawn()
-                                      .expect("Failed to start unsandboxed child process!"))
-        };
+            let _ = child_process.spawn().expect("Failed to start unsandboxed child process!");
+        }
 
         let (_receiver, sender) = server.accept().expect("Server failed to accept.");
         try!(sender.send(self));
 
-        Ok(child_process)
+        Ok(())
     }
 
     #[cfg(target_os = "windows")]
-    pub fn spawn_multiprocess(self) -> Result<ChildProcess, IOError> {
+    pub fn spawn_multiprocess(self) -> Result<(), IOError> {
         error!("Multiprocess is not supported on Windows.");
         process::exit(1);
     }
 
     #[cfg(not(windows))]
     fn setup_common<C: CommandMethods>(&self, command: &mut C, token: String) {
         C::arg(command, "--content-process");
         C::arg(command, token);
--- a/servo/components/constellation/sandboxing.rs
+++ b/servo/components/constellation/sandboxing.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use gaol::profile::{Operation, PathPattern, Profile};
+use servo_config::resource_files;
 use std::path::PathBuf;
-use util::resource_files;
 
 /// Our content process sandbox profile on Mac. As restrictive as possible.
 #[cfg(target_os = "macos")]
 pub fn content_process_sandbox_profile() -> Profile {
     use gaol::platform;
     Profile::new(vec![
         Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
         Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path()
--- a/servo/components/debugger/Cargo.toml
+++ b/servo/components/debugger/Cargo.toml
@@ -7,12 +7,11 @@ publish = false
 
 [lib]
 name = "debugger"
 path = "lib.rs"
 crate_type = ["rlib"]
 
 [dependencies]
 log = "0.3.5"
-util = {path = "../util"}
 
 [target.'cfg(not(target_os = "android"))'.dependencies]
 ws = "0.5.3"
--- a/servo/components/debugger/lib.rs
+++ b/servo/components/debugger/lib.rs
@@ -1,21 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[macro_use]
 extern crate log;
-extern crate util;
 #[cfg(not(target_os = "android"))]
 extern crate ws;
 
 use std::sync::mpsc;
 use std::sync::mpsc::channel;
-use util::thread::spawn_named;
+use std::thread;
 #[cfg(not(target_os = "android"))]
 use ws::{Builder, CloseCode, Handler, Handshake};
 
 enum Message {
     ShutdownServer,
 }
 
 pub struct Sender(mpsc::Sender<Message>);
@@ -40,33 +39,33 @@ impl Handler for Connection {
         self.sender.send(message)
     }
 }
 
 #[cfg(not(target_os = "android"))]
 pub fn start_server(port: u16) -> Sender {
     debug!("Starting server.");
     let (sender, receiver) = channel();
-    spawn_named("debugger".to_owned(), move || {
+    thread::Builder::new().name("debugger".to_owned()).spawn(move || {
         let socket = Builder::new().build(|sender: ws::Sender| {
             Connection { sender: sender }
         }).unwrap();
         let sender = socket.broadcaster();
-        spawn_named("debugger-websocket".to_owned(), move || {
+        thread::Builder::new().name("debugger-websocket".to_owned()).spawn(move || {
             socket.listen(("127.0.0.1", port)).unwrap();
-        });
+        }).expect("Thread spawning failed");
         while let Ok(message) = receiver.recv() {
             match message {
                 Message::ShutdownServer => {
                     break;
                 }
             }
         }
         sender.shutdown().unwrap();
-    });
+    }).expect("Thread spawning failed");
     Sender(sender)
 }
 
 #[cfg(target_os = "android")]
 pub fn start_server(_: u16) -> Sender {
     panic!("Debugger is not supported on Android");
 }
 
--- a/servo/components/devtools/Cargo.toml
+++ b/servo/components/devtools/Cargo.toml
@@ -17,9 +17,8 @@ hyper_serde = "0.1.4"
 ipc-channel = "0.5"
 log = "0.3.5"
 msg = {path = "../msg"}
 plugins = {path = "../plugins"}
 serde = "0.8"
 serde_json = "0.8"
 serde_derive = "0.8"
 time = "0.1"
-util = {path = "../util"}
--- a/servo/components/devtools/actors/timeline.rs
+++ b/servo/components/devtools/actors/timeline.rs
@@ -14,17 +14,16 @@ use protocol::JsonPacketStream;
 use serde::{Serialize, Serializer};
 use serde_json::Value;
 use std::cell::RefCell;
 use std::collections::BTreeMap;
 use std::net::TcpStream;
 use std::sync::{Arc, Mutex};
 use std::thread;
 use std::time::Duration;
-use util::thread::spawn_named;
 
 pub struct TimelineActor {
     name: String,
     script_sender: IpcSender<DevtoolScriptControlMsg>,
     marker_types: Vec<TimelineMarkerType>,
     pipeline: PipelineId,
     is_recording: Arc<Mutex<bool>>,
     stream: RefCell<Option<TcpStream>>,
@@ -145,31 +144,31 @@ impl TimelineActor {
 
     fn pull_timeline_data(&self, receiver: IpcReceiver<Option<TimelineMarker>>, mut emitter: Emitter) {
         let is_recording = self.is_recording.clone();
 
         if !*is_recording.lock().unwrap() {
             return;
         }
 
-        spawn_named("PullTimelineMarkers".to_owned(), move || {
+        thread::Builder::new().name("PullTimelineMarkers".to_owned()).spawn(move || {
             loop {
                 if !*is_recording.lock().unwrap() {
                     break;
                 }
 
                 let mut markers = vec![];
                 while let Ok(Some(marker)) = receiver.try_recv() {
                     markers.push(emitter.marker(marker));
                 }
                 emitter.send(markers);
 
                 thread::sleep(Duration::from_millis(DEFAULT_TIMELINE_DATA_PULL_TIMEOUT));
             }
-        });
+        }).expect("Thread spawning failed");
     }
 }
 
 impl Actor for TimelineActor {
     fn name(&self) -> String {
         self.name.clone()
     }
 
--- a/servo/components/devtools/lib.rs
+++ b/servo/components/devtools/lib.rs
@@ -25,17 +25,16 @@ extern crate ipc_channel;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate serde_json;
 extern crate time;
-extern crate util;
 
 use actor::{Actor, ActorRegistry};
 use actors::console::ConsoleActor;
 use actors::framerate::FramerateActor;
 use actors::inspector::InspectorActor;
 use actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg};
 use actors::performance::PerformanceActor;
 use actors::profiler::ProfilerActor;
@@ -52,18 +51,18 @@ use msg::constellation_msg::PipelineId;
 use protocol::JsonPacketStream;
 use std::borrow::ToOwned;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::net::{Shutdown, TcpListener, TcpStream};
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::{Receiver, Sender, channel};
+use std::thread;
 use time::precise_time_ns;
-use util::thread::spawn_named;
 
 mod actor;
 /// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
 mod actors {
     pub mod console;
     pub mod framerate;
     pub mod inspector;
     pub mod memory;
@@ -132,19 +131,19 @@ struct ResponseStartUpdateMsg {
     response: ResponseStartMsg,
 }
 
 /// Spin up a devtools server that listens for connections on the specified port.
 pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
     let (sender, receiver) = channel();
     {
         let sender = sender.clone();
-        spawn_named("Devtools".to_owned(), move || {
+        thread::Builder::new().name("Devtools".to_owned()).spawn(move || {
             run_server(sender, receiver, port)
-        });
+        }).expect("Thread spawning failed");
     }
     sender
 }
 
 fn run_server(sender: Sender<DevtoolsControlMsg>,
               receiver: Receiver<DevtoolsControlMsg>,
               port: u16) {
     let listener = TcpListener::bind(&("127.0.0.1", port)).unwrap();
@@ -480,33 +479,33 @@ fn run_server(sender: Sender<DevtoolsCon
                 entry.insert(actor_name.clone());
                 actors.register(box actor);
                 actor_name
             }
         }
     }
 
     let sender_clone = sender.clone();
-    spawn_named("DevtoolsClientAcceptor".to_owned(), move || {
+    thread::Builder::new().name("DevtoolsClientAcceptor".to_owned()).spawn(move || {
         // accept connections and process them, spawning a new thread for each one
         for stream in listener.incoming() {
             // connection succeeded
             sender_clone.send(DevtoolsControlMsg::FromChrome(
                     ChromeToDevtoolsControlMsg::AddClient(stream.unwrap()))).unwrap();
         }
-    });
+    }).expect("Thread spawning failed");
 
     while let Ok(msg) = receiver.recv() {
         match msg {
             DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => {
                 let actors = actors.clone();
                 accepted_connections.push(stream.try_clone().unwrap());
-                spawn_named("DevtoolsClientHandler".to_owned(), move || {
+                thread::Builder::new().name("DevtoolsClientHandler".to_owned()).spawn(move || {
                     handle_client(actors, stream.try_clone().unwrap())
-                })
+                }).expect("Thread spawning failed");
             }
             DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::FramerateTick(
                         actor_name, tick)) =>
                 handle_framerate_tick(actors.clone(), actor_name, tick),
             DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::NewGlobal(
                         ids, script_sender, pageinfo)) =>
                 handle_new_global(actors.clone(), ids, script_sender, &mut actor_pipelines,
                                   &mut actor_workers, pageinfo),
new file mode 100644
--- /dev/null
+++ b/servo/components/geometry/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "servo_geometry"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+publish = false
+
+[lib]
+name = "servo_geometry"
+path = "lib.rs"
+
+[features]
+# servo as opposed to geckolib
+servo = ["app_units/plugins", "euclid/unstable"]
+
+[dependencies]
+app_units = "0.3"
+euclid = "0.10.1"
+heapsize = "0.3.0"
new file mode 100644
--- /dev/null
+++ b/servo/components/geometry/lib.rs
@@ -0,0 +1,54 @@
+/* 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/. */
+
+extern crate app_units;
+#[macro_use] extern crate euclid;
+#[macro_use] extern crate heapsize;
+
+use app_units::{Au, MAX_AU};
+use euclid::point::Point2D;
+use euclid::rect::Rect;
+use euclid::size::Size2D;
+use std::i32;
+
+// Units for use with euclid::length and euclid::scale_factor.
+
+/// A normalized "pixel" at the default resolution for the display.
+///
+/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
+/// should approximate a device-independent reference length.  This unit corresponds to Android's
+/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
+///
+/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
+/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
+/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
+/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
+///
+/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
+/// `servo::windowing::WindowMethods::hidpi_factor`.
+#[derive(Clone, Copy, Debug)]
+pub enum ScreenPx {}
+
+known_heap_size!(0, ScreenPx);
+
+// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
+// originally proposed in 2002 as a standard unit of measure in Gecko.
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
+
+#[inline(always)]
+pub fn max_rect() -> Rect<Au> {
+    Rect::new(Point2D::new(Au(i32::MIN / 2), Au(i32::MIN / 2)), Size2D::new(MAX_AU, MAX_AU))
+}
+
+/// A helper function to convert a rect of `f32` pixels to a rect of app units.
+pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
+    Rect::new(Point2D::new(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
+              Size2D::new(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
+}
+
+/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
+pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
+    Rect::new(Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
+              Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()))
+}
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -27,24 +27,24 @@ log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 ordered-float = "0.2.2"
 plugins = {path = "../plugins"}
 range = {path = "../range"}
 rustc-serialize = "0.3"
 serde = "0.8"
 servo_atoms = {path = "../atoms"}
+servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 serde_derive = "0.8"
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
-util = {path = "../util"}
 xi-unicode = "0.0.1"
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive", "ipc"]
 
 [target.'cfg(target_os = "macos")'.dependencies]
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -20,25 +20,25 @@ use euclid::num::{One, Zero};
 use euclid::rect::TypedRect;
 use euclid::side_offsets::SideOffsets2D;
 use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId};
 use gfx_traits::print_tree::PrintTree;
 use ipc_channel::ipc::IpcSharedMemory;
 use msg::constellation_msg::PipelineId;
 use net_traits::image::base::{Image, PixelFormat};
 use range::Range;
+use servo_geometry::{au_rect_to_f32_rect, f32_rect_to_au_rect, max_rect};
 use std::cmp::{self, Ordering};
 use std::collections::HashMap;
 use std::fmt;
 use std::sync::Arc;
 use style::computed_values::{border_style, filter, image_rendering, mix_blend_mode};
 use style_traits::cursor::Cursor;
 use text::TextRun;
 use text::glyph::ByteIndex;
-use util::geometry::{self, max_rect};
 use webrender_traits::{self, ColorF, GradientStop, WebGLContextId};
 
 pub use style::dom::OpaqueNode;
 
 /// The factor that we multiply the blur radius by in order to inflate the boundaries of display
 /// items that involve a blur. This ensures that the display item boundaries include all the ink.
 pub static BLUR_INFLATION_FACTOR: i32 = 3;
 
@@ -392,19 +392,19 @@ impl StackingContext {
         // uncommon case.
         let origin_x = self.bounds.origin.x.to_f32_px();
         let origin_y = self.bounds.origin.y.to_f32_px();
 
         let transform = Matrix4D::identity().pre_translated(origin_x, origin_y, 0.0)
                                             .pre_mul(&self.transform);
         let transform_2d = transform.to_2d();
 
-        let overflow = geometry::au_rect_to_f32_rect(self.overflow);
+        let overflow = au_rect_to_f32_rect(self.overflow);
         let overflow = transform_2d.transform_rect(&overflow);
-        geometry::f32_rect_to_au_rect(overflow)
+        f32_rect_to_au_rect(overflow)
     }
 
     pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
         print_tree.new_level(format!("{:?}", self));
         for kid in self.children() {
             kid.print_with_tree(print_tree);
         }
         print_tree.end_level();
--- a/servo/components/gfx/font_cache_thread.rs
+++ b/servo/components/gfx/font_cache_thread.rs
@@ -13,23 +13,24 @@ use platform::font_list::for_each_availa
 use platform::font_list::for_each_variation;
 use platform::font_list::last_resort_font_families;
 use platform::font_list::system_default_family;
 use platform::font_template::FontTemplateData;
 use servo_atoms::Atom;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
+use std::fmt;
 use std::mem;
 use std::ops::Deref;
 use std::sync::{Arc, Mutex};
+use std::thread;
 use std::u32;
 use style::font_face::{EffectiveSources, Source};
 use style::properties::longhands::font_family::computed_value::FontFamily;
-use util::thread::spawn_named;
 use webrender_traits;
 
 /// A list of font templates that make up a given font family.
 struct FontTemplates {
     templates: Vec<FontTemplate>,
 }
 
 #[derive(Serialize, Deserialize, Debug)]
@@ -217,41 +218,46 @@ impl FontCache {
                     destination: Destination::Font,
                     origin: url.clone(),
                     .. RequestInit::default()
                 };
 
                 let channel_to_self = self.channel_to_self.clone();
                 let bytes = Mutex::new(Vec::new());
                 let response_valid = Mutex::new(false);
+                debug!("Loading @font-face {} from {}", family_name, url);
                 fetch_async(request, &self.core_resource_thread, move |response| {
                     match response {
                         FetchResponseMsg::ProcessRequestBody |
                         FetchResponseMsg::ProcessRequestEOF => (),
                         FetchResponseMsg::ProcessResponse(meta_result) => {
+                            trace!("@font-face {} metadata ok={:?}", family_name, meta_result.is_ok());
                             *response_valid.lock().unwrap() = meta_result.is_ok();
                         }
                         FetchResponseMsg::ProcessResponseChunk(new_bytes) => {
+                            trace!("@font-face {} chunk={:?}", family_name, new_bytes);
                             if *response_valid.lock().unwrap() {
                                 bytes.lock().unwrap().extend(new_bytes.into_iter())
                             }
                         }
                         FetchResponseMsg::ProcessResponseEOF(response) => {
+                            trace!("@font-face {} EOF={:?}", family_name, response);
                             if response.is_err() || !*response_valid.lock().unwrap() {
                                 let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone());
                                 channel_to_self.send(msg).unwrap();
                                 return;
                             }
                             let bytes = mem::replace(&mut *bytes.lock().unwrap(), vec![]);
+                            trace!("@font-face {} data={:?}", family_name, bytes);
                             let bytes = match fontsan::process(&bytes) {
                                 Ok(san) => san,
                                 Err(_) => {
                                     // FIXME(servo/fontsan#1): get an error message
                                     debug!("Sanitiser rejected web font: \
-                                            family={:?} url={:?}", family_name, url);
+                                            family={} url={:?}", family_name, url);
                                     let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone());
                                     channel_to_self.send(msg).unwrap();
                                     return;
                                 },
                             };
                             let command =
                                 Command::AddDownloadedWebFont(family_name.clone(),
                                                               url.clone(),
@@ -391,17 +397,17 @@ pub struct FontCacheThread {
 }
 
 impl FontCacheThread {
     pub fn new(core_resource_thread: CoreResourceThread,
                webrender_api: Option<webrender_traits::RenderApi>) -> FontCacheThread {
         let (chan, port) = ipc::channel().unwrap();
 
         let channel_to_self = chan.clone();
-        spawn_named("FontCacheThread".to_owned(), move || {
+        thread::Builder::new().name("FontCacheThread".to_owned()).spawn(move || {
             // TODO: Allow users to specify these.
             let generic_fonts = populate_generic_fonts();
 
             let mut cache = FontCache {
                 port: port,
                 channel_to_self: channel_to_self,
                 generic_fonts: generic_fonts,
                 local_families: HashMap::new(),
@@ -409,17 +415,17 @@ impl FontCacheThread {
                 font_context: FontContextHandle::new(),
                 core_resource_thread: core_resource_thread,
                 webrender_api: webrender_api,
                 webrender_fonts: HashMap::new(),
             };
 
             cache.refresh_local_families();
             cache.run();
-        });
+        }).expect("Thread spawning failed");
 
         FontCacheThread {
             chan: chan,
         }
     }
 
     pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
                                                 -> Option<FontTemplateInfo> {
@@ -483,8 +489,14 @@ impl LowercaseString {
 impl Deref for LowercaseString {
     type Target = str;
 
     #[inline]
     fn deref(&self) -> &str {
         &*self.inner
     }
 }
+
+impl fmt::Display for LowercaseString {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
--- a/servo/components/gfx/lib.rs
+++ b/servo/components/gfx/lib.rs
@@ -58,26 +58,26 @@ extern crate msg;
 extern crate net_traits;
 extern crate ordered_float;
 #[macro_use]
 extern crate range;
 extern crate rustc_serialize;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
+extern crate servo_geometry;
 extern crate servo_url;
 #[macro_use] extern crate servo_atoms;
 #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
 extern crate simd;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate time;
 extern crate unicode_script;
-extern crate util;
 extern crate webrender_traits;
 extern crate xi_unicode;
 
 #[deny(unsafe_code)]
 pub mod display_list;
 
 // Fonts
 #[macro_use] pub mod font;
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -34,20 +34,20 @@ range = {path = "../range"}
 rayon = "0.5"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = "0.15"
 serde = "0.8"
 serde_derive = "0.8"
 serde_json = "0.8"
 servo_atoms = {path = "../atoms"}
+servo_config = {path = "../config"}
 servo_url = {path = "../url"}
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 unicode-bidi = "0.2"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
-util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive", "ipc"]
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -50,23 +50,22 @@ use model::{AdjoiningMargins, Collapsibl
 use model::{specified, specified_or_none};
 use sequential;
 use serde::{Serialize, Serializer};
 use std::cmp::{max, min};
 use std::fmt;
 use std::sync::Arc;
 use style::computed_values::{border_collapse, box_sizing, display, float, overflow_x, overflow_y};
 use style::computed_values::{position, text_align};
-use style::context::{SharedStyleContext, StyleContext};
+use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPOSITION};
 use style::values::computed::{LengthOrPercentageOrNone, LengthOrPercentage};
 use style::values::computed::LengthOrPercentageOrAuto;
-use util::clamp;
 
 /// Information specific to floated blocks.
 #[derive(Clone, Serialize)]
 pub struct FloatedBlockInfo {
     /// The amount of inline size that is available for the float.
     pub containing_inline_size: Au,
 
     /// The float ceiling, relative to `BaseFlow::position::cur_b` (i.e. the top part of the border
@@ -1529,17 +1528,17 @@ impl BlockFlow {
             if let MaybeAuto::Specified(size) = MaybeAuto::from_style(specified_inline_size,
                                                                       container_size) {
                 match self.fragment.style().get_position().box_sizing {
                     box_sizing::T::border_box => size,
                     box_sizing::T::content_box =>
                         size + self.fragment.border_padding.inline_start_end(),
                 }
             } else {
-                clamp(min_inline_size, available_inline_size, max_inline_size)
+                max(min_inline_size, min(available_inline_size, max_inline_size))
             };
         self.base.position.size.inline = inline_size + self.fragment.margin.inline_start_end();
 
         // If float speculation failed, fixup our layout, and re-layout all the children.
         if self.fragment.margin_box_inline_size() != self.base.position.size.inline {
             debug!("assign_inline_position_for_formatting_context: float speculation failed");
             // Fix-up our own layout.
             // We can't just traverse_flow_tree_preorder ourself, because that would re-run
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -33,16 +33,17 @@ use gfx::display_list::OpaqueNode;
 use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow};
 use inline::{InlineFragmentNodeInfo, LAST_FRAGMENT_OF_ELEMENT};
 use linked_list::prepend_from;
 use list_item::{ListItemFlow, ListStyleTypeContent};
 use multicol::{MulticolColumnFlow, MulticolFlow};
 use parallel;
 use script_layout_interface::{LayoutElementType, LayoutNodeType, is_image_data};
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
+use servo_config::opts;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::LinkedList;
 use std::marker::PhantomData;
 use std::mem;
 use std::sync::Arc;
 use std::sync::atomic::Ordering;
 use style::computed_values::{caption_side, display, empty_cells, float, list_style_position};
@@ -59,17 +60,16 @@ use table::TableFlow;
 use table_caption::TableCaptionFlow;
 use table_cell::TableCellFlow;
 use table_colgroup::TableColGroupFlow;
 use table_row::TableRowFlow;
 use table_rowgroup::TableRowGroupFlow;
 use table_wrapper::TableWrapperFlow;
 use text::TextRunScanner;
 use traversal::PostorderNodeMutTraversal;
-use util::opts;
 use wrapper::{LayoutNodeLayoutData, TextContent, ThreadSafeLayoutNodeHelpers};
 
 /// The results of flow construction for a DOM node.
 #[derive(Clone)]
 pub enum ConstructionResult {
     /// This node contributes nothing at all (`display: none`). Alternately, this is what newly
     /// created nodes have their `ConstructionResult` set to.
     None,
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -12,62 +12,73 @@ use gfx::display_list::WebRenderImageInf
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context::FontContext;
 use heapsize::HeapSizeOf;
 use ipc_channel::ipc;
 use net_traits::image::base::Image;
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread, ImageResponse, ImageState};
 use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
 use parking_lot::RwLock;
+use servo_config::opts;
 use servo_url::ServoUrl;
 use std::borrow::Borrow;
 use std::cell::{RefCell, RefMut};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
-use style::context::{LocalStyleContext, StyleContext, SharedStyleContext};
-use util::opts;
+use style::context::{SharedStyleContext, ThreadLocalStyleContext};
 
-struct LocalLayoutContext {
-    style_context: LocalStyleContext,
-
-    font_context: RefCell<FontContext>,
+pub struct ThreadLocalLayoutContext {
+    pub style_context: ThreadLocalStyleContext,
+    pub font_context: RefCell<FontContext>,
 }
 
-impl HeapSizeOf for LocalLayoutContext {
+impl ThreadLocalLayoutContext {
+    pub fn new(shared: &SharedLayoutContext) -> Rc<Self> {
+        let font_cache_thread = shared.font_cache_thread.lock().unwrap().clone();
+        let local_style_data = shared.style_context.local_context_creation_data.lock().unwrap();
+
+        Rc::new(ThreadLocalLayoutContext {
+            style_context: ThreadLocalStyleContext::new(&local_style_data),
+            font_context: RefCell::new(FontContext::new(font_cache_thread)),
+        })
+    }
+}
+
+impl Borrow<ThreadLocalStyleContext> for ThreadLocalLayoutContext {
+    fn borrow(&self) -> &ThreadLocalStyleContext {
+        &self.style_context
+    }
+}
+
+impl HeapSizeOf for ThreadLocalLayoutContext {
     // FIXME(njn): measure other fields eventually.
     fn heap_size_of_children(&self) -> usize {
         self.font_context.heap_size_of_children()
     }
 }
 
-thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<LocalLayoutContext>>> = RefCell::new(None));
+thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<ThreadLocalLayoutContext>>> = RefCell::new(None));
 
 pub fn heap_size_of_local_context() -> usize {
     LOCAL_CONTEXT_KEY.with(|r| {
         r.borrow().clone().map_or(0, |context| context.heap_size_of_children())
     })
 }
 
 // Keep this implementation in sync with the one in ports/geckolib/traversal.rs.
-fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext)
-                               -> Rc<LocalLayoutContext> {
+pub fn create_or_get_local_context(shared: &SharedLayoutContext)
+                                   -> Rc<ThreadLocalLayoutContext> {
     LOCAL_CONTEXT_KEY.with(|r| {
         let mut r = r.borrow_mut();
         if let Some(context) = r.clone() {
             context
         } else {
-            let font_cache_thread = shared_layout_context.font_cache_thread.lock().unwrap().clone();
-            let local_style_data = shared_layout_context.style_context.local_context_creation_data.lock().unwrap();
-
-            let context = Rc::new(LocalLayoutContext {
-                style_context: LocalStyleContext::new(&local_style_data),
-                font_context: RefCell::new(FontContext::new(font_cache_thread)),
-            });
+            let context = ThreadLocalLayoutContext::new(shared);
             *r = Some(context.clone());
             context
         }
     })
 }
 
 /// Layout information shared among all workers. This must be thread-safe.
 pub struct SharedLayoutContext {
@@ -92,47 +103,47 @@ pub struct SharedLayoutContext {
 impl Borrow<SharedStyleContext> for SharedLayoutContext {
     fn borrow(&self) -> &SharedStyleContext {
         &self.style_context
     }
 }
 
 pub struct LayoutContext<'a> {
     pub shared: &'a SharedLayoutContext,
-    cached_local_layout_context: Rc<LocalLayoutContext>,
+    pub thread_local: &'a ThreadLocalLayoutContext,
 }
 
-impl<'a> StyleContext<'a> for LayoutContext<'a> {
-    fn shared_context(&self) -> &'a SharedStyleContext {
-        &self.shared.style_context
-    }
-
-    fn local_context(&self) -> &LocalStyleContext {
-        &self.cached_local_layout_context.style_context
+impl<'a> LayoutContext<'a> {
+    pub fn new(shared: &'a SharedLayoutContext,
+               thread_local: &'a ThreadLocalLayoutContext) -> Self
+    {
+        LayoutContext {
+            shared: shared,
+            thread_local: thread_local,
+        }
     }
 }
 
 impl<'a> LayoutContext<'a> {
-    pub fn new(shared_layout_context: &'a SharedLayoutContext) -> LayoutContext<'a> {
-        let local_context = create_or_get_local_context(shared_layout_context);
-
-        LayoutContext {
-            shared: shared_layout_context,
-            cached_local_layout_context: local_context,
-        }
+    // FIXME(bholley): The following two methods are identical and should be merged.
+    // shared_context() is the appropriate name, but it involves renaming a lot of
+    // calls.
+    #[inline(always)]
+    pub fn shared_context(&self) -> &SharedStyleContext {
+        &self.shared.style_context
     }
 
     #[inline(always)]
     pub fn style_context(&self) -> &SharedStyleContext {
         &self.shared.style_context
     }
 
     #[inline(always)]
     pub fn font_context(&self) -> RefMut<FontContext> {
-        self.cached_local_layout_context.font_context.borrow_mut()
+        self.thread_local.font_context.borrow_mut()
     }
 }
 
 impl SharedLayoutContext {
     fn get_or_request_image_synchronously(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
                                           -> Option<Arc<Image>> {
         debug_assert!(opts::get().output_file.is_some() || opts::get().exit_after_load);
 
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -30,16 +30,17 @@ use gfx::display_list::{TextDisplayItem,
 use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId};
 use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
 use ipc_channel::ipc;
 use list_item::ListItemFlow;
 use model::{self, MaybeAuto, ToGfxMatrix};
 use net_traits::image::base::PixelFormat;
 use net_traits::image_cache_thread::UsePlaceholder;
 use range::Range;
+use servo_config::opts;
 use servo_url::ServoUrl;
 use std::{cmp, f32};
 use std::collections::HashMap;
 use std::default::Default;
 use std::mem;
 use std::sync::Arc;
 use style::computed_values::{background_attachment, background_clip, background_origin};
 use style::computed_values::{background_repeat, background_size, border_style};
@@ -48,21 +49,20 @@ use style::computed_values::{pointer_eve
 use style::computed_values::_servo_overflow_clip_box as overflow_clip_box;
 use style::computed_values::filter::Filter;
 use style::computed_values::text_shadow::TextShadow;
 use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
 use style::properties::{self, ServoComputedValues};
 use style::properties::style_structs;
 use style::servo::restyle_damage::REPAINT;
 use style::values::{self, Either, RGBA, computed};
-use style::values::computed::{Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto};
-use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
+use style::values::computed::{AngleOrCorner, Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto};
+use style::values::specified::{HorizontalDirection, VerticalDirection};
 use style_traits::cursor::Cursor;
 use table_cell::CollapsedBordersForCell;
-use util::opts;
 use webrender_traits::{ColorF, GradientStop};
 
 trait RgbColor {
     fn rgb(r: u8, g: u8, b: u8) -> Self;
 }
 
 impl RgbColor for ColorF {
     fn rgb(r: u8, g: u8, b: u8) -> Self {
@@ -750,21 +750,22 @@ impl FragmentDisplayListBuilding for Fra
                     // If the ‘background-attachment’ value for this image is ‘fixed’, then
                     // 'background-origin' has no effect.
                     origin_x = Au(0);
                     origin_y = Au(0);
                     (Au(0), Au(0))
                 }
             };
 
-            let position = *get_cyclic(&background.background_position.0, index);
+            let horiz_position = *get_cyclic(&background.background_position_x.0, index);
+            let vert_position = *get_cyclic(&background.background_position_y.0, index);
             // Use `background-position` to get the offset.
-            let horizontal_position = model::specified(position.horizontal,
+            let horizontal_position = model::specified(horiz_position.0,
                                                        bounds.size.width - image_size.width);
-            let vertical_position = model::specified(position.vertical,
+            let vertical_position = model::specified(vert_position.0,
                                                      bounds.size.height - image_size.height);
 
             // The anchor position for this background, based on both the background-attachment
             // and background-position properties.
             let anchor_origin_x = border.left + virtual_origin_x + origin_x + horizontal_position;
             let anchor_origin_y = border.top + virtual_origin_y + origin_y + vertical_position;
 
             let mut tile_spacing = Size2D::zero();
--- a/servo/components/layout/flex.rs
+++ b/servo/components/layout/flex.rs
@@ -21,17 +21,17 @@ use gfx_traits::ScrollRootId;
 use layout_debug;
 use model::{IntrinsicISizes, MaybeAuto, SizeConstraint};
 use model::{specified, specified_or_none};
 use std::cmp::{max, min};
 use std::ops::Range;
 use std::sync::Arc;
 use style::computed_values::{align_content, align_self, flex_direction, flex_wrap, justify_content};
 use style::computed_values::border_collapse;
-use style::context::{SharedStyleContext, StyleContext};
+use style::context::SharedStyleContext;
 use style::logical_geometry::{Direction, LogicalSize};
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
 use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone};
 
 /// The size of an axis. May be a specified size, a min/max
 /// constraint, or an unlimited size
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -27,17 +27,17 @@ use range::{Range, RangeIndex};
 use script_layout_interface::wrapper_traits::PseudoElementType;
 use std::{fmt, i32, isize, mem};
 use std::cmp::max;
 use std::collections::VecDeque;
 use std::sync::Arc;
 use style::arc_ptr_eq;
 use style::computed_values::{display, overflow_x, position, text_align, text_justify};
 use style::computed_values::{vertical_align, white_space};
-use style::context::{SharedStyleContext, StyleContext};
+use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
 use style::properties::{longhands, ServoComputedValues};
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPOSITION, RESOLVE_GENERATED_CONTENT};
 use text;
 use unicode_bidi;
 
 /// `Line`s are represented as offsets into the child list, rather than
 /// as an object that "owns" fragments. Choosing a different set of line
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -44,23 +44,23 @@ extern crate range;
 extern crate rayon;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate serde_json;
 #[macro_use] extern crate servo_atoms;
+extern crate servo_config;
 extern crate servo_url;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate unicode_bidi;
 extern crate unicode_script;
-extern crate util;
 extern crate webrender_traits;
 
 #[macro_use]
 pub mod layout_debug;
 
 pub mod animation;
 mod block;
 pub mod construct;
--- a/servo/components/layout/multicol.rs
+++ b/servo/components/layout/multicol.rs
@@ -16,17 +16,17 @@ use floats::FloatKind;
 use flow::{Flow, FlowClass, OpaqueFlow, mut_base, FragmentationContext};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx::display_list::StackingContext;
 use gfx_traits::ScrollRootId;
 use gfx_traits::print_tree::PrintTree;
 use std::cmp::{min, max};
 use std::fmt;
 use std::sync::Arc;
-use style::context::{StyleContext, SharedStyleContext};
+use style::context::SharedStyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use style::values::Either;
 use style::values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 
 pub struct MulticolFlow {
     pub block_flow: BlockFlow,
 
--- a/servo/components/layout/parallel.rs
+++ b/servo/components/layout/parallel.rs
@@ -3,28 +3,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Implements parallel traversals over the DOM and flow trees.
 //!
 //! This code is highly unsafe. Keep this file small and easy to audit.
 
 #![allow(unsafe_code)]
 
-use context::{LayoutContext, SharedLayoutContext};
+use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext};
+use context::create_or_get_local_context;
 use flow::{self, Flow, MutableFlowUtils, PostorderFlowTraversal, PreorderFlowTraversal};
 use flow_ref::FlowRef;
 use profile_traits::time::{self, TimerMetadata, profile};
 use rayon;
+use servo_config::opts;
 use std::mem;
 use std::sync::atomic::{AtomicIsize, Ordering};
 use style::dom::UnsafeNode;
 use style::parallel::CHUNK_SIZE;
 use traversal::{AssignISizes, BubbleISizes};
 use traversal::AssignBSizes;
-use util::opts;
 
 pub use style::parallel::traverse_dom;
 
 #[allow(dead_code)]
 fn static_assertion(node: UnsafeNode) {
     unsafe {
         let _: UnsafeFlow = ::std::intrinsics::transmute(node);
     }
@@ -47,17 +48,17 @@ pub fn borrowed_flow_to_unsafe_flow(flow
     unsafe {
         mem::transmute::<&Flow, UnsafeFlow>(flow)
     }
 }
 
 pub type ChunkedFlowTraversalFunction<'scope> =
     extern "Rust" fn(Box<[UnsafeFlow]>, &'scope SharedLayoutContext, &rayon::Scope<'scope>);
 
-pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &SharedLayoutContext);
+pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &LayoutContext);
 
 /// Information that we need stored in each flow.
 pub struct FlowParallelInfo {
     /// The number of children that still need work done.
     pub children_count: AtomicIsize,
     /// The address of the parent flow.
     pub parent: UnsafeFlow,
 }
@@ -135,21 +136,24 @@ trait ParallelPreorderFlowTraversal : Pr
                             layout_context: &'scope SharedLayoutContext,
                             scope: &rayon::Scope<'scope>);
 
     fn should_record_thread_ids(&self) -> bool;
 
     #[inline(always)]
     fn run_parallel_helper<'scope>(&self,
                                    unsafe_flows: &[UnsafeFlow],
-                                   layout_context: &'scope SharedLayoutContext,
+                                   shared: &'scope SharedLayoutContext,
                                    scope: &rayon::Scope<'scope>,
                                    top_down_func: ChunkedFlowTraversalFunction<'scope>,
                                    bottom_up_func: FlowTraversalFunction)
     {
+        let tlc = create_or_get_local_context(shared);
+        let context = LayoutContext::new(&shared, &*tlc);
+
         let mut discovered_child_flows = vec![];
         for unsafe_flow in unsafe_flows {
             let mut had_children = false;
             unsafe {
                 // Get a real flow.
                 let flow: &mut Flow = mem::transmute(*unsafe_flow);
 
                 if self.should_record_thread_ids() {
@@ -170,25 +174,25 @@ trait ParallelPreorderFlowTraversal : Pr
                 for kid in flow::child_iter_mut(flow) {
                     had_children = true;
                     discovered_child_flows.push(borrowed_flow_to_unsafe_flow(kid));
                 }
             }
 
             // If there were no more children, start assigning block-sizes.
             if !had_children {
-                bottom_up_func(*unsafe_flow, layout_context)
+                bottom_up_func(*unsafe_flow, &context)
             }
         }
 
         for chunk in discovered_child_flows.chunks(CHUNK_SIZE) {
             let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
 
             scope.spawn(move |scope| {
-                top_down_func(nodes, layout_context, scope);
+                top_down_func(nodes, shared, scope);
             });
         }
     }
 }
 
 impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
     fn run_parallel<'scope>(&self,
                                   unsafe_flows: &[UnsafeFlow],
@@ -215,39 +219,39 @@ fn assign_inline_sizes<'scope>(unsafe_fl
     let assign_inline_sizes_traversal = AssignISizes {
         shared_context: &shared_layout_context.style_context,
     };
     assign_inline_sizes_traversal.run_parallel(&unsafe_flows, shared_layout_context, scope)
 }
 
 fn assign_block_sizes_and_store_overflow(
         unsafe_flow: UnsafeFlow,
-        shared_layout_context: &SharedLayoutContext) {
-    let layout_context = LayoutContext::new(shared_layout_context);
+        context: &LayoutContext) {
     let assign_block_sizes_traversal = AssignBSizes {
-        layout_context: &layout_context,
+        layout_context: context,
     };
     assign_block_sizes_traversal.run_parallel(unsafe_flow)
 }
 
 pub fn traverse_flow_tree_preorder(
         root: &mut Flow,
         profiler_metadata: Option<TimerMetadata>,
         time_profiler_chan: time::ProfilerChan,
-        shared_layout_context: &SharedLayoutContext,
+        shared: &SharedLayoutContext,
         queue: &rayon::ThreadPool) {
     if opts::get().bubble_inline_sizes_separately {
-        let layout_context = LayoutContext::new(shared_layout_context);
-        let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
+        let tlc = ThreadLocalLayoutContext::new(shared);
+        let context = LayoutContext::new(shared, &*tlc);
+        let bubble_inline_sizes = BubbleISizes { layout_context: &context };
         root.traverse_postorder(&bubble_inline_sizes);
     }
 
     let nodes = vec![borrowed_flow_to_unsafe_flow(root)].into_boxed_slice();
 
     queue.install(move || {
         rayon::scope(move |scope| {
             profile(time::ProfilerCategory::LayoutParallelWarmup,
                     profiler_metadata, time_profiler_chan, move || {
-                assign_inline_sizes(nodes, &shared_layout_context, scope);
+                assign_inline_sizes(nodes, &shared, scope);
             });
         });
     });
 }
--- a/servo/components/layout/query.rs
+++ b/servo/components/layout/query.rs
@@ -1,16 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Utilities for querying the layout, as needed by the layout thread.
 
 use app_units::Au;
 use construct::ConstructionResult;
+use context::SharedLayoutContext;
+use context::create_or_get_local_context;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::size::Size2D;
 use flow::{self, Flow};
 use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
 use gfx::display_list::{DisplayItemMetadata, DisplayList, OpaqueNode, ScrollOffsetMap};
 use gfx_traits::ScrollRootId;
 use ipc_channel::ipc::IpcSender;
@@ -619,39 +621,44 @@ pub fn process_node_scroll_area_request<
             Rect::new(Point2D::new(iterator.origin_rect.origin.x, top),
                       Size2D::new(right, iterator.origin_rect.size.height))
         }
     }
 }
 
 /// Return the resolved value of property for a given (pseudo)element.
 /// https://drafts.csswg.org/cssom/#resolved-value
-pub fn process_resolved_style_request<'a, N, C>(requested_node: N,
-                                                style_context: &'a C,
-                                                pseudo: &Option<PseudoElement>,
-                                                property: &PropertyId,
-                                                layout_root: &mut Flow) -> String
+pub fn process_resolved_style_request<'a, N>(shared: &SharedLayoutContext,
+                                             requested_node: N,
+                                             pseudo: &Option<PseudoElement>,
+                                             property: &PropertyId,
+                                             layout_root: &mut Flow) -> String
     where N: LayoutNode,
-          C: StyleContext<'a>
 {
     use style::traversal::{clear_descendant_data, style_element_in_display_none_subtree};
     let element = requested_node.as_element().unwrap();
 
     // We call process_resolved_style_request after performing a whole-document
     // traversal, so the only reason we wouldn't have an up-to-date style here
     // is that the requested node is in a display:none subtree. We currently
     // maintain the invariant that elements in display:none subtrees always have
     // no ElementData, so we need to temporarily bend those invariants here, and
     // then throw them the style data away again before returning to preserve them.
     // We could optimize this later to keep the style data cached somehow, but
     // we'd need a mechanism to prevent detect when it's stale (since we don't
     // traverse display:none subtrees during restyle).
     let display_none_root = if element.get_data().is_none() {
-        Some(style_element_in_display_none_subtree(element, &|e| e.as_node().initialize_data(),
-                                                   style_context))
+        let tlc = create_or_get_local_context(shared);
+        let context = StyleContext {
+            shared: &shared.style_context,
+            thread_local: &tlc.style_context,
+        };
+
+        Some(style_element_in_display_none_subtree(&context, element,
+                                                   &|e| e.as_node().initialize_data()))
     } else {
         None
     };
 
     let layout_el = requested_node.to_threadsafe().as_element().unwrap();
     let layout_el = match *pseudo {
         Some(PseudoElement::Before) => layout_el.get_before_pseudo(),
         Some(PseudoElement::After) => layout_el.get_after_pseudo(),
--- a/servo/components/layout/sequential.rs
+++ b/servo/components/layout/sequential.rs
@@ -1,69 +1,70 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Implements sequential traversals over the DOM and flow trees.
 
 use app_units::Au;
-use context::{LayoutContext, SharedLayoutContext};
+use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext};
 use display_list_builder::DisplayListBuildState;
 use euclid::point::Point2D;
 use floats::SpeculatedFloatPlacement;
 use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
 use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
 use flow::IS_ABSOLUTELY_POSITIONED;
 use fragment::FragmentBorderBoxIterator;
 use generated_content::ResolveGeneratedContent;
 use gfx_traits::ScrollRootId;
-use style::context::StyleContext;
+use servo_config::opts;
 use style::servo::restyle_damage::{REFLOW, STORE_OVERFLOW};
 use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
-use util::opts;
 
 pub use style::sequential::traverse_dom;
 
-pub fn resolve_generated_content(root: &mut Flow, shared_layout_context: &SharedLayoutContext) {
+pub fn resolve_generated_content(root: &mut Flow, shared: &SharedLayoutContext) {
     fn doit(flow: &mut Flow, level: u32, traversal: &mut ResolveGeneratedContent) {
         if !traversal.should_process(flow) {
             return
         }
 
         traversal.process(flow, level);
 
         for kid in flow::mut_base(flow).children.iter_mut() {
             doit(kid, level + 1, traversal)
         }
     }
 
-    let layout_context = LayoutContext::new(shared_layout_context);
+    let tlc = ThreadLocalLayoutContext::new(shared);
+    let layout_context = LayoutContext::new(shared, &*tlc);
     let mut traversal = ResolveGeneratedContent::new(&layout_context);
     doit(root, 0, &mut traversal)
 }
 
 pub fn traverse_flow_tree_preorder(root: &mut Flow,
-                                   shared_layout_context: &SharedLayoutContext) {
+                                   shared: &SharedLayoutContext) {
     fn doit(flow: &mut Flow,
             assign_inline_sizes: AssignISizes,
             assign_block_sizes: AssignBSizes) {
         if assign_inline_sizes.should_process(flow) {
             assign_inline_sizes.process(flow);
         }
 
         for kid in flow::child_iter_mut(flow) {
             doit(kid, assign_inline_sizes, assign_block_sizes);
         }
 
         if assign_block_sizes.should_process(flow) {
             assign_block_sizes.process(flow);
         }
     }
 
-    let layout_context = LayoutContext::new(shared_layout_context);
+    let tlc = ThreadLocalLayoutContext::new(shared);
+    let layout_context = LayoutContext::new(shared, &*tlc);
 
     if opts::get().bubble_inline_sizes_separately {
         let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
         {
             let root: &mut Flow = root;
             root.traverse_postorder(&bubble_inline_sizes);
         }
     }
--- a/servo/components/layout/traversal.rs
+++ b/servo/components/layout/traversal.rs
@@ -1,97 +1,89 @@
 /* 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 construct::FlowConstructor;
-use context::{LayoutContext, SharedLayoutContext};
+use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext};
+use context::create_or_get_local_context;
 use display_list_builder::DisplayListBuildState;
 use flow::{self, PreorderFlowTraversal};
 use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
 use gfx::display_list::OpaqueNode;
 use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
-use std::mem;
+use servo_config::opts;
+use std::rc::Rc;
 use style::atomic_refcell::AtomicRefCell;
-use style::context::{LocalStyleContext, SharedStyleContext, StyleContext};
+use style::context::{SharedStyleContext, StyleContext};
 use style::data::ElementData;
 use style::dom::{TElement, TNode};
 use style::selector_parser::RestyleDamage;
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
-use style::traversal::{DomTraversalContext, recalc_style_at, remove_from_bloom_filter};
+use style::traversal::{DomTraversal, recalc_style_at, remove_from_bloom_filter};
 use style::traversal::PerLevelTraversalData;
-use util::opts;
 use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData};
 
-pub struct RecalcStyleAndConstructFlows<'lc> {
-    context: LayoutContext<'lc>,
+pub struct RecalcStyleAndConstructFlows {
+    shared: SharedLayoutContext,
     root: OpaqueNode,
 }
 
+impl RecalcStyleAndConstructFlows {
+    pub fn shared_layout_context(&self) -> &SharedLayoutContext {
+        &self.shared
+    }
+}
+
+impl RecalcStyleAndConstructFlows {
+    /// Creates a traversal context, taking ownership of the shared layout context.
+    pub fn new(shared: SharedLayoutContext, root: OpaqueNode) -> Self {
+        RecalcStyleAndConstructFlows {
+            shared: shared,
+            root: root,
+        }
+    }
+
+    /// Consumes this traversal context, returning ownership of the shared layout
+    /// context to the caller.
+    pub fn destroy(self) -> SharedLayoutContext {
+        self.shared
+    }
+}
+
 #[allow(unsafe_code)]
-impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc>
+impl<N> DomTraversal<N> for RecalcStyleAndConstructFlows
     where N: LayoutNode + TNode,
           N::ConcreteElement: TElement
-
 {
-    type SharedContext = SharedLayoutContext;
-    #[allow(unsafe_code)]
-    fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self {
-        // FIXME(bholley): This transmutation from &'a to &'lc is very unfortunate, but I haven't
-        // found a way to avoid it despite spending several days on it (and consulting Manishearth,
-        // brson, and nmatsakis).
-        //
-        // The crux of the problem is that parameterizing DomTraversalContext on the lifetime of
-        // the SharedContext doesn't work for a variety of reasons [1]. However, the code in
-        // parallel.rs needs to be able to use the DomTraversalContext trait (or something similar)
-        // to stack-allocate a struct (a generalized LayoutContext<'a>) that holds a borrowed
-        // SharedContext, which means that the struct needs to be parameterized on a lifetime.
-        // Given the aforementioned constraint, the only way to accomplish this is to avoid
-        // propagating the borrow lifetime from the struct to the trait, but that means that the
-        // new() method on the trait cannot require the lifetime of its argument to match the
-        // lifetime of the Self object it creates.
-        //
-        // This could be solved with an associated type with an unbound lifetime parameter, but
-        // that would require higher-kinded types, which don't exist yet and probably aren't coming
-        // for a while.
-        //
-        // So we transmute. :-( This is safe because the DomTravesalContext is stack-allocated on
-        // the worker thread while processing a WorkUnit, whereas the borrowed SharedContext is
-        // live for the entire duration of the restyle. This really could _almost_ compile: all
-        // we'd need to do is change the signature to to |new<'a: 'lc>|, and everything would
-        // work great. But we can't do that, because that would cause a mismatch with the signature
-        // in the trait we're implementing, and we can't mention 'lc in that trait at all for the
-        // reasons described above.
-        //
-        // [1] For example, the WorkQueue type needs to be parameterized on the concrete type of
-        // DomTraversalContext::SharedContext, and the WorkQueue lifetime is similar to that of the
-        // LayoutThread, generally much longer than that of a given SharedLayoutContext borrow.
-        let shared_lc: &'lc SharedLayoutContext = unsafe { mem::transmute(shared) };
-        RecalcStyleAndConstructFlows {
-            context: LayoutContext::new(shared_lc),
-            root: root,
-        }
-    }
+    type ThreadLocalContext = ThreadLocalLayoutContext;
 
     fn process_preorder(&self, node: N, traversal_data: &mut PerLevelTraversalData) {
         // FIXME(pcwalton): Stop allocating here. Ideally this should just be
         // done by the HTML parser.
         node.initialize_data();
 
         if !node.is_text_node() {
             let el = node.as_element().unwrap();
             let mut data = el.mutate_data().unwrap();
-            recalc_style_at::<_, _, Self>(&self.context, traversal_data, el, &mut data);
+            let tlc = create_or_get_local_context(&self.shared);
+            let context = StyleContext {
+                shared: &self.shared.style_context,
+                thread_local: &tlc.style_context,
+            };
+            recalc_style_at(self, traversal_data, &context, el, &mut data);
         }
     }
 
     fn process_postorder(&self, node: N) {
-        construct_flows_at(&self.context, self.root, node);
+        let tlc = create_or_get_local_context(&self.shared);
+        let context = LayoutContext::new(&self.shared, &*tlc);
+        construct_flows_at(&context, self.root, node);
     }
 
     fn text_node_needs_traversal(node: N) -> bool {
         // Text nodes never need styling. However, there are two cases they may need
         // flow construction:
         // (1) They child doesn't yet have layout data (preorder traversal initializes it).
         // (2) The parent element has restyle damage (so the text flow also needs fixup).
         node.get_raw_data().is_none() ||
@@ -102,31 +94,37 @@ impl<'lc, N> DomTraversalContext<N> for 
         element.as_node().initialize_data();
         element.get_data().unwrap()
     }
 
     unsafe fn clear_element_data(element: &N::ConcreteElement) {
         element.as_node().clear_data();
     }
 
-    fn local_context(&self) -> &LocalStyleContext {
-        self.context.local_context()
+    fn shared_context(&self) -> &SharedStyleContext {
+        &self.shared.style_context
+    }
+
+    fn create_or_get_thread_local_context(&self) -> Rc<ThreadLocalLayoutContext> {
+        create_or_get_local_context(&self.shared)
     }
 }
 
 /// A bottom-up, parallelizable traversal.
 pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> {
     /// The operation to perform. Return true to continue or false to stop.
     fn process(&mut self, node: &ConcreteThreadSafeLayoutNode);
 }
 
 /// The flow construction traversal, which builds flows for styled nodes.
 #[inline]
 #[allow(unsafe_code)]
-fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: OpaqueNode, node: N) {
+fn construct_flows_at<'a, N>(context: &LayoutContext<'a>, root: OpaqueNode, node: N)
+    where N: LayoutNode,
+{
     debug!("construct_flows_at: {:?}", node);
 
     // Construct flows for this node.
     {
         let tnode = node.to_threadsafe();
 
         // Always reconstruct if incremental layout is turned off.
         let nonincremental_layout = opts::get().nonincremental_layout;
@@ -141,17 +139,17 @@ fn construct_flows_at<'a, N: LayoutNode>
             }
         }
     }
 
     if let Some(el) = node.as_element() {
         el.mutate_data().unwrap().persist();
         unsafe { el.unset_dirty_descendants(); }
 
-        remove_from_bloom_filter(context, root, el);
+        remove_from_bloom_filter(&context.shared.style_context, root, el);
     }
 }
 
 /// 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>,
 }
--- a/servo/components/layout/webrender_helpers.rs
+++ b/servo/components/layout/webrender_helpers.rs
@@ -11,17 +11,17 @@ use app_units::Au;
 use euclid::{Point2D, Rect, Size2D};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
 use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal, StackingContextType};
 use gfx_traits::{FragmentType, ScrollPolicy, ScrollRootId};
 use msg::constellation_msg::PipelineId;
 use style::computed_values::{image_rendering, mix_blend_mode};
 use style::computed_values::filter::{self, Filter};
 use style::values::computed::BorderStyle;
-use webrender_traits::{self, DisplayListBuilder};
+use webrender_traits::{self, DisplayListBuilder, LayoutTransform};
 
 pub trait WebRenderDisplayListConverter {
     fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
 }
 
 trait WebRenderDisplayItemConverter {
     fn convert_to_webrender(&self, builder: &mut DisplayListBuilder);
 }
@@ -56,46 +56,48 @@ impl ToBoxShadowClipMode for BoxShadowCl
             BoxShadowClipMode::None => webrender_traits::BoxShadowClipMode::None,
             BoxShadowClipMode::Inset => webrender_traits::BoxShadowClipMode::Inset,
             BoxShadowClipMode::Outset => webrender_traits::BoxShadowClipMode::Outset,
         }
     }
 }
 
 trait ToSizeF {
-    fn to_sizef(&self) -> Size2D<f32>;
+    fn to_sizef(&self) -> webrender_traits::LayoutSize;
 }
 
 trait ToPointF {
-    fn to_pointf(&self) -> Point2D<f32>;
+    fn to_pointf(&self) -> webrender_traits::LayoutPoint;
 }
 
 impl ToPointF for Point2D<Au> {
-    fn to_pointf(&self) -> Point2D<f32> {
-        Point2D::new(self.x.to_f32_px(), self.y.to_f32_px())
+    fn to_pointf(&self) -> webrender_traits::LayoutPoint {
+        webrender_traits::LayoutPoint::new(self.x.to_f32_px(), self.y.to_f32_px())
     }
 }
 
 impl ToSizeF for Size2D<Au> {
-    fn to_sizef(&self) -> Size2D<f32> {
-        Size2D::new(self.width.to_f32_px(), self.height.to_f32_px())
+    fn to_sizef(&self) -> webrender_traits::LayoutSize {
+        webrender_traits::LayoutSize::new(self.width.to_f32_px(), self.height.to_f32_px())
     }
 }
 
 trait ToRectF {
-    fn to_rectf(&self) -> Rect<f32>;
+    fn to_rectf(&self) -> webrender_traits::LayoutRect;
 }
 
 impl ToRectF for Rect<Au> {
-    fn to_rectf(&self) -> Rect<f32> {
+    fn to_rectf(&self) -> webrender_traits::LayoutRect {
         let x = self.origin.x.to_f32_px();
         let y = self.origin.y.to_f32_px();
         let w = self.size.width.to_f32_px();
         let h = self.size.height.to_f32_px();
-        Rect::new(Point2D::new(x, y), Size2D::new(w, h))
+        let point = webrender_traits::LayoutPoint::new(x, y);
+        let size = webrender_traits::LayoutSize::new(w, h);
+        webrender_traits::LayoutRect::new(point, size)
     }
 }
 
 trait ToClipRegion {
     fn to_clip_region(&self, builder: &mut DisplayListBuilder) -> webrender_traits::ClipRegion;
 }
 
 impl ToClipRegion for ClippingRegion {
@@ -335,22 +337,26 @@ impl WebRenderDisplayItemConverter for D
                 let stacking_context = &item.stacking_context;
                 debug_assert!(stacking_context.context_type == StackingContextType::Real);
 
                 let webrender_scroll_policy = match stacking_context.scroll_policy {
                     ScrollPolicy::Scrollable => webrender_traits::ScrollPolicy::Scrollable,
                     ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed,
                 };
 
+                let clip = builder.new_clip_region(&stacking_context.overflow.to_rectf(),
+                                                   vec![],
+                                                   None);
+
                 builder.push_stacking_context(webrender_scroll_policy,
                                               stacking_context.bounds.to_rectf(),
-                                              stacking_context.overflow.to_rectf(),
+                                              clip,
                                               stacking_context.z_index,
-                                              &stacking_context.transform,
-                                              &stacking_context.perspective,
+                                              &LayoutTransform::from_untyped(&stacking_context.transform),
+                                              &LayoutTransform::from_untyped(&stacking_context.perspective),
                                               stacking_context.blend_mode.to_blend_mode(),
                                               stacking_context.filters.to_filter_ops());
             }
             DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(),
             DisplayItem::PushScrollRoot(ref item) => {
                 builder.push_scroll_layer(item.scroll_root.clip.to_rectf(),
                                           item.scroll_root.size.to_sizef(),
                                           item.scroll_root.id.convert_to_webrender());
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -29,16 +29,17 @@ plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rayon = "0.5"
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = "0.15"
 serde_derive = "0.8"
 serde_json = "0.8"
+servo_config = {path = "../config"}
+servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 style = {path = "../style"}
-util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive", "ipc"]
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -35,19 +35,20 @@ extern crate parking_lot;
 #[macro_use]
 extern crate profile_traits;
 extern crate rayon;
 extern crate script;
 extern crate script_layout_interface;
 extern crate script_traits;
 extern crate selectors;
 extern crate serde_json;
+extern crate servo_config;
+extern crate servo_geometry;
 extern crate servo_url;
 extern crate style;
-extern crate util;
 extern crate webrender_traits;
 
 use app_units::Au;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::Size2D;
 use fnv::FnvHasher;
@@ -57,17 +58,17 @@ use gfx::font;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context;
 use gfx_traits::{Epoch, FragmentType, ScrollRootId};
 use heapsize::HeapSizeOf;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use layout::animation;
 use layout::construct::ConstructionResult;
-use layout::context::{LayoutContext, SharedLayoutContext, heap_size_of_local_context};
+use layout::context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext, heap_size_of_local_context};
 use layout::display_list_builder::ToGfxColor;
 use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
 use layout::flow_ref::FlowRef;
 use layout::incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT};
 use layout::layout_debug;
 use layout::parallel;
 use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
 use layout::query::{process_margin_style_query, process_node_overflow_request, process_resolved_style_request};
@@ -89,44 +90,44 @@ use profile_traits::time::{TimerMetadata
 use script::layout_wrapper::{ServoLayoutElement, ServoLayoutDocument, ServoLayoutNode};
 use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
 use script_layout_interface::reporter::CSSErrorReporter;
 use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowResponse, OffsetParentResponse};
 use script_layout_interface::wrapper_traits::LayoutNode;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
 use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
 use selectors::Element;
+use servo_config::opts;
+use servo_config::prefs::PREFS;
+use servo_config::resource_files::read_resource_file;
+use servo_geometry::max_rect;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::ops::{Deref, DerefMut};
 use std::process;
 use std::sync::{Arc, Mutex, MutexGuard};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::mpsc::{Receiver, Sender, channel};
+use std::thread;
 use style::animation::Animation;
-use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext};
+use style::context::{ReflowGoal, SharedStyleContext, ThreadLocalStyleContextCreationInfo};
 use style::data::StoredRestyleHint;
 use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
 use style::error_reporting::{ParseErrorReporter, StdoutErrorReporter};
 use style::logical_geometry::LogicalPoint;
 use style::media_queries::{Device, MediaType};
 use style::parser::ParserContextExtraData;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
 use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
 use style::stylist::Stylist;
 use style::thread_state;
 use style::timer::Timer;
-use style::traversal::DomTraversalContext;
-use util::geometry::max_rect;
-use util::opts;
-use util::prefs::PREFS;
-use util::resource_files::read_resource_file;
-use util::thread;
+use style::traversal::DomTraversal;
 
 /// Information needed by the layout thread.
 pub struct LayoutThread {
     /// The ID of the pipeline that we belong to.
     id: PipelineId,
 
     /// The URL of the pipeline that we belong to.
     url: ServoUrl,
@@ -224,17 +225,17 @@ pub struct LayoutThread {
 
     // Webrender interface.
     webrender_api: webrender_traits::RenderApi,
 
     /// The timer object to control the timing of the animations. This should
     /// only be a test-mode timer during testing for animations.
     timer: Timer,
 
-    // Number of layout threads. This is copied from `util::opts`, but we'd
+    // Number of layout threads. This is copied from `servo_config::opts`, but we'd
     // rather limit the dependency on that module here.
     layout_threads: usize,
 }
 
 impl LayoutThreadFactory for LayoutThread {
     type Message = Msg;
 
     /// Spawns a new layout thread.
@@ -248,18 +249,17 @@ impl LayoutThreadFactory for LayoutThrea
               script_chan: IpcSender<ConstellationControlMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
               mem_profiler_chan: mem::ProfilerChan,
               content_process_shutdown_chan: Option<IpcSender<()>>,
               webrender_api_sender: webrender_traits::RenderApiSender,
               layout_threads: usize) {
-        thread::spawn_named(format!("LayoutThread {:?}", id),
-                      move || {
+        thread::Builder::new().name(format!("LayoutThread {:?}", id)).spawn(move || {
             thread_state::initialize(thread_state::LAYOUT);
 
             if let Some(top_level_frame_id) = top_level_frame_id {
                 FrameId::install(top_level_frame_id);
             }
 
             { // Ensures layout thread is destroyed before we send shutdown message
                 let sender = chan.0;
@@ -280,17 +280,17 @@ impl LayoutThreadFactory for LayoutThrea
                 let reporter_name = format!("layout-reporter-{}", id);
                 mem_profiler_chan.run_with_memory_reporting(|| {
                     layout.start();
                 }, reporter_name, sender, Msg::CollectReports);
             }
             if let Some(content_process_shutdown_chan) = content_process_shutdown_chan {
                 let _ = content_process_shutdown_chan.send(());
             }
-        });
+        }).expect("Thread spawning failed");
     }
 }
 
 /// The `LayoutThread` `rw_data` lock must remain locked until the first reflow,
 /// as RPC calls don't make sense until then. Use this in combination with
 /// `LayoutThread::lock_rw_data` and `LayoutThread::return_rw_data`.
 pub enum RWGuard<'a> {
     /// If the lock was previously held, from when the thread started.
@@ -502,29 +502,30 @@ impl LayoutThread {
     }
 
     // Create a layout context for use in building display lists, hit testing, &c.
     fn build_shared_layout_context(&self,
                                    rw_data: &LayoutThreadData,
                                    screen_size_changed: bool,
                                    goal: ReflowGoal)
                                    -> SharedLayoutContext {
-        let local_style_context_creation_data = LocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
+        let thread_local_style_context_creation_data =
+            ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
 
         SharedLayoutContext {
             style_context: SharedStyleContext {
                 viewport_size: self.viewport_size.clone(),
                 screen_size_changed: screen_size_changed,
                 stylist: rw_data.stylist.clone(),
                 generation: self.generation,
                 goal: goal,
                 running_animations: self.running_animations.clone(),
                 expired_animations: self.expired_animations.clone(),
                 error_reporter: self.error_reporter.clone(),
-                local_context_creation_data: Mutex::new(local_style_context_creation_data),
+                local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
                 timer: self.timer.clone(),
             },
             image_cache_thread: Mutex::new(self.image_cache_thread.clone()),
             image_cache_sender: Mutex::new(self.image_cache_sender.clone()),
             font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
             webrender_image_cache: self.webrender_image_cache.clone(),
         }
     }
@@ -956,18 +957,19 @@ impl LayoutThread {
             let builder = rw_data.display_list.as_ref().unwrap().convert_to_webrender(self.id);
 
             let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(),
                                             self.viewport_size.height.to_f32_px());
 
             self.epoch.next();
             let Epoch(epoch_number) = self.epoch;
 
+            let viewport_size = webrender_traits::LayoutSize::from_untyped(&viewport_size);
             self.webrender_api.set_root_display_list(
-                get_root_flow_background_color(layout_root),
+                Some(get_root_flow_background_color(layout_root)),
                 webrender_traits::Epoch(epoch_number),
                 viewport_size,
                 builder);
         });
     }
 
     /// The high-level routine that performs layout threads.
     fn handle_reflow<'a, 'b>(&mut self,
@@ -1137,34 +1139,41 @@ impl LayoutThread {
             }
         }
 
         // Create a layout context for use throughout the following passes.
         let mut shared_layout_context = self.build_shared_layout_context(&*rw_data,
                                                                          viewport_size_changed,
                                                                          data.reflow_info.goal);
 
+        // NB: Type inference falls apart here for some reason, so we need to be very verbose. :-(
+        let traversal = RecalcStyleAndConstructFlows::new(shared_layout_context, element.as_node().opaque());
         let dom_depth = Some(0); // This is always the root node.
-        let token = <RecalcStyleAndConstructFlows as DomTraversalContext<ServoLayoutNode>>
-            ::pre_traverse(element, &shared_layout_context.style_context.stylist, /* skip_root = */ false);
+        let token = {
+            let stylist = &<RecalcStyleAndConstructFlows as
+                            DomTraversal<ServoLayoutNode>>::shared_context(&traversal).stylist;
+            <RecalcStyleAndConstructFlows as
+             DomTraversal<ServoLayoutNode>>::pre_traverse(element, stylist, /* skip_root = */ false)
+        };
+
         if token.should_traverse() {
             // Recalculate CSS styles and rebuild flows and fragments.
             profile(time::ProfilerCategory::LayoutStyleRecalc,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || {
                 // Perform CSS selector matching and flow construction.
-                if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
+                if let (true, Some(pool)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
                     // Parallel mode
                     parallel::traverse_dom::<ServoLayoutNode, RecalcStyleAndConstructFlows>(
-                        element, dom_depth, &shared_layout_context, token, traversal);
+                        &traversal, element, dom_depth, token, pool);
                 } else {
                     // Sequential mode
                     sequential::traverse_dom::<ServoLayoutNode, RecalcStyleAndConstructFlows>(
-                        element, &shared_layout_context, token);
+                        &traversal, element, token);
                 }
             });
             // TODO(pcwalton): Measure energy usage of text shaping, perhaps?
             let text_shaping_time =
                 (font::get_and_reset_text_shaping_performance_counter() as u64) /
                 (self.layout_threads as u64);
             time::send_profile_data(time::ProfilerCategory::LayoutTextShaping,
                                     self.profiler_metadata(),
@@ -1173,16 +1182,18 @@ impl LayoutThread {
                                     text_shaping_time,
                                     0,
                                     0);
 
             // Retrieve the (possibly rebuilt) root flow.
             self.root_flow = self.try_get_layout_root(element.as_node());
         }
 
+        shared_layout_context = traversal.destroy();
+
         if opts::get().dump_style_tree {
             println!("{:?}", ShowSubtreeDataAndPrimaryValues(element.as_node()));
         }
 
         if opts::get().dump_rule_tree {
             shared_layout_context.style_context.stylist.rule_tree.dump_stdout();
         }
 
@@ -1199,17 +1210,17 @@ impl LayoutThread {
         self.respond_to_query_if_necessary(&data.query_type,
                                            &mut *rw_data,
                                            &mut shared_layout_context);
     }
 
     fn respond_to_query_if_necessary(&mut self,
                                      query_type: &ReflowQueryType,
                                      rw_data: &mut LayoutThreadData,
-                                     shared_layout_context: &mut SharedLayoutContext) {
+                                     shared: &mut SharedLayoutContext) {
         let mut root_flow = match self.root_flow.clone() {
             Some(root_flow) => root_flow,
             None => return,
         };
         let root_flow = FlowRef::deref_mut(&mut root_flow);
         match *query_type {
             ReflowQueryType::ContentBoxQuery(node) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
@@ -1247,20 +1258,19 @@ impl LayoutThread {
                 rw_data.overflow_response = process_node_overflow_request(node);
             },
             ReflowQueryType::NodeScrollRootIdQuery(node) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
                 rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(node));
             },
             ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
-                let layout_context = LayoutContext::new(&shared_layout_context);
                 rw_data.resolved_style_response =
-                    process_resolved_style_request(node,
-                                                   &layout_context,
+                    process_resolved_style_request(shared,
+                                                   node,
                                                    pseudo,
                                                    property,
                                                    root_flow);
             },
             ReflowQueryType::OffsetParentQuery(node) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
                 rw_data.offset_parent_response = process_offset_parent_query(node, root_flow);
             },
@@ -1359,17 +1369,17 @@ impl LayoutThread {
                                                      &mut layout_context);
     }
 
     fn perform_post_style_recalc_layout_passes(&mut self,
                                                data: &Reflow,
                                                query_type: Option<&ReflowQueryType>,
                                                document: Option<&ServoLayoutDocument>,
                                                rw_data: &mut LayoutThreadData,
-                                               layout_context: &mut SharedLayoutContext) {
+                                               shared: &mut SharedLayoutContext) {
         if let Some(mut root_flow) = self.root_flow.clone() {
             // Kick off animations if any were triggered, expire completed ones.
             animation::update_animation_state(&self.constellation_chan,
                                               &self.script_chan,
                                               &mut *self.running_animations.write(),
                                               &mut *self.expired_animations.write(),
                                               &self.new_animations_receiver,
                                               self.id,
@@ -1391,17 +1401,17 @@ impl LayoutThread {
             if opts::get().trace_layout {
                 layout_debug::begin_trace(root_flow.clone());
             }
 
             // Resolve generated content.
             profile(time::ProfilerCategory::LayoutGeneratedContent,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
-                    || sequential::resolve_generated_content(FlowRef::deref_mut(&mut root_flow), &layout_context));
+                    || sequential::resolve_generated_content(FlowRef::deref_mut(&mut root_flow), &shared));
 
             // Guess float placement.
             profile(time::ProfilerCategory::LayoutFloatPlacementSpeculation,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || sequential::guess_float_placement(FlowRef::deref_mut(&mut root_flow)));
 
             // Perform the primary layout passes over the flow tree to compute the locations of all
@@ -1414,38 +1424,39 @@ impl LayoutThread {
                     let profiler_metadata = self.profiler_metadata();
 
                     if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
                         // Parallel mode.
                         LayoutThread::solve_constraints_parallel(traversal,
                                                                  FlowRef::deref_mut(&mut root_flow),
                                                                  profiler_metadata,
                                                                  self.time_profiler_chan.clone(),
-                                                                 &*layout_context);
+                                                                 &*shared);
                     } else {
                         //Sequential mode
-                        LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &layout_context)
+                        LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &shared)
                     }
                 });
             }
 
             profile(time::ProfilerCategory::LayoutStoreOverflow,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || {
-                let layout_context = LayoutContext::new(&*layout_context);
-                sequential::store_overflow(&layout_context,
+                let tlc = ThreadLocalLayoutContext::new(&shared);
+                let context = LayoutContext::new(&shared, &*tlc);
+                sequential::store_overflow(&context,
                                            FlowRef::deref_mut(&mut root_flow) as &mut Flow);
             });
 
             self.perform_post_main_layout_passes(data,
                                                  query_type,
                                                  document,
                                                  rw_data,
-                                                 layout_context);
+                                                 shared);
         }
     }
 
     fn perform_post_main_layout_passes(&mut self,
                                        data: &Reflow,
                                        query_type: Option<&ReflowQueryType>,
                                        document: Option<&ServoLayoutDocument>,
                                        rw_data: &mut LayoutThreadData,
@@ -1536,30 +1547,32 @@ fn get_ua_stylesheets() -> Result<UserAg
         let res = try!(read_resource_file(filename).map_err(|_| filename));
         Ok(Stylesheet::from_bytes(
             &res,
             ServoUrl::parse(&format!("chrome://resources/{:?}", filename)).unwrap(),
             None,
             None,
             Origin::UserAgent,
             Default::default(),
+            None,
             Box::new(StdoutErrorReporter),
             ParserContextExtraData::default()))
     }
 
     let mut user_or_user_agent_stylesheets = vec!();
     // 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"] {
         user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(filename)));
     }
     for &(ref contents, ref url) in &opts::get().user_stylesheets {
         user_or_user_agent_stylesheets.push(Stylesheet::from_bytes(
             &contents, url.clone(), None, None, Origin::User, Default::default(),
-            Box::new(StdoutErrorReporter), ParserContextExtraData::default()));
+            None, Box::new(StdoutErrorReporter),
+            ParserContextExtraData::default()));
     }
 
     let quirks_mode_stylesheet = try!(parse_ua_stylesheet("quirks-mode.css"));
 
     Ok(UserAgentStylesheets {
         user_or_user_agent_stylesheets: user_or_user_agent_stylesheets,
         quirks_mode_stylesheet: quirks_mode_stylesheet,
     })
--- a/servo/components/net/Cargo.toml
+++ b/servo/components/net/Cargo.toml
@@ -29,22 +29,22 @@ msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 openssl = "0.7.6"
 openssl-verify = "0.1"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rustc-serialize = "0.3"
 serde = "0.8"
 serde_derive = "0.8"
+servo_config = {path = "../config"}
 servo_url = {path = "../url"}
 threadpool = "1.0"
 time = "0.1.17"
 unicase = "1.4.0"
 url = {version = "1.2", features = ["heap_size", "rustc-serialize"]}
-util = {path = "../util"}
 uuid = {version = "0.3.1", features = ["v4"]}
 websocket = "0.17"
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive", "ipc"]
 
--- a/servo/components/net/chrome_loader.rs
+++ b/servo/components/net/chrome_loader.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+use servo_config::resource_files::resources_dir_path;
 use servo_url::ServoUrl;
 use std::fs::canonicalize;
 use url::percent_encoding::percent_decode;
-use util::resource_files::resources_dir_path;
 
 pub fn resolve_chrome_url(url: &ServoUrl) -> Result<ServoUrl, ()> {
     assert_eq!(url.scheme(), "chrome");
     if url.host_str() != Some("resources") {
         return Err(())
     }
     let resources = canonicalize(resources_dir_path().expect("Error finding resource folder"))
         .expect("Error canonicalizing path to the resources directory");
--- a/servo/components/net/connector.rs
+++ b/servo/components/net/connector.rs
@@ -1,18 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use hyper::client::Pool;
 use hyper::net::{HttpStream, HttpsConnector, SslClient};
 use openssl::ssl::{SSL_OP_NO_COMPRESSION, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_VERIFY_PEER};
 use openssl::ssl::{Ssl, SslContext, SslMethod, SslStream};
+use servo_config::resource_files::resources_dir_path;
 use std::sync::Arc;
-use util::resource_files::resources_dir_path;
 
 pub type Connector = HttpsConnector<ServoSslClient>;
 
 // The basic logic here is to prefer ciphers with ECDSA certificates, Forward
 // Secrecy, AES GCM ciphers, AES ciphers, and finally 3DES ciphers.
 // A complete discussion of the issues involved in TLS configuration can be found here:
 // https://wiki.mozilla.org/Security/Server_Side_TLS
 const DEFAULT_CIPHERS: &'static str = concat!(
--- a/servo/components/net/content_blocker.rs
+++ b/servo/components/net/content_blocker.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use content_blocker_parser::{RuleList, parse_list};
+use servo_config::resource_files::read_resource_file;
 use std::str;
 use std::sync::Arc;
-use util::resource_files::read_resource_file;
 
 lazy_static! {
     pub static ref BLOCKED_CONTENT_RULES: Arc<Option<RuleList>> = Arc::new(create_rule_list());
 }
 
 fn create_rule_list() -> Option<RuleList> {
     let contents = match read_resource_file("blocked-content.json") {
         Ok(c) => c,
--- a/servo/components/net/fetch/methods.rs
+++ b/servo/components/net/fetch/methods.rs
@@ -20,17 +20,17 @@ use net_traits::request::{Type, Origin, 
 use net_traits::response::{Response, ResponseBody, ResponseType};
 use std::borrow::Cow;
 use std::fs::File;
 use std::io::Read;
 use std::mem;
 use std::rc::Rc;
 use std::sync::mpsc::{Sender, Receiver};
 
-pub type Target = Option<Box<FetchTaskTarget + Send>>;
+pub type Target<'a> = &'a mut (FetchTaskTarget + Send);
 
 pub enum Data {
     Payload(Vec<u8>),
     Done,
 }
 
 pub struct FetchContext {
     pub state: HttpState,
@@ -38,27 +38,25 @@ pub struct FetchContext {
     pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
     pub filemanager: FileManager,
 }
 
 pub type DoneChannel = Option<(Sender<Data>, Receiver<Data>)>;
 
 /// [Fetch](https://fetch.spec.whatwg.org#concept-fetch)
 pub fn fetch(request: Rc<Request>,
-             target: &mut Target,
-             context: &FetchContext)
-             -> Response {
-    fetch_with_cors_cache(request, &mut CorsCache::new(), target, context)
+             target: Target,
+             context: &FetchContext) {
+    fetch_with_cors_cache(request, &mut CorsCache::new(), target, context);
 }
 
 pub fn fetch_with_cors_cache(request: Rc<Request>,
                              cache: &mut CorsCache,
-                             target: &mut Target,
-                             context: &FetchContext)
-                             -> Response {
+                             target: Target,
+                             context: &FetchContext) {
     // Step 1
     if request.window.get() == Window::Client {
         // TODO: Set window to request's client object if client is a Window object
     } else {
         request.window.set(Window::NoWindow);
     }
 
     // Step 2
@@ -107,25 +105,25 @@ pub fn fetch_with_cors_cache(request: Rc
     // TODO: Figure out what a Priority object is
 
     // Step 6
     if request.is_subresource_request() {
         // TODO: create a fetch record and append it to request's client's fetch group list
     }
 
     // Step 7
-    main_fetch(request, cache, false, false, target, &mut None, &context)
+    main_fetch(request, cache, false, false, target, &mut None, &context);
 }
 
 /// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
 pub fn main_fetch(request: Rc<Request>,
                   cache: &mut CorsCache,
                   cors_flag: bool,
                   recursive_flag: bool,
-                  target: &mut Target,
+                  target: Target,
                   done_chan: &mut DoneChannel,
                   context: &FetchContext)
                   -> Response {
     // TODO: Implement main fetch spec
 
     // Step 1
     let mut response = None;
 
@@ -292,110 +290,94 @@ pub fn main_fetch(request: Rc<Request>,
         //         response = Response::network_error();
         //         internal_response = Response::network_error();
         //     }
         // }
     }
 
     // Step 19
     if request.synchronous {
-        if let Some(ref mut target) = *target {
-            // process_response is not supposed to be used
-            // by sync fetch, but we overload it here for simplicity
-            target.process_response(&response);
-        }
+        // process_response is not supposed to be used
+        // by sync fetch, but we overload it here for simplicity
+        target.process_response(&response);
 
         if let Some(ref ch) = *done_chan {
             loop {
                 match ch.1.recv()
                         .expect("fetch worker should always send Done before terminating") {
                     Data::Payload(vec) => {
-                        if let Some(ref mut target) = *target {
-                            target.process_response_chunk(vec);
-                        }
+                        target.process_response_chunk(vec);
                     }
                     Data::Done => break,
                 }
             }
         } else {
             let body = response.body.lock().unwrap();
             if let ResponseBody::Done(ref vec) = *body {
                 // in case there was no channel to wait for, the body was
                 // obtained synchronously via basic_fetch for data/file/about/etc
                 // We should still send the body across as a chunk
-                if let Some(ref mut target) = *target {
-                    target.process_response_chunk(vec.clone());
-                }
+                target.process_response_chunk(vec.clone());
             } else {
                 assert!(*body == ResponseBody::Empty)
             }
         }
 
         // overloaded similarly to process_response
-        if let Some(ref mut target) = *target {
-            target.process_response_eof(&response);
-        }
+        target.process_response_eof(&response);
         return response;
     }
 
     // Step 20
     if request.body.borrow().is_some() && matches!(request.current_url().scheme(), "http" | "https") {
-        if let Some(ref mut target) = *target {
-            // XXXManishearth: We actually should be calling process_request
-            // in http_network_fetch. However, we can't yet follow the request
-            // upload progress, so I'm keeping it here for now and pretending
-            // the body got sent in one chunk
-            target.process_request_body(&request);
-            target.process_request_eof(&request);
-        }
+        // XXXManishearth: We actually should be calling process_request
+        // in http_network_fetch. However, we can't yet follow the request
+        // upload progress, so I'm keeping it here for now and pretending
+        // the body got sent in one chunk
+        target.process_request_body(&request);
+        target.process_request_eof(&request);
     }
 
     // Step 21
-    if let Some(ref mut target) = *target {
-        target.process_response(&response);
-    }
+    target.process_response(&response);
 
     // Step 22
     if let Some(ref ch) = *done_chan {
         loop {
             match ch.1.recv()
                     .expect("fetch worker should always send Done before terminating") {
                 Data::Payload(vec) => {
-                    if let Some(ref mut target) = *target {
-                        target.process_response_chunk(