servo: Merge #13711 - Remove old rendering backend (from glennw:remove-old-renderer); r=larsbergstrom
authorGlenn Watson <github@intuitionlibrary.com>
Mon, 17 Oct 2016 19:22:20 -0500
changeset 339939 2c5e94db60df33c1453b52ecb7eb060021d10282
parent 339938 e5f3601ef06d292cdaa4e2f9bc5ab0e56e5f66a9
child 339940 685dfe58df3dd2e2e43d7013be9af89981d64852
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslarsbergstrom
servo: Merge #13711 - Remove old rendering backend (from glennw:remove-old-renderer); r=larsbergstrom This removes paint threads, rust-layers dependency, and changes optional webrender types to be required. The use_webrender option has been removed, however I've left the "-w" command line option in place for now so that wpt runner can continue to pass that. Once it's removed from there we can also remove the -w option. Once this stage is complete, it should be fine to change the display list building code to generate webrender display lists directly and avoid the conversion step. Source-Repo: https://github.com/servo/servo Source-Revision: f96718d03da969510dc992699cb6f25c2e21ae1e
servo/components/canvas/canvas_paint_thread.rs
servo/components/canvas/webgl_paint_thread.rs
servo/components/canvas_traits/lib.rs
servo/components/compositing/Cargo.toml
servo/components/compositing/compositor.rs
servo/components/compositing/compositor_layer.rs
servo/components/compositing/compositor_thread.rs
servo/components/compositing/lib.rs
servo/components/compositing/surface_map.rs
servo/components/compositing/touch.rs
servo/components/compositing/windowing.rs
servo/components/constellation/Cargo.toml
servo/components/constellation/constellation.rs
servo/components/constellation/lib.rs
servo/components/constellation/pipeline.rs
servo/components/gfx/Cargo.toml
servo/components/gfx/font.rs
servo/components/gfx/font_cache_thread.rs
servo/components/gfx/font_context.rs
servo/components/gfx/lib.rs
servo/components/gfx/paint_thread.rs
servo/components/gfx/text/text_run.rs
servo/components/gfx_traits/Cargo.toml
servo/components/gfx_traits/lib.rs
servo/components/gfx_traits/paint_listener.rs
servo/components/layout/block.rs
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/flow.rs
servo/components/layout/inline.rs
servo/components/layout/webrender_helpers.rs
servo/components/layout_thread/lib.rs
servo/components/layout_traits/Cargo.toml
servo/components/layout_traits/lib.rs
servo/components/net/image_cache_thread.rs
servo/components/net_traits/image/base.rs
servo/components/script/dom/canvasrenderingcontext2d.rs
servo/components/script/dom/window.rs
servo/components/script/script_thread.rs
servo/components/script_layout_interface/Cargo.toml
servo/components/script_layout_interface/lib.rs
servo/components/script_layout_interface/message.rs
servo/components/script_traits/Cargo.toml
servo/components/script_traits/lib.rs
servo/components/script_traits/script_msg.rs
servo/components/servo/Cargo.lock
servo/components/servo/lib.rs
servo/components/util/opts.rs
servo/ports/cef/Cargo.lock
servo/ports/cef/Cargo.toml
servo/ports/cef/lib.rs
servo/ports/cef/window.rs
servo/ports/glutin/Cargo.toml
servo/ports/glutin/lib.rs
servo/ports/glutin/window.rs
--- a/servo/components/canvas/canvas_paint_thread.rs
+++ b/servo/components/canvas/canvas_paint_thread.rs
@@ -53,18 +53,18 @@ impl<'a> CanvasPaintThread<'a> {
 }
 
 pub struct CanvasPaintThread<'a> {
     drawtarget: DrawTarget,
     /// TODO(pcwalton): Support multiple paths.
     path_builder: PathBuilder,
     state: CanvasPaintState<'a>,
     saved_states: Vec<CanvasPaintState<'a>>,
-    webrender_api: Option<webrender_traits::RenderApi>,
-    webrender_image_key: Option<webrender_traits::ImageKey>,
+    webrender_api: webrender_traits::RenderApi,
+    webrender_image_key: webrender_traits::ImageKey,
 }
 
 #[derive(Clone)]
 struct CanvasPaintState<'a> {
     draw_options: DrawOptions,
     fill_style: Pattern,
     stroke_style: Pattern,
     stroke_opts: StrokeOptions<'a>,
@@ -95,36 +95,36 @@ impl<'a> CanvasPaintState<'a> {
             shadow_blur: 0.0,
             shadow_color: color::transparent(),
         }
     }
 }
 
 impl<'a> CanvasPaintThread<'a> {
     fn new(size: Size2D<i32>,
-           webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+           webrender_api_sender: webrender_traits::RenderApiSender,
            antialias: bool) -> CanvasPaintThread<'a> {
         let draw_target = CanvasPaintThread::create(size);
         let path_builder = draw_target.create_path_builder();
-        let webrender_api = webrender_api_sender.map(|wr| wr.create_api());
-        let webrender_image_key = webrender_api.as_ref().map(|wr| wr.alloc_image());
+        let webrender_api = webrender_api_sender.create_api();
+        let webrender_image_key = webrender_api.alloc_image();
         CanvasPaintThread {
             drawtarget: draw_target,
             path_builder: path_builder,
             state: CanvasPaintState::new(antialias),
             saved_states: vec![],
             webrender_api: webrender_api,
             webrender_image_key: webrender_image_key,
         }
     }
 
     /// Creates a new `CanvasPaintThread` and returns an `IpcSender` to
     /// communicate with it.
     pub fn start(size: Size2D<i32>,
-                 webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+                 webrender_api_sender: webrender_traits::RenderApiSender,
                  antialias: bool)
                  -> IpcSender<CanvasMsg> {
         let (sender, receiver) = ipc::channel::<CanvasMsg>().unwrap();
         spawn_named("CanvasThread".to_owned(), move || {
             let mut painter = CanvasPaintThread::new(size, webrender_api_sender, antialias);
             loop {
                 let msg = receiver.recv();
                 match msg.unwrap() {
@@ -537,24 +537,22 @@ impl<'a> CanvasPaintThread<'a> {
     }
 
     fn recreate(&mut self, size: Size2D<i32>) {
         self.drawtarget = CanvasPaintThread::create(size);
     }
 
     fn send_data(&mut self, chan: IpcSender<CanvasData>) {
         self.drawtarget.snapshot().get_data_surface().with_data(|element| {
-            if let Some(ref webrender_api) = self.webrender_api {
-                let size = self.drawtarget.get_size();
-                webrender_api.update_image(self.webrender_image_key.unwrap(),
-                                           size.width as u32,
-                                           size.height as u32,
-                                           webrender_traits::ImageFormat::RGBA8,
-                                           element.into());
-            }
+            let size = self.drawtarget.get_size();
+            self.webrender_api.update_image(self.webrender_image_key,
+                                            size.width as u32,
+                                            size.height as u32,
+                                            webrender_traits::ImageFormat::RGBA8,
+                                            element.into());
 
             let pixel_data = CanvasPixelData {
                 image_data: IpcSharedMemory::from_bytes(element),
                 image_key: self.webrender_image_key,
             };
             chan.send(CanvasData::Pixels(pixel_data)).unwrap();
         })
     }
@@ -705,19 +703,17 @@ impl<'a> CanvasPaintThread<'a> {
                                                                self.state.shadow_offset_y as AzFloat),
                                                  (self.state.shadow_blur / 2.0f64) as AzFloat,
                                                  self.state.draw_options.composition);
     }
 }
 
 impl<'a> Drop for CanvasPaintThread<'a> {
     fn drop(&mut self) {
-        if let Some(ref mut wr) = self.webrender_api {
-            wr.delete_image(self.webrender_image_key.unwrap());
-        }
+        self.webrender_api.delete_image(self.webrender_image_key);
     }
 }
 
 /// Used by drawImage to get rid of the extra pixels of the image data that
 /// won't be copied to the canvas
 /// image_data: Color pixel data of the image
 /// image_size: Image dimensions
 /// crop_rect: It determines the area of the image we want to keep
--- a/servo/components/canvas/webgl_paint_thread.rs
+++ b/servo/components/canvas/webgl_paint_thread.rs
@@ -82,84 +82,77 @@ impl GLContextWrapper {
                 cmd.apply(ctx);
             }
         }
     }
 }
 
 enum WebGLPaintTaskData {
     WebRender(webrender_traits::RenderApi, webrender_traits::WebGLContextId),
-    Readback(GLContextWrapper, (Option<(webrender_traits::RenderApi, webrender_traits::ImageKey)>)),
+    Readback(GLContextWrapper, webrender_traits::RenderApi, webrender_traits::ImageKey),
 }
 
 pub struct WebGLPaintThread {
     size: Size2D<i32>,
     data: WebGLPaintTaskData,
 }
 
 fn create_readback_painter(size: Size2D<i32>,
                            attrs: GLContextAttributes,
-                           webrender_api: Option<webrender_traits::RenderApi>)
+                           webrender_api: webrender_traits::RenderApi)
     -> Result<(WebGLPaintThread, GLLimits), String> {
     let context = try!(GLContextWrapper::new(size, attrs));
     let limits = context.get_limits();
-    let webrender_api_and_image_key = webrender_api.map(|wr| {
-        let key = wr.alloc_image();
-        (wr, key)
-    });
+    let image_key = webrender_api.alloc_image();
     let painter = WebGLPaintThread {
         size: size,
-        data: WebGLPaintTaskData::Readback(context, webrender_api_and_image_key)
+        data: WebGLPaintTaskData::Readback(context, webrender_api, image_key)
     };
 
     Ok((painter, limits))
 }
 
 impl WebGLPaintThread {
     fn new(size: Size2D<i32>,
            attrs: GLContextAttributes,
-           webrender_api_sender: Option<webrender_traits::RenderApiSender>)
+           webrender_api_sender: webrender_traits::RenderApiSender)
         -> Result<(WebGLPaintThread, GLLimits), String> {
-        if let Some(sender) = webrender_api_sender {
-            let wr_api = sender.create_api();
-            match wr_api.request_webgl_context(&size, attrs) {
-                Ok((id, limits)) => {
-                    let painter = WebGLPaintThread {
-                        data: WebGLPaintTaskData::WebRender(wr_api, id),
-                        size: size
-                    };
-                    Ok((painter, limits))
-                },
-                Err(msg) => {
-                    warn!("Initial context creation failed, falling back to readback: {}", msg);
-                    create_readback_painter(size, attrs, Some(wr_api))
-                }
+        let wr_api = webrender_api_sender.create_api();
+        match wr_api.request_webgl_context(&size, attrs) {
+            Ok((id, limits)) => {
+                let painter = WebGLPaintThread {
+                    data: WebGLPaintTaskData::WebRender(wr_api, id),
+                    size: size
+                };
+                Ok((painter, limits))
+            },
+            Err(msg) => {
+                warn!("Initial context creation failed, falling back to readback: {}", msg);
+                create_readback_painter(size, attrs, wr_api)
             }
-        } else {
-            create_readback_painter(size, attrs, None)
         }
     }
 
     fn handle_webgl_message(&self, message: webrender_traits::WebGLCommand) {
         debug!("WebGL message: {:?}", message);
         match self.data {
             WebGLPaintTaskData::WebRender(ref api, id) => {
                 api.send_webgl_command(id, message);
             }
-            WebGLPaintTaskData::Readback(ref ctx, _) => {
+            WebGLPaintTaskData::Readback(ref ctx, _, _) => {
                 ctx.apply_command(message);
             }
         }
     }
 
     /// Creates a new `WebGLPaintThread` and returns an `IpcSender` to
     /// communicate with it.
     pub fn start(size: Size2D<i32>,
                  attrs: GLContextAttributes,
-                 webrender_api_sender: Option<webrender_traits::RenderApiSender>)
+                 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 || {
             let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender) {
                 Ok((thread, limits)) => {
                     result_chan.send(Ok(limits)).unwrap();
                     thread
@@ -191,17 +184,17 @@ impl WebGLPaintThread {
             }
         });
 
         result_port.recv().unwrap().map(|limits| (sender, limits))
     }
 
     fn send_data(&mut self, chan: IpcSender<CanvasData>) {
         match self.data {
-            WebGLPaintTaskData::Readback(_, ref webrender_api_and_image_key) => {
+            WebGLPaintTaskData::Readback(_, ref webrender_api, image_key) => {
                 let width = self.size.width as usize;
                 let height = self.size.height as usize;
 
                 let mut pixels = gl::read_pixels(0, 0,
                                                  self.size.width as gl::GLsizei,
                                                  self.size.height as gl::GLsizei,
                                                  gl::RGBA, gl::UNSIGNED_BYTE);
                 // flip image vertically (texture is upside down)
@@ -212,43 +205,41 @@ impl WebGLPaintThread {
                     let src_start = (height - y - 1) * stride;
                     let src_slice = &orig_pixels[src_start .. src_start + stride];
                     (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
                 }
 
                 // rgba -> bgra
                 byte_swap(&mut pixels);
 
-                if let Some((ref wr, wr_image_key)) = *webrender_api_and_image_key {
-                    // TODO: This shouldn't be a common path, but try to avoid
-                    // the spurious clone().
-                    wr.update_image(wr_image_key,
-                                    width as u32,
-                                    height as u32,
-                                    webrender_traits::ImageFormat::RGBA8,
-                                    pixels.clone());
-                }
+                // TODO: This shouldn't be a common path, but try to avoid
+                // the spurious clone().
+                webrender_api.update_image(image_key,
+                                           width as u32,
+                                           height as u32,
+                                           webrender_traits::ImageFormat::RGBA8,
+                                           pixels.clone());
 
                 let pixel_data = CanvasPixelData {
                     image_data: IpcSharedMemory::from_bytes(&pixels[..]),
-                    image_key: webrender_api_and_image_key.as_ref().map(|&(_, key)| key),
+                    image_key: image_key,
                 };
 
                 chan.send(CanvasData::Pixels(pixel_data)).unwrap();
             }
             WebGLPaintTaskData::WebRender(_, id) => {
                 chan.send(CanvasData::WebGL(id)).unwrap();
             }
         }
     }
 
     #[allow(unsafe_code)]
     fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
         match self.data {
-            WebGLPaintTaskData::Readback(ref mut context, _) => {
+            WebGLPaintTaskData::Readback(ref mut context, _, _) => {
                 if size.width > self.size.width ||
                    size.height > self.size.height {
                     self.size = try!(context.resize(size));
                 } else {
                     self.size = size;
                     unsafe { gl::Scissor(0, 0, size.width, size.height); }
                 }
             }
@@ -256,21 +247,21 @@ impl WebGLPaintThread {
                 // TODO
             }
         }
 
         Ok(())
     }
 
     fn init(&mut self) {
-        if let WebGLPaintTaskData::Readback(ref context, _) = self.data {
+        if let WebGLPaintTaskData::Readback(ref context, _, _) = self.data {
             context.make_current();
         }
     }
 }
 
 impl Drop for WebGLPaintThread {
     fn drop(&mut self) {
-        if let WebGLPaintTaskData::Readback(_, Some((ref mut wr, image_key))) = self.data {
+        if let WebGLPaintTaskData::Readback(_, ref mut wr, image_key) = self.data {
             wr.delete_image(image_key);
         }
     }
 }
--- a/servo/components/canvas_traits/lib.rs
+++ b/servo/components/canvas_traits/lib.rs
@@ -64,17 +64,17 @@ pub enum CanvasCommonMsg {
 pub enum CanvasData {
     Pixels(CanvasPixelData),
     WebGL(WebGLContextId),
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub struct CanvasPixelData {
     pub image_data: IpcSharedMemory,
-    pub image_key: Option<webrender_traits::ImageKey>,
+    pub image_key: webrender_traits::ImageKey,
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum FromLayoutMsg {
     SendData(IpcSender<CanvasData>),
 }
 
 #[derive(Clone, Deserialize, Serialize)]
--- a/servo/components/compositing/Cargo.toml
+++ b/servo/components/compositing/Cargo.toml
@@ -5,24 +5,21 @@ authors = ["The Servo Project Developers
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "compositing"
 path = "lib.rs"
 
 [dependencies]
-app_units = "0.3"
-azure = {git = "https://github.com/servo/rust-azure", features = ["plugins"]}
 euclid = "0.10.1"
 gfx_traits = {path = "../gfx_traits"}
 gleam = "0.2.8"
 image = "0.10"
 ipc-channel = "0.5"
-layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
 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"
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -1,86 +1,67 @@
 /* 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 CompositionPipeline;
 use SendableFrameTree;
-use app_units::Au;
-use compositor_layer::{CompositorData, CompositorLayer, RcCompositorLayer, WantsScrollEventsFlag};
 use compositor_thread::{CompositorProxy, CompositorReceiver};
 use compositor_thread::{InitialCompositorState, Msg, RenderListener};
 use delayed_composition::DelayedCompositionTimerProxy;
-use euclid::{Matrix4D, Point2D, Rect, Size2D};
+use euclid::{Point2D, Size2D};
 use euclid::point::TypedPoint2D;
-use euclid::rect::TypedRect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
-use gfx_traits::{ChromeToPaintMsg, PaintRequest, ScrollPolicy, StackingContextId};
-use gfx_traits::{color, Epoch, FrameTreeId, FragmentType, LayerId, LayerKind, LayerProperties};
-use gfx_traits::print_tree::PrintTree;
+use gfx_traits::{DevicePixel, LayerPixel, StackingContextId};
+use gfx_traits::{Epoch, FrameTreeId, FragmentType, LayerId};
 use gleam::gl;
 use gleam::gl::types::{GLint, GLsizei};
 use image::{DynamicImage, ImageFormat, RgbImage};
 use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
 use ipc_channel::router::ROUTER;
-use layers::geometry::{DevicePixel, LayerPixel};
-use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
-use layers::platform::surface::NativeDisplay;
-use layers::rendergl;
-use layers::rendergl::RenderContext;
-use layers::scene::Scene;
 use msg::constellation_msg::{Image, PixelFormat, Key, KeyModifiers, KeyState};
 use msg::constellation_msg::{LoadData, TraversalDirection, PipelineId};
 use msg::constellation_msg::{PipelineIndex, PipelineNamespaceId, WindowSizeType};
-use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
+use profile_traits::mem::{self, Reporter, ReporterRequest};
 use profile_traits::time::{self, ProfilerCategory, profile};
 use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
 use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton, MouseEventType};
 use script_traits::{StackingContextScrollState, TouchpadPressurePhase, TouchEventType};
 use script_traits::{TouchId, WindowSizeData};
 use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent};
-use std::collections::{HashMap, HashSet};
-use std::collections::hash_map::Entry::{Occupied, Vacant};
+use std::collections::HashMap;
 use std::fs::File;
-use std::mem as std_mem;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use style_traits::{PagePx, ViewportPx};
 use style_traits::viewport::ViewportConstraints;
-use surface_map::SurfaceMap;
 use time::{precise_time_ns, precise_time_s};
 use touch::{TouchHandler, TouchAction};
 use url::Url;
 use util::geometry::ScreenPx;
 use util::opts;
 use util::prefs::PREFS;
 use webrender;
 use webrender_traits::{self, ScrollEventPhase};
 use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
 
 #[derive(Debug, PartialEq)]
 enum UnableToComposite {
-    NoContext,
     WindowUnprepared,
     NotReadyToPaintImage(NotReadyToPaint),
 }
 
 #[derive(Debug, PartialEq)]
 enum NotReadyToPaint {
-    LayerHasOutstandingPaintMessages,
-    MissingRoot,
-    PendingSubpages(usize),
     AnimationsActive,
     JustNotifiedConstellation,
     WaitingOnConstellation,
 }
 
-const BUFFER_MAP_SIZE: usize = 10000000;
-
 // Default viewport constraints
 const MAX_ZOOM: f32 = 8.0;
 const MIN_ZOOM: f32 = 0.1;
 
 trait ConvertPipelineIdFromWebRender {
     fn from_webrender(&self) -> PipelineId;
 }
 
@@ -128,34 +109,27 @@ enum ReadyState {
     ReadyToSaveImage,
 }
 
 /// NB: Never block on the constellation, because sometimes the constellation blocks on us.
 pub struct IOCompositor<Window: WindowMethods> {
     /// The application window.
     window: Rc<Window>,
 
-    /// The display this compositor targets. Will be None when using webrender.
-    native_display: Option<NativeDisplay>,
-
     /// The port on which we receive messages.
     port: Box<CompositorReceiver>,
 
-    /// The render context. This will be `None` if the windowing system has not yet sent us a
-    /// `PrepareRenderingEvent`.
-    context: Option<RenderContext>,
-
     /// The root pipeline.
     root_pipeline: Option<CompositionPipeline>,
 
     /// Tracks details about each active pipeline that the compositor knows about.
     pipeline_details: HashMap<PipelineId, PipelineDetails>,
 
-    /// The canvas to paint a page.
-    scene: Scene<CompositorData>,
+    /// The scene scale, to allow for zooming and high-resolution painting.
+    scale: ScaleFactor<f32, LayerPixel, DevicePixel>,
 
     /// The application window size.
     window_size: TypedSize2D<u32, DevicePixel>,
 
     /// The overridden viewport.
     viewport: Option<(TypedPoint2D<u32, DevicePixel>, TypedSize2D<u32, DevicePixel>)>,
 
     /// "Mobile-style" zoom that does not reflow the page.
@@ -208,50 +182,37 @@ pub struct IOCompositor<Window: WindowMe
     constellation_chan: Sender<ConstellationMsg>,
 
     /// The channel on which messages can be sent to the time profiler.
     time_profiler_chan: time::ProfilerChan,
 
     /// The channel on which messages can be sent to the memory profiler.
     mem_profiler_chan: mem::ProfilerChan,
 
-    /// Pending scroll to fragment event, if any
-    fragment_point: Option<Point2D<f32>>,
-
     /// Touch input state machine
     touch_handler: TouchHandler,
 
     /// Pending scroll/zoom events.
     pending_scroll_zoom_events: Vec<ScrollZoomEvent>,
 
     /// Whether we're waiting on a recomposite after dispatching a scroll.
     waiting_for_results_of_scroll: bool,
 
     /// Used by the logic that determines when it is safe to output an
     /// image for the reftest framework.
     ready_to_save_state: ReadyState,
 
-    /// A data structure to cache unused NativeSurfaces.
-    surface_map: SurfaceMap,
-
-    /// Pipeline IDs of subpages that the compositor has seen in a layer tree but which have not
-    /// yet been painted.
-    pending_subpages: HashSet<PipelineId>,
-
-    /// The id of the pipeline that was last sent a mouse move event, if any.
-    last_mouse_move_recipient: Option<PipelineId>,
-
     /// Whether a scroll is in progress; i.e. whether the user's fingers are down.
     scroll_in_progress: bool,
 
-    /// The webrender renderer, if enabled.
-    webrender: Option<webrender::Renderer>,
+    /// The webrender renderer.
+    webrender: webrender::Renderer,
 
     /// The webrender interface, if enabled.
-    webrender_api: Option<webrender_traits::RenderApi>,
+    webrender_api: webrender_traits::RenderApi,
 }
 
 #[derive(Copy, Clone)]
 struct ScrollZoomEvent {
     /// Change the pinch zoom level by this factor
     magnification: f32,
     /// Scroll by this offset
     delta: TypedPoint2D<f32, DevicePixel>,
@@ -272,45 +233,34 @@ enum CompositionRequest {
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 enum ShutdownState {
     NotShuttingDown,
     ShuttingDown,
     FinishedShuttingDown,
 }
 
-struct HitTestResult {
-    /// The topmost layer containing the requested point
-    layer: Rc<Layer<CompositorData>>,
-    /// The point in client coordinates of the innermost window or frame containing `layer`
-    point: TypedPoint2D<f32, LayerPixel>,
-}
-
 struct PipelineDetails {
     /// The pipeline associated with this PipelineDetails object.
     pipeline: Option<CompositionPipeline>,
 
-    /// The current layout epoch that this pipeline wants to draw.
-    current_epoch: Epoch,
-
     /// Whether animations are running
     animations_running: bool,
 
     /// Whether there are animation callbacks
     animation_callbacks_running: bool,
 
     /// Whether this pipeline is visible
     visible: bool,
 }
 
 impl PipelineDetails {
     fn new() -> PipelineDetails {
         PipelineDetails {
             pipeline: None,
-            current_epoch: Epoch(0),
             animations_running: false,
             animation_callbacks_running: false,
             visible: true,
         }
     }
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -323,25 +273,23 @@ enum CompositeTarget {
 
     /// Compose to a PNG, write it to disk, and then exit the browser (used for reftests)
     PngFile
 }
 
 struct RenderTargetInfo {
     framebuffer_ids: Vec<gl::GLuint>,
     texture_ids: Vec<gl::GLuint>,
-    renderbuffer_ids: Vec<gl::GLuint>,
 }
 
 impl RenderTargetInfo {
     fn empty() -> RenderTargetInfo {
         RenderTargetInfo {
             framebuffer_ids: Vec::new(),
             texture_ids: Vec::new(),
-            renderbuffer_ids: Vec::new()
         }
     }
 }
 
 fn initialize_png(width: usize, height: usize) -> RenderTargetInfo {
     let framebuffer_ids = gl::gen_framebuffers(1);
     gl::bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]);
 
@@ -353,36 +301,19 @@ fn initialize_png(width: usize, height: 
     gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
     gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
 
     gl::framebuffer_texture_2d(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D,
                                texture_ids[0], 0);
 
     gl::bind_texture(gl::TEXTURE_2D, 0);
 
-    let renderbuffer_ids = if opts::get().use_webrender {
-        let renderbuffer_ids = gl::gen_renderbuffers(1);
-        gl::bind_renderbuffer(gl::RENDERBUFFER, renderbuffer_ids[0]);
-        gl::renderbuffer_storage(gl::RENDERBUFFER,
-                                 gl::STENCIL_INDEX8,
-                                 width as GLsizei,
-                                 height as GLsizei);
-        gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
-                                     gl::STENCIL_ATTACHMENT,
-                                     gl::RENDERBUFFER,
-                                     renderbuffer_ids[0]);
-        renderbuffer_ids
-    } else {
-        Vec::new()
-    };
-
     RenderTargetInfo {
         framebuffer_ids: framebuffer_ids,
         texture_ids: texture_ids,
-        renderbuffer_ids: renderbuffer_ids
     }
 }
 
 fn reporter_name() -> String {
     "compositor-reporter".to_owned()
 }
 
 struct RenderNotifier {
@@ -445,35 +376,23 @@ impl<Window: WindowMethods> IOCompositor
 
         let window_size = window.framebuffer_size();
         let scale_factor = window.scale_factor();
         let composite_target = match opts::get().output_file {
             Some(_) => CompositeTarget::PngFile,
             None => CompositeTarget::Window
         };
 
-        let webrender_api = state.webrender_api_sender.map(|sender| {
-            sender.create_api()
-        });
-
-        let native_display = if state.webrender.is_some() {
-            None
-        } else {
-            Some(window.native_display())
-        };
-
         IOCompositor {
             window: window,
-            native_display: native_display,
             port: state.receiver,
-            context: None,
             root_pipeline: None,
             pipeline_details: HashMap::new(),
-            scene: Scene::new(TypedRect::new(TypedPoint2D::zero(), window_size.to_f32())),
             window_size: window_size,
+            scale: ScaleFactor::new(1.0),
             viewport: None,
             scale_factor: scale_factor,
             channel_to_self: state.sender.clone_compositor_proxy(),
             delayed_composition_timer: DelayedCompositionTimerProxy::new(state.sender),
             composition_request: CompositionRequest::NoCompositingNecessary,
             touch_handler: TouchHandler::new(),
             pending_scroll_zoom_events: Vec::new(),
             waiting_for_results_of_scroll: false,
@@ -485,38 +404,32 @@ impl<Window: WindowMethods> IOCompositor
             max_viewport_zoom: None,
             zoom_action: false,
             zoom_time: 0f64,
             got_load_complete_message: false,
             frame_tree_id: FrameTreeId(0),
             constellation_chan: state.constellation_chan,
             time_profiler_chan: state.time_profiler_chan,
             mem_profiler_chan: state.mem_profiler_chan,
-            fragment_point: None,
             last_composite_time: 0,
             ready_to_save_state: ReadyState::Unknown,
-            surface_map: SurfaceMap::new(BUFFER_MAP_SIZE),
-            pending_subpages: HashSet::new(),
-            last_mouse_move_recipient: None,
             scroll_in_progress: false,
             webrender: state.webrender,
-            webrender_api: webrender_api,
+            webrender_api: state.webrender_api_sender.create_api(),
         }
     }
 
     pub fn create(window: Rc<Window>, state: InitialCompositorState) -> IOCompositor<Window> {
         let mut compositor = IOCompositor::new(window, state);
 
-        if let Some(ref mut webrender) = compositor.webrender {
-            let compositor_proxy_for_webrender = compositor.channel_to_self
-                                                           .clone_compositor_proxy();
-            let render_notifier = RenderNotifier::new(compositor_proxy_for_webrender,
-                                                      compositor.constellation_chan.clone());
-            webrender.set_render_notifier(Box::new(render_notifier));
-        }
+        let compositor_proxy_for_webrender = compositor.channel_to_self
+                                                       .clone_compositor_proxy();
+        let render_notifier = RenderNotifier::new(compositor_proxy_for_webrender,
+                                                  compositor.constellation_chan.clone());
+        compositor.webrender.set_render_notifier(Box::new(render_notifier));
 
         // Set the size of the root layer.
         compositor.update_zoom_transform();
 
         // Tell the constellation about the initial window size.
         compositor.send_window_size(WindowSizeType::Initial);
 
         compositor
@@ -531,21 +444,16 @@ impl<Window: WindowMethods> IOCompositor
         self.mem_profiler_chan.send(mem::ProfilerMsg::UnregisterReporter(reporter_name()));
 
         self.shutdown_state = ShutdownState::ShuttingDown;
     }
 
     fn finish_shutting_down(&mut self) {
         debug!("Compositor received message that constellation shutdown is complete");
 
-        // Clear out the compositor layers so that painting threads can destroy the buffers.
-        if let Some(ref root_layer) = self.scene.root {
-            root_layer.forget_all_tiles();
-        }
-
         // Drain compositor port, sometimes messages contain channels that are blocking
         // another thread from finishing (i.e. SetFrameTree).
         while self.port.try_recv_compositor_msg().is_some() {}
 
         // Tell the profiler, memory profiler, and scrolling timer to shut down.
         match ipc::channel() {
             Ok((sender, receiver)) => {
                 self.time_profiler_chan.send(time::ProfilerMsg::Exit(sender));
@@ -586,65 +494,20 @@ impl<Window: WindowMethods> IOCompositor
 
             (Msg::ChangePageUrl(pipeline_id, url), ShutdownState::NotShuttingDown) => {
                 self.change_page_url(pipeline_id, url);
             }
 
             (Msg::SetFrameTree(frame_tree, response_chan),
              ShutdownState::NotShuttingDown) => {
                 self.set_frame_tree(&frame_tree, response_chan);
-                self.send_viewport_rects_for_all_layers();
+                self.send_viewport_rects();
                 self.title_for_main_frame();
             }
 
-            (Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties),
-             ShutdownState::NotShuttingDown) => {
-                debug!("initializing layers for pipeline: {:?}", pipeline_id);
-                self.pipeline_details(pipeline_id).current_epoch = epoch;
-
-                self.collect_old_layers(pipeline_id, &properties);
-                for (index, layer_properties) in properties.iter().enumerate() {
-                    if index == 0 {
-                        self.create_or_update_base_layer(pipeline_id, *layer_properties);
-                    } else {
-                        self.create_or_update_descendant_layer(pipeline_id, *layer_properties);
-                    }
-                }
-
-                self.send_buffer_requests_for_all_layers();
-                self.dump_layer_tree();
-            }
-
-            (Msg::GetNativeDisplay(chan),
-             ShutdownState::NotShuttingDown) => {
-                if let Err(e) = chan.send(self.native_display.clone()) {
-                    warn!("Sending response to get native display failed ({}).", e);
-                }
-            }
-
-            (Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id),
-             ShutdownState::NotShuttingDown) => {
-                self.pending_subpages.remove(&pipeline_id);
-
-                for (layer_id, new_layer_buffer_set) in replies {
-                    self.assign_painted_buffers(pipeline_id,
-                                                layer_id,
-                                                new_layer_buffer_set,
-                                                epoch,
-                                                frame_tree_id);
-                }
-            }
-
-            (Msg::ReturnUnusedNativeSurfaces(native_surfaces),
-             ShutdownState::NotShuttingDown) => {
-                if let Some(ref native_display) = self.native_display {
-                    self.surface_map.insert_surfaces(native_display, native_surfaces);
-                }
-            }
-
             (Msg::ScrollFragmentPoint(pipeline_id, layer_id, point, _),
              ShutdownState::NotShuttingDown) => {
                 self.scroll_fragment_to_point(pipeline_id, layer_id, point);
             }
 
             (Msg::MoveTo(point),
              ShutdownState::NotShuttingDown) => {
                 self.window.set_position(point);
@@ -716,21 +579,16 @@ impl<Window: WindowMethods> IOCompositor
             (Msg::CreatePng(reply), ShutdownState::NotShuttingDown) => {
                 let res = self.composite_specific_target(CompositeTarget::WindowAndPng);
                 let img = res.unwrap_or(None);
                 if let Err(e) = reply.send(img) {
                     warn!("Sending reply to create png failed ({}).", e);
                 }
             }
 
-            (Msg::PaintThreadExited(pipeline_id), _) => {
-                debug!("compositor learned about paint thread exiting: {:?}", pipeline_id);
-                self.remove_pipeline_root_layer(pipeline_id);
-            }
-
             (Msg::ViewportConstrained(pipeline_id, constraints),
              ShutdownState::NotShuttingDown) => {
                 self.constrain_viewport(pipeline_id, constraints);
             }
 
             (Msg::IsReadyToSaveImageReply(is_ready), ShutdownState::NotShuttingDown) => {
                 assert!(self.ready_to_save_state == ReadyState::WaitingForConstellationReply);
                 if is_ready {
@@ -751,57 +609,33 @@ impl<Window: WindowMethods> IOCompositor
                 self.window.set_favicon(url);
             }
 
             (Msg::HeadParsed, ShutdownState::NotShuttingDown) => {
                 self.window.head_parsed();
             }
 
             (Msg::CollectMemoryReports(reports_chan), ShutdownState::NotShuttingDown) => {
-                let name = "compositor-thread";
-                // These are both `ExplicitUnknownLocationSize` because the memory might be in the
-                // GPU or on the heap.
-                let reports = vec![mem::Report {
-                    path: path![name, "surface-map"],
-                    kind: ReportKind::ExplicitUnknownLocationSize,
-                    size: self.surface_map.mem(),
-                }, mem::Report {
-                    path: path![name, "layer-tree"],
-                    kind: ReportKind::ExplicitUnknownLocationSize,
-                    size: self.scene.get_memory_usage(),
-                }];
+                let reports = vec![];
                 reports_chan.send(reports);
             }
 
             (Msg::PipelineVisibilityChanged(pipeline_id, visible), ShutdownState::NotShuttingDown) => {
                 self.pipeline_details(pipeline_id).visible = visible;
                 if visible {
                     self.process_animations();
                 }
             }
 
             (Msg::PipelineExited(pipeline_id, sender), _) => {
                 debug!("Compositor got pipeline exited: {:?}", pipeline_id);
-                self.pending_subpages.remove(&pipeline_id);
                 self.remove_pipeline_root_layer(pipeline_id);
                 let _ = sender.send(());
             }
 
-            (Msg::GetScrollOffset(pipeline_id, layer_id, sender), ShutdownState::NotShuttingDown) => {
-                match self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) {
-                    Some(ref layer) => {
-                        let typed = layer.extra_data.borrow().scroll_offset;
-                        let _ = sender.send(Point2D::new(typed.x, typed.y));
-                    },
-                    None => {
-                        warn!("Can't find requested layer in handling Msg::GetScrollOffset");
-                    },
-                }
-            }
-
             (Msg::NewScrollFrameReady(recomposite_needed), ShutdownState::NotShuttingDown) => {
                 self.waiting_for_results_of_scroll = false;
                 if recomposite_needed {
                     self.composition_request = CompositionRequest::CompositeNow(
                         CompositingReason::NewWebRenderScrollFrame);
                 }
             }
 
@@ -875,408 +709,72 @@ impl<Window: WindowMethods> IOCompositor
 
     fn set_frame_tree(&mut self,
                       frame_tree: &SendableFrameTree,
                       response_chan: IpcSender<()>) {
         if let Err(e) = response_chan.send(()) {
             warn!("Sending reponse to set frame tree failed ({}).", e);
         }
 
-        // There are now no more pending iframes.
-        self.pending_subpages.clear();
-
         self.root_pipeline = Some(frame_tree.pipeline.clone());
 
-        if let Some(ref webrender_api) = self.webrender_api {
-            let pipeline_id = frame_tree.pipeline.id.to_webrender();
-            webrender_api.set_root_pipeline(pipeline_id);
-        }
-
-        // If we have an old root layer, release all old tiles before replacing it.
-        let old_root_layer = self.scene.root.take();
-        if let Some(ref old_root_layer) = old_root_layer {
-            old_root_layer.clear_all_tiles(self)
-        }
-
-        self.scene.root = Some(self.create_root_layer_for_pipeline_and_size(&frame_tree.pipeline,
-                                                                            None));
-        self.scene.set_root_layer_size(self.window_size.to_f32());
+        let pipeline_id = frame_tree.pipeline.id.to_webrender();
+        self.webrender_api.set_root_pipeline(pipeline_id);
 
         self.create_pipeline_details_for_frame_tree(&frame_tree);
 
         self.send_window_size(WindowSizeType::Initial);
 
         self.frame_tree_id.next();
-        self.composite_if_necessary_if_not_using_webrender(CompositingReason::NewFrameTree);
-    }
-
-    fn create_root_layer_for_pipeline_and_size(&mut self,
-                                               pipeline: &CompositionPipeline,
-                                               frame_size: Option<TypedSize2D<f32, PagePx>>)
-                                               -> Rc<Layer<CompositorData>> {
-        let layer_properties = LayerProperties {
-            id: LayerId::null(),
-            parent_id: None,
-            rect: Rect::zero(),
-            background_color: color::transparent(),
-            scroll_policy: ScrollPolicy::Scrollable,
-            transform: Matrix4D::identity(),
-            perspective: Matrix4D::identity(),
-            subpage_pipeline_id: None,
-            establishes_3d_context: true,
-            scrolls_overflow_area: false,
-        };
-
-        let root_layer = CompositorData::new_layer(pipeline.id,
-                                                   layer_properties,
-                                                   WantsScrollEventsFlag::WantsScrollEvents,
-                                                   opts::get().tile_size);
-
-        self.pipeline_details(pipeline.id).pipeline = Some(pipeline.clone());
-
-        // All root layers mask to bounds.
-        *root_layer.masks_to_bounds.borrow_mut() = true;
-
-        if let Some(ref frame_size) = frame_size {
-            root_layer.bounds.borrow_mut().size =
-                TypedSize2D::new(frame_size.width, frame_size.height);
-        }
-
-        root_layer
     }
 
     fn create_pipeline_details_for_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
         self.pipeline_details(frame_tree.pipeline.id).pipeline = Some(frame_tree.pipeline.clone());
 
         for kid in &frame_tree.children {
             self.create_pipeline_details_for_frame_tree(kid);
         }
     }
 
-    fn find_pipeline_root_layer(&self, pipeline_id: PipelineId)
-                                -> Option<Rc<Layer<CompositorData>>> {
-        if !self.pipeline_details.contains_key(&pipeline_id) {
-            warn!("Tried to create or update layer for unknown pipeline");
-            return None;
-        }
-        self.find_layer_with_pipeline_and_layer_id(pipeline_id, LayerId::null())
-    }
-
-    fn collect_old_layers(&mut self,
-                          pipeline_id: PipelineId,
-                          new_layers: &[LayerProperties]) {
-        let root_layer = match self.scene.root {
-            Some(ref root_layer) => root_layer.clone(),
-            None => return,
-        };
-
-        let mut pipelines_removed = Vec::new();
-        root_layer.collect_old_layers(self, pipeline_id, new_layers, &mut pipelines_removed);
-
-        for pipeline_removed in pipelines_removed.into_iter() {
-            self.pending_subpages.remove(&pipeline_removed);
-        }
-    }
-
     fn remove_pipeline_root_layer(&mut self, pipeline_id: PipelineId) {
-        let root_layer = match self.scene.root {
-            Some(ref root_layer) => root_layer.clone(),
-            None => return,
-        };
-
-        // Remove all the compositor layers for this pipeline and recache
-        // any buffers that they owned.
-        root_layer.remove_root_layer_with_pipeline_id(self, pipeline_id);
         self.pipeline_details.remove(&pipeline_id);
     }
 
-    fn update_layer_if_exists(&mut self,
-                              pipeline_id: PipelineId,
-                              properties: LayerProperties)
-                              -> bool {
-        if let Some(subpage_id) = properties.subpage_pipeline_id {
-            match self.find_layer_with_pipeline_and_layer_id(subpage_id, LayerId::null()) {
-                Some(layer) => {
-                    *layer.bounds.borrow_mut() =
-                        TypedRect::new(TypedPoint2D::zero(),
-                                       TypedSize2D::from_untyped(&properties.rect.size));
-                }
-                None => warn!("Tried to update non-existent subpage root layer: {:?}", subpage_id),
-            }
-        }
-
-        match self.find_layer_with_pipeline_and_layer_id(pipeline_id, properties.id) {
-            Some(existing_layer) => {
-                // If this layer contains a subpage, then create the root layer for that subpage
-                // now.
-                if properties.subpage_pipeline_id.is_some() {
-                    self.create_root_layer_for_subpage_if_necessary(properties,
-                                                                    existing_layer.clone())
-                }
-
-                existing_layer.update_layer(properties);
-                true
-            }
-            None => false,
-        }
-    }
-
-    fn create_or_update_base_layer(&mut self,
-                                   pipeline_id: PipelineId,
-                                   layer_properties: LayerProperties) {
-        debug_assert!(layer_properties.parent_id.is_none());
-
-        let root_layer = match self.find_pipeline_root_layer(pipeline_id) {
-            Some(root_layer) => root_layer,
-            None => {
-                debug!("Ignoring CreateOrUpdateBaseLayer message for pipeline \
-                        ({:?}) shutting down.",
-                       pipeline_id);
-                return;
-            }
-        };
-
-        let need_new_base_layer = !self.update_layer_if_exists(pipeline_id, layer_properties);
-        if need_new_base_layer {
-            root_layer.update_layer_except_bounds(layer_properties);
-
-            let base_layer = CompositorData::new_layer(
-                pipeline_id,
-                layer_properties,
-                WantsScrollEventsFlag::DoesntWantScrollEvents,
-                opts::get().tile_size);
-
-            // Add the base layer to the front of the child list, so that child
-            // iframe layers are painted on top of the base layer. These iframe
-            // layers were added previously when creating the layer tree
-            // skeleton in create_frame_tree_root_layers.
-            root_layer.children().insert(0, base_layer);
-        }
-
-        self.scroll_layer_to_fragment_point_if_necessary(pipeline_id,
-                                                         layer_properties.id);
-    }
-
-    fn create_or_update_descendant_layer(&mut self,
-                                         pipeline_id: PipelineId,
-                                         layer_properties: LayerProperties) {
-        debug_assert!(layer_properties.parent_id.is_some());
-
-        if !self.update_layer_if_exists(pipeline_id, layer_properties) {
-            self.create_descendant_layer(pipeline_id, layer_properties);
-        }
-        self.update_subpage_size_if_necessary(&layer_properties);
-        self.scroll_layer_to_fragment_point_if_necessary(pipeline_id,
-                                                         layer_properties.id);
-    }
-
-    fn create_descendant_layer(&mut self,
-                               pipeline_id: PipelineId,
-                               layer_properties: LayerProperties) {
-        let parent_id = match layer_properties.parent_id {
-            None => return error!("Creating descendent layer without a parent id."),
-            Some(parent_id) => parent_id,
-        };
-        if let Some(parent_layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id,
-                                                                               parent_id) {
-            let wants_scroll_events = if layer_properties.scrolls_overflow_area {
-                WantsScrollEventsFlag::WantsScrollEvents
-            } else {
-                WantsScrollEventsFlag::DoesntWantScrollEvents
-            };
-
-            let new_layer = CompositorData::new_layer(pipeline_id,
-                                                      layer_properties,
-                                                      wants_scroll_events,
-                                                      parent_layer.tile_size);
-
-            if layer_properties.scrolls_overflow_area {
-                *new_layer.masks_to_bounds.borrow_mut() = true
-            }
-
-            // If this layer contains a subpage, then create the root layer for that subpage now.
-            if layer_properties.subpage_pipeline_id.is_some() {
-                self.create_root_layer_for_subpage_if_necessary(layer_properties,
-                                                                new_layer.clone())
-            }
-
-            parent_layer.add_child(new_layer.clone());
-        }
-
-        self.dump_layer_tree();
-    }
-
-    fn create_root_layer_for_subpage_if_necessary(&mut self,
-                                                  layer_properties: LayerProperties,
-                                                  parent_layer: Rc<Layer<CompositorData>>) {
-        if parent_layer.children
-                       .borrow()
-                       .iter()
-                       .any(|child| child.extra_data.borrow().subpage_info.is_some()) {
-            return
-        }
-
-        let subpage_pipeline_id =
-            layer_properties.subpage_pipeline_id
-                            .expect("create_root_layer_for_subpage() called for non-subpage?!");
-        let subpage_layer_properties = LayerProperties {
-            id: LayerId::null(),
-            parent_id: None,
-            rect: Rect::new(Point2D::zero(), layer_properties.rect.size),
-            background_color: layer_properties.background_color,
-            scroll_policy: ScrollPolicy::Scrollable,
-            transform: Matrix4D::identity(),
-            perspective: Matrix4D::identity(),
-            subpage_pipeline_id: Some(subpage_pipeline_id),
-            establishes_3d_context: true,
-            scrolls_overflow_area: true,
-        };
-
-        let wants_scroll_events = if subpage_layer_properties.scrolls_overflow_area {
-            WantsScrollEventsFlag::WantsScrollEvents
-        } else {
-            WantsScrollEventsFlag::DoesntWantScrollEvents
-        };
-        let subpage_layer = CompositorData::new_layer(subpage_pipeline_id,
-                                                      subpage_layer_properties,
-                                                      wants_scroll_events,
-                                                      parent_layer.tile_size);
-        *subpage_layer.masks_to_bounds.borrow_mut() = true;
-        parent_layer.add_child(subpage_layer);
-        self.pending_subpages.insert(subpage_pipeline_id);
-    }
-
     fn send_window_size(&self, size_type: WindowSizeType) {
         let dppx = self.page_zoom * self.device_pixels_per_screen_px();
         let initial_viewport = self.window_size.to_f32() / dppx;
         let visible_viewport = initial_viewport / self.viewport_zoom;
         let msg = ConstellationMsg::WindowSize(WindowSizeData {
             device_pixel_ratio: dppx,
             initial_viewport: initial_viewport,
             visible_viewport: visible_viewport,
         }, size_type);
 
         if let Err(e) = self.constellation_chan.send(msg) {
             warn!("Sending window resize to constellation failed ({}).", e);
         }
     }
 
-    /// Sends the size of the given subpage up to the constellation. This will often trigger a
-    /// reflow of that subpage.
-    fn update_subpage_size_if_necessary(&self, layer_properties: &LayerProperties) {
-        let subpage_pipeline_id = match layer_properties.subpage_pipeline_id {
-            Some(ref subpage_pipeline_id) => subpage_pipeline_id,
-            None => return,
-        };
-
-        let msg = ConstellationMsg::FrameSize(*subpage_pipeline_id, layer_properties.rect.size);
-        if let Err(e) = self.constellation_chan.send(msg) {
-            warn!("Sending subpage resize to constellation failed ({}).", e);
-        }
-    }
-
-    fn move_layer(&self,
-                  pipeline_id: PipelineId,
-                  layer_id: LayerId,
-                  origin: TypedPoint2D<f32, LayerPixel>)
-                  -> bool {
-        match self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) {
-            Some(ref layer) => {
-                if layer.wants_scroll_events() == WantsScrollEventsFlag::WantsScrollEvents {
-                    layer.clamp_scroll_offset_and_scroll_layer(TypedPoint2D::zero() - origin);
-                }
-                true
-            }
-            None => false,
-        }
-    }
-
-    fn scroll_layer_to_fragment_point_if_necessary(&mut self,
-                                                   pipeline_id: PipelineId,
-                                                   layer_id: LayerId) {
-        if let Some(point) = self.fragment_point.take() {
-            if !self.move_layer(pipeline_id, layer_id, TypedPoint2D::from_untyped(&point)) {
-                return warn!("Compositor: Tried to scroll to fragment with unknown layer.");
-            }
-
-            self.perform_updates_after_scroll();
-        }
-    }
-
     fn schedule_delayed_composite_if_necessary(&mut self) {
         match self.composition_request {
             CompositionRequest::CompositeNow(_) => return,
             CompositionRequest::DelayedComposite(_) |
             CompositionRequest::NoCompositingNecessary => {}
         }
 
         let timestamp = precise_time_ns();
         self.delayed_composition_timer.schedule_composite(timestamp);
         self.composition_request = CompositionRequest::DelayedComposite(timestamp);
     }
 
-    fn assign_painted_buffers(&mut self,
-                              pipeline_id: PipelineId,
-                              layer_id: LayerId,
-                              new_layer_buffer_set: Box<LayerBufferSet>,
-                              epoch: Epoch,
-                              frame_tree_id: FrameTreeId) {
-        // If the frame tree id has changed since this paint request was sent,
-        // reject the buffers and send them back to the paint thread. If this isn't handled
-        // correctly, the content_age in the tile grid can get out of sync when iframes are
-        // loaded and the frame tree changes. This can result in the compositor thinking it
-        // has already drawn the most recently painted buffer, and missing a frame.
-        if frame_tree_id == self.frame_tree_id {
-            if let Some(layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id,
-                                                                            layer_id) {
-                let requested_epoch = layer.extra_data.borrow().requested_epoch;
-                if requested_epoch == epoch {
-                    self.assign_painted_buffers_to_layer(layer, new_layer_buffer_set, epoch);
-                    return
-                } else {
-                    debug!("assign_painted_buffers epoch mismatch {:?} {:?} req={:?} actual={:?}",
-                           pipeline_id,
-                           layer_id,
-                           requested_epoch,
-                           epoch);
-                }
-            }
-        }
-
-        self.cache_unused_buffers(new_layer_buffer_set.buffers);
-    }
-
-    fn assign_painted_buffers_to_layer(&mut self,
-                                       layer: Rc<Layer<CompositorData>>,
-                                       new_layer_buffer_set: Box<LayerBufferSet>,
-                                       epoch: Epoch) {
-        debug!("compositor received new frame at size {:?}x{:?}",
-               self.window_size.width,
-               self.window_size.height);
-
-        // From now on, if we destroy the buffers, they will leak.
-        let mut new_layer_buffer_set = new_layer_buffer_set;
-        new_layer_buffer_set.mark_will_leak();
-
-        // FIXME(pcwalton): This is going to cause problems with inconsistent frames since
-        // we only composite one layer at a time.
-        layer.add_buffers(self, new_layer_buffer_set, epoch);
-        self.composite_if_necessary_if_not_using_webrender(CompositingReason::NewPaintedBuffers);
-    }
-
     fn scroll_fragment_to_point(&mut self,
-                                pipeline_id: PipelineId,
-                                layer_id: LayerId,
-                                point: Point2D<f32>) {
-        if self.move_layer(pipeline_id, layer_id, TypedPoint2D::from_untyped(&point)) {
-            self.perform_updates_after_scroll();
-            self.send_viewport_rects_for_all_layers()
-        } else {
-            self.fragment_point = Some(point)
-        }
+                                _pipeline_id: PipelineId,
+                                _layer_id: LayerId,
+                                _point: Point2D<f32>) {
+        println!("TODO: Support scroll_fragment_to_point again");
     }
 
     fn handle_window_message(&mut self, event: WindowEvent) {
         match event {
             WindowEvent::Idle => {}
 
             WindowEvent::Refresh => {
                 self.composite();
@@ -1378,28 +876,27 @@ impl<Window: WindowMethods> IOCompositor
         }
 
         if self.window_size == new_size {
             return;
         }
 
         self.window_size = new_size;
 
-        self.scene.set_root_layer_size(new_size.to_f32());
         self.send_window_size(WindowSizeType::Resize);
     }
 
     fn on_load_url_window_event(&mut self, url_string: String) {
         debug!("osmain: loading URL `{}`", url_string);
         self.got_load_complete_message = false;
         match Url::parse(&url_string) {
             Ok(url) => {
                 self.window.set_page_url(url.clone());
-                let msg = match self.scene.root {
-                    Some(ref layer) => ConstellationMsg::LoadUrl(layer.pipeline_id(), LoadData::new(url, None, None)),
+                let msg = match self.root_pipeline {
+                    Some(ref pipeline) => ConstellationMsg::LoadUrl(pipeline.id, LoadData::new(url, None, None)),
                     None => ConstellationMsg::InitLoadUrl(url)
                 };
                 if let Err(e) = self.constellation_chan.send(msg) {
                     warn!("Sending load url to constellation failed ({}).", e);
                 }
             },
             Err(e) => warn!("Parsing URL {} failed ({}).", url_string, e),
         }
@@ -1420,99 +917,67 @@ impl<Window: WindowMethods> IOCompositor
 
     fn dispatch_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) {
         let point = match mouse_window_event {
             MouseWindowEvent::Click(_, p) => p,
             MouseWindowEvent::MouseDown(_, p) => p,
             MouseWindowEvent::MouseUp(_, p) => p,
         };
 
-        if self.webrender_api.is_some() {
-            let root_pipeline_id = match self.get_root_pipeline_id() {
-                Some(root_pipeline_id) => root_pipeline_id,
-                None => return,
-            };
+        let root_pipeline_id = match self.get_root_pipeline_id() {
+            Some(root_pipeline_id) => root_pipeline_id,
+            None => return,
+        };
 
-            if let Some(pipeline) = self.pipeline(root_pipeline_id) {
-                let dppx = self.page_zoom * self.device_pixels_per_screen_px();
-                let translated_point = (point / dppx).to_untyped();
-                let event_to_send = match mouse_window_event {
-                    MouseWindowEvent::Click(button, _) => {
-                        MouseButtonEvent(MouseEventType::Click, button, translated_point)
-                    }
-                    MouseWindowEvent::MouseDown(button, _) => {
-                        MouseButtonEvent(MouseEventType::MouseDown, button, translated_point)
-                    }
-                    MouseWindowEvent::MouseUp(button, _) => {
-                        MouseButtonEvent(MouseEventType::MouseUp, button, translated_point)
-                    }
-                };
-                let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event_to_send);
-                if let Err(e) = pipeline.script_chan.send(msg) {
-                    warn!("Sending control event to script failed ({}).", e);
+        if let Some(pipeline) = self.pipeline(root_pipeline_id) {
+            let dppx = self.page_zoom * self.device_pixels_per_screen_px();
+            let translated_point = (point / dppx).to_untyped();
+            let event_to_send = match mouse_window_event {
+                MouseWindowEvent::Click(button, _) => {
+                    MouseButtonEvent(MouseEventType::Click, button, translated_point)
                 }
+                MouseWindowEvent::MouseDown(button, _) => {
+                    MouseButtonEvent(MouseEventType::MouseDown, button, translated_point)
+                }
+                MouseWindowEvent::MouseUp(button, _) => {
+                    MouseButtonEvent(MouseEventType::MouseUp, button, translated_point)
+                }
+            };
+            let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event_to_send);
+            if let Err(e) = pipeline.script_chan.send(msg) {
+                warn!("Sending control event to script failed ({}).", e);
             }
-            return
-        }
-
-        match self.find_topmost_layer_at_point(point / self.scene.scale) {
-            Some(result) => result.layer.send_mouse_event(self, mouse_window_event, result.point),
-            None => {},
         }
     }
 
     fn on_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) {
         if opts::get().convert_mouse_to_touch {
             self.on_touch_move(TouchId(0), cursor);
             return
         }
 
         self.dispatch_mouse_window_move_event_class(cursor);
     }
 
     fn dispatch_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) {
-        if self.webrender_api.is_some() {
-            let root_pipeline_id = match self.get_root_pipeline_id() {
-                Some(root_pipeline_id) => root_pipeline_id,
-                None => return,
-            };
-            if self.pipeline(root_pipeline_id).is_none() {
-                return;
-            }
-
-            let dppx = self.page_zoom * self.device_pixels_per_screen_px();
-            let event_to_send = MouseMoveEvent(Some((cursor / dppx).to_untyped()));
-            let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event_to_send);
-            if let Some(pipeline) = self.pipeline(root_pipeline_id) {
-                if let Err(e) = pipeline.script_chan.send(msg) {
-                    warn!("Sending mouse control event to script failed ({}).", e);
-                }
-            }
-            return
+        let root_pipeline_id = match self.get_root_pipeline_id() {
+            Some(root_pipeline_id) => root_pipeline_id,
+            None => return,
+        };
+        if self.pipeline(root_pipeline_id).is_none() {
+            return;
         }
 
-        match self.find_topmost_layer_at_point(cursor / self.scene.scale) {
-            Some(result) => {
-                // In the case that the mouse was previously over a different layer,
-                // that layer must update its state.
-                if let Some(last_pipeline_id) = self.last_mouse_move_recipient {
-                    if last_pipeline_id != result.layer.pipeline_id() {
-                        if let Some(pipeline) = self.pipeline(last_pipeline_id) {
-                            let _ = pipeline.script_chan
-                                            .send(ConstellationControlMsg::SendEvent(
-                                                last_pipeline_id.clone(),
-                                                MouseMoveEvent(None)));
-                        }
-                    }
-                }
-
-                self.last_mouse_move_recipient = Some(result.layer.pipeline_id());
-                result.layer.send_mouse_move_event(self, result.point);
+        let dppx = self.page_zoom * self.device_pixels_per_screen_px();
+        let event_to_send = MouseMoveEvent(Some((cursor / dppx).to_untyped()));
+        let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event_to_send);
+        if let Some(pipeline) = self.pipeline(root_pipeline_id) {
+            if let Err(e) = pipeline.script_chan.send(msg) {
+                warn!("Sending mouse control event to script failed ({}).", e);
             }
-            None => {}
         }
     }
 
     fn send_event_to_root_pipeline(&self, event: CompositorEvent) {
         let root_pipeline_id = match self.get_root_pipeline_id() {
             Some(root_pipeline_id) => root_pipeline_id,
             None => return,
         };
@@ -1546,17 +1011,16 @@ impl<Window: WindowMethods> IOCompositor
                 let cursor = TypedPoint2D::new(-1, -1);  // Make sure this hits the base layer.
                 self.pending_scroll_zoom_events.push(ScrollZoomEvent {
                     magnification: magnification,
                     delta: scroll_delta,
                     cursor: cursor,
                     phase: ScrollEventPhase::Move(true),
                     event_count: 1,
                 });
-                self.composite_if_necessary_if_not_using_webrender(CompositingReason::Zoom);
             }
             TouchAction::DispatchEvent => {
                 let dppx = self.page_zoom * self.device_pixels_per_screen_px();
                 let translated_point = (point / dppx).to_untyped();
                 self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Move,
                                                             identifier,
                                                             translated_point));
             }
@@ -1612,198 +1076,104 @@ impl<Window: WindowMethods> IOCompositor
                               cursor: TypedPoint2D<i32, DevicePixel>) {
         self.pending_scroll_zoom_events.push(ScrollZoomEvent {
             magnification: 1.0,
             delta: delta,
             cursor: cursor,
             phase: ScrollEventPhase::Move(self.scroll_in_progress),
             event_count: 1,
         });
-        self.composite_if_necessary_if_not_using_webrender(CompositingReason::Scroll);
     }
 
     fn on_scroll_start_window_event(&mut self,
                                     delta: TypedPoint2D<f32, DevicePixel>,
                                     cursor: TypedPoint2D<i32, DevicePixel>) {
         self.scroll_in_progress = true;
         self.pending_scroll_zoom_events.push(ScrollZoomEvent {
             magnification: 1.0,
             delta: delta,
             cursor: cursor,
             phase: ScrollEventPhase::Start,
             event_count: 1,
         });
-        self.composite_if_necessary_if_not_using_webrender(CompositingReason::Scroll);
     }
 
     fn on_scroll_end_window_event(&mut self,
                                   delta: TypedPoint2D<f32, DevicePixel>,
                                   cursor: TypedPoint2D<i32, DevicePixel>) {
         self.scroll_in_progress = false;
         self.pending_scroll_zoom_events.push(ScrollZoomEvent {
             magnification: 1.0,
             delta: delta,
             cursor: cursor,
             phase: ScrollEventPhase::End,
             event_count: 1,
         });
-        self.composite_if_necessary_if_not_using_webrender(CompositingReason::Scroll);
     }
 
     fn process_pending_scroll_events(&mut self) {
         let had_events = self.pending_scroll_zoom_events.len() > 0;
 
-        match self.webrender_api {
-            Some(ref webrender_api) => {
-                // Batch up all scroll events into one, or else we'll do way too much painting.
-                let mut last_combined_event: Option<ScrollZoomEvent> = None;
-                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.scene.scale).to_untyped();
-                            let cursor =
-                                (combined_event.cursor.to_f32() / self.scene.scale).to_untyped();
-                            webrender_api.scroll(delta, 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,
-                                delta: this_delta,
-                                cursor: this_cursor,
-                                phase: scroll_event.phase,
-                                event_count: 1,
-                            })
-                        }
-                        (&mut Some(ref mut last_combined_event),
-                         ScrollEventPhase::Move(false)) => {
-                            // Mac OS X sometimes delivers scroll events out of vsync during a
-                            // fling. This causes events to get bunched up occasionally, causing
-                            // nasty-looking "pops". To mitigate this, during a fling we average
-                            // deltas instead of summing them.
-                            let old_event_count =
-                                ScaleFactor::new(last_combined_event.event_count as f32);
-                            last_combined_event.event_count += 1;
-                            let new_event_count =
-                                ScaleFactor::new(last_combined_event.event_count as f32);
-                            last_combined_event.delta =
-                                (last_combined_event.delta * old_event_count + this_delta) /
-                                new_event_count;
-                        }
-                        (&mut Some(ref mut last_combined_event), _) => {
-                            last_combined_event.delta = last_combined_event.delta + this_delta;
-                            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.scene.scale).to_untyped();
-                    let cursor = (combined_event.cursor.to_f32() / self.scene.scale).to_untyped();
-                    webrender_api.scroll(delta, cursor, combined_event.phase);
-                    self.waiting_for_results_of_scroll = true
+        // Batch up all scroll events into one, or else we'll do way too much painting.
+        let mut last_combined_event: Option<ScrollZoomEvent> = None;
+        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);
+                    last_combined_event = None
                 }
             }
-            None => {
-                for event in std_mem::replace(&mut self.pending_scroll_zoom_events,
-                                                     Vec::new()) {
-                    let delta = event.delta / self.scene.scale;
-                    let cursor = event.cursor.to_f32() / self.scene.scale;
 
-                    if let Some(ref mut layer) = self.scene.root {
-                        layer.handle_scroll_event(delta, cursor);
-                    }
-
-                    if event.magnification != 1.0 {
-                        self.zoom_action = true;
-                        self.zoom_time = precise_time_s();
-                        self.viewport_zoom = ScaleFactor::new(
-                            (self.viewport_zoom.get() * event.magnification)
-                            .min(self.max_viewport_zoom.as_ref().map_or(MAX_ZOOM, ScaleFactor::get))
-                            .max(self.min_viewport_zoom.as_ref().map_or(MIN_ZOOM, ScaleFactor::get)));
-                        self.update_zoom_transform();
-                    }
-
-                    self.perform_updates_after_scroll();
+            match (&mut last_combined_event, scroll_event.phase) {
+                (last_combined_event @ &mut None, _) => {
+                    *last_combined_event = Some(ScrollZoomEvent {
+                        magnification: scroll_event.magnification,
+                        delta: this_delta,
+                        cursor: this_cursor,
+                        phase: scroll_event.phase,
+                        event_count: 1,
+                    })
+                }
+                (&mut Some(ref mut last_combined_event),
+                 ScrollEventPhase::Move(false)) => {
+                    // Mac OS X sometimes delivers scroll events out of vsync during a
+                    // fling. This causes events to get bunched up occasionally, causing
+                    // nasty-looking "pops". To mitigate this, during a fling we average
+                    // deltas instead of summing them.
+                    let old_event_count =
+                        ScaleFactor::new(last_combined_event.event_count as f32);
+                    last_combined_event.event_count += 1;
+                    let new_event_count =
+                        ScaleFactor::new(last_combined_event.event_count as f32);
+                    last_combined_event.delta =
+                        (last_combined_event.delta * old_event_count + this_delta) /
+                        new_event_count;
+                }
+                (&mut Some(ref mut last_combined_event), _) => {
+                    last_combined_event.delta = last_combined_event.delta + this_delta;
+                    last_combined_event.event_count += 1
                 }
             }
         }
 
-        if had_events {
-            self.send_viewport_rects_for_all_layers();
-        }
-    }
-
-    /// Computes new display ports for each layer, taking the scroll position into account, and
-    /// sends them to layout as necessary. This ultimately triggers a rerender of the content.
-    fn send_updated_display_ports_to_layout(&mut self) {
-        fn process_layer(layer: &Layer<CompositorData>,
-                         window_size: &TypedSize2D<f32, LayerPixel>,
-                         new_display_ports: &mut HashMap<PipelineId, Vec<(LayerId, Rect<Au>)>>) {
-            let visible_rect =
-                TypedRect::new(TypedPoint2D::zero(), *window_size)
-                    .translate(&-*layer.content_offset.borrow())
-                    .intersection(&*layer.bounds.borrow())
-                    .unwrap_or(TypedRect::zero())
-                    .to_untyped();
-            let visible_rect = TypedRect::new(
-                TypedPoint2D::new(Au::from_f32_px(visible_rect.origin.x),
-                                  Au::from_f32_px(visible_rect.origin.y)),
-                TypedSize2D::new(Au::from_f32_px(visible_rect.size.width),
-                                 Au::from_f32_px(visible_rect.size.height)));
-
-            let extra_layer_data = layer.extra_data.borrow();
-            if !new_display_ports.contains_key(&extra_layer_data.pipeline_id) {
-                new_display_ports.insert(extra_layer_data.pipeline_id, Vec::new());
-            }
-            if let Some(new_display_port) = new_display_ports.get_mut(&extra_layer_data.pipeline_id) {
-                new_display_port.push((extra_layer_data.id, visible_rect));
-            }
-
-            for kid in &*layer.children.borrow() {
-                process_layer(&*kid, window_size, new_display_ports)
-            }
+        // 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 cursor = (combined_event.cursor.to_f32() / self.scale).to_untyped();
+            self.webrender_api.scroll(delta, cursor, combined_event.phase);
+            self.waiting_for_results_of_scroll = true
         }
 
-        let dppx = self.page_zoom * self.device_pixels_per_screen_px();
-        let window_size = self.window_size.to_f32() / dppx * ScaleFactor::new(1.0);
-        let mut new_visible_rects = HashMap::new();
-        if let Some(ref layer) = self.scene.root {
-            process_layer(&**layer, &window_size, &mut new_visible_rects)
-        }
-
-        for (pipeline_id, new_visible_rects) in &new_visible_rects {
-            if let Some(pipeline_details) = self.pipeline_details.get(&pipeline_id) {
-                if let Some(ref pipeline) = pipeline_details.pipeline {
-                    let msg = LayoutControlMsg::SetVisibleRects((*new_visible_rects).clone());
-                    if let Err(e) = pipeline.layout_chan.send(msg) {
-                        warn!("Sending layout control message failed ({}).", e);
-                    }
-                }
-            }
-        }
-    }
-
-    /// Performs buffer requests and starts the scrolling timer or schedules a recomposite as
-    /// necessary.
-    fn perform_updates_after_scroll(&mut self) {
-        self.send_updated_display_ports_to_layout();
-        if opts::get().use_webrender {
-            return
-        }
-        if self.send_buffer_requests_for_all_layers() {
-            self.schedule_delayed_composite_if_necessary();
-        } else {
-            self.channel_to_self.send(Msg::Recomposite(CompositingReason::ContinueScroll));
+        if had_events {
+            self.send_viewport_rects();
         }
     }
 
     /// If there are any animations running, dispatches appropriate messages to the constellation.
     fn process_animations(&mut self) {
         let mut pipeline_ids = vec![];
         for (pipeline_id, pipeline_details) in &self.pipeline_details {
             if (pipeline_details.animations_running ||
@@ -1860,21 +1230,17 @@ impl<Window: WindowMethods> IOCompositor
     }
 
     fn device_pixels_per_page_px(&self) -> ScaleFactor<f32, PagePx, DevicePixel> {
         self.viewport_zoom * self.page_zoom * self.device_pixels_per_screen_px()
     }
 
     fn update_zoom_transform(&mut self) {
         let scale = self.device_pixels_per_page_px();
-        self.scene.scale = ScaleFactor::new(scale.get());
-
-        // We need to set the size of the root layer again, since the window size
-        // has changed in unscaled layer pixels.
-        self.scene.set_root_layer_size(self.window_size.to_f32());
+        self.scale = ScaleFactor::new(scale.get());
     }
 
     fn on_zoom_reset_window_event(&mut self) {
         self.page_zoom = ScaleFactor::new(1.0);
         self.update_zoom_transform();
         self.send_window_size(WindowSizeType::Resize);
     }
 
@@ -1889,17 +1255,16 @@ impl<Window: WindowMethods> IOCompositor
     fn on_pinch_zoom_window_event(&mut self, magnification: f32) {
         self.pending_scroll_zoom_events.push(ScrollZoomEvent {
             magnification: magnification,
             delta: TypedPoint2D::zero(), // TODO: Scroll to keep the center in view?
             cursor:  TypedPoint2D::new(-1, -1), // Make sure this hits the base layer.
             phase: ScrollEventPhase::Move(true),
             event_count: 1,
         });
-        self.composite_if_necessary_if_not_using_webrender(CompositingReason::Zoom);
     }
 
     fn on_navigation_window_event(&self, direction: WindowNavigateMsg) {
         let direction = match direction {
             windowing::WindowNavigateMsg::Forward => TraversalDirection::Forward(1),
             windowing::WindowNavigateMsg::Back => TraversalDirection::Back(1),
         };
         let msg = ConstellationMsg::TraverseHistory(None, direction);
@@ -1910,203 +1275,40 @@ impl<Window: WindowMethods> IOCompositor
 
     fn on_key_event(&self, ch: Option<char>, key: Key, state: KeyState, modifiers: KeyModifiers) {
         let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers);
         if let Err(e) = self.constellation_chan.send(msg) {
             warn!("Sending key event to constellation failed ({}).", e);
         }
     }
 
-    fn fill_paint_request_with_cached_layer_buffers(&mut self, paint_request: &mut PaintRequest) {
-        for buffer_request in &mut paint_request.buffer_requests {
-            if self.surface_map.mem() == 0 {
-                return;
-            }
-
-            let size = Size2D::new(buffer_request.screen_rect.size.width as i32,
-                                   buffer_request.screen_rect.size.height as i32);
-            if let Some(mut native_surface) = self.surface_map.find(size) {
-                native_surface.mark_wont_leak();
-                buffer_request.native_surface = Some(native_surface);
-            }
-        }
-    }
-
-    fn convert_buffer_requests_to_pipeline_requests_map(&mut self,
-                                                        requests: Vec<(Rc<Layer<CompositorData>>,
-                                                                       Vec<BufferRequest>)>)
-                                                        -> HashMap<PipelineId, Vec<PaintRequest>> {
-        let scale = self.device_pixels_per_page_px();
-        let mut results: HashMap<PipelineId, Vec<PaintRequest>> = HashMap::new();
-
-        for (layer, mut layer_requests) in requests {
-            let pipeline_id = layer.pipeline_id();
-            let current_epoch = self.pipeline_details(pipeline_id).current_epoch;
-            layer.extra_data.borrow_mut().requested_epoch = current_epoch;
-            let vec = match results.entry(pipeline_id) {
-                Occupied(entry) => {
-                    entry.into_mut()
-                }
-                Vacant(entry) => {
-                    entry.insert(Vec::new())
-                }
+    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 {
+                stacking_context_id: scroll_layer_state.stacking_context_id.from_webrender(),
+                scroll_offset: scroll_layer_state.scroll_offset,
             };
-
-            // All the BufferRequests are in layer/device coordinates, but the paint thread
-            // wants to know the page coordinates. We scale them before sending them.
-            for request in &mut layer_requests {
-                request.page_rect = request.page_rect / scale.get();
-            }
-
-            let layer_kind = if layer.transform_state.borrow().has_transform {
-                LayerKind::HasTransform
-            } else {
-                LayerKind::NoTransform
-            };
-
-            let mut paint_request = PaintRequest {
-                buffer_requests: layer_requests,
-                scale: scale.get(),
-                layer_id: layer.extra_data.borrow().id,
-                epoch: layer.extra_data.borrow().requested_epoch,
-                layer_kind: layer_kind,
-            };
-            self.fill_paint_request_with_cached_layer_buffers(&mut paint_request);
-            vec.push(paint_request);
-        }
-
-        results
-    }
-
-    fn send_viewport_rect_for_layer(&self, layer: Rc<Layer<CompositorData>>) {
-        if layer.extra_data.borrow().id == LayerId::null() {
-            let layer_rect = Rect::new(-layer.extra_data.borrow().scroll_offset.to_untyped(),
-                                       layer.bounds.borrow().size.to_untyped());
-            if let Some(pipeline) = self.pipeline(layer.pipeline_id()) {
-                let msg = ConstellationControlMsg::Viewport(pipeline.id.clone(), layer_rect);
-                if let Err(e) = pipeline.script_chan.send(msg) {
-                    warn!("Send viewport to script failed ({})", e);
-                }
-            }
-        }
-
-        for kid in &*layer.children() {
-            self.send_viewport_rect_for_layer(kid.clone());
-        }
-    }
-
-    fn send_viewport_rects_for_all_layers(&self) {
-        if opts::get().use_webrender {
-            return self.send_webrender_viewport_rects()
+            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);
         }
 
-        if let Some(ref root) = self.scene.root {
-            self.send_viewport_rect_for_layer(root.clone())
-        }
-    }
-
-    fn send_webrender_viewport_rects(&self) {
-        let mut stacking_context_scroll_states_per_pipeline = HashMap::new();
-        if let Some(ref webrender_api) = self.webrender_api {
-            for scroll_layer_state in webrender_api.get_scroll_layer_state() {
-                let stacking_context_scroll_state = StackingContextScrollState {
-                    stacking_context_id: scroll_layer_state.stacking_context_id.from_webrender(),
-                    scroll_offset: scroll_layer_state.scroll_offset,
-                };
-                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);
-            }
-
-            for (pipeline_id, stacking_context_scroll_states) in
-                    stacking_context_scroll_states_per_pipeline {
-                if let Some(pipeline) = self.pipeline(pipeline_id.from_webrender()) {
-                    let msg = LayoutControlMsg::SetStackingContextScrollStates(
-                        stacking_context_scroll_states);
-                    let _ = pipeline.layout_chan.send(msg);
-                }
+        for (pipeline_id, stacking_context_scroll_states) in
+                stacking_context_scroll_states_per_pipeline {
+            if let Some(pipeline) = self.pipeline(pipeline_id.from_webrender()) {
+                let msg = LayoutControlMsg::SetStackingContextScrollStates(
+                    stacking_context_scroll_states);
+                let _ = pipeline.layout_chan.send(msg);
             }
         }
     }
 
-    /// Returns true if any buffer requests were sent or false otherwise.
-    fn send_buffer_requests_for_all_layers(&mut self) -> bool {
-        if self.webrender.is_some() {
-            return false;
-        }
-
-        if let Some(ref root_layer) = self.scene.root {
-            root_layer.update_transform_state(&Matrix4D::identity(),
-                                              &Matrix4D::identity(),
-                                              &Point2D::zero());
-        }
-
-        let mut layers_and_requests = Vec::new();
-        let mut unused_buffers = Vec::new();
-        self.scene.get_buffer_requests(&mut layers_and_requests, &mut unused_buffers);
-
-        // Return unused tiles first, so that they can be reused by any new BufferRequests.
-        self.cache_unused_buffers(unused_buffers);
-
-        if layers_and_requests.is_empty() {
-            return false;
-        }
-
-        // We want to batch requests for each pipeline to avoid race conditions
-        // when handling the resulting BufferRequest responses.
-        let pipeline_requests =
-            self.convert_buffer_requests_to_pipeline_requests_map(layers_and_requests);
-
-        for (pipeline_id, requests) in pipeline_requests {
-            let msg = ChromeToPaintMsg::Paint(requests, self.frame_tree_id);
-            if let Some(pipeline) = self.pipeline(pipeline_id) {
-                if let Err(e) = pipeline.chrome_to_paint_chan.send(msg) {
-                    warn!("Sending paint message failed ({}).", e);
-                }
-            }
-        }
-
-        true
-    }
-
-    /// Check if a layer (or its children) have any outstanding paint
-    /// results to arrive yet.
-    fn does_layer_have_outstanding_paint_messages(&self, layer: &Rc<Layer<CompositorData>>)
-                                                  -> bool {
-        let layer_data = layer.extra_data.borrow();
-        let current_epoch = match self.pipeline_details.get(&layer_data.pipeline_id) {
-            None => return false,
-            Some(ref details) => details.current_epoch,
-        };
-
-        // Only check layers that have requested the current epoch, as there may be
-        // layers that are not visible in the current viewport, and therefore
-        // have not requested a paint of the current epoch.
-        // If a layer has sent a request for the current epoch, but it hasn't
-        // arrived yet then this layer is waiting for a paint message.
-        //
-        // Also don't check the root layer, because the paint thread won't paint
-        // anything for it after first layout.
-        if layer_data.id != LayerId::null() &&
-                layer_data.requested_epoch == current_epoch &&
-                layer_data.painted_epoch != current_epoch {
-            return true;
-        }
-
-        for child in &*layer.children() {
-            if self.does_layer_have_outstanding_paint_messages(child) {
-                return true;
-            }
-        }
-
-        false
-    }
-
     // Check if any pipelines currently have active animations or animation callbacks.
     fn animations_active(&self) -> bool {
         for (_, details) in &self.pipeline_details {
             // If animations are currently running, then don't bother checking
             // with the constellation if the output image is stable.
             if details.animations_running {
                 return true;
             }
@@ -2121,49 +1323,27 @@ impl<Window: WindowMethods> IOCompositor
     /// Query the constellation to see if the current compositor
     /// output matches the current frame tree output, and if the
     /// associated script threads are idle.
     fn is_ready_to_paint_image_output(&mut self) -> Result<(), NotReadyToPaint> {
         match self.ready_to_save_state {
             ReadyState::Unknown => {
                 // Unsure if the output image is stable.
 
-                // Check if any layers are waiting for paints to complete
-                // of their current epoch request. If so, early exit
-                // from this check.
-                match self.scene.root {
-                    Some(ref root_layer) => {
-                        if self.does_layer_have_outstanding_paint_messages(root_layer) {
-                            return Err(NotReadyToPaint::LayerHasOutstandingPaintMessages);
-                        }
-                    }
-                    None => {
-                        return Err(NotReadyToPaint::MissingRoot);
-                    }
-                }
-
-                // Check if there are any pending frames. If so, the image is not stable yet.
-                if !self.pending_subpages.is_empty() {
-                    return Err(NotReadyToPaint::PendingSubpages(self.pending_subpages.len()));
-                }
-
                 // Collect the currently painted epoch of each pipeline that is
                 // complete (i.e. has *all* layers painted to the requested epoch).
                 // This gets sent to the constellation for comparison with the current
                 // frame tree.
                 let mut pipeline_epochs = HashMap::new();
-                for (id, details) in &self.pipeline_details {
-                    if let Some(ref webrender) = self.webrender {
-                        let webrender_pipeline_id = id.to_webrender();
-                        if let Some(webrender_traits::Epoch(epoch)) = webrender.current_epoch(webrender_pipeline_id) {
-                            let epoch = Epoch(epoch);
-                            pipeline_epochs.insert(*id, epoch);
-                        }
-                    } else {
-                        pipeline_epochs.insert(*id, details.current_epoch);
+                for (id, _) in &self.pipeline_details {
+                    let webrender_pipeline_id = id.to_webrender();
+                    if let Some(webrender_traits::Epoch(epoch)) = self.webrender
+                                                                      .current_epoch(webrender_pipeline_id) {
+                        let epoch = Epoch(epoch);
+                        pipeline_epochs.insert(*id, epoch);
                     }
                 }
 
                 // Pass the pipeline/epoch states to the constellation and check
                 // if it's safe to output the image.
                 let msg = ConstellationMsg::IsReadyToSaveImage(pipeline_epochs);
                 if let Err(e) = self.constellation_chan.send(msg) {
                     warn!("Sending ready to save to constellation failed ({}).", e);
@@ -2209,29 +1389,23 @@ impl<Window: WindowMethods> IOCompositor
     /// Composite either to the screen or to a png image or both.
     /// Returns Ok if composition was performed or Err if it was not possible to composite
     /// for some reason. If CompositeTarget is Window or Png no image data is returned;
     /// in the latter case the image is written directly to a file. If CompositeTarget
     /// is WindowAndPng Ok(Some(png::Image)) is returned.
     fn composite_specific_target(&mut self,
                                  target: CompositeTarget)
                                  -> Result<Option<Image>, UnableToComposite> {
-        if self.context.is_none() && self.webrender.is_none() {
-            return Err(UnableToComposite::NoContext)
-        }
         let (width, height) =
             (self.window_size.width as usize, self.window_size.height as usize);
         if !self.window.prepare_for_composite(width, height) {
             return Err(UnableToComposite::WindowUnprepared)
         }
 
-        if let Some(ref mut webrender) = self.webrender {
-            assert!(self.context.is_none());
-            webrender.update();
-        }
+        self.webrender.update();
 
         let wait_for_stable_image = match target {
             CompositeTarget::WindowAndPng | CompositeTarget::PngFile => true,
             CompositeTarget::Window => opts::get().exit_after_load,
         };
 
         if wait_for_stable_image {
             match self.is_ready_to_paint_image_output() {
@@ -2252,49 +1426,19 @@ impl<Window: WindowMethods> IOCompositor
 
         let render_target_info = match target {
             CompositeTarget::Window => RenderTargetInfo::empty(),
             _ => initialize_png(width, height)
         };
 
         profile(ProfilerCategory::Compositing, None, self.time_profiler_chan.clone(), || {
             debug!("compositor: compositing");
-            self.dump_layer_tree();
-            // Adjust the layer dimensions as necessary to correspond to the size of the window.
-            self.scene.viewport = match self.viewport {
-                Some((point, size)) => TypedRect::new(point.to_f32(), size.to_f32()),
-                None => TypedRect::new(TypedPoint2D::zero(), self.window_size.to_f32()),
-            };
 
             // Paint the scene.
-            if let Some(ref mut webrender) = self.webrender {
-                assert!(self.context.is_none());
-                webrender.render(self.window_size.to_untyped());
-            } else if let Some(ref layer) = self.scene.root {
-                match self.context {
-                    Some(context) => {
-                        if let Some((point, size)) = self.viewport {
-                            let point = point.to_untyped(); let size  = size.to_untyped();
-
-                            gl::scissor(point.x as GLint, point.y as GLint, size.width as GLsizei,
-                            size.height as GLsizei);
-
-                            gl::enable(gl::SCISSOR_TEST); rendergl::render_scene(layer.clone(),
-                            context, &self.scene); gl::disable(gl::SCISSOR_TEST);
-
-                        } else {
-                            rendergl::render_scene(layer.clone(), context, &self.scene);
-                        }
-                    }
-
-                    None => {
-                        debug!("compositor: not compositing because context not yet set up")
-                    }
-                }
-            }
+            self.webrender.render(self.window_size.to_untyped());
         });
 
         let rv = match target {
             CompositeTarget::Window => None,
             CompositeTarget::WindowAndPng => {
                 let img = self.draw_img(render_target_info,
                                         width,
                                         height);
@@ -2328,20 +1472,16 @@ impl<Window: WindowMethods> IOCompositor
 
         // Perform the page flip. This will likely block for a while.
         self.window.present();
 
         self.last_composite_time = precise_time_ns();
 
         self.composition_request = CompositionRequest::NoCompositingNecessary;
 
-        if !opts::get().use_webrender {
-            self.process_pending_scroll_events();
-        }
-
         self.process_animations();
         self.start_scrolling_bounce_if_necessary();
         self.waiting_for_results_of_scroll = false;
 
         Ok(rv)
     }
 
     fn draw_img(&self,
@@ -2353,19 +1493,16 @@ impl<Window: WindowMethods> IOCompositor
                                          width as gl::GLsizei,
                                          height as gl::GLsizei,
                                          gl::RGB, gl::UNSIGNED_BYTE);
 
         gl::bind_framebuffer(gl::FRAMEBUFFER, 0);
 
         gl::delete_buffers(&render_target_info.texture_ids);
         gl::delete_frame_buffers(&render_target_info.framebuffer_ids);
-        if opts::get().use_webrender  {
-            gl::delete_renderbuffers(&render_target_info.renderbuffer_ids);
-        }
 
         // flip image vertically (texture is upside down)
         let orig_pixels = pixels.clone();
         let stride = width * 3;
         for y in 0..height {
             let dst_start = y * stride;
             let src_start = (height - y - 1) * stride;
             let src_slice = &orig_pixels[src_start .. src_start + stride];
@@ -2380,200 +1517,31 @@ impl<Window: WindowMethods> IOCompositor
                 println!("updating composition_request ({:?})", reason);
             }
             self.composition_request = CompositionRequest::CompositeNow(reason)
         } else if opts::get().is_running_problem_test {
             println!("composition_request is already {:?}", self.composition_request);
         }
     }
 
-    fn composite_if_necessary_if_not_using_webrender(&mut self, reason: CompositingReason) {
-        if !opts::get().use_webrender {
-            self.composite_if_necessary(reason)
-        }
-    }
-
     fn initialize_compositing(&mut self) {
-        if self.webrender.is_none() {
-            let show_debug_borders = opts::get().show_debug_borders;
-            // We can unwrap native_display because it's only None when using webrender.
-            self.context = Some(rendergl::RenderContext::new(self.native_display
-                                                             .expect("n_d should be Some when not using wr").clone(),
-                                                             show_debug_borders,
-                                                             opts::get().output_file.is_some()))
-        }
-    }
-
-    fn find_topmost_layer_at_point_for_layer(&self,
-                                             layer: Rc<Layer<CompositorData>>,
-                                             point_in_parent_layer: TypedPoint2D<f32, LayerPixel>,
-                                             clip_rect_in_parent_layer: &TypedRect<f32, LayerPixel>)
-                                             -> Option<HitTestResult> {
-        let layer_bounds = *layer.bounds.borrow();
-        let masks_to_bounds = *layer.masks_to_bounds.borrow();
-        if layer_bounds.is_empty() && masks_to_bounds {
-            return None;
-        }
-        let scroll_offset = layer.extra_data.borrow().scroll_offset;
-
-        // Total offset from parent coordinates to this layer's coordinates.
-        // FIXME: This offset is incorrect for fixed-position layers.
-        let layer_offset = scroll_offset + layer_bounds.origin;
-
-        let clipped_layer_bounds = match clip_rect_in_parent_layer.intersection(&layer_bounds) {
-            Some(rect) => rect,
-            None => return None,
-        };
-
-        let clip_rect_for_children = if masks_to_bounds {
-            &clipped_layer_bounds
-        } else {
-            clip_rect_in_parent_layer
-        }.translate(&-layer_offset);
-
-        let child_point = point_in_parent_layer - layer_offset;
-        for child in layer.children().iter().rev() {
-            // Translate the clip rect into the child's coordinate system.
-            let result = self.find_topmost_layer_at_point_for_layer(child.clone(),
-                                                                    child_point,
-                                                                    &clip_rect_for_children);
-            if let Some(mut result) = result {
-                // Return the point in layer coordinates of the topmost frame containing the point.
-                let pipeline_id = layer.extra_data.borrow().pipeline_id;
-                let child_pipeline_id = result.layer.extra_data.borrow().pipeline_id;
-                if pipeline_id == child_pipeline_id {
-                    result.point = result.point + layer_offset;
-                }
-                return Some(result);
-            }
-        }
-
-        if !clipped_layer_bounds.contains(&point_in_parent_layer) {
-            return None;
-        }
-
-        Some(HitTestResult { layer: layer, point: point_in_parent_layer })
-    }
-
-    fn find_topmost_layer_at_point(&self,
-                                   point: TypedPoint2D<f32, LayerPixel>)
-                                   -> Option<HitTestResult> {
-        match self.scene.root {
-            Some(ref layer) => {
-                self.find_topmost_layer_at_point_for_layer(layer.clone(),
-                                                           point,
-                                                           &*layer.bounds.borrow())
-            }
-
-            None => None,
-        }
-    }
-
-    fn find_layer_with_pipeline_and_layer_id(&self,
-                                             pipeline_id: PipelineId,
-                                             layer_id: LayerId)
-                                             -> Option<Rc<Layer<CompositorData>>> {
-        match self.scene.root {
-            Some(ref layer) =>
-                find_layer_with_pipeline_and_layer_id_for_layer(layer.clone(),
-                                                                pipeline_id,
-                                                                layer_id),
-
-            None => None,
-        }
-    }
-
-    pub fn cache_unused_buffers<B>(&mut self, buffers: B)
-        where B: IntoIterator<Item=Box<LayerBuffer>>
-    {
-        let surfaces = buffers.into_iter().map(|buffer| buffer.native_surface);
-        if let Some(ref native_display) = self.native_display {
-            self.surface_map.insert_surfaces(native_display, surfaces);
-        }
     }
 
     fn get_root_pipeline_id(&self) -> Option<PipelineId> {
-        self.scene.root.as_ref().map(|root_layer| root_layer.extra_data.borrow().pipeline_id)
-    }
-
-    #[allow(dead_code)]
-    fn dump_layer_tree(&self) {
-        if !opts::get().dump_layer_tree {
-            return;
-        }
-
-        let mut print_tree = PrintTree::new("Layer tree".to_owned());
-        if let Some(ref layer) = self.scene.root {
-            self.dump_layer_tree_layer(&**layer, &mut print_tree);
-        }
-    }
-
-    #[allow(dead_code)]
-    fn dump_layer_tree_layer(&self, layer: &Layer<CompositorData>, print_tree: &mut PrintTree) {
-        let data = layer.extra_data.borrow();
-        let layer_string = if data.id == LayerId::null() {
-            format!("Root Layer (pipeline={})", data.pipeline_id)
-        } else {
-            "Layer".to_owned()
-        };
-
-        let masks_string = if *layer.masks_to_bounds.borrow() {
-            " (masks children)"
-        } else {
-            ""
-        };
-
-        let establishes_3d_context_string = if layer.establishes_3d_context {
-            " (3D context)"
-        } else {
-            ""
-        };
-
-        let fixed_string = if data.scroll_policy == ScrollPolicy::FixedPosition {
-            " (fixed)"
-        } else {
-            ""
-        };
-
-        let layer_string = format!("{} ({:?}) ({},{} at {},{}){}{}{}",
-                                   layer_string,
-                                   layer.extra_data.borrow().id,
-                                   (*layer.bounds.borrow()).size.to_untyped().width,
-                                   (*layer.bounds.borrow()).size.to_untyped().height,
-                                   (*layer.bounds.borrow()).origin.to_untyped().x,
-                                   (*layer.bounds.borrow()).origin.to_untyped().y,
-                                   masks_string,
-                                   establishes_3d_context_string,
-                                   fixed_string);
-
-        let children = layer.children();
-        if !children.is_empty() {
-            print_tree.new_level(layer_string);
-            for kid in &*children {
-                self.dump_layer_tree_layer(&**kid, print_tree);
-            }
-            print_tree.end_level();
-        } else {
-            print_tree.add_item(layer_string);
-        }
+        self.root_pipeline.as_ref().map(|pipeline| pipeline.id)
     }
 
     fn start_scrolling_bounce_if_necessary(&mut self) {
         if self.scroll_in_progress {
             return
         }
 
-        match self.webrender {
-            Some(ref webrender) if webrender.layers_are_bouncing_back() => {}
-            _ => return,
-        }
-
-        if let Some(ref webrender_api) = self.webrender_api {
-            webrender_api.tick_scrolling_bounce_animations();
-            self.send_webrender_viewport_rects()
+        if self.webrender.layers_are_bouncing_back() {
+            self.webrender_api.tick_scrolling_bounce_animations();
+            self.send_viewport_rects()
         }
     }
 
     pub fn handle_events(&mut self, messages: Vec<WindowEvent>) -> bool {
         // Check for new messages coming from the other threads in the system.
         let mut compositor_messages = vec![];
         let mut found_recomposite_msg = false;
         while let Some(msg) = self.port.try_recv_compositor_msg() {
@@ -2607,72 +1575,51 @@ impl<Window: WindowMethods> IOCompositor
         // Handle any messages coming from the windowing system.
         for message in messages {
             self.handle_window_message(message);
         }
 
         // If a pinch-zoom happened recently, ask for tiles at the new resolution
         if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 {
             self.zoom_action = false;
-            self.scene.mark_layer_contents_as_changed_recursively();
-            self.send_buffer_requests_for_all_layers();
         }
 
         match self.composition_request {
             CompositionRequest::NoCompositingNecessary |
             CompositionRequest::DelayedComposite(_) => {}
             CompositionRequest::CompositeNow(_) => {
                 self.composite()
             }
         }
 
-        if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll &&
-                opts::get().use_webrender {
+        if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll {
             self.process_pending_scroll_events()
         }
 
         self.shutdown_state != ShutdownState::FinishedShuttingDown
     }
 
     /// Repaints and recomposites synchronously. You must be careful when calling this, as if a
     /// paint is not scheduled the compositor will hang forever.
     ///
     /// This is used when resizing the window.
     pub fn repaint_synchronously(&mut self) {
-        if self.webrender.is_none() {
-            while self.shutdown_state != ShutdownState::ShuttingDown {
-                let msg = self.port.recv_compositor_msg();
-                let received_new_buffers = match msg {
-                    Msg::AssignPaintedBuffers(..) => true,
-                    _ => false,
-                };
-                let keep_going = self.handle_browser_message(msg);
-                if received_new_buffers {
-                    self.composite();
-                    break
-                }
-                if !keep_going {
-                    break
-                }
+        while self.shutdown_state != ShutdownState::ShuttingDown {
+            let msg = self.port.recv_compositor_msg();
+            let need_recomposite = match msg {
+                Msg::Recomposite(_) => true,
+                _ => false,
+            };
+            let keep_going = self.handle_browser_message(msg);
+            if need_recomposite {
+                self.composite();
+                break
             }
-        } else {
-            while self.shutdown_state != ShutdownState::ShuttingDown {
-                let msg = self.port.recv_compositor_msg();
-                let need_recomposite = match msg {
-                    Msg::Recomposite(_) => true,
-                    _ => false,
-                };
-                let keep_going = self.handle_browser_message(msg);
-                if need_recomposite {
-                    self.composite();
-                    break
-                }
-                if !keep_going {
-                    break
-                }
+            if !keep_going {
+                break
             }
         }
     }
 
     pub fn pinch_zoom_level(&self) -> f32 {
         self.viewport_zoom.get() as f32
     }
 
@@ -2683,37 +1630,16 @@ impl<Window: WindowMethods> IOCompositor
         };
         let msg = ConstellationMsg::GetPipelineTitle(root_pipeline_id);
         if let Err(e) = self.constellation_chan.send(msg) {
             warn!("Failed to send pipeline title ({}).", e);
         }
     }
 }
 
-fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc<Layer<CompositorData>>,
-                                                   pipeline_id: PipelineId,
-                                                   layer_id: LayerId)
-                                                   -> Option<Rc<Layer<CompositorData>>> {
-    if layer.extra_data.borrow().pipeline_id == pipeline_id &&
-       layer.extra_data.borrow().id == layer_id {
-        return Some(layer);
-    }
-
-    for kid in &*layer.children() {
-        let result = find_layer_with_pipeline_and_layer_id_for_layer(kid.clone(),
-                                                                     pipeline_id,
-                                                                     layer_id);
-        if result.is_some() {
-            return result;
-        }
-    }
-
-    None
-}
-
 /// Why we performed a composite. This is used for debugging.
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum CompositingReason {
     /// We hit the delayed composition timeout. (See `delayed_composition.rs`.)
     DelayedCompositeTimeout,
     /// The window has been scrolled and we're starting the first recomposite.
     Scroll,
     /// A scroll has continued and we need to recomposite again.
deleted file mode 100644
--- a/servo/components/compositing/compositor_layer.rs
+++ /dev/null
@@ -1,542 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use azure::azure_hl;
-use compositor::IOCompositor;
-use euclid::point::TypedPoint2D;
-use euclid::rect::TypedRect;
-use euclid::size::TypedSize2D;
-use gfx_traits::{Epoch, LayerId, LayerProperties, ScrollPolicy};
-use layers::color::Color;
-use layers::geometry::LayerPixel;
-use layers::layers::{Layer, LayerBufferSet};
-use msg::constellation_msg::PipelineId;
-use script_traits::CompositorEvent;
-use script_traits::CompositorEvent::{MouseButtonEvent, MouseMoveEvent, TouchpadPressureEvent};
-use script_traits::ConstellationControlMsg;
-use script_traits::MouseEventType;
-use script_traits::TouchpadPressurePhase;
-use std::rc::Rc;
-use windowing::{MouseWindowEvent, WindowMethods};
-
-#[derive(Debug)]
-pub struct CompositorData {
-    /// This layer's pipeline id. The compositor can associate this id with an
-    /// actual CompositionPipeline.
-    pub pipeline_id: PipelineId,
-
-    /// The ID of this layer within the pipeline.
-    pub id: LayerId,
-
-    /// The behavior of this layer when a scroll message is received.
-    pub wants_scroll_events: WantsScrollEventsFlag,
-
-    /// Whether an ancestor layer that receives scroll events moves this layer.
-    pub scroll_policy: ScrollPolicy,
-
-    /// The epoch that has been requested for this layer (via send_buffer_requests).
-    pub requested_epoch: Epoch,
-
-    /// The last accepted painted buffer for this layer (via assign_pained_buffers).
-    pub painted_epoch: Epoch,
-
-    /// The scroll offset originating from this scrolling root. This allows scrolling roots
-    /// to track their current scroll position even while their content_offset does not change.
-    pub scroll_offset: TypedPoint2D<f32, LayerPixel>,
-
-    /// The pipeline ID of this layer, if it represents a subpage.
-    pub subpage_info: Option<PipelineId>,
-}
-
-impl CompositorData {
-    pub fn new_layer(pipeline_id: PipelineId,
-                     layer_properties: LayerProperties,
-                     wants_scroll_events: WantsScrollEventsFlag,
-                     tile_size: usize)
-                     -> Rc<Layer<CompositorData>> {
-        let new_compositor_data = CompositorData {
-            pipeline_id: pipeline_id,
-            id: layer_properties.id,
-            wants_scroll_events: wants_scroll_events,
-            scroll_policy: layer_properties.scroll_policy,
-            requested_epoch: Epoch(0),
-            painted_epoch: Epoch(0),
-            scroll_offset: TypedPoint2D::zero(),
-            subpage_info: layer_properties.subpage_pipeline_id,
-        };
-
-        Rc::new(Layer::new(TypedRect::from_untyped(&layer_properties.rect),
-                           tile_size,
-                           to_layers_color(&layer_properties.background_color),
-                           1.0,
-                           layer_properties.establishes_3d_context,
-                           new_compositor_data))
-    }
-}
-
-pub trait CompositorLayer {
-    fn update_layer_except_bounds(&self, layer_properties: LayerProperties);
-
-    fn update_layer(&self, layer_properties: LayerProperties);
-
-    fn add_buffers<Window>(&self,
-                           compositor: &mut IOCompositor<Window>,
-                           new_buffers: Box<LayerBufferSet>,
-                           epoch: Epoch)
-                           where Window: WindowMethods;
-
-    /// Destroys all layer tiles, sending the buffers back to the painter to be destroyed or
-    /// reused.
-    fn clear<Window>(&self, compositor: &mut IOCompositor<Window>) where Window: WindowMethods;
-
-    /// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
-    /// painter to be destroyed or reused.
-    fn clear_all_tiles<Window>(&self, compositor: &mut IOCompositor<Window>)
-                               where Window: WindowMethods;
-
-    /// Removes the root layer (and any children) for a given pipeline from the
-    /// compositor. Buffers that the compositor is holding are returned to the
-    /// owning paint thread.
-    fn remove_root_layer_with_pipeline_id<Window>(&self,
-                                                  compositor: &mut IOCompositor<Window>,
-                                                  pipeline_id: PipelineId)
-                                                  where Window: WindowMethods;
-
-    /// Destroys all tiles of all layers, including children, *without* sending them back to the
-    /// painter. You must call this only when the paint thread is destined to be going down;
-    /// otherwise, you will leak tiles.
-    ///
-    /// This is used during shutdown, when we know the paint thread is going away.
-    fn forget_all_tiles(&self);
-
-    /// Move the layer's descendants that don't want scroll events and scroll by a relative
-    /// specified amount in page coordinates. This also takes in a cursor position to see if the
-    /// mouse is over child layers first. If a layer successfully scrolled returns either
-    /// ScrollPositionUnchanged or ScrollPositionChanged. If no layer was targeted by the event
-    /// returns ScrollEventUnhandled.
-    fn handle_scroll_event(&self,
-                           delta: TypedPoint2D<f32, LayerPixel>,
-                           cursor: TypedPoint2D<f32, LayerPixel>)
-                           -> ScrollEventResult;
-
-    // Takes in a MouseWindowEvent, determines if it should be passed to children, and
-    // sends the event off to the appropriate pipeline. NB: the cursor position is in
-    // client coordinates.
-    fn send_mouse_event<Window>(&self,
-                                compositor: &IOCompositor<Window>,
-                                event: MouseWindowEvent,
-                                cursor: TypedPoint2D<f32, LayerPixel>)
-                                where Window: WindowMethods;
-
-    fn send_mouse_move_event<Window>(&self,
-                                     compositor: &IOCompositor<Window>,
-                                     cursor: TypedPoint2D<f32, LayerPixel>)
-                                     where Window: WindowMethods;
-
-    fn send_event<Window>(&self,
-                          compositor: &IOCompositor<Window>,
-                          event: CompositorEvent)
-                          where Window: WindowMethods;
-
-    fn send_touchpad_pressure_event<Window>(&self,
-                                            compositor: &IOCompositor<Window>,
-                                            cursor: TypedPoint2D<f32, LayerPixel>,
-                                            pressure: f32,
-                                            phase: TouchpadPressurePhase)
-                                            where Window: WindowMethods;
-
-    fn clamp_scroll_offset_and_scroll_layer(&self,
-                                            new_offset: TypedPoint2D<f32, LayerPixel>)
-                                            -> ScrollEventResult;
-
-    fn scroll_layer_and_all_child_layers(&self,
-                                         new_offset: TypedPoint2D<f32, LayerPixel>)
-                                         -> bool;
-
-    /// Return a flag describing how this layer deals with scroll events.
-    fn wants_scroll_events(&self) -> WantsScrollEventsFlag;
-
-    /// Return the pipeline id associated with this layer.
-    fn pipeline_id(&self) -> PipelineId;
-}
-
-pub trait RcCompositorLayer {
-    /// Traverses the existing layer hierarchy and removes any layers that
-    /// currently exist but which are no longer required.
-    fn collect_old_layers<Window>(&self,
-                                  compositor: &mut IOCompositor<Window>,
-                                  pipeline_id: PipelineId,
-                                  new_layers: &[LayerProperties],
-                                  pipelines_removed: &mut Vec<PipelineId>)
-                                  where Window: WindowMethods;
-}
-
-#[derive(Copy, PartialEq, Clone, Debug)]
-pub enum WantsScrollEventsFlag {
-    WantsScrollEvents,
-    DoesntWantScrollEvents,
-}
-
-fn to_layers_color(color: &azure_hl::Color) -> Color {
-    Color { r: color.r, g: color.g, b: color.b, a: color.a }
-}
-
-trait Clampable {
-    fn clamp(&self, mn: &Self, mx: &Self) -> Self;
-}
-
-impl Clampable for f32 {
-    /// Returns the number constrained within the range `mn <= self <= mx`.
-    /// If any of the numbers are `NAN` then `NAN` is returned.
-    #[inline]
-    fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
-        match () {
-            _ if self.is_nan()   => *self,
-            _ if !(*self <= *mx) => *mx,
-            _ if !(*self >= *mn) => *mn,
-            _                    => *self,
-        }
-    }
-}
-
-fn calculate_content_size_for_layer(layer: &Layer<CompositorData>)
-                                    -> TypedSize2D<f32, LayerPixel> {
-    layer.children().iter().fold(TypedRect::zero(),
-                                 |unioned_rect, child_rect| {
-                                    unioned_rect.union(&*child_rect.bounds.borrow())
-                                 }).size
-}
-
-#[derive(PartialEq)]
-pub enum ScrollEventResult {
-    ScrollEventUnhandled,
-    ScrollPositionChanged,
-    ScrollPositionUnchanged,
-}
-
-impl CompositorLayer for Layer<CompositorData> {
-    fn update_layer_except_bounds(&self, layer_properties: LayerProperties) {
-        self.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
-        self.extra_data.borrow_mut().subpage_info = layer_properties.subpage_pipeline_id;
-        *self.transform.borrow_mut() = layer_properties.transform;
-        *self.perspective.borrow_mut() = layer_properties.perspective;
-
-        *self.background_color.borrow_mut() = to_layers_color(&layer_properties.background_color);
-
-        self.contents_changed();
-    }
-
-    fn update_layer(&self, layer_properties: LayerProperties) {
-        *self.bounds.borrow_mut() = TypedRect::from_untyped(&layer_properties.rect);
-
-        // Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the
-        // cursor position to make sure the scroll isn't propagated downwards.
-        self.handle_scroll_event(TypedPoint2D::zero(), TypedPoint2D::new(-1f32, -1f32));
-        self.update_layer_except_bounds(layer_properties);
-    }
-
-    // Add LayerBuffers to the specified layer. Returns the layer buffer set back if the layer that
-    // matches the given pipeline ID was not found; otherwise returns None and consumes the layer
-    // buffer set.
-    //
-    // If the epoch of the message does not match the layer's epoch, the message is ignored, the
-    // layer buffer set is consumed, and None is returned.
-    fn add_buffers<Window>(&self,
-                           compositor: &mut IOCompositor<Window>,
-                           new_buffers: Box<LayerBufferSet>,
-                           epoch: Epoch)
-                           where Window: WindowMethods {
-        self.extra_data.borrow_mut().painted_epoch = epoch;
-        assert!(self.extra_data.borrow().painted_epoch == self.extra_data.borrow().requested_epoch);
-
-        for buffer in new_buffers.buffers.into_iter().rev() {
-            self.add_buffer(buffer);
-        }
-
-        compositor.cache_unused_buffers(self.collect_unused_buffers())
-    }
-
-    fn clear<Window>(&self, compositor: &mut IOCompositor<Window>) where Window: WindowMethods {
-        let buffers = self.collect_buffers();
-
-        if !buffers.is_empty() {
-            compositor.cache_unused_buffers(buffers);
-        }
-    }
-
-    /// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
-    /// painter to be destroyed or reused.
-    fn clear_all_tiles<Window>(&self,
-                               compositor: &mut IOCompositor<Window>)
-                               where Window: WindowMethods {
-        self.clear(compositor);
-        for kid in &*self.children() {
-            kid.clear_all_tiles(compositor);
-        }
-    }
-
-    fn remove_root_layer_with_pipeline_id<Window>(&self,
-                                                  compositor: &mut IOCompositor<Window>,
-                                                  pipeline_id: PipelineId)
-                                                  where Window: WindowMethods {
-        // Find the child that is the root layer for this pipeline.
-        let index = self.children().iter().position(|kid| {
-            let extra_data = kid.extra_data.borrow();
-            extra_data.pipeline_id == pipeline_id && extra_data.id == LayerId::null()
-        });
-
-        match index {
-            Some(index) => {
-                // Remove the root layer, and return buffers to the paint thread
-                let child = self.children().remove(index);
-                child.clear_all_tiles(compositor);
-            }
-            None => {
-                // Wasn't found, recurse into child layers
-                for kid in &*self.children() {
-                    kid.remove_root_layer_with_pipeline_id(compositor, pipeline_id);
-                }
-            }
-        }
-    }
-
-    /// Destroys all tiles of all layers, including children, *without* sending them back to the
-    /// painter. You must call this only when the paint thread is destined to be going down;
-    /// otherwise, you will leak tiles.
-    ///
-    /// This is used during shutdown, when we know the paint thread is going away.
-    fn forget_all_tiles(&self) {
-        let tiles = self.collect_buffers();
-        for tile in tiles {
-            let mut tile = tile;
-            tile.mark_wont_leak()
-        }
-
-        for kid in &*self.children() {
-            kid.forget_all_tiles();
-        }
-    }
-
-    fn handle_scroll_event(&self,
-                           delta: TypedPoint2D<f32, LayerPixel>,
-                           cursor: TypedPoint2D<f32, LayerPixel>)
-                           -> ScrollEventResult {
-        // Allow children to scroll.
-        let scroll_offset = self.extra_data.borrow().scroll_offset;
-        let new_cursor = cursor - scroll_offset;
-        for child in self.children().iter().rev() {
-            let child_bounds = child.bounds.borrow();
-            if child_bounds.contains(&new_cursor) {
-                let result = child.handle_scroll_event(delta, new_cursor - child_bounds.origin);
-                if result != ScrollEventResult::ScrollEventUnhandled {
-                    return result;
-                }
-            }
-        }
-
-        // If this layer doesn't want scroll events, it can't handle scroll events.
-        if self.wants_scroll_events() != WantsScrollEventsFlag::WantsScrollEvents {
-            return ScrollEventResult::ScrollEventUnhandled;
-        }
-
-        self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta)
-    }
-
-    fn clamp_scroll_offset_and_scroll_layer(&self, new_offset: TypedPoint2D<f32, LayerPixel>)
-                                            -> ScrollEventResult {
-        let layer_size = self.bounds.borrow().size;
-        let content_size = calculate_content_size_for_layer(self);
-        let min_x = (layer_size.width - content_size.width).min(0.0);
-        let min_y = (layer_size.height - content_size.height).min(0.0);
-        let new_offset: TypedPoint2D<f32, LayerPixel> =
-            TypedPoint2D::new(new_offset.x.clamp(&min_x, &0.0),
-                              new_offset.y.clamp(&min_y, &0.0));
-
-        if self.extra_data.borrow().scroll_offset == new_offset {
-            return ScrollEventResult::ScrollPositionUnchanged;
-        }
-
-        // The scroll offset is just a record of the scroll position of this scrolling root,
-        // but scroll_layer_and_all_child_layers actually moves the child layers.
-        self.extra_data.borrow_mut().scroll_offset = new_offset;
-
-        let mut result = false;
-        for child in &*self.children() {
-            result |= child.scroll_layer_and_all_child_layers(new_offset);
-        }
-
-        if result {
-            ScrollEventResult::ScrollPositionChanged
-        } else {
-            ScrollEventResult::ScrollPositionUnchanged
-        }
-    }
-
-    fn send_mouse_event<Window>(&self,
-                                compositor: &IOCompositor<Window>,
-                                event: MouseWindowEvent,
-                                cursor: TypedPoint2D<f32, LayerPixel>)
-                                where Window: WindowMethods {
-        let event_point = cursor.to_untyped();
-        let message = match event {
-            MouseWindowEvent::Click(button, _) =>
-                MouseButtonEvent(MouseEventType::Click, button, event_point),
-            MouseWindowEvent::MouseDown(button, _) =>
-                MouseButtonEvent(MouseEventType::MouseDown, button, event_point),
-            MouseWindowEvent::MouseUp(button, _) =>
-                MouseButtonEvent(MouseEventType::MouseUp, button, event_point),
-        };
-        self.send_event(compositor, message);
-    }
-
-    fn send_mouse_move_event<Window>(&self,
-                                     compositor: &IOCompositor<Window>,
-                                     cursor: TypedPoint2D<f32, LayerPixel>)
-                                     where Window: WindowMethods {
-        self.send_event(compositor, MouseMoveEvent(Some(cursor.to_untyped())));
-    }
-
-    fn send_event<Window>(&self,
-                          compositor: &IOCompositor<Window>,
-                          event: CompositorEvent) where Window: WindowMethods {
-        if let Some(pipeline) = compositor.pipeline(self.pipeline_id()) {
-            let _ = pipeline.script_chan
-                    .send(ConstellationControlMsg::SendEvent(pipeline.id.clone(), event));
-        }
-    }
-
-    fn send_touchpad_pressure_event<Window>(&self,
-                                            compositor: &IOCompositor<Window>,
-                                            cursor: TypedPoint2D<f32, LayerPixel>,
-                                            pressure: f32,
-                                            phase: TouchpadPressurePhase)
-                                            where Window: WindowMethods {
-        if let Some(pipeline) = compositor.pipeline(self.pipeline_id()) {
-            let message = TouchpadPressureEvent(cursor.to_untyped(), pressure, phase);
-            let _ = pipeline.script_chan.send(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
-        }
-    }
-
-    fn scroll_layer_and_all_child_layers(&self, new_offset: TypedPoint2D<f32, LayerPixel>)
-                                         -> bool {
-        let mut result = false;
-
-        // Only scroll this layer if it's not fixed-positioned.
-        if self.extra_data.borrow().scroll_policy != ScrollPolicy::FixedPosition {
-            let new_offset = new_offset.to_untyped();
-            *self.content_offset.borrow_mut() = TypedPoint2D::from_untyped(&new_offset);
-            result = true
-        }
-
-        let offset_for_children = new_offset + self.extra_data.borrow().scroll_offset;
-        for child in &*self.children() {
-            result |= child.scroll_layer_and_all_child_layers(offset_for_children);
-        }
-
-        result
-    }
-
-    fn wants_scroll_events(&self) -> WantsScrollEventsFlag {
-        self.extra_data.borrow().wants_scroll_events
-    }
-
-    fn pipeline_id(&self) -> PipelineId {
-        self.extra_data.borrow().pipeline_id
-    }
-}
-
-impl RcCompositorLayer for Rc<Layer<CompositorData>> {
-    fn collect_old_layers<Window>(&self,
-                                  compositor: &mut IOCompositor<Window>,
-                                  pipeline_id: PipelineId,
-                                  new_layers: &[LayerProperties],
-                                  pipelines_removed: &mut Vec<PipelineId>)
-                                  where Window: WindowMethods {
-        fn find_root_layer_for_pipeline(layer: &Rc<Layer<CompositorData>>, pipeline_id: PipelineId)
-                                        -> Option<Rc<Layer<CompositorData>>> {
-            let extra_data = layer.extra_data.borrow();
-            if extra_data.pipeline_id == pipeline_id {
-                return Some((*layer).clone())
-            }
-
-            for kid in &*layer.children() {
-                if let Some(layer) = find_root_layer_for_pipeline(kid, pipeline_id) {
-                    return Some(layer.clone())
-                }
-            }
-            None
-        }
-
-        fn collect_old_layers_for_pipeline<Window>(
-                layer: &Layer<CompositorData>,
-                compositor: &mut IOCompositor<Window>,
-                pipeline_id: PipelineId,
-                new_layers: &[LayerProperties],
-                pipelines_removed: &mut Vec<PipelineId>,
-                layer_pipeline_id: Option<PipelineId>)
-                where Window: WindowMethods {
-            // Traverse children first so that layers are removed
-            // bottom up - allowing each layer being removed to properly
-            // clean up any tiles it owns.
-            for kid in &*layer.children() {
-                let extra_data = kid.extra_data.borrow();
-                let layer_pipeline_id = extra_data.subpage_info.or(layer_pipeline_id);
-
-                collect_old_layers_for_pipeline(kid,
-                                                compositor,
-                                                pipeline_id,
-                                                new_layers,
-                                                pipelines_removed,
-                                                layer_pipeline_id);
-            }
-
-            // Retain child layers that also exist in the new layer list.
-            layer.children().retain(|child| {
-                let extra_data = child.extra_data.borrow();
-                if pipeline_id == extra_data.pipeline_id {
-                    // Never remove our own root layer.
-                    if extra_data.id == LayerId::null() {
-                        return true
-                    }
-
-                    // Keep this layer if it exists in the new layer list.
-                    if new_layers.iter().any(|properties| properties.id == extra_data.id) {
-                        return true
-                    }
-                }
-
-                if let Some(layer_pipeline_id) = layer_pipeline_id {
-                    for layer_properties in new_layers.iter() {
-                        // Keep this layer if a reference to it exists.
-                        if let Some(ref subpage_pipeline_id) = layer_properties.subpage_pipeline_id {
-                            if *subpage_pipeline_id == layer_pipeline_id {
-                                return true
-                            }
-                        }
-                    }
-
-                    pipelines_removed.push(extra_data.pipeline_id);
-                }
-
-                // When removing a layer, clear any tiles and surfaces associated with the layer.
-                child.clear_all_tiles(compositor);
-                false
-            });
-        }
-
-        // First, find the root layer with the given pipeline ID.
-        let root_layer = match find_root_layer_for_pipeline(self, pipeline_id) {
-            Some(root_layer) => root_layer,
-            None => return,
-        };
-
-        // Then collect all old layers underneath that layer.
-        collect_old_layers_for_pipeline(&root_layer,
-                                        compositor,
-                                        pipeline_id,
-                                        new_layers,
-                                        pipelines_removed,
-                                        None);
-    }
-}
--- a/servo/components/compositing/compositor_thread.rs
+++ b/servo/components/compositing/compositor_thread.rs
@@ -3,26 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Communication with the compositor thread.
 
 use SendableFrameTree;
 use compositor::CompositingReason;
 use euclid::point::Point2D;
 use euclid::size::Size2D;
-use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerProperties, PaintListener};
+use gfx_traits::LayerId;
 use ipc_channel::ipc::IpcSender;
-use layers::layers::{BufferRequest, LayerBufferSet};
-use layers::platform::surface::{NativeDisplay, NativeSurface};
 use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState, PipelineId};
 use profile_traits::mem;
 use profile_traits::time;
 use script_traits::{AnimationState, ConstellationMsg, EventResult};
 use std::fmt::{Debug, Error, Formatter};
-use std::sync::mpsc::{Receiver, Sender, channel};
+use std::sync::mpsc::{Receiver, Sender};
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
 use url::Url;
 use webrender;
 use webrender_traits;
 
 /// Sends messages to the compositor. This is a trait supplied by the port because the method used
 /// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
@@ -58,87 +56,28 @@ pub trait RenderListener {
 }
 
 impl RenderListener for Box<CompositorProxy + 'static> {
     fn recomposite(&mut self, reason: CompositingReason) {
         self.send(Msg::Recomposite(reason));
     }
 }
 
-/// Implementation of the abstract `PaintListener` interface.
-impl PaintListener for Box<CompositorProxy + 'static + Send> {
-    fn native_display(&mut self) -> Option<NativeDisplay> {
-        let (chan, port) = channel();
-        self.send(Msg::GetNativeDisplay(chan));
-        // If the compositor is shutting down when a paint thread
-        // is being created, the compositor won't respond to
-        // this message, resulting in an eventual panic. Instead,
-        // just return None in this case, since the paint thread
-        // will exit shortly and never actually be requested
-        // to paint buffers by the compositor.
-        port.recv().unwrap_or(None)
-    }
-
-    fn assign_painted_buffers(&mut self,
-                              pipeline_id: PipelineId,
-                              epoch: Epoch,
-                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
-                              frame_tree_id: FrameTreeId) {
-        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
-    }
-
-    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
-        let mut native_surfaces = Vec::new();
-        for request in buffer_requests.into_iter() {
-            if let Some(native_surface) = request.native_surface {
-                native_surfaces.push(native_surface);
-            }
-        }
-        if !native_surfaces.is_empty() {
-            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
-        }
-    }
-
-    fn initialize_layers_for_pipeline(&mut self,
-                                      pipeline_id: PipelineId,
-                                      properties: Vec<LayerProperties>,
-                                      epoch: Epoch) {
-        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
-        // that all other layers are immediate children of it. This is sufficient to handle
-        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
-        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
-    }
-
-    fn notify_paint_thread_exiting(&mut self, pipeline_id: PipelineId) {
-        self.send(Msg::PaintThreadExited(pipeline_id))
-    }
-}
-
 /// Messages from the painting thread and the constellation thread to the compositor thread.
 pub enum Msg {
     /// Requests that the compositor shut down.
     Exit,
 
     /// Informs the compositor that the constellation has completed shutdown.
     /// Required because the constellation can have pending calls to make
     /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
     ShutdownComplete,
 
-    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
-    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
-    /// is the pixel format.
-    GetNativeDisplay(Sender<Option<NativeDisplay>>),
-
-    /// Tells the compositor to create or update the layers for a pipeline if necessary
-    /// (i.e. if no layer with that ID exists).
-    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
     /// Scroll a page in a window
     ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
-    /// Requests that the compositor assign the painted buffers to the given layers.
-    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
     /// Alerts the compositor that the current page has changed its title.
     ChangePageTitle(PipelineId, Option<String>),
     /// Alerts the compositor that the current page has changed its URL.
     ChangePageUrl(PipelineId, Url),
     /// Alerts the compositor that the given pipeline has changed whether it is running animations.
     ChangeRunningAnimationsState(PipelineId, AnimationState),
     /// Replaces the current frame tree, typically called during main frame navigation.
     SetFrameTree(SendableFrameTree, IpcSender<()>),
@@ -153,41 +92,34 @@ pub enum Msg {
     /// Sends an unconsumed key event back to the compositor.
     KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
     /// Script has handled a touch event, and either prevented or allowed default actions.
     TouchEventProcessed(EventResult),
     /// Changes the cursor.
     SetCursor(Cursor),
     /// Composite to a PNG file and return the Image over a passed channel.
     CreatePng(IpcSender<Option<Image>>),
-    /// Informs the compositor that the paint thread for the given pipeline has exited.
-    PaintThreadExited(PipelineId),
     /// Alerts the compositor that the viewport has been constrained in some manner
     ViewportConstrained(PipelineId, ViewportConstraints),
     /// A reply to the compositor asking if the output image is stable.
     IsReadyToSaveImageReply(bool),
     /// A favicon was detected
     NewFavicon(Url),
     /// <head> tag finished parsing
     HeadParsed,
-    /// Signal that the paint thread ignored the paint requests that carried
-    /// these native surfaces, so that they can be re-added to the surface cache.
-    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
     /// Collect memory reports and send them back to the given mem::ReportsChan.
     CollectMemoryReports(mem::ReportsChan),
     /// A status message to be displayed by the browser chrome.
     Status(Option<String>),
     /// Get Window Informations size and position
     GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
     /// Move the window to a point
     MoveTo(Point2D<i32>),
     /// Resize the window to size
     ResizeTo(Size2D<u32>),
-    /// Get scroll offset of a layer
-    GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>),
     /// Pipeline visibility changed
     PipelineVisibilityChanged(PipelineId, bool),
     /// WebRender has successfully processed a scroll. The boolean specifies whether a composite is
     /// needed.
     NewScrollFrameReady(bool),
     /// A pipeline was shut down.
     // This message acts as a synchronization point between the constellation,
     // when it shuts down a pipeline, to the compositor; when the compositor
@@ -196,46 +128,40 @@ pub enum Msg {
     PipelineExited(PipelineId, IpcSender<()>),
 }
 
 impl Debug for Msg {
     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
         match *self {
             Msg::Exit => write!(f, "Exit"),
             Msg::ShutdownComplete => write!(f, "ShutdownComplete"),
-            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
-            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
             Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
-            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
             Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
             Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
             Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
             Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
             Msg::LoadComplete(..) => write!(f, "LoadComplete"),
             Msg::LoadStart(..) => write!(f, "LoadStart"),
             Msg::DelayedCompositionTimeout(..) => write!(f, "DelayedCompositionTimeout"),
             Msg::Recomposite(..) => write!(f, "Recomposite"),
             Msg::KeyEvent(..) => write!(f, "KeyEvent"),
             Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
             Msg::SetCursor(..) => write!(f, "SetCursor"),
             Msg::CreatePng(..) => write!(f, "CreatePng"),
-            Msg::PaintThreadExited(..) => write!(f, "PaintThreadExited"),
             Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
             Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
             Msg::NewFavicon(..) => write!(f, "NewFavicon"),
             Msg::HeadParsed => write!(f, "HeadParsed"),
-            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
             Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
             Msg::Status(..) => write!(f, "Status"),
             Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
             Msg::MoveTo(..) => write!(f, "MoveTo"),
             Msg::ResizeTo(..) => write!(f, "ResizeTo"),
             Msg::PipelineVisibilityChanged(..) => write!(f, "PipelineVisibilityChanged"),
             Msg::PipelineExited(..) => write!(f, "PipelineExited"),
-            Msg::GetScrollOffset(..) => write!(f, "GetScrollOffset"),
             Msg::NewScrollFrameReady(..) => write!(f, "NewScrollFrameReady"),
         }
     }
 }
 
 /// Data used to construct a compositor.
 pub struct InitialCompositorState {
     /// A channel to the compositor.
@@ -243,12 +169,12 @@ pub struct InitialCompositorState {
     /// A port on which messages inbound to the compositor can be received.
     pub receiver: Box<CompositorReceiver>,
     /// A channel to the constellation.
     pub constellation_chan: Sender<ConstellationMsg>,
     /// A channel to the time profiler thread.
     pub time_profiler_chan: time::ProfilerChan,
     /// A channel to the memory profiler thread.
     pub mem_profiler_chan: mem::ProfilerChan,
-    /// Instance of webrender API if enabled
-    pub webrender: Option<webrender::Renderer>,
-    pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+    /// Instance of webrender API
+    pub webrender: webrender::Renderer,
+    pub webrender_api_sender: webrender_traits::RenderApiSender,
 }
--- a/servo/components/compositing/lib.rs
+++ b/servo/components/compositing/lib.rs
@@ -5,25 +5,21 @@
 #![feature(box_syntax)]
 #![feature(custom_derive)]
 #![feature(plugin)]
 #![feature(proc_macro)]
 #![plugin(plugins)]
 
 #![deny(unsafe_code)]
 
-extern crate app_units;
-
-extern crate azure;
 extern crate euclid;
 extern crate gfx_traits;
 extern crate gleam;
 extern crate image;
 extern crate ipc_channel;
-extern crate layers;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 #[macro_use]
 extern crate profile_traits;
 extern crate script_traits;
 #[macro_use]
@@ -34,37 +30,32 @@ extern crate url;
 #[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 gfx_traits::ChromeToPaintMsg;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
-use std::sync::mpsc::Sender;
 use style_traits::PagePx;
 
 mod compositor;
-mod compositor_layer;
 pub mod compositor_thread;
 mod delayed_composition;
-mod surface_map;
 mod touch;
 pub mod windowing;
 
 pub struct SendableFrameTree {
     pub pipeline: CompositionPipeline,
     pub size: Option<TypedSize2D<f32, PagePx>>,
     pub children: Vec<SendableFrameTree>,
 }
 
 /// The subset of the pipeline that is needed for layer composition.
 #[derive(Clone)]
 pub struct CompositionPipeline {
     pub id: PipelineId,
     pub script_chan: IpcSender<ConstellationControlMsg>,
     pub layout_chan: IpcSender<LayoutControlMsg>,
-    pub chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
 }
deleted file mode 100644
--- a/servo/components/compositing/surface_map.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use euclid::size::Size2D;
-use layers::platform::surface::{NativeDisplay, NativeSurface};
-use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-use std::hash::{Hash, Hasher};
-
-/// This is a struct used to store surfaces when they are not in use.
-/// The paint thread can quickly query for a particular size of surface when it
-/// needs it.
-pub struct SurfaceMap {
-    /// A HashMap that stores the Buffers.
-    map: HashMap<SurfaceKey, SurfaceValue>,
-    /// The current amount of memory stored by the SurfaceMap's surfaces.
-    mem: usize,
-    /// The maximum allowed memory. Unused surfaces will be deleted
-    /// when this threshold is exceeded.
-    max_mem: usize,
-    /// A monotonically increasing counter to track how recently tile sizes were used.
-    counter: usize,
-}
-
-/// A key with which to store surfaces. It is based on the size of the surface.
-#[derive(Eq, Copy, Clone)]
-struct SurfaceKey([i32; 2]);
-
-impl Hash for SurfaceKey {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.0.hash(state);
-    }
-}
-
-impl PartialEq for SurfaceKey {
-    fn eq(&self, other: &SurfaceKey) -> bool {
-        let SurfaceKey(s) = *self;
-        let SurfaceKey(o) = *other;
-        s[0] == o[0] && s[1] == o[1]
-    }
-}
-
-/// Create a key from a given size
-impl SurfaceKey {
-    fn get(input: Size2D<i32>) -> SurfaceKey {
-        SurfaceKey([input.width, input.height])
-    }
-}
-
-/// A helper struct to keep track of surfaces in the HashMap
-struct SurfaceValue {
-    /// An array of surfaces, all the same size
-    surfaces: Vec<NativeSurface>,
-    /// The counter when this size was last requested
-    last_action: usize,
-}
-
-impl SurfaceMap {
-    // Creates a new SurfaceMap with a given surface limit.
-    pub fn new(max_mem: usize) -> SurfaceMap {
-        SurfaceMap {
-            map: HashMap::new(),
-            mem: 0,
-            max_mem: max_mem,
-            counter: 0,
-        }
-    }
-
-    pub fn insert_surfaces<I>(&mut self, display: &NativeDisplay, surfaces: I)
-        where I: IntoIterator<Item=NativeSurface>
-    {
-        for surface in surfaces {
-            self.insert(display, surface);
-        }
-    }
-
-    /// Insert a new buffer into the map.
-    pub fn insert(&mut self, display: &NativeDisplay, mut new_surface: NativeSurface) {
-        let new_key = SurfaceKey::get(new_surface.get_size());
-
-        // If all our surfaces are the same size and we're already at our
-        // memory limit, no need to store this new buffer; just let it drop.
-        let new_total_memory_usage = self.mem + new_surface.get_memory_usage();
-        if new_total_memory_usage > self.max_mem && self.map.len() == 1 &&
-            self.map.contains_key(&new_key) {
-            new_surface.destroy(display);
-            return;
-        }
-
-        self.mem = new_total_memory_usage;
-        new_surface.mark_wont_leak();
-
-        // use lazy insertion function to prevent unnecessary allocation
-        let counter = &self.counter;
-        match self.map.entry(new_key) {
-            Occupied(entry) => {
-                entry.into_mut().surfaces.push(new_surface);
-            }
-            Vacant(entry) => {
-                entry.insert(SurfaceValue {
-                    surfaces: vec!(new_surface),
-                    last_action: *counter,
-                });
-            }
-        }
-
-        let mut opt_key: Option<SurfaceKey> = None;
-        while self.mem > self.max_mem {
-            let old_key = match opt_key {
-                Some(key) => key,
-                None => {
-                    match self.map.iter().min_by_key(|&(_, x)| x.last_action) {
-                        Some((k, _)) => *k,
-                        None => panic!("SurfaceMap: tried to delete with no elements in map"),
-                    }
-                }
-            };
-            if {
-                let list = &mut self.map.get_mut(&old_key).unwrap().surfaces;
-                let mut condemned_surface = list.pop().take().unwrap();
-                self.mem -= condemned_surface.get_memory_usage();
-                condemned_surface.destroy(display);
-                list.is_empty()
-            }
-            { // then
-                self.map.remove(&old_key); // Don't store empty vectors!
-                opt_key = None;
-            } else {
-                opt_key = Some(old_key);
-            }
-        }
-    }
-
-    // Try to find a buffer for the given size.
-    pub fn find(&mut self, size: Size2D<i32>) -> Option<NativeSurface> {
-        let mut flag = false; // True if key needs to be popped after retrieval.
-        let key = SurfaceKey::get(size);
-        let ret = match self.map.get_mut(&key) {
-            Some(ref mut surface_val) => {
-                surface_val.last_action = self.counter;
-                self.counter += 1;
-
-                let surface = surface_val.surfaces.pop().take().unwrap();
-                self.mem -= surface.get_memory_usage();
-                if surface_val.surfaces.is_empty() {
-                    flag = true;
-                }
-                Some(surface)
-            }
-            None => None,
-        };
-
-        if flag {
-            self.map.remove(&key); // Don't store empty vectors!
-        }
-
-        ret
-    }
-
-    pub fn mem(&self) -> usize {
-        self.mem
-    }
-}
--- a/servo/components/compositing/touch.rs
+++ b/servo/components/compositing/touch.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 euclid::point::TypedPoint2D;
 use euclid::scale_factor::ScaleFactor;
-use layers::geometry::DevicePixel;
+use gfx_traits::DevicePixel;
 use script_traits::{EventResult, TouchId};
 use self::TouchState::*;
 
 /// Minimum number of ScreenPx to begin touch scrolling.
 const TOUCH_PAN_MIN_SCREEN_PX: f32 = 20.0;
 
 pub struct TouchHandler {
     pub state: TouchState,
--- a/servo/components/compositing/windowing.rs
+++ b/servo/components/compositing/windowing.rs
@@ -4,18 +4,17 @@
 
 //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
 
 use compositor_thread::{CompositorProxy, CompositorReceiver};
 use euclid::{Point2D, Size2D};
 use euclid::point::TypedPoint2D;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
-use layers::geometry::DevicePixel;
-use layers::platform::surface::NativeDisplay;
+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 std::fmt::{Debug, Error, Formatter};
 use style_traits::cursor::Cursor;
 use url::Url;
 use util::geometry::ScreenPx;
 
@@ -134,19 +133,16 @@ pub trait WindowMethods {
     /// Called when the browser encounters an error while loading a URL
     fn load_error(&self, code: NetError, url: String);
     /// Called when the <head> tag has finished parsing
     fn head_parsed(&self);
 
     /// Returns the scale factor of the system (device pixels / screen pixels).
     fn scale_factor(&self) -> ScaleFactor<f32, ScreenPx, DevicePixel>;
 
-    /// Gets the OS native graphics display for this window.
-    fn native_display(&self) -> NativeDisplay;
-
     /// Creates a channel to the compositor. The dummy parameter is needed because we don't have
     /// UFCS in Rust yet.
     ///
     /// This is part of the windowing system because its implementation often involves OS-specific
     /// magic to wake the up window's event loop.
     fn create_compositor_channel(&self) -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>);
 
     /// Requests that the window system prepare a composite. Typically this will involve making
--- a/servo/components/constellation/Cargo.toml
+++ b/servo/components/constellation/Cargo.toml
@@ -14,17 +14,16 @@ backtrace = "0.2.1"
 canvas = {path = "../canvas"}
 canvas_traits = {path = "../canvas_traits"}
 compositing = {path = "../compositing"}
 devtools_traits = {path = "../devtools_traits"}
 euclid = "0.10.1"
 gfx = {path = "../gfx"}
 gfx_traits = {path = "../gfx_traits"}
 ipc-channel = "0.5"
-layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
 layout_traits = {path = "../layout_traits"}
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 offscreen_gl_context = "0.4"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rand = "0.3"
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -167,18 +167,18 @@ pub struct Constellation<Message, LTF, S
 
     /// 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, if enabled.
-    webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+    // Webrender interface.
+    webrender_api_sender: webrender_traits::RenderApiSender,
 
     /// Are we shutting down?
     shutting_down: bool,
 
     /// Have we seen any warnings? Hopefully always empty!
     /// The buffer contains `(thread_name, reason)` entries.
     handled_warnings: VecDeque<(Option<String>, String)>,
 
@@ -204,18 +204,18 @@ pub struct InitialConstellationState {
     /// A channel to the resource thread.
     pub private_resource_threads: ResourceThreads,
     /// A channel to the time profiler thread.
     pub time_profiler_chan: time::ProfilerChan,
     /// A channel to the memory profiler thread.
     pub mem_profiler_chan: mem::ProfilerChan,
     /// Whether the constellation supports the clipboard.
     pub supports_clipboard: bool,
-    /// Optional webrender API reference (if enabled).
-    pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+    /// Webrender API.
+    pub webrender_api_sender: webrender_traits::RenderApiSender,
 }
 
 #[derive(Debug, Clone)]
 struct FrameState {
     instant: Instant,
     pipeline_id: PipelineId,
     frame_id: FrameId,
 }
@@ -966,19 +966,16 @@ impl<Message, LTF, STF> Constellation<Me
             FromScriptMsg::SendKeyEvent(ch, key, key_state, key_modifiers) => {
                 self.compositor_proxy.send(ToCompositorMsg::KeyEvent(ch, key, key_state, key_modifiers))
             }
 
             FromScriptMsg::TouchEventProcessed(result) => {
                 self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result))
             }
 
-            FromScriptMsg::GetScrollOffset(pid, lid, send) => {
-                self.compositor_proxy.send(ToCompositorMsg::GetScrollOffset(pid, lid, send));
-            }
             FromScriptMsg::RegisterServiceWorker(scope_things, scope) => {
                 debug!("constellation got store registration scope message");
                 self.handle_register_serviceworker(scope_things, scope);
             }
             FromScriptMsg::ForwardDOMMessage(msg_vec, scope_url) => {
                 if let Some(ref mgr) = self.swmanager_chan {
                     let _ = mgr.send(ServiceWorkerMsg::ForwardDOMMessage(msg_vec, scope_url));
                 } else {
@@ -1847,18 +1844,17 @@ impl<Message, LTF, STF> Constellation<Me
         if let Some(prev_pipeline) = self.pipelines.get(&prev_pipeline_id) {
             prev_pipeline.freeze();
         }
         if let Some(next_pipeline) = self.pipelines.get(&next_pipeline_id) {
             next_pipeline.thaw();
         }
 
         // Set paint permissions correctly for the compositor layers.
-        self.revoke_paint_permission(prev_pipeline_id);
-        self.send_frame_tree_and_grant_paint_permission();
+        self.send_frame_tree();
 
         // 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,
                                                                 prev_pipeline_id,
                                                                 next_pipeline_id);
             let result = match self.pipelines.get(&parent_pipeline_id) {
@@ -1905,22 +1901,16 @@ impl<Message, LTF, STF> Constellation<Me
         if let Some(old_pipeline_id) = frame_change.old_pipeline_id {
             if let Some(old_frame_id) = self.pipelines.get(&old_pipeline_id).map(|pipeline| pipeline.frame_id) {
                 if self.focused_pipeline_in_tree(old_frame_id) {
                     self.focus_pipeline_id = Some(frame_change.new_pipeline_id);
                 }
             }
         }
 
-        if let Some(old_pipeline_id) = frame_change.old_pipeline_id {
-            // The new pipeline is replacing an old one.
-            // Remove paint permissions for the pipeline being replaced.
-            self.revoke_paint_permission(old_pipeline_id);
-        };
-
         if self.frames.contains_key(&frame_change.frame_id) {
             // Mature the new pipeline, and return frames evicted from history.
             if let Some(ref mut pipeline) = self.pipelines.get_mut(&frame_change.new_pipeline_id) {
                 pipeline.is_mature = true;
             }
 
             if frame_change.replace {
                 let evicted = self.frames.get_mut(&frame_change.frame_id).map(|frame| {
@@ -1953,18 +1943,18 @@ impl<Message, LTF, STF> Constellation<Me
             // If this is an iframe, send a mozbrowser location change event.
             // This is the result of a link being clicked and a navigation completing.
             self.trigger_mozbrowserlocationchange(frame_change.new_pipeline_id);
 
             let top_level_frame_id = self.get_top_level_frame_for_pipeline(Some(frame_change.new_pipeline_id));
             self.clear_joint_session_future(top_level_frame_id);
         }
 
-        // Build frame tree and send permission
-        self.send_frame_tree_and_grant_paint_permission();
+        // Build frame tree
+        self.send_frame_tree();
     }
 
     fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) {
         debug!("Document ready to activate {:?}", pipeline_id);
 
         if let Some(ref child_pipeline) = self.pipelines.get(&pipeline_id) {
             if let Some(ref parent_info) = child_pipeline.parent_info {
                 if let Some(parent_pipeline) = self.pipelines.get(&parent_info.0) {
@@ -2334,46 +2324,30 @@ impl<Message, LTF, STF> Constellation<Me
                     }
                 }
 
                 frame_tree
             })
         })
     }
 
-    // Revoke paint permission from a pipeline, and all children.
-    fn revoke_paint_permission(&self, pipeline_id: PipelineId) {
-        if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
-            for frame in self.current_frame_tree_iter(pipeline.frame_id) {
-                if let Some(pipeline) = self.pipelines.get(&frame.current.pipeline_id) {
-                    pipeline.revoke_paint_permission();
-                }
-            }
-        }
-    }
-
-    // Send the current frame tree to compositor, and grant paint
-    // permission to each pipeline in the current frame tree.
-    fn send_frame_tree_and_grant_paint_permission(&mut self) {
+    // Send the current frame tree to compositor
+    fn send_frame_tree(&mut self) {
         // Note that this function can panic, due to ipc-channel creation failure.
         // avoiding this panic would require a mechanism for dealing
         // with low-resource scenarios.
         if let Some(frame_tree) = self.frame_to_sendable(self.root_frame_id) {
             let (chan, port) = ipc::channel().expect("Failed to create IPC channel!");
             self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree,
                                                                      chan));
             if port.recv().is_err() {
                 warn!("Compositor has discarded SetFrameTree");
                 return; // Our message has been discarded, probably shutting down.
             }
         }
-
-        for frame in self.current_frame_tree_iter(self.root_frame_id) {
-            self.pipelines.get(&frame.current.pipeline_id).map(|pipeline| pipeline.grant_paint_permission());
-        }
     }
 
     /// For a given pipeline, determine the mozbrowser iframe that transitively contains
     /// it. There could be arbitrary levels of nested iframes in between them.
     fn get_mozbrowser_ancestor_info(&self, original_pipeline_id: PipelineId) -> Option<(PipelineId, PipelineId)> {
         let mut pipeline_id = original_pipeline_id;
         loop {
             match self.pipelines.get(&pipeline_id) {
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -17,17 +17,16 @@ extern crate canvas_traits;
 extern crate compositing;
 extern crate devtools_traits;
 extern crate euclid;
 #[cfg(not(target_os = "windows"))]
 extern crate gaol;
 extern crate gfx;
 extern crate gfx_traits;
 extern crate ipc_channel;
-extern crate layers;
 extern crate layout_traits;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 extern crate offscreen_gl_context;
 #[macro_use]
 extern crate profile_traits;
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -6,41 +6,37 @@ use compositing::CompositionPipeline;
 use compositing::CompositorProxy;
 use compositing::compositor_thread::Msg as CompositorMsg;
 use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 #[cfg(not(target_os = "windows"))]
 use gaol;
 use gfx::font_cache_thread::FontCacheThread;
-use gfx::paint_thread::{LayoutToPaintMsg, PaintThread};
-use gfx_traits::ChromeToPaintMsg;
+use gfx_traits::DevicePixel;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
-use layers::geometry::DevicePixel;
 use layout_traits::LayoutThreadFactory;
 use msg::constellation_msg::{FrameId, FrameType, LoadData, PipelineId, PipelineNamespaceId};
 use net_traits::{IpcSend, ResourceThreads};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::mem as profile_mem;
 use profile_traits::time;
 use script_traits::{ConstellationControlMsg, InitialScriptState, MozBrowserEvent};
 use script_traits::{LayoutControlMsg, LayoutMsg, NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
 use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
 use std::collections::HashMap;
 use std::env;
 use std::ffi::OsStr;
 use std::io::Error as IOError;
 use std::process;
-use std::sync::mpsc::{Sender, channel};
+use std::sync::mpsc::Sender;
 use style_traits::{PagePx, ViewportPx};
 use url::Url;
-use util;
-use util::ipc::OptionalIpcSender;
 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"))]
@@ -53,17 +49,16 @@ pub struct Pipeline {
     /// The ID of the frame that contains this Pipeline.
     pub frame_id: FrameId,
     pub parent_info: Option<(PipelineId, FrameType)>,
     pub script_chan: IpcSender<ConstellationControlMsg>,
     /// 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>,
-    pub chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
     /// URL corresponding to the most recently-loaded page.
     pub url: Url,
     /// The title of the most recently-loaded page.
     pub title: Option<String>,
     pub size: Option<TypedSize2D<f32, PagePx>>,
     /// Whether this pipeline is currently running animations. Pipelines that are running
     /// animations cause composites to be continually scheduled.
     pub running_animations: bool,
@@ -122,50 +117,47 @@ pub struct InitialPipelineState {
     /// then `parent_info` must also be `Some`.
     pub script_chan: Option<IpcSender<ConstellationControlMsg>>,
     /// 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>,
-    /// Optional webrender api (if enabled).
-    pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+    /// 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>
         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 (layout_to_paint_chan, layout_to_paint_port) = util::ipc::optional_ipc_channel();
-        let (chrome_to_paint_chan, chrome_to_paint_port) = channel();
         let (pipeline_chan, pipeline_port) = ipc::channel()
             .expect("Pipeline main chan");;
 
         let (layout_content_process_shutdown_chan, layout_content_process_shutdown_port) =
             ipc::channel().expect("Pipeline layout content shutdown chan");
 
         let (script_chan, content_ports) = match state.script_chan {
             Some(script_chan) => {
                 let (parent_pipeline_id, frame_type) =
                     state.parent_info.expect("script_pipeline != None but parent_info == None");
                 let new_layout_info = NewLayoutInfo {
                     parent_pipeline_id: parent_pipeline_id,
                     new_pipeline_id: state.id,
                     frame_type: frame_type,
                     load_data: state.load_data.clone(),
-                    paint_chan: layout_to_paint_chan.clone().to_opaque(),
                     pipeline_port: pipeline_port,
                     layout_to_constellation_chan: state.layout_to_constellation_chan.clone(),
                     content_process_shutdown_chan: layout_content_process_shutdown_chan.clone(),
                     layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
                 };
 
                 if let Err(e) = script_chan.send(ConstellationControlMsg::AttachLayout(new_layout_info)) {
                     warn!("Sending to script during pipeline creation failed ({})", e);
@@ -173,26 +165,16 @@ impl Pipeline {
                 (script_chan, None)
             }
             None => {
                 let (script_chan, script_port) = ipc::channel().expect("Pipeline script chan");
                 (script_chan, Some((script_port, pipeline_port)))
             }
         };
 
-        PaintThread::create(state.id,
-                            state.load_data.url.clone(),
-                            chrome_to_paint_chan.clone(),
-                            layout_to_paint_port,
-                            chrome_to_paint_port,
-                            state.compositor_proxy.clone_compositor_proxy(),
-                            state.font_cache_thread.clone(),
-                            state.time_profiler_chan.clone(),
-                            state.mem_profiler_chan.clone());
-
         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| {
@@ -233,17 +215,16 @@ impl Pipeline {
                 mem_profiler_chan: state.mem_profiler_chan,
                 window_size: window_size,
                 layout_to_constellation_chan: state.layout_to_constellation_chan,
                 script_chan: script_chan.clone(),
                 load_data: state.load_data.clone(),
                 script_port: script_port,
                 opts: (*opts::get()).clone(),
                 prefs: PREFS.cloned(),
-                layout_to_paint_chan: layout_to_paint_chan,
                 pipeline_port: pipeline_port,
                 pipeline_namespace_id: state.pipeline_namespace_id,
                 layout_content_process_shutdown_chan: layout_content_process_shutdown_chan,
                 layout_content_process_shutdown_port: layout_content_process_shutdown_port,
                 script_content_process_shutdown_chan: script_content_process_shutdown_chan,
                 script_content_process_shutdown_port: script_content_process_shutdown_port,
                 webrender_api_sender: state.webrender_api_sender,
             };
@@ -259,67 +240,55 @@ impl Pipeline {
         }
 
         let pipeline = Pipeline::new(state.id,
                                      state.frame_id,
                                      state.parent_info,
                                      script_chan,
                                      pipeline_chan,
                                      state.compositor_proxy,
-                                     chrome_to_paint_chan,
                                      state.is_private,
                                      state.load_data.url,
                                      state.window_size,
                                      state.prev_visibility.unwrap_or(true));
 
         pipeline.notify_visibility();
 
         Ok((pipeline, child_process))
     }
 
     fn new(id: PipelineId,
            frame_id: FrameId,
            parent_info: Option<(PipelineId, FrameType)>,
            script_chan: IpcSender<ConstellationControlMsg>,
            layout_chan: IpcSender<LayoutControlMsg>,
            compositor_proxy: Box<CompositorProxy + 'static + Send>,
-           chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
            is_private: bool,
            url: Url,
            size: Option<TypedSize2D<f32, PagePx>>,
            visible: bool)
            -> Pipeline {
         Pipeline {
             id: id,
             frame_id: frame_id,
             parent_info: parent_info,
             script_chan: script_chan,
             layout_chan: layout_chan,
             compositor_proxy: compositor_proxy,
-            chrome_to_paint_chan: chrome_to_paint_chan,
             url: url,
             title: None,
             children: vec!(),
             size: size,
             running_animations: false,
             visible: visible,
             is_private: is_private,
             is_mature: false,
         }
     }
 
-    pub fn grant_paint_permission(&self) {
-        let _ = self.chrome_to_paint_chan.send(ChromeToPaintMsg::PaintPermissionGranted);
-    }
-
-    pub fn revoke_paint_permission(&self) {
-        debug!("pipeline revoking paint channel paint permission");
-        let _ = self.chrome_to_paint_chan.send(ChromeToPaintMsg::PaintPermissionRevoked);
-    }
-
     pub fn exit(&self) {
         debug!("pipeline {:?} exiting", self.id);
 
         // The compositor wants to know when pipelines shut down too.
         // It may still have messages to process from these other threads
         // before they can be safely shut down.
         // It's OK for the constellation to block on the compositor,
         // since the compositor never blocks on the constellation.
@@ -348,30 +317,26 @@ impl Pipeline {
             warn!("Sending freeze message failed ({}).", e);
         }
     }
 
     pub fn force_exit(&self) {
         if let Err(e) = self.script_chan.send(ConstellationControlMsg::ExitPipeline(self.id)) {
             warn!("Sending script exit message failed ({}).", e);
         }
-        if let Err(e) = self.chrome_to_paint_chan.send(ChromeToPaintMsg::Exit) {
-            warn!("Sending paint 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.clone(),
             layout_chan: self.layout_chan.clone(),
-            chrome_to_paint_chan: self.chrome_to_paint_chan.clone(),
         }
     }
 
     pub fn add_child(&mut self, frame_id: FrameId) {
         self.children.push(frame_id);
     }
 
     pub fn remove_child(&mut self, frame_id: FrameId) {
@@ -425,26 +390,25 @@ pub struct UnprivilegedPipelineContent {
     font_cache_thread: FontCacheThread,
     resource_threads: ResourceThreads,
     time_profiler_chan: time::ProfilerChan,
     mem_profiler_chan: profile_mem::ProfilerChan,
     window_size: Option<WindowSizeData>,
     script_chan: IpcSender<ConstellationControlMsg>,
     load_data: LoadData,
     script_port: IpcReceiver<ConstellationControlMsg>,
-    layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
     opts: Opts,
     prefs: HashMap<String, Pref>,
     pipeline_port: IpcReceiver<LayoutControlMsg>,
     pipeline_namespace_id: PipelineNamespaceId,
     layout_content_process_shutdown_chan: IpcSender<()>,
     layout_content_process_shutdown_port: IpcReceiver<()>,
     script_content_process_shutdown_chan: IpcSender<()>,
     script_content_process_shutdown_port: IpcReceiver<()>,
-    webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+    webrender_api_sender: webrender_traits::RenderApiSender,
 }
 
 impl UnprivilegedPipelineContent {
     pub fn start_all<Message, LTF, STF>(self, wait_for_completion: bool)
         where LTF: LayoutThreadFactory<Message=Message>,
               STF: ScriptThreadFactory<Message=Message>
     {
         let layout_pair = STF::create(InitialScriptState {
@@ -467,17 +431,16 @@ impl UnprivilegedPipelineContent {
 
         LTF::create(self.id,
                     self.load_data.url,
                     self.parent_info.is_some(),
                     layout_pair,
                     self.pipeline_port,
                     self.layout_to_constellation_chan,
                     self.script_chan,
-                    self.layout_to_paint_chan,
                     self.image_cache_thread,
                     self.font_cache_thread,
                     self.time_profiler_chan,
                     self.mem_profiler_chan,
                     self.layout_content_process_shutdown_chan,
                     self.webrender_api_sender,
                     self.prefs.get("layout.threads").expect("exists").value()
                         .as_u64().expect("count") as usize);
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -17,27 +17,24 @@ bitflags = "0.7"
 euclid = "0.10.1"
 fnv = "1.0"
 fontsan = {git = "https://github.com/servo/fontsan"}
 gfx_traits = {path = "../gfx_traits"}
 harfbuzz-sys = "0.1"
 heapsize = "0.3.0"
 heapsize_plugin = "0.1.2"
 ipc-channel = "0.5"
-layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
 lazy_static = "0.2"
 libc = "0.2"
 log = "0.3.5"
 mime = "0.2"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 ordered-float = "0.2.2"
 plugins = {path = "../plugins"}
-profile_traits = {path = "../profile_traits"}
-rand = "0.3"
 range = {path = "../range"}
 rustc-serialize = "0.3"
 serde = "0.8"
 serde_derive = "0.8"
 smallvec = "0.1"
 string_cache = {version = "0.2.26", features = ["heap_size"]}
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
--- a/servo/components/gfx/font.rs
+++ b/servo/components/gfx/font.rs
@@ -107,26 +107,26 @@ pub struct Font {
     pub metrics: FontMetrics,
     pub variant: font_variant::T,
     pub descriptor: FontTemplateDescriptor,
     pub requested_pt_size: Au,
     pub actual_pt_size: Au,
     shaper: Option<Shaper>,
     shape_cache: RefCell<HashMap<ShapeCacheEntry, Arc<GlyphStore>>>,
     glyph_advance_cache: RefCell<HashMap<u32, FractionalPixel>>,
-    pub font_key: Option<webrender_traits::FontKey>,
+    pub font_key: webrender_traits::FontKey,
 }
 
 impl Font {
     pub fn new(handle: FontHandle,
                variant: font_variant::T,
                descriptor: FontTemplateDescriptor,
                requested_pt_size: Au,
                actual_pt_size: Au,
-               font_key: Option<webrender_traits::FontKey>) -> Font {
+               font_key: webrender_traits::FontKey) -> Font {
         let metrics = handle.metrics();
         Font {
             handle: handle,
             shaper: None,
             variant: variant,
             descriptor: descriptor,
             requested_pt_size: requested_pt_size,
             actual_pt_size: actual_pt_size,
--- a/servo/components/gfx/font_cache_thread.rs
+++ b/servo/components/gfx/font_cache_thread.rs
@@ -344,26 +344,28 @@ impl FontCache {
             let templates = self.web_families.get_mut(&family_name).unwrap();
             templates.find_font_for_style(desc, &self.font_context)
         } else {
             None
         }
     }
 
     fn get_font_template_info(&mut self, template: Arc<FontTemplateData>) -> FontTemplateInfo {
-        let webrender_fonts = &mut self.webrender_fonts;
-        let font_key = self.webrender_api.as_ref().map(|webrender_api| {
-            *webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| {
+        let mut font_key = None;
+
+        if let Some(ref webrender_api) = self.webrender_api {
+            let webrender_fonts = &mut self.webrender_fonts;
+            font_key = Some(*webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| {
                 match (template.bytes_if_in_memory(), template.native_font()) {
                     (Some(bytes), _) => webrender_api.add_raw_font(bytes),
                     (None, Some(native_font)) => webrender_api.add_native_font(native_font),
                     (None, None) => webrender_api.add_raw_font(template.bytes().clone()),
                 }
-            })
-        });
+            }));
+        }
 
         FontTemplateInfo {
             font_template: template,
             font_key: font_key,
         }
     }
 
     fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
--- a/servo/components/gfx/font_context.rs
+++ b/servo/components/gfx/font_context.rs
@@ -104,17 +104,17 @@ impl FontContext {
     }
 
     /// Create a font for use in layout calculations.
     fn create_layout_font(&self,
                           template: Arc<FontTemplateData>,
                           descriptor: FontTemplateDescriptor,
                           pt_size: Au,
                           variant: font_variant::T,
-                          font_key: Option<webrender_traits::FontKey>) -> Result<Font, ()> {
+                          font_key: webrender_traits::FontKey) -> Result<Font, ()> {
         // TODO: (Bug #3463): Currently we only support fake small-caps
         // painting. We should also support true small-caps (where the
         // font supports it) in the future.
         let actual_pt_size = match variant {
             font_variant::T::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
             font_variant::T::normal => pt_size,
         };
 
@@ -192,17 +192,18 @@ impl FontContext {
                 let template_info = self.font_cache_thread.find_font_template(family.clone(),
                                                                              desc.clone());
                 match template_info {
                     Some(template_info) => {
                         let layout_font = self.create_layout_font(template_info.font_template,
                                                                   desc.clone(),
                                                                   style.font_size,
                                                                   style.font_variant,
-                                                                  template_info.font_key);
+                                                                  template_info.font_key
+                                                                               .expect("No font key present!"));
                         let font = match layout_font {
                             Ok(layout_font) => {
                                 let layout_font = Rc::new(RefCell::new(layout_font));
                                 fonts.push(layout_font.clone());
 
                                 Some(layout_font)
                             }
                             Err(_) => None
@@ -237,17 +238,17 @@ impl FontContext {
         }
 
         if !cache_hit {
             let template_info = self.font_cache_thread.last_resort_font_template(desc.clone());
             let layout_font = self.create_layout_font(template_info.font_template,
                                                       desc.clone(),
                                                       style.font_size,
                                                       style.font_variant,
-                                                      template_info.font_key);
+                                                      template_info.font_key.expect("No font key present!"));
             match layout_font {
                 Ok(layout_font) => {
                     let layout_font = Rc::new(RefCell::new(layout_font));
                     self.fallback_font_cache.push(FallbackFontCacheEntry {
                         font: layout_font.clone(),
                     });
                     fonts.push(layout_font);
                 }
--- a/servo/components/gfx/lib.rs
+++ b/servo/components/gfx/lib.rs
@@ -4,17 +4,16 @@
 
 // For simd (currently x86_64/aarch64)
 #![cfg_attr(any(target_os = "linux", target_os = "android", target_os = "windows"), feature(heap_api))]
 
 #![feature(alloc)]
 #![feature(box_syntax)]
 #![feature(custom_attribute)]
 #![feature(custom_derive)]
-#![feature(mpsc_select)]
 #![feature(plugin)]
 #![feature(proc_macro)]
 #![feature(range_contains)]
 #![feature(rustc_attrs)]
 #![feature(structural_match)]
 #![feature(unique)]
 
 #![plugin(heapsize_plugin)]
@@ -52,31 +51,27 @@ extern crate freetype;
 extern crate gfx_traits;
 
 // Eventually we would like the shaper to be pluggable, as many operating systems have their own
 // shapers. For now, however, this is a hard dependency.
 extern crate harfbuzz_sys as harfbuzz;
 
 extern crate heapsize;
 extern crate ipc_channel;
-extern crate layers;
 #[allow(unused_extern_crates)]
 #[macro_use]
 extern crate lazy_static;
 extern crate libc;
 #[macro_use]
 extern crate log;
 extern crate mime;
 extern crate msg;
 extern crate net_traits;
 extern crate ordered_float;
 #[macro_use]
-extern crate profile_traits;
-extern crate rand;
-#[macro_use]
 extern crate range;
 extern crate rustc_serialize;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 
 #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
 extern crate simd;
@@ -105,16 +100,14 @@ mod paint_context;
 pub mod display_list;
 
 // Fonts
 #[macro_use] pub mod font;
 pub mod font_cache_thread;
 pub mod font_context;
 pub mod font_template;
 
-pub mod paint_thread;
-
 // Platform-specific implementations.
 #[allow(unsafe_code)]
 mod platform;
 
 // Text
 pub mod text;
deleted file mode 100644
--- a/servo/components/gfx/paint_thread.rs
+++ /dev/null
@@ -1,779 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//! The thread that handles all painting.
-
-use app_units::Au;
-use azure::AzFloat;
-use azure::azure_hl::{BackendType, Color, DrawTarget, SurfaceFormat};
-use display_list::{DisplayItem, DisplayList, DisplayListTraversal};
-use display_list::{LayerInfo, StackingContext, StackingContextType};
-use euclid::Matrix4D;
-use euclid::point::Point2D;
-use euclid::rect::{Rect, TypedRect};
-use euclid::size::Size2D;
-use font_cache_thread::FontCacheThread;
-use font_context::FontContext;
-use gfx_traits::{ChromeToPaintMsg, Epoch, LayerId, LayerKind, LayerProperties};
-use gfx_traits::{PaintListener, PaintRequest, StackingContextId};
-use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
-use layers::platform::surface::{NativeDisplay, NativeSurface};
-use msg::constellation_msg::PipelineId;
-use paint_context::PaintContext;
-use profile_traits::mem;
-use profile_traits::time;
-use rand::{self, Rng};
-use std::borrow::ToOwned;
-use std::collections::HashMap;
-use std::mem as std_mem;
-use std::sync::Arc;
-use std::sync::mpsc::{Receiver, Sender, channel};
-use style::thread_state;
-use url::Url;
-use util::geometry::ExpandToPixelBoundaries;
-use util::opts;
-use util::thread;
-
-#[derive(Clone, HeapSizeOf)]
-struct PaintLayer {
-    /// The LayerProperties, which describe the layer in a way that the Compositor
-    /// can consume.
-    pub layer_properties: LayerProperties,
-
-    /// The StackingContextId of the StackingContext that is the immediate
-    /// parent of this layer. This is used to ensure applying the proper transform
-    /// when painting.
-    pub starting_stacking_context_id: StackingContextId,
-
-    /// The indices (in the DisplayList) to the first and last display item
-    /// that are the contents of this layer.
-    pub display_list_indices: Option<(usize, usize)>,
-
-    /// When painting, whether to draw the start by entering the surrounding StackingContext
-    /// or simply to draw the single item this PaintLayer contains.
-    pub single_item: bool,
-
-    /// The layer's bounds start at the overflow origin, but display items are
-    /// positioned relative to the stacking context bounds, so we need to
-    /// offset by the overflow rect (which will be in the coordinate system of
-    /// the stacking context bounds).
-    pub display_list_origin: Point2D<f32>
-}
-
-impl PaintLayer {
-    fn new_from_stacking_context(layer_info: &LayerInfo,
-                                 stacking_context: &StackingContext,
-                                 parent_origin: &Point2D<Au>,
-                                 transform: &Matrix4D<f32>,
-                                 perspective: &Matrix4D<f32>,
-                                 parent_id: Option<LayerId>)
-                                 -> PaintLayer {
-        let bounds = Rect::new(stacking_context.bounds.origin + stacking_context.overflow.origin,
-                               stacking_context.overflow.size);
-        let layer_boundaries = Rect::new(
-            Point2D::new((parent_origin.x + bounds.min_x()).to_nearest_px() as f32,
-                         (parent_origin.y + bounds.min_y()).to_nearest_px() as f32),
-            Size2D::new(bounds.size.width.to_nearest_px() as f32,
-                        bounds.size.height.to_nearest_px() as f32));
-
-        let transform = transform.pre_mul(&stacking_context.transform);
-        let perspective = perspective.pre_mul(&stacking_context.perspective);
-        let establishes_3d_context = stacking_context.establishes_3d_context;
-        let scrolls_overflow_area = stacking_context.scrolls_overflow_area;
-
-        PaintLayer {
-            layer_properties: LayerProperties {
-                id: layer_info.layer_id,
-                parent_id: parent_id,
-                rect: layer_boundaries,
-                background_color: layer_info.background_color,
-                scroll_policy: layer_info.scroll_policy,
-                transform: transform,
-                perspective: perspective,
-                establishes_3d_context: establishes_3d_context,
-                scrolls_overflow_area: scrolls_overflow_area,
-                subpage_pipeline_id: layer_info.subpage_pipeline_id,
-            },
-            starting_stacking_context_id: stacking_context.id,
-            display_list_indices: None,
-            single_item: false,
-            display_list_origin: Point2D::new(stacking_context.overflow.origin.x.to_f32_px(),
-                                              stacking_context.overflow.origin.y.to_f32_px()),
-        }
-    }
-
-    fn new_for_display_item(layer_info: &LayerInfo,
-                            item_bounds: &Rect<Au>,
-                            parent_origin: &Point2D<Au>,
-                            transform: &Matrix4D<f32>,
-                            perspective: &Matrix4D<f32>,
-                            parent_id: Option<LayerId>,
-                            stacking_context_id: StackingContextId,
-                            item_index: usize)
-                            -> PaintLayer {
-        let bounds = item_bounds.expand_to_px_boundaries();
-        let layer_boundaries = Rect::new(
-            Point2D::new((parent_origin.x + bounds.min_x()).to_nearest_px() as f32,
-                         (parent_origin.y + bounds.min_y()).to_nearest_px() as f32),
-            Size2D::new(bounds.size.width.to_nearest_px() as f32,
-                        bounds.size.height.to_nearest_px() as f32));
-
-        PaintLayer {
-            layer_properties: LayerProperties {
-                id: layer_info.layer_id,
-                parent_id: parent_id,
-                rect: layer_boundaries,
-                background_color: layer_info.background_color,
-                scroll_policy: layer_info.scroll_policy,
-                transform: *transform,
-                perspective: *perspective,
-                establishes_3d_context: false,
-                scrolls_overflow_area: false,
-                subpage_pipeline_id: layer_info.subpage_pipeline_id,
-            },
-            starting_stacking_context_id: stacking_context_id,
-            display_list_indices: Some((item_index, item_index)),
-            single_item: true,
-            display_list_origin: Point2D::new(bounds.origin.x.to_f32_px(),
-                                              bounds.origin.y.to_f32_px()),
-        }
-    }
-
-    fn add_item(&mut self, index: usize) {
-        let indices = match self.display_list_indices {
-            Some((first, _)) => (first, index),
-            None => (index, index),
-        };
-        self.display_list_indices = Some(indices);
-    }
-
-    fn make_companion_layer(&mut self) {
-        self.layer_properties.id = self.layer_properties.id.companion_layer_id();
-        self.display_list_indices = None;
-    }
-}
-
-struct LayerCreator {
-    layers: Vec<PaintLayer>,
-    layer_details_stack: Vec<PaintLayer>,
-    current_layer: Option<PaintLayer>,
-}
-
-impl LayerCreator {
-    fn create_layers_with_display_list<'a>(display_list: &'a DisplayList) -> Vec<PaintLayer> {
-        let mut layer_creator = LayerCreator {
-            layers: Vec::new(),
-            layer_details_stack: Vec::new(),
-            current_layer: None,
-        };
-        let mut traversal = DisplayListTraversal::new(display_list);
-        layer_creator.process_stacking_context_items(&mut traversal,
-                                                     &Point2D::zero(),
-                                                     &Matrix4D::identity(),
-                                                     &Matrix4D::identity());
-        layer_creator.layers
-    }
-
-    fn finalize_current_layer(&mut self) {
-        if let Some(current_layer) = self.current_layer.take() {
-            self.layers.push(current_layer);
-        }
-    }
-
-    fn current_parent_layer_id(&self) -> Option<LayerId> {
-        self.layer_details_stack.last().as_ref().map(|layer|
-            layer.layer_properties.id
-        )
-    }
-
-    fn current_parent_stacking_context_id(&self) -> StackingContextId {
-        self.layer_details_stack.last().unwrap().starting_stacking_context_id
-    }
-
-    fn create_layers_for_stacking_context<'a>(&mut self,
-                                              stacking_context: &StackingContext,
-                                              traversal: &mut DisplayListTraversal<'a>,
-                                              parent_origin: &Point2D<Au>,
-                                              transform: &Matrix4D<f32>,
-                                              perspective: &Matrix4D<f32>) {
-        if let Some(ref layer_info) = stacking_context.layer_info {
-            self.finalize_current_layer();
-            let new_layer = PaintLayer::new_from_stacking_context(
-                    layer_info,
-                    stacking_context,
-                    parent_origin,
-                    transform,
-                    perspective,
-                    self.current_parent_layer_id());
-            self.layer_details_stack.push(new_layer.clone());
-            self.current_layer = Some(new_layer);
-
-            // When there is a new layer, the transforms and origin are handled by
-            // the compositor, so the new transform and perspective matrices are
-            // just the identity.
-            //
-            // The origin for child layers which might be somewhere other than the
-            // layer origin, since layer boundaries are expanded to include overflow.
-            self.process_stacking_context_items(traversal,
-                                                &-stacking_context.overflow.origin,
-                                                &Matrix4D::identity(),
-                                                &Matrix4D::identity());
-            self.finalize_current_layer();
-            self.layer_details_stack.pop();
-            return;
-        }
-
-        debug_assert!(stacking_context.context_type == StackingContextType::Real);
-        self.process_stacking_context_items(traversal,
-                                            &(stacking_context.bounds.origin + *parent_origin),
-                                            &transform.pre_mul(&stacking_context.transform),
-                                            &perspective.pre_mul(&stacking_context.perspective));
-    }
-
-    fn process_stacking_context_items<'a>(&mut self,
-                                          traversal: &mut DisplayListTraversal<'a>,
-                                          parent_origin: &Point2D<Au>,
-                                          transform: &Matrix4D<f32>,
-                                          perspective: &Matrix4D<f32>) {
-        while let Some(item) = traversal.next() {
-            match item {
-                &DisplayItem::PushStackingContextClass(ref stacking_context_item) => {
-                    self.create_layers_for_stacking_context(&stacking_context_item.stacking_context,
-                                                            traversal,
-                                                            parent_origin,
-                                                            transform,
-                                                            perspective);
-                }
-                &DisplayItem::PopStackingContextClass(_) => return,
-                _ => {
-                    self.create_layers_for_item(traversal.previous_item_id(),
-                                                item,
-                                                parent_origin,
-                                                transform,
-                                                perspective);
-                }
-            }
-        }
-    }
-
-
-    fn create_layers_for_item<'a>(&mut self,
-                                  current_item_index: usize,
-                                  item: &DisplayItem,
-                                  parent_origin: &Point2D<Au>,
-                                  transform: &Matrix4D<f32>,
-                                  perspective: &Matrix4D<f32>) {
-        if let &DisplayItem::LayeredItemClass(ref layered_item) = item {
-            // We need to finalize the last layer here before incrementing the item
-            // index, otherwise this item will be placed into the parent layer.
-            self.finalize_current_layer();
-            let layer = PaintLayer::new_for_display_item(
-                &layered_item.layer_info,
-                &layered_item.item.bounds(),
-                parent_origin,
-                transform,
-                perspective,
-                self.current_parent_layer_id(),
-                self.current_parent_stacking_context_id(),
-                current_item_index);
-            self.layers.push(layer);
-            return;
-        }
-
-        // If we don't have a current layer, we are an item that belonged to a
-        // previous layer that was finalized by a child layer. We need to
-        // resurrect a copy of the original ancestor layer to ensure that this
-        // item is ordered on top of the child layers when painted.
-        if self.current_layer.is_none() {
-            let mut new_layer = self.layer_details_stack.pop().unwrap();
-            new_layer.make_companion_layer();
-
-            if new_layer.layer_properties.parent_id == None {
-                new_layer.layer_properties.parent_id =
-                    Some(new_layer.layer_properties.id.original());
-            }
-
-            self.layer_details_stack.push(new_layer.clone());
-            self.current_layer = Some(new_layer);
-        }
-
-        if let Some(ref mut current_layer) = self.current_layer {
-            current_layer.add_item(current_item_index);
-        }
-    }
-}
-
-pub enum Msg {
-    FromLayout(LayoutToPaintMsg),
-    FromChrome(ChromeToPaintMsg),
-}
-
-#[derive(Deserialize, Serialize)]
-pub enum LayoutToPaintMsg {
-    PaintInit(Epoch, Arc<DisplayList>),
-    Exit,
-}
-
-pub struct PaintThread<C> {
-    id: PipelineId,
-    _url: Url,
-    layout_to_paint_port: Receiver<LayoutToPaintMsg>,
-    chrome_to_paint_port: Receiver<ChromeToPaintMsg>,
-    compositor: C,
-
-    /// A channel to the time profiler.
-    time_profiler_chan: time::ProfilerChan,
-
-    /// The root paint layer sent to us by the layout thread.
-    root_display_list: Option<Arc<DisplayList>>,
-
-    /// A map that associates LayerIds with their corresponding layers.
-    layer_map: HashMap<LayerId, Arc<PaintLayer>>,
-
-    /// Permission to send paint messages to the compositor
-    paint_permission: bool,
-
-    /// The current epoch counter is passed by the layout thread
-    current_epoch: Option<Epoch>,
-
-    /// Communication handles to each of the worker threads.
-    worker_threads: Vec<WorkerThreadProxy>,
-}
-
-// If we implement this as a function, we get borrowck errors from borrowing
-// the whole PaintThread struct.
-macro_rules! native_display(
-    ($thread:expr) => (
-        $thread.native_display.as_ref().expect("Need a graphics context to do painting")
-    )
-);
-
-impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
-    pub fn create(id: PipelineId,
-                  url: Url,
-                  chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
-                  layout_to_paint_port: Receiver<LayoutToPaintMsg>,
-                  chrome_to_paint_port: Receiver<ChromeToPaintMsg>,
-                  mut compositor: C,
-                  font_cache_thread: FontCacheThread,
-                  time_profiler_chan: time::ProfilerChan,
-                  mem_profiler_chan: mem::ProfilerChan) {
-        thread::spawn_named(format!("PaintThread {:?}", id), move || {
-            thread_state::initialize(thread_state::PAINT);
-            PipelineId::install(id);
-
-            let native_display = compositor.native_display();
-            let worker_threads = WorkerThreadProxy::spawn(native_display,
-                                                          font_cache_thread,
-                                                          time_profiler_chan.clone());
-
-            let mut paint_thread = PaintThread {
-                id: id,
-                _url: url,
-                layout_to_paint_port: layout_to_paint_port,
-                chrome_to_paint_port: chrome_to_paint_port,
-                compositor: compositor,
-                time_profiler_chan: time_profiler_chan,
-                root_display_list: None,
-                layer_map: HashMap::new(),
-                paint_permission: false,
-                current_epoch: None,
-                worker_threads: worker_threads,
-            };
-
-            let reporter_name = format!("paint-reporter-{}", id);
-            mem_profiler_chan.run_with_memory_reporting(|| {
-                paint_thread.start();
-            }, reporter_name, chrome_to_paint_chan, ChromeToPaintMsg::CollectReports);
-
-            // Tell all the worker threads to shut down.
-            for worker_thread in &mut paint_thread.worker_threads {
-                worker_thread.exit()
-            }
-        });
-    }
-
-    #[allow(unsafe_code)]
-    fn start(&mut self) {
-        debug!("PaintThread: beginning painting loop");
-
-        loop {
-            let message = {
-                let layout_to_paint = &self.layout_to_paint_port;
-                let chrome_to_paint = &self.chrome_to_paint_port;
-                select! {
-                    msg = layout_to_paint.recv() =>
-                        Msg::FromLayout(msg.expect("expected message from layout")),
-                    msg = chrome_to_paint.recv() =>
-                        Msg::FromChrome(msg.expect("expected message from chrome"))
-                }
-            };
-
-            match message {
-                Msg::FromLayout(LayoutToPaintMsg::PaintInit(epoch, display_list)) => {
-                    self.current_epoch = Some(epoch);
-                    self.root_display_list = Some(display_list);
-
-                    if self.paint_permission {
-                        self.initialize_layers();
-                    }
-                }
-                Msg::FromChrome(ChromeToPaintMsg::Paint(requests, frame_tree_id)) => {
-                    if self.paint_permission && self.root_display_list.is_some() {
-                        let mut replies = Vec::new();
-                        for PaintRequest { buffer_requests, scale, layer_id, epoch, layer_kind }
-                              in requests {
-                            if self.current_epoch == Some(epoch) {
-                                self.paint(&mut replies, buffer_requests, scale, layer_id, layer_kind);
-                            } else {
-                                debug!("PaintThread: Ignoring requests with epoch mismatch: {:?} != {:?}",
-                                       self.current_epoch,
-                                       epoch);
-                                self.compositor.ignore_buffer_requests(buffer_requests);
-                            }
-                        }
-
-                        debug!("PaintThread: returning surfaces");
-                        self.compositor.assign_painted_buffers(self.id,
-                                                               self.current_epoch.unwrap(),
-                                                               replies,
-                                                               frame_tree_id);
-                    }
-                }
-                Msg::FromChrome(ChromeToPaintMsg::PaintPermissionGranted) => {
-                    self.paint_permission = true;
-
-                    if self.root_display_list.is_some() {
-                        self.initialize_layers();
-                    }
-                }
-                Msg::FromChrome(ChromeToPaintMsg::PaintPermissionRevoked) => {
-                    self.paint_permission = false;
-                }
-                Msg::FromChrome(ChromeToPaintMsg::CollectReports(ref channel)) => {
-                    // FIXME(njn): should eventually measure the paint thread.
-                    channel.send(Vec::new())
-                }
-                Msg::FromLayout(LayoutToPaintMsg::Exit) => {
-                    // Ask the compositor to remove any layers it is holding for this paint thread.
-                    // FIXME(mrobinson): This can probably move back to the constellation now.
-                    debug!("PaintThread: Exiting.");
-                    self.compositor.notify_paint_thread_exiting(self.id);
-
-                    break;
-                }
-                Msg::FromChrome(ChromeToPaintMsg::Exit) => {
-                    // Ask the compositor to remove any layers it is holding for this paint thread.
-                    // FIXME(mrobinson): This can probably move back to the constellation now.
-                    debug!("PaintThread: Exiting.");
-                    self.compositor.notify_paint_thread_exiting(self.id);
-
-                    break;
-                }
-            }
-        }
-    }
-
-    /// Paints one layer and places the painted tiles in `replies`.
-    fn paint(&mut self,
-              replies: &mut Vec<(LayerId, Box<LayerBufferSet>)>,
-              mut tiles: Vec<BufferRequest>,
-              scale: f32,
-              layer_id: LayerId,
-              layer_kind: LayerKind) {
-        time::profile(time::ProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || {
-            let display_list = match self.root_display_list {
-                Some(ref display_list) => display_list.clone(),
-                None => return,
-            };
-
-            // Bail out if there is no appropriate layer.
-            let layer = match self.layer_map.get(&layer_id) {
-                Some(layer) => layer.clone(),
-                None => return,
-            };
-
-            // Divide up the layer into tiles and distribute them to workers via a simple round-
-            // robin strategy.
-            let tiles = std_mem::replace(&mut tiles, Vec::new());
-            let tile_count = tiles.len();
-            for (i, tile) in tiles.into_iter().enumerate() {
-                let thread_id = i % self.worker_threads.len();
-                self.worker_threads[thread_id].paint_tile(thread_id,
-                                                          tile,
-                                                          display_list.clone(),
-                                                          layer.clone(),
-                                                          scale,
-                                                          layer_kind);
-            }
-            let new_buffers = (0..tile_count).map(|i| {
-                let thread_id = i % self.worker_threads.len();
-                self.worker_threads[thread_id].painted_tile_buffer()
-            }).collect();
-
-            let layer_buffer_set = box LayerBufferSet {
-                buffers: new_buffers,
-            };
-            replies.push((layer_id, layer_buffer_set));
-        })
-    }
-
-    fn initialize_layers(&mut self) {
-        let root_display_list = match self.root_display_list {
-            None => return,
-            Some(ref root_display_list) => root_display_list,
-        };
-        let layers = LayerCreator::create_layers_with_display_list(&root_display_list);
-        let properties = layers.iter().map(|layer| layer.layer_properties.clone()).collect();
-        self.compositor.initialize_layers_for_pipeline(self.id,
-                                                       properties,
-                                                       self.current_epoch.unwrap());
-        self.layer_map.clear();
-        for layer in layers.into_iter() {
-            self.layer_map.insert(layer.layer_properties.id, Arc::new(layer));
-        }
-    }
-}
-
-struct WorkerThreadProxy {
-    sender: Sender<MsgToWorkerThread>,
-    receiver: Receiver<MsgFromWorkerThread>,
-}
-
-impl WorkerThreadProxy {
-    fn spawn(native_display: Option<NativeDisplay>,
-             font_cache_thread: FontCacheThread,
-             time_profiler_chan: time::ProfilerChan)
-             -> Vec<WorkerThreadProxy> {
-        // Don't make any paint threads if we're using WebRender. They're just a waste of
-        // resources.
-        if opts::get().use_webrender {
-            return vec![]
-        }
-
-        let thread_count = opts::get().paint_threads;
-        (0..thread_count).map(|_| {
-            let (from_worker_sender, from_worker_receiver) = channel();
-            let (to_worker_sender, to_worker_receiver) = channel();
-            let font_cache_thread = font_cache_thread.clone();
-            let time_profiler_chan = time_profiler_chan.clone();
-            thread::spawn_named("PaintWorker".to_owned(), move || {
-                let mut worker_thread = WorkerThread::new(from_worker_sender,
-                                                          to_worker_receiver,
-                                                          native_display,
-                                                          font_cache_thread,
-                                                          time_profiler_chan);
-                worker_thread.main();
-            });
-            WorkerThreadProxy {
-                receiver: from_worker_receiver,
-                sender: to_worker_sender,
-            }
-        }).collect()
-    }
-
-    fn paint_tile(&mut self,
-                  thread_id: usize,
-                  tile: BufferRequest,
-                  display_list: Arc<DisplayList>,
-                  paint_layer: Arc<PaintLayer>,
-                  scale: f32,
-                  layer_kind: LayerKind) {
-        let msg = MsgToWorkerThread::PaintTile(thread_id,
-                                               tile,
-                                               display_list,
-                                               paint_layer,
-                                               scale,
-                                               layer_kind);
-        self.sender.send(msg).unwrap()
-    }
-
-    fn painted_tile_buffer(&mut self) -> Box<LayerBuffer> {
-        match self.receiver.recv().unwrap() {
-            MsgFromWorkerThread::PaintedTile(layer_buffer) => layer_buffer,
-        }
-    }
-
-    fn exit(&mut self) {
-        self.sender.send(MsgToWorkerThread::Exit).unwrap()
-    }
-}
-
-struct WorkerThread {
-    sender: Sender<MsgFromWorkerThread>,
-    receiver: Receiver<MsgToWorkerThread>,
-    native_display: Option<NativeDisplay>,
-    font_context: Box<FontContext>,
-    time_profiler_sender: time::ProfilerChan,
-}
-
-impl WorkerThread {
-    fn new(sender: Sender<MsgFromWorkerThread>,
-           receiver: Receiver<MsgToWorkerThread>,
-           native_display: Option<NativeDisplay>,
-           font_cache_thread: FontCacheThread,
-           time_profiler_sender: time::ProfilerChan)
-           -> WorkerThread {
-        WorkerThread {
-            sender: sender,
-            receiver: receiver,
-            native_display: native_display,
-            font_context: box FontContext::new(font_cache_thread.clone()),
-            time_profiler_sender: time_profiler_sender,
-        }
-    }
-
-    fn main(&mut self) {
-        loop {
-            match self.receiver.recv().unwrap() {
-                MsgToWorkerThread::Exit => break,
-                MsgToWorkerThread::PaintTile(thread_id,
-                                             tile,
-                                             display_list,
-                                             paint_layer,
-                                             scale,
-                                             layer_kind) => {
-                    let buffer = self.optimize_and_paint_tile(thread_id,
-                                                              tile,
-                                                              display_list,
-                                                              paint_layer,
-                                                              scale,
-                                                              layer_kind);
-                    self.sender.send(MsgFromWorkerThread::PaintedTile(buffer)).unwrap()
-                }
-            }
-        }
-    }
-
-    fn optimize_and_paint_tile(&mut self,
-                               thread_id: usize,
-                               mut tile: BufferRequest,
-                               display_list: Arc<DisplayList>,
-                               paint_layer: Arc<PaintLayer>,
-                               scale: f32,
-                               layer_kind: LayerKind)
-                               -> Box<LayerBuffer> {
-        let size = Size2D::new(tile.screen_rect.size.width as i32,
-                               tile.screen_rect.size.height as i32);
-        let mut buffer = self.create_layer_buffer(&mut tile, scale);
-        let draw_target = DrawTarget::new(BackendType::Skia, size, SurfaceFormat::B8G8R8A8);
-
-        {
-            // Build the paint context.
-            let mut paint_context = PaintContext {
-                draw_target: draw_target.clone(),
-                font_context: &mut self.font_context,
-                page_rect: TypedRect::from_untyped(&tile.page_rect.translate(&paint_layer.display_list_origin)),
-                screen_rect: TypedRect::from_untyped(&tile.screen_rect),
-                clip_rect: None,
-                transient_clip: None,
-                layer_kind: layer_kind,
-                subpixel_offset: Point2D::zero(),
-            };
-
-            // Apply the translation to paint the tile we want.
-            let matrix = Matrix4D::identity();
-            let matrix = matrix.pre_scaled(scale as AzFloat, scale as AzFloat, 1.0);
-            let tile_bounds = tile.page_rect.translate(&paint_layer.display_list_origin);
-            let matrix = matrix.pre_translated(-tile_bounds.origin.x as AzFloat,
-                                                -tile_bounds.origin.y as AzFloat,
-                                                0.0);
-
-            // Clear the buffer.
-            paint_context.clear();
-
-            // Draw the display list.
-            time::profile(time::ProfilerCategory::PaintingPerTile,
-                          None,
-                          self.time_profiler_sender.clone(), || {
-                              if let Some((start, end)) = paint_layer.display_list_indices {
-                                  if paint_layer.single_item {
-                                      display_list.draw_item_at_index_into_context(
-                                        &mut paint_context, &matrix, start);
-                                  } else {
-                                      display_list.draw_into_context(
-                                          &mut paint_context,
-                                          &matrix,
-                                          paint_layer.starting_stacking_context_id,
-                                          start,
-                                          end);
-                                  }
-                              }
-                              paint_context.draw_target.flush();
-                         });
-
-            if opts::get().show_debug_parallel_paint {
-                // Overlay a transparent solid color to identify the thread that
-                // painted this tile.
-                let color = THREAD_TINT_COLORS[thread_id % THREAD_TINT_COLORS.len()];
-                paint_context.draw_solid_color(&Rect::new(Point2D::new(Au(0), Au(0)),
-                                                          Size2D::new(Au::from_px(size.width),
-                                                                      Au::from_px(size.height))),
-                                               color);
-            }
-            if opts::get().paint_flashing {
-                // Overlay a random transparent color.
-                let color = *rand::thread_rng().choose(&THREAD_TINT_COLORS[..]).unwrap();
-                paint_context.draw_solid_color(&Rect::new(Point2D::new(Au(0), Au(0)),
-                                                          Size2D::new(Au::from_px(size.width),
-                                                                      Au::from_px(size.height))),
-                                               color);
-            }
-        }
-
-        // Extract the texture from the draw target and place it into its slot in the buffer.
-        // Upload it first.
-        draw_target.snapshot().get_data_surface().with_data(|data| {
-            buffer.native_surface.upload(native_display!(self), data);
-            debug!("painting worker thread uploading to native surface {}",
-                   buffer.native_surface.get_id());
-        });
-
-        draw_target.finish();
-        buffer
-    }
-
-    fn create_layer_buffer(&mut self,
-                           tile: &mut BufferRequest,
-                           scale: f32)
-                           -> Box<LayerBuffer> {
-        // Create an empty native surface. We mark it as not leaking
-        // in case it dies in transit to the compositor thread.
-        let width = tile.screen_rect.size.width;
-        let height = tile.screen_rect.size.height;
-        let mut native_surface = tile.native_surface.take().unwrap_or_else(|| {
-            NativeSurface::new(native_display!(self), Size2D::new(width as i32, height as i32))
-        });
-        native_surface.mark_wont_leak();
-
-        box LayerBuffer {
-            native_surface: native_surface,
-            rect: tile.page_rect,
-            screen_pos: tile.screen_rect,
-            resolution: scale,
-            painted_with_cpu: true,
-            content_age: tile.content_age,
-        }
-    }
-}
-
-enum MsgToWorkerThread {
-    Exit,
-    PaintTile(usize, BufferRequest, Arc<DisplayList>, Arc<PaintLayer>, f32, LayerKind),
-}
-
-enum MsgFromWorkerThread {
-    PaintedTile(Box<LayerBuffer>),
-}
-
-pub static THREAD_TINT_COLORS: [Color; 8] = [
-    Color { r: 6.0 / 255.0, g: 153.0 / 255.0, b: 198.0 / 255.0, a: 0.7 },
-    Color { r: 255.0 / 255.0, g: 212.0 / 255.0, b: 83.0 / 255.0, a: 0.7 },
-    Color { r: 116.0 / 255.0, g: 29.0 / 255.0, b: 109.0 / 255.0, a: 0.7 },
-    Color { r: 204.0 / 255.0, g: 158.0 / 255.0, b: 199.0 / 255.0, a: 0.7 },
-    Color { r: 242.0 / 255.0, g: 46.0 / 255.0, b: 121.0 / 255.0, a: 0.7 },
-    Color { r: 116.0 / 255.0, g: 203.0 / 255.0, b: 196.0 / 255.0, a: 0.7 },
-    Color { r: 255.0 / 255.0, g: 249.0 / 255.0, b: 201.0 / 255.0, a: 0.7 },
-    Color { r: 137.0 / 255.0, g: 196.0 / 255.0, b: 78.0 / 255.0, a: 0.7 },
-];
--- a/servo/components/gfx/text/text_run.rs
+++ b/servo/components/gfx/text/text_run.rs
@@ -24,17 +24,17 @@ thread_local! {
 /// A single "paragraph" of text in one font size and style.
 #[derive(Clone, Deserialize, Serialize)]
 pub struct TextRun {
     /// The UTF-8 string represented by this text run.
     pub text: Arc<String>,
     pub font_template: Arc<FontTemplateData>,
     pub actual_pt_size: Au,
     pub font_metrics: FontMetrics,
-    pub font_key: Option<webrender_traits::FontKey>,
+    pub font_key: webrender_traits::FontKey,
     /// The glyph runs that make up this text run.
     pub glyphs: Arc<Vec<GlyphRun>>,
     pub bidi_level: u8,
     pub extra_word_spacing: Au,
 }
 
 impl Drop for TextRun {
     fn drop(&mut self) {
--- a/servo/components/gfx_traits/Cargo.toml
+++ b/servo/components/gfx_traits/Cargo.toml
@@ -6,19 +6,15 @@ license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "gfx_traits"
 path = "lib.rs"
 
 [dependencies]
 azure = {git = "https://github.com/servo/rust-azure", features = ["plugins"]}
-euclid = "0.10.1"
 heapsize = "0.3.0"
 heapsize_plugin = "0.1.2"
-layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
-msg = {path = "../msg"}
 plugins = {path = "../plugins"}
-profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 rustc-serialize = "0.3"
 serde = "0.8"
 serde_derive = "0.8"
--- a/servo/components/gfx_traits/lib.rs
+++ b/servo/components/gfx_traits/lib.rs
@@ -6,55 +6,57 @@
 #![plugin(heapsize_plugin, plugins)]
 
 #![crate_name = "gfx_traits"]
 #![crate_type = "rlib"]
 
 #![deny(unsafe_code)]
 
 extern crate azure;
-extern crate euclid;
 extern crate heapsize;
-extern crate layers;
-extern crate msg;
-extern crate profile_traits;
 #[macro_use]
 extern crate range;
 extern crate rustc_serialize;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 
 pub mod color;
-mod paint_listener;
 pub mod print_tree;
 
-pub use paint_listener::PaintListener;
-use azure::azure_hl::Color;
-use euclid::Matrix4D;
-use euclid::rect::Rect;
-use layers::layers::BufferRequest;
-use msg::constellation_msg::PipelineId;
-use profile_traits::mem::ReportsChan;
 use range::RangeIndex;
 use std::fmt::{self, Debug, Formatter};
 use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
 
 /// The next ID that will be used for a special stacking context.
 ///
 /// A special stacking context is a stacking context that is one of (a) the outer stacking context
 /// of an element with `overflow: scroll`; (b) generated content; (c) both (a) and (b).
 static NEXT_SPECIAL_STACKING_CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
 
 /// If none of the bits outside this mask are set, the stacking context is a special stacking
 /// context.
 ///
 /// Note that we assume that the top 16 bits of the address space are unused on the platform.
 const SPECIAL_STACKING_CONTEXT_ID_MASK: usize = 0xffff;
 
+// Units for use with euclid::length and euclid::scale_factor.
+
+/// One hardware pixel.
+///
+/// This unit corresponds to the smallest addressable element of the display hardware.
+#[derive(Copy, Clone, RustcEncodable, Debug)]
+pub enum DevicePixel {}
+
+/// One pixel in layer coordinate space.
+///
+/// This unit corresponds to a "pixel" in layer coordinate space, which after scaling and
+/// transformation becomes a device pixel.
+#[derive(Copy, Clone, RustcEncodable, Debug)]
+pub enum LayerPixel {}
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum LayerKind {
     NoTransform,
     HasTransform,
 }
 
 #[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
@@ -123,43 +125,16 @@ impl LayerId {
         LayerId(layer_type, id, 0)
     }
 
     pub fn kind(&self) -> LayerType {
         self.0
     }
 }
 
-/// All layer-specific information that the painting task sends to the compositor other than the
-/// buffer contents of the layer itself.
-#[derive(Copy, Clone, HeapSizeOf)]
-pub struct LayerProperties {
-    /// An opaque ID. This is usually the address of the flow and index of the box within it.
-    pub id: LayerId,
-    /// The id of the parent layer.
-    pub parent_id: Option<LayerId>,
-    /// The position and size of the layer in pixels.
-    pub rect: Rect<f32>,
-    /// The background color of the layer.
-    pub background_color: Color,
-    /// The scrolling policy of this layer.
-    pub scroll_policy: ScrollPolicy,
-    /// The transform for this layer
-    pub transform: Matrix4D<f32>,
-    /// The perspective transform for this layer
-    pub perspective: Matrix4D<f32>,
-    /// The subpage that this layer represents. If this is `Some`, this layer represents an
-    /// iframe.
-    pub subpage_pipeline_id: Option<PipelineId>,
-    /// Whether this layer establishes a new 3d rendering context.
-    pub establishes_3d_context: bool,
-    /// Whether this layer scrolls its overflow area.
-    pub scrolls_overflow_area: bool,
-}
-
 /// A newtype struct for denoting the age of messages; prevents race conditions.
 #[derive(PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Deserialize, Serialize)]
 pub struct Epoch(pub u32);
 
 impl Epoch {
     pub fn next(&mut self) {
         self.0 += 1;
     }
@@ -267,24 +242,8 @@ impl FragmentType {
 
 int_range_index! {
     #[derive(Deserialize, Serialize, RustcEncodable)]
     #[doc = "An index that refers to a byte offset in a text run. This could \
              point to the middle of a glyph."]
     #[derive(HeapSizeOf)]
     struct ByteIndex(isize)
 }
-
-pub struct PaintRequest {
-    pub buffer_requests: Vec<BufferRequest>,
-    pub scale: f32,
-    pub layer_id: LayerId,
-    pub epoch: Epoch,
-    pub layer_kind: LayerKind,
-}
-
-pub enum ChromeToPaintMsg {
-    Paint(Vec<PaintRequest>, FrameTreeId),
-    PaintPermissionGranted,
-    PaintPermissionRevoked,
-    CollectReports(ReportsChan),
-    Exit,
-}
deleted file mode 100644
--- a/servo/components/gfx_traits/paint_listener.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use Epoch;
-use FrameTreeId;
-use LayerId;
-use LayerProperties;
-use layers::layers::{BufferRequest, LayerBufferSet};
-use layers::platform::surface::NativeDisplay;
-use msg::constellation_msg::PipelineId;
-
-/// The interface used by the painter to acquire draw targets for each paint frame and
-/// submit them to be drawn to the display.
-pub trait PaintListener {
-    fn native_display(&mut self) -> Option<NativeDisplay>;
-
-    /// Informs the compositor of the layers for the given pipeline. The compositor responds by
-    /// creating and/or destroying paint layers as necessary.
-    fn initialize_layers_for_pipeline(&mut self,
-                                      pipeline_id: PipelineId,
-                                      properties: Vec<LayerProperties>,
-                                      epoch: Epoch);
-
-    /// Sends new buffers for the given layers to the compositor.
-    fn assign_painted_buffers(&mut self,
-                              pipeline_id: PipelineId,
-                              epoch: Epoch,
-                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
-                              frame_tree_id: FrameTreeId);
-
-    /// Inform the compositor that these buffer requests will be ignored.
-    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>);
-
-    // Notification that the paint task wants to exit.
-    fn notify_paint_thread_exiting(&mut self, pipeline_id: PipelineId);
-}
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -26,17 +26,17 @@
 //!   http://dev.w3.org/csswg/css-sizing/
 
 #![deny(unsafe_code)]
 
 use app_units::{Au, MAX_AU};
 use context::{LayoutContext, SharedLayoutContext};
 use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
 use display_list_builder::BlockFlowDisplayListBuilding;
-use euclid::{Point2D, Rect, Size2D};
+use euclid::{Point2D, Size2D};
 use floats::{ClearType, FloatKind, Floats, PlacementInfo};
 use flow::{self, BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ForceNonfloatedFlag};
 use flow::{BLOCK_POSITION_IS_STATIC, CLEARS_LEFT, CLEARS_RIGHT};
 use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, INLINE_POSITION_IS_STATIC};
 use flow::{FragmentationContext, NEEDS_LAYER, PreorderFlowTraversal};
 use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
 use flow::IS_ABSOLUTELY_POSITIONED;
 use flow_list::FlowList;
@@ -59,20 +59,16 @@ 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, transform_style};
 use style::context::{SharedStyleContext, StyleContext};
 use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
 use style::values::computed::{LengthOrNone, LengthOrPercentageOrNone};
 use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use util::clamp;
-use util::geometry::max_rect;
-
-/// The number of screens of data we're allowed to generate display lists for in each direction.
-const DISPLAY_PORT_SIZE_FACTOR: i32 = 8;
 
 /// Information specific to floated blocks.
 #[derive(Clone, RustcEncodable)]
 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
@@ -1954,41 +1950,39 @@ impl Flow for BlockFlow {
                    flow::base(self).debug_id());
             self.assign_block_size_block_base(
                 layout_context,
                 fragmentation_context,
                 MarginsMayCollapseFlag::MarginsMayCollapse)
         }
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, _layout_context: &SharedLayoutContext) {
         if self.base.flags.contains(NEEDS_LAYER) {
             self.fragment.flags.insert(HAS_LAYER)
         }
 
         // FIXME (mbrubeck): Get the real container size, taking the container writing mode into
         // account.  Must handle vertical writing modes.
         let container_size = Size2D::new(self.base.block_container_inline_size, Au(0));
 
         if self.is_root() {
             self.base.clip = ClippingRegion::max();
-            self.base.stacking_relative_position_of_display_port = max_rect();
         }
 
         let transform_style = self.fragment.style().get_used_transform_style();
 
         if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
             // `overflow: auto` and `overflow: scroll` force creation of layers, since we can only
             // scroll layers.
             match (self.fragment.style().get_box().overflow_x,
                    self.fragment.style().get_box().overflow_y.0) {
                 (overflow_x::T::auto, _) | (overflow_x::T::scroll, _) |
                 (_, overflow_x::T::auto) | (_, overflow_x::T::scroll) => {
                     self.base.clip = ClippingRegion::max();
-                    self.base.stacking_relative_position_of_display_port = max_rect();
                 }
                 _ => {}
             }
 
             let position_start = self.base.position.start.to_physical(self.base.writing_mode,
                                                                       container_size);
 
             // Compute our position relative to the nearest ancestor stacking context. This will be
@@ -2080,35 +2074,16 @@ impl Flow for BlockFlow {
             //
             // FIXME(pcwalton): Is this vertical-writing-direction-safe?
             let margin = self.fragment.margin.to_physical(self.base.writing_mode);
             Point2D::new(-margin.left, Au(0))
         } else {
             self.base.stacking_relative_position + relative_offset
         };
 
-        let stacking_relative_position_of_display_port_for_children =
-            if is_stacking_context || self.is_root() {
-                let visible_rect =
-                    match layout_context.visible_rects.get(&self.layer_id()) {
-                        Some(visible_rect) => *visible_rect,
-                        None => Rect::new(Point2D::zero(), layout_context.style_context.viewport_size),
-                    };
-
-                let viewport_size = layout_context.style_context.viewport_size;
-                visible_rect.inflate(viewport_size.width * DISPLAY_PORT_SIZE_FACTOR,
-                                     viewport_size.height * DISPLAY_PORT_SIZE_FACTOR)
-            } else if is_stacking_context {
-                self.base
-                    .stacking_relative_position_of_display_port
-                    .translate(&-self.base.stacking_relative_position)
-            } else {
-                self.base.stacking_relative_position_of_display_port
-            };
-
         let stacking_relative_border_box =
             self.fragment
                 .stacking_relative_border_box(&self.base.stacking_relative_position,
                                               &self.base
                                                    .early_absolute_position_info
                                                    .relative_containing_block_size,
                                               self.base
                                                   .early_absolute_position_info
@@ -2163,18 +2138,16 @@ impl Flow for BlockFlow {
                         kid_base.stacking_relative_position.x = origin_for_children.x +
                             physical_position.origin.x
                     }
                 }
             }
 
             flow::mut_base(kid).late_absolute_position_info =
                 late_absolute_position_info_for_children;
-            flow::mut_base(kid).stacking_relative_position_of_display_port =
-                stacking_relative_position_of_display_port_for_children;
 
             // This clipping region is in our coordinate system. The child will fix it up to be in
             // its own coordinate system by itself if necessary.
             //
             // Rationale: If the child is absolutely positioned, it hasn't been positioned at this
             // point (as absolutely-positioned flows position themselves in
             // `compute_absolute_position()`). Therefore, we don't always know what the child's
             // coordinate system is here. So we store the clipping region in our coordinate system
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -10,17 +10,17 @@
 use app_units::Au;
 use euclid::Rect;
 use fnv::FnvHasher;
 use gfx::display_list::WebRenderImageInfo;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context::FontContext;
 use gfx_traits::LayerId;
 use heapsize::HeapSizeOf;
-use ipc_channel::ipc::{self, IpcSharedMemory};
+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 std::cell::{RefCell, RefMut};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex, RwLock};
@@ -191,44 +191,35 @@ impl SharedLayoutContext {
             // Image has been requested, is still pending. Return no image for this paint loop.
             // When the image loads it will trigger a reflow and/or repaint.
             Err(ImageState::Pending) => None,
         }
     }
 
     pub fn get_webrender_image_for_url(&self,
                                        url: &Url,
-                                       use_placeholder: UsePlaceholder,
-                                       fetch_image_data_as_well: bool)
-                                       -> Option<(WebRenderImageInfo, Option<IpcSharedMemory>)> {
-        if !fetch_image_data_as_well {
-            let webrender_image_cache = self.webrender_image_cache.read().unwrap();
-            if let Some(existing_webrender_image) =
-                    webrender_image_cache.get(&((*url).clone(), use_placeholder)) {
-                return Some(((*existing_webrender_image).clone(), None))
-            }
+                                       use_placeholder: UsePlaceholder)
+                                       -> Option<WebRenderImageInfo> {
+        if let Some(existing_webrender_image) = self.webrender_image_cache
+                                                    .read()
+                                                    .unwrap()
+                                                    .get(&((*url).clone(), use_placeholder)) {
+            return Some((*existing_webrender_image).clone())
         }
 
         match self.get_or_request_image_or_meta((*url).clone(), use_placeholder) {
             Some(ImageOrMetadataAvailable::ImageAvailable(image)) => {
                 let image_info = WebRenderImageInfo::from_image(&*image);
                 if image_info.key.is_none() {
-                    let bytes = if !fetch_image_data_as_well {
-                        None
-                    } else {
-                        Some(image.bytes.clone())
-                    };
-                    Some((image_info, bytes))
-                } else if !fetch_image_data_as_well {
+                    Some(image_info)
+                } else {
                     let mut webrender_image_cache = self.webrender_image_cache
                                                         .write()
                                                         .unwrap();
                     webrender_image_cache.insert(((*url).clone(), use_placeholder),
                                                  image_info);
-                    Some((image_info, None))
-                } else {
-                    Some((image_info, Some(image.bytes.clone())))
+                    Some(image_info)
                 }
             }
             None | Some(ImageOrMetadataAvailable::MetadataAvailable(_)) => None,
         }
     }
 }
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -20,20 +20,19 @@ use flex::FlexFlow;
 use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
 use flow_ref;
 use fragment::{CoordinateSystem, Fragment, HAS_LAYER, ImageFragmentInfo, ScannedTextFragmentInfo};
 use fragment::SpecificFragmentInfo;
 use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
 use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayListSection, GradientDisplayItem};
 use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem};
-use gfx::display_list::{LayerInfo, LayeredItem, LineDisplayItem, OpaqueNode};
+use gfx::display_list::{LayerInfo, LineDisplayItem, OpaqueNode};
 use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType};
 use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo};
-use gfx::paint_thread::THREAD_TINT_COLORS;
 use gfx_traits::{ScrollPolicy, StackingContextId, color};
 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;
@@ -55,16 +54,27 @@ use style::values::RGBA;
 use style::values::computed;
 use style::values::computed::{Gradient, GradientKind, LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
 use style_traits::cursor::Cursor;
 use table_cell::CollapsedBordersForCell;
 use url::Url;
 use util::opts;
 
+static THREAD_TINT_COLORS: [Color; 8] = [
+    Color { r: 6.0 / 255.0, g: 153.0 / 255.0, b: 198.0 / 255.0, a: 0.7 },
+    Color { r: 255.0 / 255.0, g: 212.0 / 255.0, b: 83.0 / 255.0, a: 0.7 },
+    Color { r: 116.0 / 255.0, g: 29.0 / 255.0, b: 109.0 / 255.0, a: 0.7 },
+    Color { r: 204.0 / 255.0, g: 158.0 / 255.0, b: 199.0 / 255.0, a: 0.7 },
+    Color { r: 242.0 / 255.0, g: 46.0 / 255.0, b: 121.0 / 255.0, a: 0.7 },
+    Color { r: 116.0 / 255.0, g: 203.0 / 255.0, b: 196.0 / 255.0, a: 0.7 },
+    Color { r: 255.0 / 255.0, g: 249.0 / 255.0, b: 201.0 / 255.0, a: 0.7 },
+    Color { r: 137.0 / 255.0, g: 196.0 / 255.0, b: 78.0 / 255.0, a: 0.7 },
+];
+
 fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
     &arr[index % arr.len()]
 }
 
 pub struct DisplayListBuildState<'a> {
     pub shared_layout_context: &'a SharedLayoutContext,
     pub items: Vec<DisplayItem>,
     pub stacking_context_id_stack: Vec<StackingContextId>,
@@ -225,27 +235,24 @@ pub trait FragmentDisplayListBuilding {
     /// * `state`: The display building state, including the display list currently
     ///   under construction and other metadata useful for constructing it.
     /// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
     /// * `stacking_relative_flow_origin`: Position of the origin of the owning flow with respect
     ///   to its nearest ancestor stacking context.
     /// * `relative_containing_block_size`: The size of the containing block that
     ///   `position: relative` makes use of.
     /// * `clip`: The region to clip the display items to.
-    /// * `stacking_relative_display_port`: The position and size of the display port with respect
-    ///   to the nearest ancestor stacking context.
     fn build_display_list(&mut self,
                           state: &mut DisplayListBuildState,
                           stacking_relative_flow_origin: &Point2D<Au>,
                           relative_containing_block_size: &LogicalSize<Au>,
                           relative_containing_block_mode: WritingMode,
                           border_painting_mode: BorderPaintingMode,
                           display_list_section: DisplayListSection,
-                          clip: &ClippingRegion,
-                          stacking_relative_display_port: &Rect<Au>);
+                          clip: &ClippingRegion);
 
     /// Adjusts the clipping region for all descendants of this fragment as appropriate.
     fn adjust_clipping_region_for_children(&self,
                                            current_clip: &mut ClippingRegion,
                                            stacking_relative_border_box: &Rect<Au>);
 
     /// Adjusts the clipping rectangle for a fragment to take the `clip` property into account
     /// per CSS 2.1 ยง 11.1.2.
@@ -492,23 +499,21 @@ impl FragmentDisplayListBuilding for Fra
                                                state: &mut DisplayListBuildState,
                                                style: &ServoComputedValues,
                                                display_list_section: DisplayListSection,
                                                absolute_bounds: &Rect<Au>,
                                                clip: &ClippingRegion,
                                                image_url: &Url,
                                                index: usize) {
         let background = style.get_background();
-        let fetch_image_data_as_well = !opts::get().use_webrender;
         let webrender_image = state.shared_layout_context
                                    .get_webrender_image_for_url(image_url,
-                                                                UsePlaceholder::No,
-                                                                fetch_image_data_as_well);
+                                                                UsePlaceholder::No);
 
-        if let Some((webrender_image, image_data)) = webrender_image {
+        if let Some(webrender_image) = webrender_image {
             debug!("(building display list) building background image");
 
             // Use `background-size` to get the size.
             let mut bounds = *absolute_bounds;
             let image_size = self.compute_background_image_size(style, &bounds,
                                                                 &webrender_image, index);
 
             // Clip.
@@ -628,17 +633,17 @@ impl FragmentDisplayListBuilding for Fra
             let base = state.create_base_display_item(&bounds,
                                                     &clip,
                                                     self.node,
                                                     style.get_cursor(Cursor::Default),
                                                     display_list_section);
             state.add_display_item(DisplayItem::ImageClass(box ImageDisplayItem {
               base: base,
               webrender_image: webrender_image,
-              image_data: image_data.map(Arc::new),
+              image_data: None,
               stretch_size: stretch_size,
               tile_spacing: tile_spacing,
               image_rendering: style.get_inheritedbox().image_rendering.clone(),
             }));
 
         }
     }
 
@@ -1075,18 +1080,17 @@ impl FragmentDisplayListBuilding for Fra
 
     fn build_display_list(&mut self,
                           state: &mut DisplayListBuildState,
                           stacking_relative_flow_origin: &Point2D<Au>,
                           relative_containing_block_size: &LogicalSize<Au>,
                           relative_containing_block_mode: WritingMode,
                           border_painting_mode: BorderPaintingMode,
                           display_list_section: DisplayListSection,
-                          clip: &ClippingRegion,
-                          stacking_relative_display_port: &Rect<Au>) {
+                          clip: &ClippingRegion) {
         self.restyle_damage.remove(REPAINT);
         if self.style().get_inheritedbox().visibility != visibility::T::visible {
             return
         }
 
         // Compute the fragment position relative to the parent stacking context. If the fragment
         // itself establishes a stacking context, then the origin of its position will be (0, 0)
         // for the purposes of this computation.
@@ -1097,24 +1101,16 @@ impl FragmentDisplayListBuilding for Fra
                                               CoordinateSystem::Own);
 
         debug!("Fragment::build_display_list at rel={:?}, abs={:?}, flow origin={:?}: {:?}",
                self.border_box,
                stacking_relative_border_box,
                stacking_relative_flow_origin,
                self);
 
-        // webrender deals with all culling via aabb
-        if !opts::get().use_webrender {
-            if !stacking_relative_border_box.intersects(stacking_relative_display_port) {
-                debug!("Fragment::build_display_list: outside display port");
-                return
-            }
-        }
-
         // Check the clip rect. If there's nothing to render at all, don't even construct display
         // list items.
         let empty_rect = !clip.might_intersect_rect(&stacking_relative_border_box);
         if self.is_primary_fragment() && !empty_rect {
             // Add shadows, background, borders, and outlines, if applicable.
             if let Some(ref inline_context) = self.inline_context {
                 for node in inline_context.nodes.iter().rev() {
                     self.build_display_list_for_background_if_applicable(
@@ -1265,27 +1261,17 @@ impl FragmentDisplayListBuilding for Fra
                         self.node,
                         self.style.get_cursor(Cursor::Default),
                         DisplayListSection::Content);
                     let item = DisplayItem::IframeClass(box IframeDisplayItem {
                         base: base,
                         iframe: fragment_info.pipeline_id,
                     });
 
-                    if opts::get().use_webrender {
-                        state.add_display_item(item);
-                    } else {
-                        state.add_display_item(DisplayItem::LayeredItemClass(box LayeredItem {
-                            item: item,
-                            layer_info: LayerInfo::new(self.layer_id(),
-                                                       ScrollPolicy::Scrollable,
-                                                       Some(fragment_info.pipeline_id),
-                                                       color::transparent()),
-                        }));
-                    }
+                    state.add_display_item(item);
                 }
             }
             SpecificFragmentInfo::Image(ref mut image_fragment) => {
                 // Place the image into the display list.
                 if let Some(ref image) = image_fragment.image {
                     let base = state.create_base_display_item(
                         &stacking_relative_content_box,
                         clip,
@@ -1306,17 +1292,16 @@ impl FragmentDisplayListBuilding for Fra
                 let width = canvas_fragment_info.replaced_image_fragment_info
                     .computed_inline_size.map_or(0, |w| w.to_px() as usize);
                 let height = canvas_fragment_info.replaced_image_fragment_info
                     .computed_block_size.map_or(0, |h| h.to_px() as usize);
                 if width > 0 && height > 0 {
                     let computed_width = canvas_fragment_info.canvas_inline_size().to_px();
                     let computed_height = canvas_fragment_info.canvas_block_size().to_px();
 
-                    let layer_id = self.layer_id();
                     let canvas_data = match canvas_fragment_info.ipc_renderer {
                         Some(ref ipc_renderer) => {
                             let ipc_renderer = ipc_renderer.lock().unwrap();
                             let (sender, receiver) = ipc::channel().unwrap();
                             ipc_renderer.send(CanvasMsg::FromLayout(
                                 FromLayoutMsg::SendData(sender))).unwrap();
                             receiver.recv().unwrap()
                         },
@@ -1333,42 +1318,32 @@ impl FragmentDisplayListBuilding for Fra
                         CanvasData::Pixels(canvas_data) => {
                             DisplayItem::ImageClass(box ImageDisplayItem {
                                 base: base,
                                 image_data: Some(Arc::new(canvas_data.image_data)),
                                 webrender_image: WebRenderImageInfo {
                                     width: computed_width as u32,
                                     height: computed_height as u32,
                                     format: PixelFormat::RGBA8,
-                                    key: canvas_data.image_key,
+                                    key: Some(canvas_data.image_key),
                                 },
                                 stretch_size: stacking_relative_content_box.size,
                                 tile_spacing: Size2D::zero(),
                                 image_rendering: image_rendering::T::auto,
                             })
                         }
                         CanvasData::WebGL(context_id) => {
                             DisplayItem::WebGLClass(box WebGLDisplayItem {
                                 base: base,
                                 context_id: context_id,
                             })
                         }
                     };
 
-                    if opts::get().use_webrender {
-                        state.add_display_item(display_item);
-                    } else {
-                        state.add_display_item(DisplayItem::LayeredItemClass(box LayeredItem {
-                            item: display_item,
-                            layer_info: LayerInfo::new(layer_id,
-                                                       ScrollPolicy::Scrollable,
-                                                       None,
-                                                       color::transparent()),
-                        }));
-                    }
+                    state.add_display_item(display_item);
                 }
             }
             SpecificFragmentInfo::UnscannedText(_) => {
                 panic!("Shouldn't see unscanned fragments here.")
             }
             SpecificFragmentInfo::TableColumn(_) => {
                 panic!("Shouldn't see table column fragments here.")
             }
@@ -1376,35 +1351,31 @@ impl FragmentDisplayListBuilding for Fra
     }
 
     fn create_stacking_context(&self,
                                id: StackingContextId,
                                base_flow: &BaseFlow,
                                scroll_policy: ScrollPolicy,
                                mode: StackingContextCreationMode)
                                -> StackingContext {
-        let use_webrender = opts::get().use_webrender;
         let border_box = match mode {
             StackingContextCreationMode::InnerScrollWrapper => {
                 Rect::new(Point2D::zero(), base_flow.overflow.scroll.size)
             }
             _ => {
                 self.stacking_relative_border_box(&base_flow.stacking_relative_position,
                                                   &base_flow.early_absolute_position_info
                                                             .relative_containing_block_size,
                                                   base_flow.early_absolute_position_info
                                                            .relative_containing_block_mode,
                                                   CoordinateSystem::Parent)
             }
         };
         let overflow = match mode {
-            StackingContextCreationMode::InnerScrollWrapper if !use_webrender => {
-                Rect::new(Point2D::zero(), base_flow.overflow.paint.size)
-            }
-            StackingContextCreationMode::InnerScrollWrapper if use_webrender => {
+            StackingContextCreationMode::InnerScrollWrapper => {
                 Rect::new(Point2D::zero(), base_flow.overflow.scroll.size)
             }
             StackingContextCreationMode::OuterScrollWrapper => {
                 Rect::new(Point2D::zero(), border_box.size)
             }
             _ => {
                 // First, compute the offset of our border box (including relative positioning)
                 // from our flow origin, since that is what `BaseFlow::overflow` is relative to.
@@ -1869,18 +1840,17 @@ impl BlockFlowDisplayListBuilding for Bl
                                 &self.base
                                      .early_absolute_position_info
                                      .relative_containing_block_size,
                                 self.base
                                     .early_absolute_position_info
                                     .relative_containing_block_mode,
                                 border_painting_mode,
                                 background_border_section,
-                                &self.base.clip,
-                                &self.base.stacking_relative_position_of_display_port);
+                                &self.base.clip);
 
         self.base.build_display_items_for_debugging_tint(state, self.fragment.node);
     }
 
     fn switch_coordinate_system_if_necessary(&mut self) {
         // Avoid overflows!
         if self.base.clip.is_max() {
             return
@@ -1977,18 +1947,17 @@ impl InlineFlowDisplayListBuilding for I
                                     &self.base
                                          .early_absolute_position_info
                                          .relative_containing_block_size,
                                     self.base
                                         .early_absolute_position_info
                                         .relative_containing_block_mode,
                                     BorderPaintingMode::Separate,
                                     DisplayListSection::Content,
-                                    &self.base.clip,
-                                    &self.base.stacking_relative_position_of_display_port);
+                                    &self.base.clip);
     }
 
     fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState) {
         // TODO(#228): Once we form lines and have their cached bounds, we can be smarter and
         // not recurse on a line if nothing in it can intersect the dirty region.
         debug!("Flow: building display list for {} inline fragments", self.fragments.len());
 
         // We iterate using an index here, because we want to avoid doing a doing
@@ -2034,20 +2003,17 @@ impl ListItemFlowDisplayListBuilding for
                                            .early_absolute_position_info
                                            .relative_containing_block_size,
                                       self.block_flow
                                           .base
                                           .early_absolute_position_info
                                           .relative_containing_block_mode,
                                       BorderPaintingMode::Separate,
                                       DisplayListSection::Content,
-                                      &self.block_flow.base.clip,
-                                      &self.block_flow
-                                           .base
-                                           .stacking_relative_position_of_display_port);
+                                      &self.block_flow.base.clip);
         }
 
         // Draw the rest of the block.
         self.block_flow.build_display_list_for_block(state, BorderPaintingMode::Separate)
     }
 }
 
 pub trait FlexFlowDisplayListBuilding {
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -24,17 +24,17 @@
 //!   fragments/flows that are subject to inline layout and line breaking and structs to represent
 //!   line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and
 //!   similar methods.
 
 use app_units::Au;
 use block::{BlockFlow, FormattingContextType};
 use context::{LayoutContext, SharedLayoutContext};
 use display_list_builder::DisplayListBuildState;
-use euclid::{Point2D, Rect, Size2D};
+use euclid::{Point2D, Size2D};
 use floats::{Floats, SpeculatedFloatPlacement};
 use flow_list::{FlowList, MutFlowListIterator};
 use flow_ref::{self, FlowRef, WeakFlowRef};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
 use gfx::display_list::{ClippingRegion, StackingContext};
 use gfx_traits::{LayerId, LayerType, StackingContextId};
 use gfx_traits::print_tree::PrintTree;
 use inline::InlineFlow;
@@ -935,22 +935,16 @@ pub struct BaseFlow {
     /// assignment.
     pub late_absolute_position_info: LateAbsolutePositionInfo,
 
     /// The clipping region for this flow and its descendants, in the coordinate system of the
     /// nearest ancestor stacking context. If this flow itself represents a stacking context, then
     /// this is in the flow's own coordinate system.
     pub clip: ClippingRegion,
 
-    /// The stacking-relative position of the display port.
-    ///
-    /// FIXME(pcwalton): This might be faster as an Arc, since this varies only
-    /// per-stacking-context.
-    pub stacking_relative_position_of_display_port: Rect<Au>,
-
     /// The writing mode for this flow.
     pub writing_mode: WritingMode,
 
     /// For debugging and profiling, the identifier of the thread that laid out this fragment.
     pub thread_id: u8,
 
     /// Various flags for flows, tightly packed to save space.
     pub flags: FlowFlags,
@@ -1119,17 +1113,16 @@ impl BaseFlow {
             speculated_float_placement_out: SpeculatedFloatPlacement::zero(),
             block_container_inline_size: Au(0),
             block_container_writing_mode: writing_mode,
             block_container_explicit_block_size: None,
             absolute_cb: ContainingBlockLink::new(),
             early_absolute_position_info: EarlyAbsolutePositionInfo::new(writing_mode),
             late_absolute_position_info: LateAbsolutePositionInfo::new(),
             clip: ClippingRegion::max(),
-            stacking_relative_position_of_display_port: Rect::zero(),
             flags: flags,
             writing_mode: writing_mode,
             thread_id: 0,
             stacking_context_id: StackingContextId::new(0),
         }
     }
 
     /// Return a new BaseFlow like this one but with the given children list
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -1561,33 +1561,29 @@ impl Flow for InlineFlow {
                         block_flow.base
                                   .late_absolute_position_info
                                   .stacking_relative_position_of_absolute_containing_block =
                             stacking_relative_position + *padding_box_origin;
                     }
 
                     block_flow.base.stacking_relative_position =
                         stacking_relative_content_box.origin;
-                    block_flow.base.stacking_relative_position_of_display_port =
-                        self.base.stacking_relative_position_of_display_port;
 
                     // Write the clip in our coordinate system into the child flow. (The kid will
                     // fix it up to be in its own coordinate system if necessary.)
                     block_flow.base.clip = self.base.clip.clone()
                 }
                 SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
                     let flow = flow_ref::deref_mut(&mut info.flow_ref);
                     let block_flow = flow.as_mut_block();
                     block_flow.base.late_absolute_position_info =
                         self.base.late_absolute_position_info;
 
                     block_flow.base.stacking_relative_position =
                         stacking_relative_border_box.origin;
-                    block_flow.base.stacking_relative_position_of_display_port =
-                        self.base.stacking_relative_position_of_display_port;
 
                     // As above, this is in our coordinate system for now.
                     block_flow.base.clip = self.base.clip.clone()
                 }
                 SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
                     let flow = flow_ref::deref_mut(&mut info.flow_ref);
                     let block_flow = flow.as_mut_block();
                     block_flow.base.late_absolute_position_info =
@@ -1597,18 +1593,16 @@ impl Flow for InlineFlow {
                     let padding_box_origin = containing_block_positions.next().unwrap();
                     block_flow.base
                               .late_absolute_position_info
                               .stacking_relative_position_of_absolute_containing_block =
                         stacking_relative_position + *padding_box_origin;
 
                     block_flow.base.stacking_relative_position =
                         stacking_relative_border_box.origin;
-                    block_flow.base.stacking_relative_position_of_display_port =
-                        self.base.stacking_relative_position_of_display_port;
 
                     // As above, this is in our coordinate system for now.
                     block_flow.base.clip = self.base.clip.clone()
                 }
                 _ => {}
             }
         }
 
--- a/servo/components/layout/webrender_helpers.rs
+++ b/servo/components/layout/webrender_helpers.rs
@@ -406,17 +406,17 @@ impl WebRenderDisplayItemConverter for D
                         origin.x = origin.x + glyph_advance;
                     };
                 }
 
                 if glyphs.len() > 0 {
                     builder.push_text(item.base.bounds.to_rectf(),
                                       item.base.clip.to_clip_region(frame_builder),
                                       glyphs,
-                                      item.text_run.font_key.expect("Font not added to webrender!"),
+                                      item.text_run.font_key,
                                       item.text_color.to_colorf(),
                                       item.text_run.actual_pt_size,
                                       item.blur_radius,
                                       &mut frame_builder.auxiliary_lists_builder);
                 }
             }
             DisplayItem::ImageClass(ref item) => {
                 if let Some(id) = item.webrender_image.key {
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -51,17 +51,16 @@ use euclid::rect::Rect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::Size2D;
 use fnv::FnvHasher;
 use gfx::display_list::{ClippingRegion, DisplayList, LayerInfo, OpaqueNode};
 use gfx::display_list::{StackingContext, StackingContextType, WebRenderImageInfo};
 use gfx::font;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context;
-use gfx::paint_thread::LayoutToPaintMsg;
 use gfx_traits::{Epoch, FragmentType, LayerId, ScrollPolicy, StackingContextId, color};
 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::display_list_builder::ToGfxColor;
@@ -115,17 +114,16 @@ use style::parallel::WorkQueueData;
 use style::parser::ParserContextExtraData;
 use style::selector_matching::Stylist;
 use style::stylesheets::{CSSRuleIteratorExt, Origin, Stylesheet, UserAgentStylesheets};
 use style::thread_state;
 use style::timer::Timer;
 use style::workqueue::WorkQueue;
 use url::Url;
 use util::geometry::max_rect;
-use util::ipc::OptionalIpcSender;
 use util::opts;
 use util::prefs::PREFS;
 use util::resource_files::read_resource_file;
 use util::thread;
 
 /// The number of screens we have to traverse before we decide to generate new display lists.
 const DISPLAY_PORT_THRESHOLD_SIZE_FACTOR: i32 = 4;
 
@@ -159,19 +157,16 @@ pub struct LayoutThread {
     font_cache_sender: IpcSender<()>,
 
     /// The channel on which messages can be sent to the constellation.
     constellation_chan: IpcSender<ConstellationMsg>,
 
     /// The channel on which messages can be sent to the script thread.
     script_chan: IpcSender<ConstellationControlMsg>,
 
-    /// The channel on which messages can be sent to the painting thread.
-    paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
-
     /// The channel on which messages can be sent to the time profiler.
     time_profiler_chan: time::ProfilerChan,
 
     /// The channel on which messages can be sent to the memory profiler.
     mem_profiler_chan: mem::ProfilerChan,
 
     /// The channel on which messages can be sent to the image cache.
     image_cache_thread: ImageCacheThread,
@@ -227,18 +222,18 @@ pub struct LayoutThread {
 
     /// The CSS error reporter for all CSS loaded in this layout thread
     error_reporter: CSSErrorReporter,
 
     webrender_image_cache: Arc<RwLock<HashMap<(Url, UsePlaceholder),
                                               WebRenderImageInfo,
                                               BuildHasherDefault<FnvHasher>>>>,
 
-    // Webrender interface, if enabled.
-    webrender_api: Option<webrender_traits::RenderApi>,
+    // 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
     // rather limit the dependency on that module here.
     layout_threads: usize,
@@ -250,38 +245,36 @@ impl LayoutThreadFactory for LayoutThrea
     /// Spawns a new layout thread.
     fn create(id: PipelineId,
               url: Url,
               is_iframe: bool,
               chan: (Sender<Msg>, Receiver<Msg>),
               pipeline_port: IpcReceiver<LayoutControlMsg>,
               constellation_chan: IpcSender<ConstellationMsg>,
               script_chan: IpcSender<ConstellationControlMsg>,
-              paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
               mem_profiler_chan: mem::ProfilerChan,
               content_process_shutdown_chan: IpcSender<()>,
-              webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+              webrender_api_sender: webrender_traits::RenderApiSender,
               layout_threads: usize) {
         thread::spawn_named(format!("LayoutThread {:?}", id),
                       move || {
             thread_state::initialize(thread_state::LAYOUT);
             PipelineId::install(id);
             { // Ensures layout thread is destroyed before we send shutdown message
                 let sender = chan.0;
                 let layout = LayoutThread::new(id,
                                              url,
                                              is_iframe,
                                              chan.1,
                                              pipeline_port,
                                              constellation_chan,
                                              script_chan,
-                                             paint_chan,
                                              image_cache_thread,
                                              font_cache_thread,
                                              time_profiler_chan,
                                              mem_profiler_chan.clone(),
                                              webrender_api_sender,
                                              layout_threads);
 
                 let reporter_name = format!("layout-reporter-{}", id);
@@ -383,22 +376,21 @@ impl LayoutThread {
     /// Creates a new `LayoutThread` structure.
     fn new(id: PipelineId,
            url: Url,
            is_iframe: bool,
            port: Receiver<Msg>,
            pipeline_port: IpcReceiver<LayoutControlMsg>,
            constellation_chan: IpcSender<ConstellationMsg>,
            script_chan: IpcSender<ConstellationControlMsg>,
-           paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
            image_cache_thread: ImageCacheThread,
            font_cache_thread: FontCacheThread,
            time_profiler_chan: time::ProfilerChan,
            mem_profiler_chan: mem::ProfilerChan,
-           webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+           webrender_api_sender: webrender_traits::RenderApiSender,
            layout_threads: usize)
            -> LayoutThread {
         let device = Device::new(
             MediaType::Screen,
             opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0));
         let parallel_traversal = if layout_threads != 1 {
             WorkQueue::new("LayoutWorker", thread_state::LAYOUT, layout_threads).ok()
         } else {
@@ -434,17 +426,16 @@ impl LayoutThread {
         LayoutThread {
             id: id,
             url: url,
             is_iframe: is_iframe,
             port: port,
             pipeline_port: pipeline_receiver,
             script_chan: script_chan.clone(),
             constellation_chan: constellation_chan.clone(),
-            paint_chan: paint_chan,
             time_profiler_chan: time_profiler_chan,
             mem_profiler_chan: mem_profiler_chan,
             image_cache_thread: image_cache_thread,
             font_cache_thread: font_cache_thread,
             first_reflow: true,
             image_cache_receiver: image_cache_receiver,
             image_cache_sender: ImageCacheChan(ipc_image_cache_sender),
             font_cache_receiver: font_cache_receiver,
@@ -455,17 +446,17 @@ impl LayoutThread {
             new_animations_receiver: new_animations_receiver,
             outstanding_web_fonts: outstanding_web_fonts_counter,
             root_flow: None,
             visible_rects: Arc::new(HashMap::with_hasher(Default::default())),
             running_animations: Arc::new(RwLock::new(HashMap::new())),
             expired_animations: Arc::new(RwLock::new(HashMap::new())),
             epoch: Epoch(0),
             viewport_size: Size2D::new(Au(0), Au(0)),
-            webrender_api: webrender_api_sender.map(|wr| wr.create_api()),
+            webrender_api: webrender_api_sender.create_api(),
             rw_data: Arc::new(Mutex::new(
                 LayoutThreadData {
                     constellation_chan: constellation_chan,
                     display_list: None,
                     stylist: stylist,
                     content_box_response: Rect::zero(),
                     content_boxes_response: Vec::new(),
                     client_rect_response: Rect::zero(),
@@ -758,23 +749,22 @@ impl LayoutThread {
     fn create_layout_thread(&self, info: NewLayoutThreadInfo) {
         LayoutThread::create(info.id,
                              info.url.clone(),
                              info.is_parent,
                              info.layout_pair,
                              info.pipeline_port,
                              info.constellation_chan,
                              info.script_chan.clone(),
-                             info.paint_chan.to::<LayoutToPaintMsg>(),
                              self.image_cache_thread.clone(),
                              self.font_cache_thread.clone(),
                              self.time_profiler_chan.clone(),
                              self.mem_profiler_chan.clone(),
                              info.content_process_shutdown_chan,
-                             self.webrender_api.as_ref().map(|wr| wr.clone_sender()),
+                             self.webrender_api.clone_sender(),
                              info.layout_threads);
     }
 
     /// Enters a quiescent state in which no new messages will be processed until an `ExitNow` is
     /// received. A pong is immediately sent on the given response channel.
     fn prepare_to_exit(&mut self, response_chan: Sender<()>) {
         response_chan.send(()).unwrap();
         loop {
@@ -800,18 +790,16 @@ impl LayoutThread {
     }
 
     /// Shuts down the layout thread now. If there are any DOM nodes left, layout will now (safely)
     /// crash.
     fn exit_now(&mut self) {
         if let Some(ref mut traversal) = self.parallel_traversal {
             traversal.shutdown()
         }
-
-        let _ = self.paint_chan.send(LayoutToPaintMsg::Exit);
     }
 
     fn handle_add_stylesheet<'a, 'b>(&self,
                                      stylesheet: Arc<Stylesheet>,
                                      possibly_locked_rw_data: &mut RwData<'a, 'b>) {
         // Find all font-face rules and notify the font cache of them.
         // GWTODO: Need to handle unloading web fonts.
 
@@ -1004,55 +992,48 @@ impl LayoutThread {
             if opts::get().dump_display_list_json {
                 println!("{}", serde_json::to_string_pretty(&display_list).unwrap());
             }
 
             debug!("Layout done!");
 
             self.epoch.next();
 
-            if let Some(ref mut webrender_api) = self.webrender_api {
-                // TODO: Avoid the temporary conversion and build webrender sc/dl directly!
-                let Epoch(epoch_number) = self.epoch;
-                let epoch = webrender_traits::Epoch(epoch_number);
-                let pipeline_id = self.id.to_webrender();
+            // TODO: Avoid the temporary conversion and build webrender sc/dl directly!
+            let Epoch(epoch_number) = self.epoch;
+            let epoch = webrender_traits::Epoch(epoch_number);
+            let pipeline_id = self.id.to_webrender();
 
-                // TODO(gw) For now only create a root scrolling layer!
-                let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
-                let root_scroll_layer_id = frame_builder.next_scroll_layer_id();
-                let sc_id = rw_data.display_list.as_ref().unwrap().convert_to_webrender(
-                    webrender_api,
-                    pipeline_id,
-                    epoch,
-                    Some(root_scroll_layer_id),
-                    &mut frame_builder);
-                let root_background_color = get_root_flow_background_color(layout_root);
-                let root_background_color =
-                    webrender_traits::ColorF::new(root_background_color.r,
-                                                  root_background_color.g,
-                                                  root_background_color.b,
-                                                  root_background_color.a);
+            // TODO(gw) For now only create a root scrolling layer!
+            let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
+            let root_scroll_layer_id = frame_builder.next_scroll_layer_id();
+            let sc_id = rw_data.display_list.as_ref().unwrap().convert_to_webrender(
+                &mut self.webrender_api,
+                pipeline_id,
+                epoch,
+                Some(root_scroll_layer_id),
+                &mut frame_builder);
+            let root_background_color = get_root_flow_background_color(layout_root);
+            let root_background_color =
+                webrender_traits::ColorF::new(root_background_color.r,
+                                              root_background_color.g,
+                                              root_background_color.b,
+                                              root_background_color.a);
 
-                let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(),
-                                                self.viewport_size.height.to_f32_px());
+            let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(),
+                                            self.viewport_size.height.to_f32_px());
 
-                webrender_api.set_root_stacking_context(
-                    sc_id,
-                    root_background_color,
-                    epoch,
-                    pipeline_id,
-                    viewport_size,
-                    frame_builder.stacking_contexts,
-                    frame_builder.display_lists,
-                    frame_builder.auxiliary_lists_builder.finalize());
-            } else {
-                self.paint_chan
-                    .send(LayoutToPaintMsg::PaintInit(self.epoch, display_list))
-                    .unwrap();
-            }
+            self.webrender_api.set_root_stacking_context(sc_id,
+                                                         root_background_color,
+                                                         epoch,
+                                                         pipeline_id,
+                                                         viewport_size,
+                                                         frame_builder.stacking_contexts,
+                                                         frame_builder.display_lists,
+                                                         frame_builder.auxiliary_lists_builder.finalize());
         });
     }
 
     /// The high-level routine that performs layout threads.
     fn handle_reflow<'a, 'b>(&mut self,
                              data: &ScriptReflow,
                              possibly_locked_rw_data: &mut RwData<'a, 'b>) {
         let document = unsafe { ServoLayoutNode::new(&data.document) };
--- a/servo/components/layout_traits/Cargo.toml
+++ b/servo/components/layout_traits/Cargo.toml
@@ -10,16 +10,15 @@ name = "layout_traits"
 path = "lib.rs"
 
 [dependencies]
 gfx = {path = "../gfx"}
 script_traits = {path = "../script_traits"}
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 profile_traits = {path = "../profile_traits"}
-util = {path = "../util"}
 ipc-channel = "0.5"
 url = {version = "1.2", features = ["heap_size"]}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
 default_features = false
 features = ["serde_derive"]
--- a/servo/components/layout_traits/lib.rs
+++ b/servo/components/layout_traits/lib.rs
@@ -6,48 +6,44 @@
 
 extern crate gfx;
 extern crate ipc_channel;
 extern crate msg;
 extern crate net_traits;
 extern crate profile_traits;
 extern crate script_traits;
 extern crate url;
-extern crate util;
 extern crate webrender_traits;
 
 // This module contains traits in layout used generically
 //   in the rest of Servo.
 // The traits are here instead of in layout so
 //   that these modules won't have to depend on layout.
 
 use gfx::font_cache_thread::FontCacheThread;
-use gfx::paint_thread::LayoutToPaintMsg;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use msg::constellation_msg::PipelineId;
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::{mem, time};
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
 use script_traits::LayoutMsg as ConstellationMsg;
 use std::sync::mpsc::{Receiver, Sender};
 use url::Url;
-use util::ipc::OptionalIpcSender;
 
 // A static method creating a layout thread
 // Here to remove the compositor -> layout dependency
 pub trait LayoutThreadFactory {
     type Message;
     fn create(id: PipelineId,
               url: Url,
               is_iframe: bool,
               chan: (Sender<Self::Message>, Receiver<Self::Message>),
               pipeline_port: IpcReceiver<LayoutControlMsg>,
               constellation_chan: IpcSender<ConstellationMsg>,
               script_chan: IpcSender<ConstellationControlMsg>,
-              layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
               mem_profiler_chan: mem::ProfilerChan,
               content_process_shutdown_chan: IpcSender<()>,
-              webrender_api_sender: Option<webrender_traits::RenderApiSender>,
+              webrender_api_sender: webrender_traits::RenderApiSender,
               layout_threads: usize);
 }
--- a/servo/components/net/image_cache_thread.rs
+++ b/servo/components/net/image_cache_thread.rs
@@ -247,18 +247,18 @@ struct ImageCache {
     pending_loads: AllPendingLoads,
 
     // Images that have finished loading (successful or not)
     completed_loads: HashMap<Arc<Url>, CompletedLoad>,
 
     // The placeholder image used when an image fails to load
     placeholder_image: Option<Arc<Image>>,
 
-    // Webrender API instance, if enabled.
-    webrender_api: Option<webrender_traits::RenderApi>,
+    // Webrender API instance.
+    webrender_api: webrender_traits::RenderApi,
 }
 
 /// Message that the decoder worker threads send to main image cache thread.
 struct DecoderMsg {
     key: LoadKey,
     image: Option<Image>,
 }
 
@@ -313,34 +313,33 @@ impl LoadOrigin for ImageCacheOrigin {
     fn referrer_policy(&self) -> Option<ReferrerPolicy> {
         None
     }
     fn pipeline_id(&self) -> Option<PipelineId> {
         None
     }
 }
 
-fn get_placeholder_image(webrender_api: &Option<webrender_traits::RenderApi>) -> io::Result<Arc<Image>> {
+fn get_placeholder_image(webrender_api: &webrender_traits::RenderApi) -> io::Result<Arc<Image>> {
     let mut placeholder_path = try!(resources_dir_path());
     placeholder_path.push("rippy.png");
     let mut file = try!(File::open(&placeholder_path));
     let mut image_data = vec![];
     try!(file.read_to_end(&mut image_data));
     let mut image = load_from_memory(&image_data).unwrap();
-    if let Some(ref webrender_api) = *webrender_api {
-        let format = convert_format(image.format);
-        let mut bytes = Vec::new();
-        bytes.extend_from_slice(&*image.bytes);
-        image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
-    }
+    let format = convert_format(image.format);
+    let mut bytes = Vec::new();
+    bytes.extend_from_slice(&*image.bytes);
+    image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
     Ok(Arc::new(image))
 }
+
 impl ImageCache {
     fn run(core_resource_thread: CoreResourceThread,
-           webrender_api: Option<webrender_traits::RenderApi>,
+           webrender_api: webrender_traits::RenderApi,
            ipc_command_receiver: IpcReceiver<ImageCacheCommand>) {
         // Preload the placeholder image, used when images fail to load.
         let placeholder_image = get_placeholder_image(&webrender_api).ok();
 
         // Ask the router to proxy messages received over IPC to us.
         let cmd_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_command_receiver);
 
         let (progress_sender, progress_receiver) = channel();
@@ -474,26 +473,24 @@ impl ImageCache {
         };
         self.complete_load(msg.key, image);
     }
 
     // Change state of a url from pending -> loaded.
     fn complete_load(&mut self, key: LoadKey, mut load_result: LoadResult) {
         let pending_load = self.pending_loads.remove(&key).unwrap();
 
-        if let Some(ref webrender_api) = self.webrender_api {
-            match load_result {
-                LoadResult::Loaded(ref mut image) => {
-                    let format = convert_format(image.format);
-                    let mut bytes = Vec::new();
-                    bytes.extend_from_slice(&*image.bytes);
-                    image.id = Some(webrender_api.add_image(image.width, image.height, format, bytes));
-                }
-                LoadResult::PlaceholderLoaded(..) | LoadResult::None => {}
+        match load_result {
+            LoadResult::Loaded(ref mut image) => {
+                let format = convert_format(image.format);
+                let mut bytes = Vec::new();
+                bytes.extend_from_slice(&*image.bytes);
+                image.id = Some(self.webrender_api.add_image(image.width, image.height, format, bytes));
             }
+            LoadResult::PlaceholderLoaded(..) | LoadResult::None => {}
         }
 
         let image_response = match load_result {
             LoadResult::Loaded(image) => ImageResponse::Loaded(Arc::new(image)),
             LoadResult::PlaceholderLoaded(image) => ImageResponse::PlaceholderLoaded(image),
             LoadResult::None => ImageResponse::None,
         };
 
@@ -622,17 +619,17 @@ impl ImageCache {
             action: action,
             key: load_key,
         });
     }
 }
 
 /// Create a new image cache.
 pub fn new_image_cache_thread(core_resource_thread: CoreResourceThread,
-                              webrender_api: Option<webrender_traits::RenderApi>) -> ImageCacheThread {
+                              webrender_api: webrender_traits::RenderApi) -> ImageCacheThread {
     let (ipc_command_sender, ipc_command_receiver) = ipc::channel().unwrap();
 
     spawn_named("ImageCacheThread".to_owned(), move || {
         ImageCache::run(core_resource_thread, webrender_api, ipc_command_receiver)
     });
 
     ImageCacheThread::new(ipc_command_sender)
 }
--- a/servo/components/net_traits/image/base.rs
+++ b/servo/components/net_traits/image/base.rs
@@ -1,49 +1,38 @@
 /* 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 ipc_channel::ipc::IpcSharedMemory;
 use piston_image::{self, DynamicImage, ImageFormat};
-use util::opts;
 
 pub use msg::constellation_msg::{Image, PixelFormat};
 
 #[derive(Clone, Deserialize, Eq, PartialEq, Serialize, HeapSizeOf)]
 pub struct ImageMetadata {
     pub width: u32,
     pub height: u32,
 }
 
 // FIXME: Images must not be copied every frame. Instead we should atomically
 // reference count them.
 
 // TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this.
 fn byte_swap_and_premultiply(data: &mut [u8]) {
     let length = data.len();
 
-    // No need to pre-multiply alpha when using direct GPU rendering.
-    let premultiply_alpha = !opts::get().use_webrender;
-
     for i in (0..length).step_by(4) {
         let r = data[i + 2];
         let g = data[i + 1];
         let b = data[i + 0];
-        let a = data[i + 3];
 
-        if premultiply_alpha {
-            data[i + 0] = ((r as u32) * (a as u32) / 255) as u8;
-            data[i + 1] = ((g as u32) * (a as u32) / 255) as u8;
-            data[i + 2] = ((b as u32) * (a as u32) / 255) as u8;
-        } else {
-            data[i + 0] = r;
-            data[i + 1] = g;
-            data[i + 2] = b;
-        }
+        data[i + 0] = r;
+        data[i + 1] = g;
+        data[i + 2] = b;
     }
 }
 
 pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
     if buffer.is_empty() {
         return None;
     }
 
--- a/servo/components/script/dom/canvasrenderingcontext2d.rs
+++ b/servo/components/script/dom/canvasrenderingcontext2d.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 canvas_traits::{Canvas2dMsg, CanvasCommonMsg, CanvasMsg};
 use canvas_traits::{CompositionOrBlending, FillOrStrokeStyle, FillRule};
 use canvas_traits::{LineCapStyle, LineJoinStyle, LinearGradientStyle};
-use canvas_traits::{RadialGradientStyle, RepetitionStyle, byte_swap, byte_swap_and_premultiply};
+use canvas_traits::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply};
 use cssparser::{Parser, RGBA};
 use cssparser::Color as CSSColor;
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
 use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding;
 use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule;
 use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap;
 use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin;
@@ -42,17 +42,16 @@ use net_traits::image::base::PixelFormat
 use net_traits::image_cache_thread::ImageResponse;
 use num_traits::ToPrimitive;
 use script_traits::ScriptMsg as ConstellationMsg;
 use std::{cmp, fmt};
 use std::cell::Cell;
 use std::str::FromStr;
 use unpremultiplytable::UNPREMULTIPLY_TABLE;
 use url::Url;
-use util::opts;
 
 #[must_root]
 #[derive(JSTraceable, Clone, HeapSizeOf)]
 #[allow(dead_code)]
 enum CanvasFillOrStrokeStyle {
     Color(RGBA),
     Gradient(JS<CanvasGradient>),
     Pattern(JS<CanvasPattern>),
@@ -292,24 +291,17 @@ impl CanvasRenderingContext2D {
             HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::HTMLImageElement(ref image) => {
                 // https://html.spec.whatwg.org/multipage/#img-error
                 // If the image argument is an HTMLImageElement object that is in the broken state,
                 // then throw an InvalidStateError exception
                 let (image_data, image_size) = match self.fetch_image_data(image) {
                     Some((mut data, size)) => {
                         // Pixels come from cache in BGRA order and drawImage expects RGBA so we
                         // have to swap the color values
-                        if opts::get().use_webrender {
-                            // Webrender doesn't pre-multiply alpha when decoding
-                            // images, but canvas expects the images to be
-                            // pre-multiplied alpha.
-                            byte_swap_and_premultiply(&mut data);
-                        } else {
-                            byte_swap(&mut data);
-                        }
+                        byte_swap_and_premultiply(&mut data);
                         let size = Size2D::new(size.width as f64, size.height as f64);
                         (data, size)
                     },
                     None => return Err(Error::InvalidState),
                 };
                 let dw = dw.unwrap_or(image_size.width);
                 let dh = dh.unwrap_or(image_size.height);
                 let sw = sw.unwrap_or(image_size.width);
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -1215,52 +1215,30 @@ impl Window {
         assert!(self.reflow(ReflowGoal::ForScriptQuery,
                             ReflowQueryType::NodeOverflowQuery(node),
                             ReflowReason::Query));
 
         self.layout_rpc.node_overflow().0.unwrap()
     }
 
     pub fn scroll_offset_query(&self, node: &Node) -> Point2D<f32> {
-        // WebRender always keeps the scroll offsets up to date and stored here in the window. So,
-        // if WR is in use, all we need to do is to check our list of scroll offsets and return the
-        // result.
-        if opts::get().use_webrender {
-            let mut node = Root::from_ref(node);
-            loop {
-                if let Some(scroll_offset) = self.scroll_offsets
-                                                 .borrow()
-                                                 .get(&node.to_untrusted_node_address()) {
-                    return *scroll_offset
-                }
-                node = match node.GetParentNode() {
-                    Some(node) => node,
-                    None => break,
-                }
+        let mut node = Root::from_ref(node);
+        loop {
+            if let Some(scroll_offset) = self.scroll_offsets
+                                             .borrow()
+                                             .get(&node.to_untrusted_node_address()) {
+                return *scroll_offset
             }
-            let offset = self.current_viewport.get().origin;
-            return Point2D::new(offset.x.to_f32_px(), offset.y.to_f32_px())
-        }
-
-        let node = node.to_trusted_node_address();
-        if !self.reflow(ReflowGoal::ForScriptQuery,
-                        ReflowQueryType::NodeLayerIdQuery(node),
-                        ReflowReason::Query) {
-            return Point2D::zero();
+            node = match node.GetParentNode() {
+                Some(node) => node,
+                None => break,
+            }
         }
-
-        let layer_id = self.layout_rpc.node_layer_id().layer_id;
-
-        let (send, recv) = ipc::channel::<Point2D<f32>>().unwrap();
-        let global_scope = self.upcast::<GlobalScope>();
-        global_scope
-            .constellation_chan()
-            .send(ConstellationMsg::GetScrollOffset(global_scope.pipeline_id(), layer_id, send))
-            .unwrap();
-        recv.recv().unwrap_or(Point2D::zero())
+        let offset = self.current_viewport.get().origin;
+        Point2D::new(offset.x.to_f32_px(), offset.y.to_f32_px())
     }
 
     // https://drafts.csswg.org/cssom-view/#dom-element-scroll
     pub fn scroll_node(&self, node: TrustedNodeAddress,
                        x_: f64, y_: f64, behavior: ScrollBehavior) {
         if !self.reflow(ReflowGoal::ForScriptQuery,
                         ReflowQueryType::NodeLayerIdQuery(node),
                         ReflowReason::Query) {
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -1138,34 +1138,32 @@ impl ScriptThread {
     }
 
     fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
         let NewLayoutInfo {
             parent_pipeline_id,
             new_pipeline_id,
             frame_type,
             load_data,
-            paint_chan,
             pipeline_port,
             layout_to_constellation_chan,
             content_process_shutdown_chan,
             layout_threads,
         } = new_layout_info;
 
         let layout_pair = channel();
         let layout_chan = layout_pair.0.clone();
 
         let layout_creation_info = NewLayoutThreadInfo {
             id: new_pipeline_id,
             url: load_data.url.clone(),
             is_parent: false,
             layout_pair: layout_pair,
             pipeline_port: pipeline_port,
             constellation_chan: layout_to_constellation_chan,
-            paint_chan: paint_chan,
             script_chan: self.control_chan.clone(),
             image_cache_thread: self.image_cache_thread.clone(),
             content_process_shutdown_chan: content_process_shutdown_chan,
             layout_threads: layout_threads,
         };
 
         let context = self.root_browsing_context();
         let parent_context = context.find(parent_pipeline_id).expect("ScriptThread: received a layout
--- a/servo/components/script_layout_interface/Cargo.toml
+++ b/servo/components/script_layout_interface/Cargo.toml
@@ -26,9 +26,8 @@ net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 script_traits = {path = "../script_traits"}
 selectors = "0.13"
 string_cache = {version = "0.2.26", features = ["heap_size"]}
 style = {path = "../style"}
 url = {version = "1.2", features = ["heap_size"]}
-util = {path = "../util"}
--- a/servo/components/script_layout_interface/lib.rs
+++ b/servo/components/script_layout_interface/lib.rs
@@ -34,17 +34,16 @@ extern crate net_traits;
 extern crate profile_traits;
 extern crate range;
 extern crate script_traits;
 extern crate selectors;
 #[macro_use(atom, ns)]
 extern crate string_cache;
 extern crate style;
 extern crate url;
-extern crate util;
 
 pub mod message;
 pub mod reporter;
 pub mod restyle_damage;
 pub mod rpc;
 pub mod wrapper_traits;
 
 use canvas_traits::CanvasMsg;
--- a/servo/components/script_layout_interface/message.rs
+++ b/servo/components/script_layout_interface/message.rs
@@ -16,17 +16,16 @@ use script_traits::{ConstellationControl
 use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender};
 use string_cache::Atom;
 use style::context::ReflowGoal;
 use style::selector_impl::PseudoElement;
 use style::stylesheets::Stylesheet;
 use url::Url;
-use util::ipc::OptionalOpaqueIpcSender;
 
 /// Asynchronous messages that script can send to layout.
 pub enum Msg {
     /// Adds the given stylesheet to the document.
     AddStylesheet(Arc<Stylesheet>),
 
     /// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
     SetQuirksMode,
@@ -143,12 +142,11 @@ pub struct NewLayoutThreadInfo {
     pub id: PipelineId,
     pub url: Url,
     pub is_parent: bool,
     pub layout_pair: (Sender<Msg>, Receiver<Msg>),
     pub pipeline_port: IpcReceiver<LayoutControlMsg>,
     pub constellation_chan: IpcSender<ConstellationMsg>,
     pub script_chan: IpcSender<ConstellationControlMsg>,
     pub image_cache_thread: ImageCacheThread,
-    pub paint_chan: OptionalOpaqueIpcSender,
     pub content_process_shutdown_chan: IpcSender<()>,
     pub layout_threads: usize,
 }
--- a/servo/components/script_traits/Cargo.toml
+++ b/servo/components/script_traits/Cargo.toml
@@ -15,22 +15,20 @@ canvas_traits = {path = "../canvas_trait
 cookie = {version = "0.2.5", features = ["serialize-rustc"]}
 devtools_traits = {path = "../devtools_traits"}
 euclid = "0.10.1"
 gfx_traits = {path = "../gfx_traits"}
 heapsize = "0.3.0"
 heapsize_plugin = "0.1.2"
 hyper_serde = "0.1.4"
 ipc-channel = "0.5"
-layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
 libc = "0.2"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 offscreen_gl_context = "0.4"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rustc-serialize = "0.3.4"
 serde = "0.8"
 serde_derive = "0.8"
 style_traits = {path = "../style_traits", features = ["servo"]}
 time = "0.1.12"
 url = {version = "1.2", features = ["heap_size"]}
-util = {path = "../util"}
--- a/servo/components/script_traits/lib.rs
+++ b/servo/components/script_traits/lib.rs
@@ -15,65 +15,62 @@ extern crate app_units;
 extern crate canvas_traits;
 extern crate cookie as cookie_rs;
 extern crate devtools_traits;
 extern crate euclid;
 extern crate gfx_traits;
 extern crate heapsize;
 extern crate hyper_serde;
 extern crate ipc_channel;
-extern crate layers;
 extern crate libc;
 extern crate msg;
 extern crate net_traits;
 extern crate offscreen_gl_context;
 extern crate profile_traits;
 extern crate rustc_serialize;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate style_traits;
 extern crate time;
 extern crate url;
-extern crate util;
 
 mod script_msg;
 pub mod webdriver_msg;
 
 use app_units::Au;
 use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
 use euclid::Size2D;
 use euclid::length::Length;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
+use gfx_traits::DevicePixel;
 use gfx_traits::Epoch;
 use gfx_traits::LayerId;
 use gfx_traits::StackingContextId;
 use heapsize::HeapSizeOf;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
-use layers::geometry::DevicePixel;
 use libc::c_void;
 use msg::constellation_msg::{FrameId, FrameType, Image, Key, KeyModifiers, KeyState, LoadData};
 use msg::constellation_msg::{PipelineId, PipelineNamespaceId, ReferrerPolicy};
 use msg::constellation_msg::{TraversalDirection, WindowSizeType};
 use net_traits::{LoadOrigin, ResourceThreads};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::image_cache_thread::ImageCacheThread;
 use net_traits::response::HttpsState;
 use profile_traits::mem;
 use profile_traits::time as profile_time;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
 use std::collections::HashMap;
 use std::fmt;
 use std::sync::mpsc::{Receiver, Sender};
 use style_traits::{PagePx, UnsafeNode, ViewportPx};
 use url::Url;
-use util::ipc::OptionalOpaqueIpcSender;
 use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
 
 pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
 pub use script_msg::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
 
 /// The address of a node. Layout sends these back. They must be validated via
 /// `from_untrusted_node_address` before they can be used, because we do not trust layout.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -133,19 +130,16 @@ pub struct NewLayoutInfo {
     /// Id of the parent of this new pipeline.
     pub parent_pipeline_id: PipelineId,
     /// Id of the newly-created pipeline.
     pub new_pipeline_id: PipelineId,
     /// Type of the new frame associated with this pipeline.
     pub frame_type: FrameType,
     /// Network request data which will be initiated by the script thread.
     pub load_data: LoadData,
-    /// The paint channel, cast to `OptionalOpaqueIpcSender`. This is really an
-    /// `Sender<LayoutToPaintMsg>`.
-    pub paint_chan: OptionalOpaqueIpcSender,
     /// A port on which layout can receive messages from the pipeline.
     pub pipeline_port: IpcReceiver<LayoutControlMsg>,
     /// A sender for the layout thread to communicate to the constellation.
     pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
     /// A shutdown channel so that layout can tell the content process to shut down when it's done.
     pub content_process_shutdown_chan: IpcSender<()>,
     /// Number of threads to use for layout.
     pub layout_threads: usize,
--- a/servo/components/script_traits/script_msg.rs
+++ b/servo/components/script_traits/script_msg.rs
@@ -123,18 +123,16 @@ pub enum ScriptMsg {
     /// Get Window Informations size and position
     GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
     /// Move the window to a point
     MoveTo(Point2D<i32>),
     /// Resize the window to size
     ResizeTo(Size2D<u32>),
     /// Script has handled a touch event, and either prevented or allowed default actions.
     TouchEventProcessed(EventResult),
-    /// Get Scroll Offset
-    GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>),
     /// A log entry, with the pipeline id and thread name
     LogEntry(Option<PipelineId>, Option<String>, LogEntry),
     /// Notifies the constellation that this pipeline has exited.
     PipelineExited(PipelineId),
     /// Send messages from postMessage calls from serviceworker
     /// to constellation for storing in service worker manager
     ForwardDOMMessage(DOMMessage, Url),
     /// Store the data required to activate a service worker for the given scope
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -316,24 +316,21 @@ 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 = [
- "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "azure 0.9.0 (git+https://github.com/servo/rust-azure)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "gleam 0.2.22 (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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "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.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -354,17 +351,16 @@ dependencies = [
  "canvas_traits 0.0.1",
  "compositing 0.0.1",
  "devtools_traits 0.0.1",
  "euclid 0.10.2 (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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "layout_traits 0.0.1",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "offscreen_gl_context 0.4.3 (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)",
@@ -792,27 +788,24 @@ dependencies = [
  "fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "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_plugin 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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.2.3 (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)",
  "range 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "simd 0.1.1 (git+https://github.com/huonw/simd)",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -836,23 +829,19 @@ dependencies = [
  "style 0.0.1",
 ]
 
 [[package]]
 name = "gfx_traits"
 version = "0.0.1"
 dependencies = [
  "azure 0.9.0 (git+https://github.com/servo/rust-azure)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
- "msg 0.0.1",
  "plugins 0.0.1",
- "profile_traits 0.0.1",
  "range 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gif"
@@ -889,18 +878,18 @@ source = "registry+https://github.com/ru
 [[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)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gfx_traits 0.0.1",
  "gleam 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "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 (git+https://github.com/daggerbot/osmesa-rs)",
  "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)",
@@ -1136,36 +1125,16 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "language-tags"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "layers"
-version = "0.5.3"
-source = "git+https://github.com/servo/rust-layers#b064de859b2cf3f4e07b29ee11a34543f1671ac0"
-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)",
- "gleam 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "heapsize 0.3.7 (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.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "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)",
- "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-skia 0.20130412.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "azure 0.9.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
  "cssparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1245,17 +1214,16 @@ version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "webrender_traits 0.6.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -2044,17 +2012,16 @@ dependencies = [
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.2.29 (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",
 ]
 
 [[package]]
 name = "script_tests"
 version = "0.0.1"
 dependencies = [
  "msg 0.0.1",
  "plugins 0.0.1",
@@ -2071,30 +2038,28 @@ dependencies = [
  "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)",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.6 (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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "offscreen_gl_context 0.4.3 (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.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "selectors"
 version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2911,17 +2876,16 @@ dependencies = [
 "checksum io-surface 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c93eb4952ee5b903c4193391779f90209e1b75ba55911097fa494f35e975846"
 "checksum ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "675587430ede6756dd03fdfdf9888f22f83855fd131c8451d842a710b059e571"
 "checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
 "checksum jpeg-decoder 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "70be4c5ed7c80bb403fb28d95d30dd97ccf76829e943ae2350037fd6cd6961b6"
 "checksum js 0.1.3 (git+https://github.com/servo/rust-mozjs)" = "<none>"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c9d3760673c427d46f91a0350f0a84a52e6bc5a84adf26dc610b6c52436630"
 "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
-"checksum layers 0.5.3 (git+https://github.com/servo/rust-layers)" = "<none>"
 "checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
 "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
 "checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73"
 "checksum leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc"
 "checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
 "checksum libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eceb2637ee9a27c7f19764048a9f377e40e3a70a322722f348e6bc7704d565f2"
 "checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71"
 "checksum libz-sys 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "40f2df7730b5d29426c3e44ce4d088d8c5def6471c2c93ba98585b89fb201ce6"
--- a/servo/components/servo/lib.rs
+++ b/servo/components/servo/lib.rs
@@ -128,67 +128,60 @@ impl<Window> Browser<Window> where Windo
         let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
         if let Some(port) = opts.debugger_port {
             debugger::start_server(port)
         }
         let devtools_chan = opts.devtools_port.map(|port| {
             devtools::start_server(port)
         });
 
-        let (webrender, webrender_api_sender) = if opts::get().use_webrender {
-            if let Ok(mut resource_path) = resources_dir_path() {
-                resource_path.push("shaders");
+        let mut resource_path = resources_dir_path().unwrap();
+        resource_path.push("shaders");
 
-                // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up!
-                let scale_factor = window.scale_factor().get();
-                let device_pixel_ratio = match opts.device_pixels_per_px {
-                    Some(device_pixels_per_px) => device_pixels_per_px,
-                    None => match opts.output_file {
-                        Some(_) => 1.0,
-                        None => scale_factor,
-                    }
-                };
-
-                let renderer_kind = if opts::get().should_use_osmesa() {
-                    webrender_traits::RendererKind::OSMesa
-                } else {
-                    webrender_traits::RendererKind::Native
-                };
+        let (webrender, webrender_api_sender) = {
+            // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up!
+            let scale_factor = window.scale_factor().get();
+            let device_pixel_ratio = match opts.device_pixels_per_px {
+                Some(device_pixels_per_px) => device_pixels_per_px,
+                None => match opts.output_file {
+                    Some(_) => 1.0,
+                    None => scale_factor,
+                }
+            };
 
-                let (webrender, webrender_sender) =
-                    webrender::Renderer::new(webrender::RendererOptions {
-                        device_pixel_ratio: device_pixel_ratio,
-                        resource_path: resource_path,
-                        enable_aa: opts.enable_text_antialiasing,
-                        enable_msaa: opts.use_msaa,
-                        enable_profiler: opts.webrender_stats,
-                        debug: opts.webrender_debug,
-                        enable_recording: false,
-                        precache_shaders: opts.precache_shaders,
-                        enable_scrollbars: opts.output_file.is_none(),
-                        renderer_kind: renderer_kind,
-                    });
-                (Some(webrender), Some(webrender_sender))
+            let renderer_kind = if opts::get().should_use_osmesa() {
+                webrender_traits::RendererKind::OSMesa
             } else {
-                (None, None)
-            }
-        } else {
-            (None, None)
+                webrender_traits::RendererKind::Native
+            };
+
+            webrender::Renderer::new(webrender::RendererOptions {
+                device_pixel_ratio: device_pixel_ratio,
+                resource_path: resource_path,
+                enable_aa: opts.enable_text_antialiasing,
+                enable_msaa: opts.use_msaa,
+                enable_profiler: opts.webrender_stats,
+                debug: opts.webrender_debug,
+                enable_recording: false,
+                precache_shaders: opts.precache_shaders,
+                enable_scrollbars: opts.output_file.is_none(),
+                renderer_kind: renderer_kind,
+            })
         };
 
         // Create the constellation, which maintains the engine
         // pipelines, including the script and layout threads, as well
         // as the navigation context.
         let (constellation_chan, sw_senders) = create_constellation(opts.clone(),
-                                                                          compositor_proxy.clone_compositor_proxy(),
-                                                                          time_profiler_chan.clone(),
-                                                                          mem_profiler_chan.clone(),
-                                                                          devtools_chan,
-                                                                          supports_clipboard,
-                                                                          webrender_api_sender.clone());
+                                                                    compositor_proxy.clone_compositor_proxy(),
+                                                                    time_profiler_chan.clone(),
+                                                                    mem_profiler_chan.clone(),
+                                                                    devtools_chan,
+                                                                    supports_clipboard,
+                                                                    webrender_api_sender.clone());
 
         // Send the constellation's swmanager sender to service worker manager thread
         script::init(sw_senders);
 
         if cfg!(feature = "webdriver") {
             if let Some(port) = opts.webdriver_port {
                 webdriver(port, constellation_chan.clone());
             }
@@ -242,29 +235,29 @@ impl<Window> Browser<Window> where Windo
 }
 
 fn create_constellation(opts: opts::Opts,
                         compositor_proxy: Box<CompositorProxy + Send>,
                         time_profiler_chan: time::ProfilerChan,
                         mem_profiler_chan: mem::ProfilerChan,
                         devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                         supports_clipboard: bool,
-                        webrender_api_sender: Option<webrender_traits::RenderApiSender>)
+                        webrender_api_sender: webrender_traits::RenderApiSender)
                         -> (Sender<ConstellationMsg>, SWManagerSenders) {
     let bluetooth_thread: IpcSender<BluetoothMethodMsg> = BluetoothThreadFactory::new();
 
     let (public_resource_threads, private_resource_threads) =
         new_resource_threads(opts.user_agent,
                              devtools_chan.clone(),
                              time_profiler_chan.clone(),
                              opts.config_dir.map(Into::into));
     let image_cache_thread = new_image_cache_thread(public_resource_threads.sender(),
-                                                    webrender_api_sender.as_ref().map(|wr| wr.create_api()));
+                                                    webrender_api_sender.create_api());
     let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(),
-                                                 webrender_api_sender.as_ref().map(|wr| wr.create_api()));
+                                                 Some(webrender_api_sender.create_api()));
 
     let resource_sender = public_resource_threads.sender();
 
     let initial_state = InitialConstellationState {
         compositor_proxy: compositor_proxy,
         devtools_chan: devtools_chan,
         bluetooth_thread: bluetooth_thread,
         image_cache_thread: image_cache_thread,
--- a/servo/components/util/opts.rs
+++ b/servo/components/util/opts.rs
@@ -187,19 +187,16 @@ pub struct Opts {
     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 enable the webrender painting/compositing backend.
-    pub use_webrender: 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 to compile all webrender shaders at init time. This is mostly
     /// useful when modifying the shaders, to ensure they all compile
@@ -207,19 +204,16 @@ pub struct Opts {
     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<String>,
 
-    // Which rendering API to use.
-    pub render_api: RenderApi,
-
     // 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.
@@ -447,25 +441,16 @@ pub fn multiprocess() -> bool {
     MULTIPROCESS.load(Ordering::Relaxed)
 }
 
 enum UserAgent {
     Desktop,
     Android,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-pub enum RenderApi {
-    GL,
-    ES2,
-}
-
-const DEFAULT_RENDER_API: RenderApi = RenderApi::GL;
-
 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";
 
@@ -544,20 +529,18 @@ pub fn default_opts() -> Opts {
         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,
-        use_webrender: true,
         webrender_stats: false,
         use_msaa: false,
-        render_api: DEFAULT_RENDER_API,
         config_dir: None,
         full_backtraces: false,
         is_printing_version: false,
         webrender_debug: false,
         precache_shaders: false,
         signpost: false,
     }
 }
@@ -795,25 +778,16 @@ pub fn from_cmdline_args(args: &[String]
             .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 use_webrender = !opt_match.opt_present("c");
-
-    let render_api = match opt_match.opt_str("G") {
-        Some(ref ga) if ga == "gl" => RenderApi::GL,
-        Some(ref ga) if ga == "es2" => RenderApi::ES2,
-        None => DEFAULT_RENDER_API,
-        _ => args_fail(&format!("error: graphics option must be gl or es2:")),
-    };
-
     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,
@@ -837,17 +811,16 @@ pub fn from_cmdline_args(args: &[String]
         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,
-        render_api: render_api,
         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_canvas_antialiasing: !debug_options.disable_canvas_aa,
         dump_style_tree: debug_options.dump_style_tree,
@@ -857,17 +830,16 @@ pub fn from_cmdline_args(args: &[String]
         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,
-        use_webrender: use_webrender,
         webrender_stats: debug_options.webrender_stats,
         use_msaa: debug_options.use_msaa,
         config_dir: opt_match.opt_str("config-dir"),
         full_backtraces: debug_options.full_backtraces,
         is_printing_version: is_printing_version,
         webrender_debug: debug_options.webrender_debug,
         precache_shaders: debug_options.precache_shaders,
         signpost: debug_options.signpost,
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -1,19 +1,19 @@
 [root]
 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)",
+ "gfx_traits 0.0.1",
  "gleam 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin_app 0.0.1",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "libc 0.2.16 (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",
  "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "script_traits 0.0.1",
  "servo 0.0.1",
@@ -273,24 +273,21 @@ dependencies = [
 name = "color_quant"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "compositing"
 version = "0.0.1"
 dependencies = [
- "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "azure 0.9.0 (git+https://github.com/servo/rust-azure)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "gleam 0.2.22 (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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "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.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -311,17 +308,16 @@ dependencies = [
  "canvas_traits 0.0.1",
  "compositing 0.0.1",
  "devtools_traits 0.0.1",
  "euclid 0.10.2 (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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "layout_traits 0.0.1",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "offscreen_gl_context 0.4.3 (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)",
@@ -708,27 +704,24 @@ dependencies = [
  "fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "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_plugin 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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.2.3 (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)",
  "range 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "simd 0.1.1 (git+https://github.com/huonw/simd)",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -743,23 +736,19 @@ dependencies = [
  "xi-unicode 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gfx_traits"
 version = "0.0.1"
 dependencies = [
  "azure 0.9.0 (git+https://github.com/servo/rust-azure)",
- "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
- "msg 0.0.1",
  "plugins 0.0.1",
- "profile_traits 0.0.1",
  "range 0.0.1",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gif"
@@ -796,18 +785,18 @@ source = "registry+https://github.com/ru
 [[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)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gfx_traits 0.0.1",
  "gleam 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "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 (git+https://github.com/daggerbot/osmesa-rs)",
  "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)",
@@ -1043,36 +1032,16 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "language-tags"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "layers"
-version = "0.5.3"
-source = "git+https://github.com/servo/rust-layers#b064de859b2cf3f4e07b29ee11a34543f1671ac0"
-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)",
- "gleam 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "heapsize 0.3.7 (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.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "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)",
- "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-skia 0.20130412.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "azure 0.9.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
  "cssparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1145,17 +1114,16 @@ version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
  "webrender_traits 0.6.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -1895,47 +1863,44 @@ dependencies = [
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.2.29 (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",
 ]
 
 [[package]]
 name = "script_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "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)",
  "gfx_traits 0.0.1",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.6 (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)",
- "layers 0.5.3 (git+https://github.com/servo/rust-layers)",
  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "offscreen_gl_context 0.4.3 (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.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "util 0.0.1",
 ]
 
 [[package]]
 name = "selectors"
 version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2763,17 +2728,16 @@ dependencies = [
 "checksum io-surface 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c93eb4952ee5b903c4193391779f90209e1b75ba55911097fa494f35e975846"
 "checksum ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "675587430ede6756dd03fdfdf9888f22f83855fd131c8451d842a710b059e571"
 "checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
 "checksum jpeg-decoder 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "70be4c5ed7c80bb403fb28d95d30dd97ccf76829e943ae2350037fd6cd6961b6"
 "checksum js 0.1.3 (git+https://github.com/servo/rust-mozjs)" = "<none>"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c9d3760673c427d46f91a0350f0a84a52e6bc5a84adf26dc610b6c52436630"
 "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
-"checksum layers 0.5.3 (git+https://github.com/servo/rust-layers)" = "<none>"
 "checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
 "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
 "checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73"
 "checksum leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc"
 "checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
 "checksum libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eceb2637ee9a27c7f19764048a9f377e40e3a70a322722f348e6bc7704d565f2"
 "checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71"
 "checksum libz-sys 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "40f2df7730b5d29426c3e44ce4d088d8c5def6471c2c93ba98585b89fb201ce6"
--- a/servo/ports/cef/Cargo.toml
+++ b/servo/ports/cef/Cargo.toml
@@ -13,19 +13,19 @@ opt-level = 3
 # Uncomment to profile on Linux:
 # debug = true
 # lto = false
 
 [dependencies]
 compositing = {path = "../../components/compositing"}
 devtools = {path = "../../components/devtools"}
 euclid = "0.10.1"
+gfx_traits = {path = "../../components/gfx_traits"}
 gleam = "0.2.8"
 glutin_app = {path = "../glutin"}
-layers = {git = "https://github.com/servo/rust-layers"}
 libc = "0.2"
 log = {version = "0.3.5", features = ["release_max_level_info"]}
 msg = {path = "../../components/msg"}
 net_traits = {path = "../../components/net_traits"}
 plugins = {path = "../../components/plugins"}
 script_traits = {path = "../../components/script_traits"}
 servo = {path = "../../components/servo"}
 style_traits = {path = "../../components/style_traits"}
--- a/servo/ports/cef/lib.rs
+++ b/servo/ports/cef/lib.rs
@@ -14,19 +14,19 @@
 
 #[macro_use]
 extern crate log;
 
 extern crate servo;
 extern crate compositing;
 
 extern crate euclid;
+extern crate gfx_traits;
 extern crate gleam;
 extern crate glutin_app;
-extern crate layers;
 extern crate rustc_unicode;
 extern crate script_traits;
 
 extern crate net_traits;
 extern crate msg;
 extern crate util;
 extern crate style_traits;
 
--- a/servo/ports/cef/window.rs
+++ b/servo/ports/cef/window.rs
@@ -18,19 +18,18 @@ use rustc_unicode::str::Utf16Encoder;
 use types::{cef_cursor_handle_t, cef_cursor_type_t, cef_rect_t};
 use wrappers::CefWrap;
 
 use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver};
 use compositing::windowing::{WindowEvent, WindowMethods};
 use euclid::point::Point2D;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::{Size2D, TypedSize2D};
+use gfx_traits::DevicePixel;
 use gleam::gl;
-use layers::geometry::DevicePixel;
-use layers::platform::surface::NativeDisplay;
 use msg::constellation_msg::{Key, KeyModifiers};
 use net_traits::net_error_list::NetError;
 use std::cell::RefCell;
 use std::ffi::CString;
 use std::os::raw::{c_char, c_void};
 use std::ptr;
 use std::rc::Rc;
 use std::sync::mpsc::{Sender, channel};
@@ -279,29 +278,16 @@ impl WindowMethods for Window {
             }
         } else {
             // FIXME(zmike)
             // need to figure out a method for actually getting the scale factor instead of this nonsense
             ScaleFactor::new(1.0 as f32)
         }
     }
 
-    #[cfg(target_os="linux")]
-    fn native_display(&self) -> NativeDisplay {
-        use x11::xlib;
-        unsafe {
-            NativeDisplay::new(DISPLAY as *mut xlib::Display)
-        }
-    }
-
-    #[cfg(not(target_os="linux"))]
-    fn native_display(&self) -> NativeDisplay {
-        NativeDisplay::new()
-    }
-
     fn create_compositor_channel(&self)
                                  -> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
         let (sender, receiver) = channel();
         (box CefCompositorProxy {
              sender: sender,
          } as Box<CompositorProxy+Send>,
          box receiver as Box<CompositorReceiver>)
     }
--- a/servo/ports/glutin/Cargo.toml
+++ b/servo/ports/glutin/Cargo.toml
@@ -7,18 +7,18 @@ license = "MPL-2.0"
 [lib]
 name = "glutin_app"
 path = "lib.rs"
 
 [dependencies]
 bitflags = "0.7"
 compositing = {path = "../../components/compositing"}
 euclid = "0.10.1"
+gfx_traits = {path = "../../components/gfx_traits"}
 gleam = "0.2.8"
-layers = {git = "https://github.com/servo/rust-layers", features = ["plugins"]}
 log = "0.3.5"
 msg = {path = "../../components/msg"}
 net_traits = {path = "../../components/net_traits"}
 script_traits = {path = "../../components/script_traits"}
 servo-glutin = "0.6"
 style_traits = {path = "../../components/style_traits"}
 url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../../components/util"}
--- a/servo/ports/glutin/lib.rs
+++ b/servo/ports/glutin/lib.rs
@@ -6,28 +6,27 @@
 
 #![feature(box_syntax)]
 
 #[macro_use] extern crate bitflags;
 extern crate compositing;
 #[allow(unused_extern_crates)]
 #[cfg(target_os = "android")] extern crate egl;
 extern crate euclid;
+extern crate gfx_traits;
 extern crate gleam;
 extern crate glutin;
-extern crate layers;
 #[macro_use] extern crate log;
 extern crate msg;
 extern crate net_traits;
 #[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys;
 extern crate script_traits;
 extern crate style_traits;
 extern crate url;
 extern crate util;
-#[cfg(target_os = "linux")] extern crate x11;
 #[cfg(target_os = "windows")] extern crate winapi;
 #[cfg(target_os = "windows")] extern crate user32;
 #[cfg(target_os = "windows")] extern crate gdi32;
 
 use compositing::windowing::WindowEvent;
 use std::rc::Rc;
 use util::opts;
 use window::Window;
--- a/servo/ports/glutin/window.rs
+++ b/servo/ports/glutin/window.rs
@@ -8,24 +8,23 @@ use NestedEventLoopListener;
 use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver};
 use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg};
 use compositing::windowing::{WindowEvent, WindowMethods};
 use euclid::{Point2D, Size2D, TypedPoint2D};
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 #[cfg(target_os = "windows")]
 use gdi32;
+use gfx_traits::DevicePixel;
 use gleam::gl;
 use glutin;
 use glutin::{Api, ElementState, Event, GlRequest, MouseButton, MouseScrollDelta, VirtualKeyCode};
 use glutin::{ScanCode, TouchPhase};
 #[cfg(target_os = "macos")]
 use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
-use layers::geometry::DevicePixel;
-use layers::platform::surface::NativeDisplay;
 use msg::constellation_msg::{self, Key};
 use msg::constellation_msg::{ALT, CONTROL, KeyState, NONE, SHIFT, SUPER};
 use net_traits::net_error_list::NetError;
 #[cfg(any(target_os = "linux", target_os = "macos"))]
 use osmesa_sys;
 use script_traits::{TouchEventType, TouchpadPressurePhase};
 use std::cell::{Cell, RefCell};
 #[cfg(any(target_os = "linux", target_os = "macos"))]
@@ -37,18 +36,16 @@ use std::ptr;
 use std::rc::Rc;
 use std::sync::mpsc::{Sender, channel};
 use style_traits::cursor::Cursor;
 use url::Url;
 #[cfg(target_os = "windows")]
 use user32;
 use util::geometry::ScreenPx;
 use util::opts;
-#[cfg(not(target_os = "android"))]
-use util::opts::RenderApi;
 use util::prefs::PREFS;
 use util::resource_files;
 #[cfg(target_os = "windows")]
 use winapi;
 
 static mut g_nested_event_loop_listener: Option<*mut (NestedEventLoopListener + 'static)> = None;
 
 bitflags! {
@@ -313,27 +310,17 @@ impl Window {
                         WindowEvent::Resize(TypedSize2D::new(width, height)));
                 }
             }
         }
     }
 
     #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
     fn gl_version() -> GlRequest {
-        if opts::get().use_webrender {
-            return GlRequest::Specific(Api::OpenGl, (3, 2));
-        }
-        match opts::get().render_api {
-            RenderApi::GL => {
-                GlRequest::Specific(Api::OpenGl, (2, 1))
-            }
-            RenderApi::ES2 => {
-                GlRequest::Specific(Api::OpenGlEs, (2, 0))
-            }
-        }
+        return GlRequest::Specific(Api::OpenGl, (3, 2));
     }
 
     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
     fn gl_version() -> GlRequest {
         GlRequest::Specific(Api::OpenGlEs, (3, 0))
     }
 
     #[cfg(not(target_os = "android"))]
@@ -553,82 +540,38 @@ impl Window {
             WindowKind::Headless(..) => {
                 false
             }
         }
     }
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
     fn handle_next_event(&self) -> bool {
-        use std::thread;
-        use std::time::Duration;
-
-        // WebRender can use the normal blocking event check and proper vsync,
-        // because it doesn't call X11 functions from another thread, so doesn't
-        // hit the same issues explained below.
-        if opts::get().use_webrender {
-            match self.kind {
-                WindowKind::Window(ref window) => {
-                    let event = match window.wait_events().next() {
-                        None => {
-                            warn!("Window event stream closed.");
-                            return false;
-                        },
-                        Some(event) => event,
-                    };
-                    let mut close = self.handle_window_event(event);
-                    if !close {
-                        while let Some(event) = window.poll_events().next() {
-                            if self.handle_window_event(event) {
-                                close = true;
-                                break
-                            }
-                        }
-                    }
-                    close
-                }
-                WindowKind::Headless(..) => {
-                    false
-                }
-            }
-        } else {
-            // TODO(gw): This is an awful hack to work around the
-            // broken way we currently call X11 from multiple threads.
-            //
-            // On some (most?) X11 implementations, blocking here
-            // with XPeekEvent results in the paint thread getting stuck
-            // in XGetGeometry randomly. When this happens the result
-            // is that until you trigger the XPeekEvent to return
-            // (by moving the mouse over the window) the paint thread
-            // never completes and you don't see the most recent
-            // results.
-            //
-            // For now, poll events and sleep for ~1 frame if there
-            // are no events. This means we don't spin the CPU at
-            // 100% usage, but is far from ideal!
-            //
-            // See https://github.com/servo/servo/issues/5780
-            //
-            match self.kind {
-                WindowKind::Window(ref window) => {
-                    let first_event = window.poll_events().next();
-
-                    match first_event {
-                        Some(event) => {
-                            self.handle_window_event(event)
-                        }
-                        None => {
-                            thread::sleep(Duration::from_millis(16));
-                            false
+        match self.kind {
+            WindowKind::Window(ref window) => {
+                let event = match window.wait_events().next() {
+                    None => {
+                        warn!("Window event stream closed.");
+                        return false;
+                    },
+                    Some(event) => event,
+                };
+                let mut close = self.handle_window_event(event);
+                if !close {
+                    while let Some(event) = window.poll_events().next() {
+                        if self.handle_window_event(event) {
+                            close = true;
+                            break
                         }
                     }
                 }
-                WindowKind::Headless(..) => {
-                    false
-                }
+                close
+            }
+            WindowKind::Headless(..) => {
+                false
             }
         }
     }
 
     pub fn wait_events(&self) -> Vec<WindowEvent> {
         use std::mem;
 
         let mut events = mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new());
@@ -1026,43 +969,16 @@ impl WindowMethods for Window {
 
     fn set_favicon(&self, _: Url) {
     }
 
     fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool {
         true
     }
 
-    #[cfg(target_os = "linux")]
-    fn native_display(&self) -> NativeDisplay {
-        use x11::xlib;
-        unsafe {
-            match opts::get().render_api {
-                RenderApi::GL => {
-                    match self.kind {
-                        WindowKind::Window(ref window) => {
-                            NativeDisplay::new(window.platform_display() as *mut xlib::Display)
-                        }
-                        WindowKind::Headless(..) => {
-                            unreachable!()
-                        }
-                    }
-                },
-                RenderApi::ES2 => {
-                    NativeDisplay::new_egl_display()
-                }
-            }
-        }
-    }
-
-    #[cfg(not(target_os = "linux"))]
-    fn native_display(&self) -> NativeDisplay {
-        NativeDisplay::new()
-    }
-
     /// Helper function to handle keyboard events.
     fn handle_key(&self, ch: Option<char>, key: Key, mods: constellation_msg::KeyModifiers) {
         match (mods, ch, key) {
             (_, Some('+'), _) => {
                 if mods & !SHIFT == CMD_OR_CONTROL {
                     self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1));
                 } else if mods & !SHIFT == CMD_OR_CONTROL | ALT {
                     self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.1));