servo: Merge #6083 - First steps to layerize canvas (from emilio:layerize-canvas); r=pcwalton
authorecoal95 <ecoal95@gmail.com>
Wed, 20 May 2015 15:42:06 -0500
changeset 365444 38d6c8fa1b0a353e3b91e55ba5e0d95a8f471b3f
parent 365443 b03a04432d491b8a6a16e6f739ef76a6a0b7a9de
child 365445 69c53d0279cf3752c989e81582e11716e2b8c9ab
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
servo: Merge #6083 - First steps to layerize canvas (from emilio:layerize-canvas); r=pcwalton I've done a bit of job to get this done. Right now readback is still used, but we have a `LayerId` -> `CanvasRenderer` map on the paint task, that we can use to get rid of that. I'd want review, to see if this is a good approach (I know it's not the initial `CanvasId` -> renderer approach, but it's pretty similar, since a canvas involves a `PaintLayer`). I had to do a bit of refactoring to avoid cyclic dependencies between canvas and gfx. I'd want you to review them too. It's mergeable and doesn't break any tests :P Some of my main concerns: * Does the canvas render really need to be behind an `Arc<Mutex<T>>`? * I can't clone a `NativeSurface` right now (that's why the `SendNativeSurface()` msg is unimplemented in the WebGL task). It should be easy to add that to rust-layers, supposing the caller is responsible to mark it as non-leaking, any reason to not do it? cc @jdm @pcwalton Source-Repo: https://github.com/servo/servo Source-Revision: ad53e95080144485e74cd9b9d48ce75e20de4e36
servo/components/canvas/Cargo.toml
servo/components/canvas/canvas_msg.rs
servo/components/canvas/canvas_paint_task.rs
servo/components/canvas/lib.rs
servo/components/canvas/webgl_paint_task.rs
servo/components/canvas_traits/Cargo.toml
servo/components/canvas_traits/lib.rs
servo/components/compositing/Cargo.toml
servo/components/compositing/compositor.rs
servo/components/compositing/lib.rs
servo/components/gfx/Cargo.toml
servo/components/gfx/color.rs
servo/components/gfx/lib.rs
servo/components/gfx/paint_context.rs
servo/components/gfx/paint_task.rs
servo/components/gfx_traits/Cargo.toml
servo/components/gfx_traits/color.rs
servo/components/gfx_traits/lib.rs
servo/components/layout/Cargo.toml
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/fragment.rs
servo/components/layout/layout_task.rs
servo/components/layout/lib.rs
servo/components/layout/wrapper.rs
servo/components/msg/Cargo.toml
servo/components/script/Cargo.toml
servo/components/script/dom/bindings/trace.rs
servo/components/script/dom/canvasgradient.rs
servo/components/script/dom/canvasrenderingcontext2d.rs
servo/components/script/dom/htmlcanvaselement.rs
servo/components/script/dom/webglrenderingcontext.rs
servo/components/script/lib.rs
servo/components/servo/Cargo.lock
servo/ports/cef/Cargo.lock
servo/ports/gonk/Cargo.lock
--- a/servo/components/canvas/Cargo.toml
+++ b/servo/components/canvas/Cargo.toml
@@ -8,23 +8,30 @@ name = "canvas"
 path = "lib.rs"
 
 [dependencies.azure]
 git = "https://github.com/servo/rust-azure"
 
 [dependencies.geom]
 git = "https://github.com/servo/rust-geom"
 
+[dependencies.layers]
+git = "https://github.com/servo/rust-layers"
+
 [dependencies.gleam]
 git = "https://github.com/servo/gleam"
 
+[dependencies.canvas_traits]
+path = "../canvas_traits"
+
 [dependencies.util]
 path = "../util"
 
-[dependencies.gfx]
-path = "../gfx"
+[dependencies.gfx_traits]
+path = "../gfx_traits"
 
 [dependencies.offscreen_gl_context]
 git = "https://github.com/ecoal95/rust-offscreen-rendering-context"
+features = ["texture_surface"]
 
 [dependencies]
 cssparser = "0.3.1"
 num = "0.1.24"
deleted file mode 100644
--- a/servo/components/canvas/canvas_msg.rs
+++ /dev/null
@@ -1,83 +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 canvas_paint_task::{FillOrStrokeStyle, LineCapStyle, LineJoinStyle, CompositionOrBlending};
-use geom::matrix2d::Matrix2D;
-use geom::point::Point2D;
-use geom::rect::Rect;
-use geom::size::Size2D;
-use std::sync::mpsc::{Sender};
-
-#[derive(Clone)]
-pub enum CanvasMsg {
-    Canvas2d(Canvas2dMsg),
-    Common(CanvasCommonMsg),
-    WebGL(CanvasWebGLMsg),
-}
-
-#[derive(Clone)]
-pub enum Canvas2dMsg {
-    Arc(Point2D<f32>, f32, f32, f32, bool),
-    ArcTo(Point2D<f32>, Point2D<f32>, f32),
-    DrawImage(Vec<u8>, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
-    DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool),
-    BeginPath,
-    BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
-    ClearRect(Rect<f32>),
-    Clip,
-    ClosePath,
-    Fill,
-    FillRect(Rect<f32>),
-    GetImageData(Rect<f64>, Size2D<f64>, Sender<Vec<u8>>),
-    LineTo(Point2D<f32>),
-    MoveTo(Point2D<f32>),
-    PutImageData(Vec<u8>, Rect<f64>, Option<Rect<f64>>),
-    QuadraticCurveTo(Point2D<f32>, Point2D<f32>),
-    Rect(Rect<f32>),
-    RestoreContext,
-    SaveContext,
-    StrokeRect(Rect<f32>),
-    Stroke,
-    SetFillStyle(FillOrStrokeStyle),
-    SetStrokeStyle(FillOrStrokeStyle),
-    SetLineWidth(f32),
-    SetLineCap(LineCapStyle),
-    SetLineJoin(LineJoinStyle),
-    SetMiterLimit(f32),
-    SetGlobalAlpha(f32),
-    SetGlobalComposition(CompositionOrBlending),
-    SetTransform(Matrix2D<f32>),
-}
-
-#[derive(Clone)]
-pub enum CanvasWebGLMsg {
-    AttachShader(u32, u32),
-    BindBuffer(u32, u32),
-    BufferData(u32, Vec<f32>, u32),
-    Clear(u32),
-    ClearColor(f32, f32, f32, f32),
-    CompileShader(u32),
-    CreateBuffer(Sender<u32>),
-    CreateProgram(Sender<u32>),
-    CreateShader(u32, Sender<u32>),
-    DrawArrays(u32, i32, i32),
-    EnableVertexAttribArray(u32),
-    GetAttribLocation(u32, String, Sender<i32>),
-    GetShaderInfoLog(u32, Sender<String>),
-    GetShaderParameter(u32, u32, Sender<i32>),
-    GetUniformLocation(u32, String, Sender<u32>),
-    LinkProgram(u32),
-    ShaderSource(u32, Vec<String>),
-    Uniform4fv(u32, Vec<f32>),
-    UseProgram(u32),
-    VertexAttribPointer2f(u32, i32, bool, i32, i64),
-    Viewport(i32, i32, i32, i32),
-}
-
-#[derive(Clone)]
-pub enum CanvasCommonMsg {
-    Close,
-    Recreate(Size2D<i32>),
-    SendPixelContents(Sender<Vec<u8>>),
-}
--- a/servo/components/canvas/canvas_paint_task.rs
+++ b/servo/components/canvas/canvas_paint_task.rs
@@ -1,28 +1,27 @@
 /* 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::AzFloat;
 use azure::azure_hl::{DrawTarget, SurfaceFormat, BackendType, StrokeOptions, DrawOptions, Pattern};
 use azure::azure_hl::{ColorPattern, PathBuilder, DrawSurfaceOptions, Filter};
-use azure::azure_hl::{GradientStop, LinearGradientPattern, RadialGradientPattern, ExtendMode};
-use azure::azure_hl::{JoinStyle, CapStyle, CompositionOp};
-use canvas_msg::{CanvasMsg, Canvas2dMsg, CanvasCommonMsg};
+use azure::azure_hl::{JoinStyle, CapStyle};
+use canvas_traits::*;
 use geom::matrix2d::Matrix2D;
 use geom::point::Point2D;
 use geom::rect::Rect;
 use geom::size::Size2D;
-use gfx::color;
+use layers::platform::surface::NativeSurface;
+use gfx_traits::color;
 use num::ToPrimitive;
 use util::task::spawn_named;
 use util::vec::byte_swap;
 
-use cssparser::RGBA;
 use std::borrow::ToOwned;
 use std::mem;
 use std::sync::mpsc::{channel, Sender};
 
 impl<'a> CanvasPaintTask<'a> {
     /// It reads image data from the canvas
     /// canvas_size: The size of the canvas we're reading from
     /// read_rect: The area of the canvas we want to read from
@@ -252,16 +251,18 @@ impl<'a> CanvasPaintTask<'a> {
                         }
                     },
                     CanvasMsg::Common(message) => {
                         match message {
                             CanvasCommonMsg::Close => break,
                             CanvasCommonMsg::Recreate(size) => painter.recreate(size),
                             CanvasCommonMsg::SendPixelContents(chan) =>
                                 painter.send_pixel_contents(chan),
+                            CanvasCommonMsg::SendNativeSurface(chan) =>
+                                painter.send_native_surface(chan),
                         }
                     },
                     CanvasMsg::WebGL(_) => panic!("Wrong message sent to Canvas2D task"),
                 }
             }
         });
         chan
     }
@@ -492,16 +493,24 @@ impl<'a> CanvasPaintTask<'a> {
     }
 
     fn send_pixel_contents(&mut self, chan: Sender<Vec<u8>>) {
         self.drawtarget.snapshot().get_data_surface().with_data(|element| {
             chan.send(element.to_vec()).unwrap();
         })
     }
 
+    fn send_native_surface(&self, chan: Sender<NativeSurface>) {
+        let mut native_surface: NativeSurface =
+            NativeSurface::from_draw_target_backing(self.drawtarget.backing.clone());
+        native_surface.mark_wont_leak();
+
+        chan.send(native_surface).unwrap();
+    }
+
     fn get_image_data(&self, mut dest_rect: Rect<f64>, canvas_size: Size2D<f64>, chan: Sender<Vec<u8>>) {
         if dest_rect.size.width < 0.0 {
             dest_rect.size.width = -dest_rect.size.width;
             dest_rect.origin.x -= dest_rect.size.width;
         }
         if dest_rect.size.height < 0.0 {
             dest_rect.size.height = -dest_rect.size.height;
             dest_rect.origin.y -= dest_rect.size.height;
@@ -561,350 +570,16 @@ impl<'a> CanvasPaintTask<'a> {
             Point2D(image_data_rect.origin.x + source_rect.origin.x,
                     image_data_rect.origin.y + source_rect.origin.y),
             Size2D(source_rect.size.width, source_rect.size.height));
 
         self.write_pixels(&imagedata, image_data_rect.size, source_rect, dest_rect, true)
     }
 }
 
-#[derive(Clone)]
-pub struct CanvasGradientStop {
-    pub offset: f64,
-    pub color: RGBA,
-}
-
-#[derive(Clone)]
-pub struct LinearGradientStyle {
-    pub x0: f64,
-    pub y0: f64,
-    pub x1: f64,
-    pub y1: f64,
-    pub stops: Vec<CanvasGradientStop>
-}
-
-impl LinearGradientStyle {
-    pub fn new(x0: f64, y0: f64, x1: f64, y1: f64, stops: Vec<CanvasGradientStop>)
-        -> LinearGradientStyle {
-        LinearGradientStyle {
-            x0: x0,
-            y0: y0,
-            x1: x1,
-            y1: y1,
-            stops: stops,
-        }
-    }
-}
-
-#[derive(Clone)]
-pub struct RadialGradientStyle {
-    pub x0: f64,
-    pub y0: f64,
-    pub r0: f64,
-    pub x1: f64,
-    pub y1: f64,
-    pub r1: f64,
-    pub stops: Vec<CanvasGradientStop>
-}
-
-impl RadialGradientStyle {
-    pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64, stops: Vec<CanvasGradientStop>)
-        -> RadialGradientStyle {
-        RadialGradientStyle {
-            x0: x0,
-            y0: y0,
-            r0: r0,
-            x1: x1,
-            y1: y1,
-            r1: r1,
-            stops: stops,
-        }
-    }
-}
-
-#[derive(Clone)]
-pub enum FillOrStrokeStyle {
-    Color(RGBA),
-    LinearGradient(LinearGradientStyle),
-    RadialGradient(RadialGradientStyle),
-}
-
-impl FillOrStrokeStyle {
-    fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Pattern {
-        match *self {
-            FillOrStrokeStyle::Color(ref color) => {
-                Pattern::Color(ColorPattern::new(color::new(color.red,
-                                                            color.green,
-                                                            color.blue,
-                                                            color.alpha)))
-            },
-            FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => {
-                let gradient_stops: Vec<GradientStop> = linear_gradient_style.stops.iter().map(|s| {
-                    GradientStop {
-                        offset: s.offset as AzFloat,
-                        color: color::new(s.color.red, s.color.green, s.color.blue, s.color.alpha)
-                    }
-                }).collect();
-
-                Pattern::LinearGradient(LinearGradientPattern::new(
-                    &Point2D(linear_gradient_style.x0 as AzFloat, linear_gradient_style.y0 as AzFloat),
-                    &Point2D(linear_gradient_style.x1 as AzFloat, linear_gradient_style.y1 as AzFloat),
-                    drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
-                    &Matrix2D::identity()))
-            },
-            FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => {
-                let gradient_stops: Vec<GradientStop> = radial_gradient_style.stops.iter().map(|s| {
-                    GradientStop {
-                        offset: s.offset as AzFloat,
-                        color: color::new(s.color.red, s.color.green, s.color.blue, s.color.alpha)
-                    }
-                }).collect();
-
-                Pattern::RadialGradient(RadialGradientPattern::new(
-                    &Point2D(radial_gradient_style.x0 as AzFloat, radial_gradient_style.y0 as AzFloat),
-                    &Point2D(radial_gradient_style.x1 as AzFloat, radial_gradient_style.y1 as AzFloat),
-                    radial_gradient_style.r0 as AzFloat, radial_gradient_style.r1 as AzFloat,
-                    drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
-                    &Matrix2D::identity()))
-            }
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum LineCapStyle {
-    Butt = 0,
-    Round = 1,
-    Square = 2,
-}
-
-impl LineCapStyle {
-    fn to_azure_style(&self) -> CapStyle {
-        match *self {
-            LineCapStyle::Butt => CapStyle::Butt,
-            LineCapStyle::Round => CapStyle::Round,
-            LineCapStyle::Square => CapStyle::Square,
-        }
-    }
-
-    pub fn from_str(string: &str) -> Option<LineCapStyle> {
-        match string {
-            "butt" => Some(LineCapStyle::Butt),
-            "round" => Some(LineCapStyle::Round),
-            "square" => Some(LineCapStyle::Square),
-            _ => None
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum LineJoinStyle {
-    Round = 0,
-    Bevel = 1,
-    Miter = 2,
-}
-
-impl LineJoinStyle {
-    fn to_azure_style(&self) -> JoinStyle {
-        match *self {
-            LineJoinStyle::Round => JoinStyle::Round,
-            LineJoinStyle::Bevel => JoinStyle::Bevel,
-            LineJoinStyle::Miter => JoinStyle::Miter,
-        }
-    }
-
-    pub fn from_str(string: &str) -> Option<LineJoinStyle> {
-        match string {
-            "round" => Some(LineJoinStyle::Round),
-            "bevel" => Some(LineJoinStyle::Bevel),
-            "miter" => Some(LineJoinStyle::Miter),
-            _ => None
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum CompositionStyle {
-    SrcIn,
-    SrcOut,
-    SrcOver,
-    SrcAtop,
-    DestIn,
-    DestOut,
-    DestOver,
-    DestAtop,
-    Copy,
-    Lighter,
-    Xor,
-}
-
-impl CompositionStyle {
-    fn to_azure_style(&self) -> CompositionOp {
-        match *self {
-            CompositionStyle::SrcIn    => CompositionOp::In,
-            CompositionStyle::SrcOut   => CompositionOp::Out,
-            CompositionStyle::SrcOver  => CompositionOp::Over,
-            CompositionStyle::SrcAtop  => CompositionOp::Atop,
-            CompositionStyle::DestIn   => CompositionOp::DestIn,
-            CompositionStyle::DestOut  => CompositionOp::DestOut,
-            CompositionStyle::DestOver => CompositionOp::DestOver,
-            CompositionStyle::DestAtop => CompositionOp::DestAtop,
-            CompositionStyle::Copy     => CompositionOp::Source,
-            CompositionStyle::Lighter  => CompositionOp::Add,
-            CompositionStyle::Xor      => CompositionOp::Xor,
-        }
-    }
-
-    pub fn from_str(string: &str) -> Option<CompositionStyle> {
-        match string {
-            "source-in"        => Some(CompositionStyle::SrcIn),
-            "source-out"       => Some(CompositionStyle::SrcOut),
-            "source-over"      => Some(CompositionStyle::SrcOver),
-            "source-atop"      => Some(CompositionStyle::SrcAtop),
-            "destination-in"   => Some(CompositionStyle::DestIn),
-            "destination-out"  => Some(CompositionStyle::DestOut),
-            "destination-over" => Some(CompositionStyle::DestOver),
-            "destination-atop" => Some(CompositionStyle::DestAtop),
-            "copy"             => Some(CompositionStyle::Copy),
-            "lighter"          => Some(CompositionStyle::Lighter),
-            "xor"              => Some(CompositionStyle::Xor),
-            _ => None
-        }
-    }
-
-    pub fn to_str(&self) -> &str {
-        match *self {
-            CompositionStyle::SrcIn    => "source-in",
-            CompositionStyle::SrcOut   => "source-out",
-            CompositionStyle::SrcOver  => "source-over",
-            CompositionStyle::SrcAtop  => "source-atop",
-            CompositionStyle::DestIn   => "destination-in",
-            CompositionStyle::DestOut  => "destination-out",
-            CompositionStyle::DestOver => "destination-over",
-            CompositionStyle::DestAtop => "destination-atop",
-            CompositionStyle::Copy     => "copy",
-            CompositionStyle::Lighter  => "lighter",
-            CompositionStyle::Xor      => "xor",
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum BlendingStyle {
-    Multiply,
-    Screen,
-    Overlay,
-    Darken,
-    Lighten,
-    ColorDodge,
-    ColorBurn,
-    HardLight,
-    SoftLight,
-    Difference,
-    Exclusion,
-    Hue,
-    Saturation,
-    Color,
-    Luminosity,
-}
-
-impl BlendingStyle {
-    fn to_azure_style(&self) -> CompositionOp {
-        match *self {
-            BlendingStyle::Multiply   => CompositionOp::Multiply,
-            BlendingStyle::Screen     => CompositionOp::Screen,
-            BlendingStyle::Overlay    => CompositionOp::Overlay,
-            BlendingStyle::Darken     => CompositionOp::Darken,
-            BlendingStyle::Lighten    => CompositionOp::Lighten,
-            BlendingStyle::ColorDodge => CompositionOp::ColorDodge,
-            BlendingStyle::ColorBurn  => CompositionOp::ColorBurn,
-            BlendingStyle::HardLight  => CompositionOp::HardLight,
-            BlendingStyle::SoftLight  => CompositionOp::SoftLight,
-            BlendingStyle::Difference => CompositionOp::Difference,
-            BlendingStyle::Exclusion  => CompositionOp::Exclusion,
-            BlendingStyle::Hue        => CompositionOp::Hue,
-            BlendingStyle::Saturation => CompositionOp::Saturation,
-            BlendingStyle::Color      => CompositionOp::Color,
-            BlendingStyle::Luminosity => CompositionOp::Luminosity,
-        }
-    }
-
-    pub fn from_str(string: &str) -> Option<BlendingStyle> {
-        match string {
-            "multiply"    => Some(BlendingStyle::Multiply),
-            "screen"      => Some(BlendingStyle::Screen),
-            "overlay"     => Some(BlendingStyle::Overlay),
-            "darken"      => Some(BlendingStyle::Darken),
-            "lighten"     => Some(BlendingStyle::Lighten),
-            "color-dodge" => Some(BlendingStyle::ColorDodge),
-            "color-burn"  => Some(BlendingStyle::ColorBurn),
-            "hard-light"  => Some(BlendingStyle::HardLight),
-            "soft-light"  => Some(BlendingStyle::SoftLight),
-            "difference"  => Some(BlendingStyle::Difference),
-            "exclusion"   => Some(BlendingStyle::Exclusion),
-            "hue"         => Some(BlendingStyle::Hue),
-            "saturation"  => Some(BlendingStyle::Saturation),
-            "color"       => Some(BlendingStyle::Color),
-            "luminosity"  => Some(BlendingStyle::Luminosity),
-            _ => None
-        }
-    }
-
-    pub fn to_str(&self) -> &str {
-        match *self {
-            BlendingStyle::Multiply   => "multiply",
-            BlendingStyle::Screen     => "screen",
-            BlendingStyle::Overlay    => "overlay",
-            BlendingStyle::Darken     => "darken",
-            BlendingStyle::Lighten    => "lighten",
-            BlendingStyle::ColorDodge => "color-dodge",
-            BlendingStyle::ColorBurn  => "color-burn",
-            BlendingStyle::HardLight  => "hard-light",
-            BlendingStyle::SoftLight  => "soft-light",
-            BlendingStyle::Difference => "difference",
-            BlendingStyle::Exclusion  => "exclusion",
-            BlendingStyle::Hue        => "hue",
-            BlendingStyle::Saturation => "saturation",
-            BlendingStyle::Color      => "color",
-            BlendingStyle::Luminosity => "luminosity",
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum CompositionOrBlending {
-    Composition(CompositionStyle),
-    Blending(BlendingStyle),
-}
-
-impl CompositionOrBlending {
-    fn to_azure_style(&self) -> CompositionOp {
-        match *self {
-            CompositionOrBlending::Composition(op) => op.to_azure_style(),
-            CompositionOrBlending::Blending(op) => op.to_azure_style(),
-        }
-    }
-
-    pub fn default() -> CompositionOrBlending {
-        CompositionOrBlending::Composition(CompositionStyle::SrcOver)
-    }
-
-    pub fn from_str(string: &str) -> Option<CompositionOrBlending> {
-        if let Some(op) = CompositionStyle::from_str(string) {
-            return Some(CompositionOrBlending::Composition(op));
-        }
-
-        if let Some(op) = BlendingStyle::from_str(string) {
-            return Some(CompositionOrBlending::Blending(op));
-        }
-
-        None
-    }
-}
-
 /// 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
 fn crop_image(image_data: Vec<u8>,
               image_size: Size2D<f64>,
               crop_rect: Rect<f64>) -> Vec<u8>{
--- a/servo/components/canvas/lib.rs
+++ b/servo/components/canvas/lib.rs
@@ -1,23 +1,24 @@
 /* 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/. */
 
 #![feature(core)]
 #![feature(collections)]
 #![feature(rustc_private)]
 
+extern crate canvas_traits;
 extern crate azure;
 extern crate cssparser;
 extern crate geom;
-extern crate gfx;
+extern crate gfx_traits;
 extern crate util;
 extern crate gleam;
 extern crate num;
+extern crate layers;
 extern crate offscreen_gl_context;
 
 #[macro_use]
 extern crate log;
 
 pub mod canvas_paint_task;
 pub mod webgl_paint_task;
-pub mod canvas_msg;
--- a/servo/components/canvas/webgl_paint_task.rs
+++ b/servo/components/canvas/webgl_paint_task.rs
@@ -1,40 +1,43 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use canvas_msg::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg};
+use canvas_traits::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg};
 use geom::size::Size2D;
 
 use gleam::gl;
 use gleam::gl::types::{GLsizei};
 
 use util::task::spawn_named;
 
 use std::borrow::ToOwned;
 use std::slice::bytes::copy_memory;
 use std::sync::mpsc::{channel, Sender};
 use util::vec::byte_swap;
-use offscreen_gl_context::{GLContext, GLContextAttributes};
+use layers::platform::surface::NativeSurface;
+use offscreen_gl_context::{GLContext, GLContextAttributes, ColorAttachmentType};
 
 pub struct WebGLPaintTask {
     size: Size2D<i32>,
     original_context_size: Size2D<i32>,
     gl_context: GLContext,
 }
 
 // This allows trying to create the PaintTask
 // before creating the thread
 unsafe impl Send for WebGLPaintTask {}
 
 impl WebGLPaintTask {
     fn new(size: Size2D<i32>) -> Result<WebGLPaintTask, &'static str> {
         // TODO(ecoal95): Get the GLContextAttributes from the `GetContext` call
-        let context = try!(GLContext::create_offscreen(size, GLContextAttributes::default()));
+        let context = try!(GLContext::create_offscreen_with_color_attachment(size,
+                                                                             GLContextAttributes::default(),
+                                                                             ColorAttachmentType::TextureWithSurface));
         Ok(WebGLPaintTask {
             size: size,
             original_context_size: size,
             gl_context: context
         })
     }
 
     pub fn handle_webgl_message(&self, message: CanvasWebGLMsg) {
@@ -71,17 +74,20 @@ impl WebGLPaintTask {
         spawn_named("WebGLTask".to_owned(), move || {
             painter.init();
             loop {
                 match port.recv().unwrap() {
                     CanvasMsg::WebGL(message) => painter.handle_webgl_message(message),
                     CanvasMsg::Common(message) => {
                         match message {
                             CanvasCommonMsg::Close => break,
-                            CanvasCommonMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan),
+                            CanvasCommonMsg::SendPixelContents(chan) =>
+                                painter.send_pixel_contents(chan),
+                            CanvasCommonMsg::SendNativeSurface(chan) =>
+                                painter.send_native_surface(chan),
                             // TODO(ecoal95): handle error nicely
                             CanvasCommonMsg::Recreate(size) => painter.recreate(size).unwrap(),
                         }
                     },
                     CanvasMsg::Canvas2d(_) => panic!("Wrong message sent to WebGLTask"),
                 }
             }
         });
@@ -179,16 +185,22 @@ impl WebGLPaintTask {
             copy_memory(&src_slice[..stride], &mut pixels[dst_start .. dst_start + stride]);
         }
 
         // rgba -> bgra
         byte_swap(&mut pixels);
         chan.send(pixels).unwrap();
     }
 
+    fn send_native_surface(&self, _: Sender<NativeSurface>) {
+        // FIXME(ecoal95): We need to make a clone of the surface in order to
+        // implement this
+        unimplemented!()
+    }
+
     fn shader_source(&self, shader_id: u32, source_lines: Vec<String>) {
         let mut lines: Vec<&[u8]> = source_lines.iter().map(|line| line.as_bytes()).collect();
         gl::shader_source(shader_id, &mut lines);
     }
 
     fn uniform_4fv(&self, uniform_id: u32, data: Vec<f32>) {
         gl::uniform_4f(uniform_id as i32, data[0], data[1], data[2], data[3]);
     }
new file mode 100644
--- /dev/null
+++ b/servo/components/canvas_traits/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "canvas_traits"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+
+[lib]
+name = "canvas_traits"
+path = "lib.rs"
+
+[dependencies.gfx_traits]
+path = "../gfx_traits"
+
+[dependencies.geom]
+git = "https://github.com/servo/rust-geom"
+
+[dependencies.azure]
+git = "https://github.com/servo/rust-azure"
+
+[dependencies.layers]
+git = "https://github.com/servo/rust-layers"
+
+[dependencies]
+cssparser = "0.3.1"
new file mode 100644
--- /dev/null
+++ b/servo/components/canvas_traits/lib.rs
@@ -0,0 +1,433 @@
+/* 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/. */
+
+#![crate_name = "canvas_traits"]
+#![crate_type = "rlib"]
+extern crate azure;
+extern crate geom;
+extern crate cssparser;
+extern crate gfx_traits;
+extern crate layers;
+
+use azure::azure::AzFloat;
+use azure::azure_hl::{DrawTarget, Pattern, ColorPattern};
+use azure::azure_hl::{GradientStop, LinearGradientPattern, RadialGradientPattern, ExtendMode};
+use azure::azure_hl::{JoinStyle, CapStyle, CompositionOp};
+use cssparser::RGBA;
+use geom::matrix2d::Matrix2D;
+use geom::point::Point2D;
+use geom::rect::Rect;
+use geom::size::Size2D;
+use gfx_traits::color;
+use std::sync::mpsc::{Sender};
+use layers::platform::surface::NativeSurface;
+
+#[derive(Clone)]
+pub enum CanvasMsg {
+    Canvas2d(Canvas2dMsg),
+    Common(CanvasCommonMsg),
+    WebGL(CanvasWebGLMsg),
+}
+
+#[derive(Clone)]
+pub enum Canvas2dMsg {
+    Arc(Point2D<f32>, f32, f32, f32, bool),
+    ArcTo(Point2D<f32>, Point2D<f32>, f32),
+    DrawImage(Vec<u8>, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
+    DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool),
+    BeginPath,
+    BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
+    ClearRect(Rect<f32>),
+    Clip,
+    ClosePath,
+    Fill,
+    FillRect(Rect<f32>),
+    GetImageData(Rect<f64>, Size2D<f64>, Sender<Vec<u8>>),
+    LineTo(Point2D<f32>),
+    MoveTo(Point2D<f32>),
+    PutImageData(Vec<u8>, Rect<f64>, Option<Rect<f64>>),
+    QuadraticCurveTo(Point2D<f32>, Point2D<f32>),
+    Rect(Rect<f32>),
+    RestoreContext,
+    SaveContext,
+    StrokeRect(Rect<f32>),
+    Stroke,
+    SetFillStyle(FillOrStrokeStyle),
+    SetStrokeStyle(FillOrStrokeStyle),
+    SetLineWidth(f32),
+    SetLineCap(LineCapStyle),
+    SetLineJoin(LineJoinStyle),
+    SetMiterLimit(f32),
+    SetGlobalAlpha(f32),
+    SetGlobalComposition(CompositionOrBlending),
+    SetTransform(Matrix2D<f32>),
+}
+
+#[derive(Clone)]
+pub enum CanvasWebGLMsg {
+    AttachShader(u32, u32),
+    BindBuffer(u32, u32),
+    BufferData(u32, Vec<f32>, u32),
+    Clear(u32),
+    ClearColor(f32, f32, f32, f32),
+    CompileShader(u32),
+    CreateBuffer(Sender<u32>),
+    CreateProgram(Sender<u32>),
+    CreateShader(u32, Sender<u32>),
+    DrawArrays(u32, i32, i32),
+    EnableVertexAttribArray(u32),
+    GetAttribLocation(u32, String, Sender<i32>),
+    GetShaderInfoLog(u32, Sender<String>),
+    GetShaderParameter(u32, u32, Sender<i32>),
+    GetUniformLocation(u32, String, Sender<u32>),
+    LinkProgram(u32),
+    ShaderSource(u32, Vec<String>),
+    Uniform4fv(u32, Vec<f32>),
+    UseProgram(u32),
+    VertexAttribPointer2f(u32, i32, bool, i32, i64),
+    Viewport(i32, i32, i32, i32),
+}
+
+#[derive(Clone)]
+pub enum CanvasCommonMsg {
+    Close,
+    Recreate(Size2D<i32>),
+    SendPixelContents(Sender<Vec<u8>>),
+    SendNativeSurface(Sender<NativeSurface>),
+}
+
+
+#[derive(Clone)]
+pub struct CanvasGradientStop {
+    pub offset: f64,
+    pub color: RGBA,
+}
+
+#[derive(Clone)]
+pub struct LinearGradientStyle {
+    pub x0: f64,
+    pub y0: f64,
+    pub x1: f64,
+    pub y1: f64,
+    pub stops: Vec<CanvasGradientStop>
+}
+
+impl LinearGradientStyle {
+    pub fn new(x0: f64, y0: f64, x1: f64, y1: f64, stops: Vec<CanvasGradientStop>)
+        -> LinearGradientStyle {
+        LinearGradientStyle {
+            x0: x0,
+            y0: y0,
+            x1: x1,
+            y1: y1,
+            stops: stops,
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct RadialGradientStyle {
+    pub x0: f64,
+    pub y0: f64,
+    pub r0: f64,
+    pub x1: f64,
+    pub y1: f64,
+    pub r1: f64,
+    pub stops: Vec<CanvasGradientStop>
+}
+
+impl RadialGradientStyle {
+    pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64, stops: Vec<CanvasGradientStop>)
+        -> RadialGradientStyle {
+        RadialGradientStyle {
+            x0: x0,
+            y0: y0,
+            r0: r0,
+            x1: x1,
+            y1: y1,
+            r1: r1,
+            stops: stops,
+        }
+    }
+}
+
+#[derive(Clone)]
+pub enum FillOrStrokeStyle {
+    Color(RGBA),
+    LinearGradient(LinearGradientStyle),
+    RadialGradient(RadialGradientStyle),
+}
+
+impl FillOrStrokeStyle {
+    pub fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Pattern {
+        match *self {
+            FillOrStrokeStyle::Color(ref color) => {
+                Pattern::Color(ColorPattern::new(color::new(color.red,
+                                                            color.green,
+                                                            color.blue,
+                                                            color.alpha)))
+            },
+            FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => {
+                let gradient_stops: Vec<GradientStop> = linear_gradient_style.stops.iter().map(|s| {
+                    GradientStop {
+                        offset: s.offset as AzFloat,
+                        color: color::new(s.color.red, s.color.green, s.color.blue, s.color.alpha)
+                    }
+                }).collect();
+
+                Pattern::LinearGradient(LinearGradientPattern::new(
+                    &Point2D(linear_gradient_style.x0 as AzFloat, linear_gradient_style.y0 as AzFloat),
+                    &Point2D(linear_gradient_style.x1 as AzFloat, linear_gradient_style.y1 as AzFloat),
+                    drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
+                    &Matrix2D::identity()))
+            },
+            FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => {
+                let gradient_stops: Vec<GradientStop> = radial_gradient_style.stops.iter().map(|s| {
+                    GradientStop {
+                        offset: s.offset as AzFloat,
+                        color: color::new(s.color.red, s.color.green, s.color.blue, s.color.alpha)
+                    }
+                }).collect();
+
+                Pattern::RadialGradient(RadialGradientPattern::new(
+                    &Point2D(radial_gradient_style.x0 as AzFloat, radial_gradient_style.y0 as AzFloat),
+                    &Point2D(radial_gradient_style.x1 as AzFloat, radial_gradient_style.y1 as AzFloat),
+                    radial_gradient_style.r0 as AzFloat, radial_gradient_style.r1 as AzFloat,
+                    drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
+                    &Matrix2D::identity()))
+            }
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum LineCapStyle {
+    Butt = 0,
+    Round = 1,
+    Square = 2,
+}
+
+impl LineCapStyle {
+    pub fn to_azure_style(&self) -> CapStyle {
+        match *self {
+            LineCapStyle::Butt => CapStyle::Butt,
+            LineCapStyle::Round => CapStyle::Round,
+            LineCapStyle::Square => CapStyle::Square,
+        }
+    }
+
+    pub fn from_str(string: &str) -> Option<LineCapStyle> {
+        match string {
+            "butt" => Some(LineCapStyle::Butt),
+            "round" => Some(LineCapStyle::Round),
+            "square" => Some(LineCapStyle::Square),
+            _ => None
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum LineJoinStyle {
+    Round = 0,
+    Bevel = 1,
+    Miter = 2,
+}
+
+impl LineJoinStyle {
+    pub fn to_azure_style(&self) -> JoinStyle {
+        match *self {
+            LineJoinStyle::Round => JoinStyle::Round,
+            LineJoinStyle::Bevel => JoinStyle::Bevel,
+            LineJoinStyle::Miter => JoinStyle::Miter,
+        }
+    }
+
+    pub fn from_str(string: &str) -> Option<LineJoinStyle> {
+        match string {
+            "round" => Some(LineJoinStyle::Round),
+            "bevel" => Some(LineJoinStyle::Bevel),
+            "miter" => Some(LineJoinStyle::Miter),
+            _ => None
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum CompositionStyle {
+    SrcIn,
+    SrcOut,
+    SrcOver,
+    SrcAtop,
+    DestIn,
+    DestOut,
+    DestOver,
+    DestAtop,
+    Copy,
+    Lighter,
+    Xor,
+}
+
+impl CompositionStyle {
+    pub fn to_azure_style(&self) -> CompositionOp {
+        match *self {
+            CompositionStyle::SrcIn    => CompositionOp::In,
+            CompositionStyle::SrcOut   => CompositionOp::Out,
+            CompositionStyle::SrcOver  => CompositionOp::Over,
+            CompositionStyle::SrcAtop  => CompositionOp::Atop,
+            CompositionStyle::DestIn   => CompositionOp::DestIn,
+            CompositionStyle::DestOut  => CompositionOp::DestOut,
+            CompositionStyle::DestOver => CompositionOp::DestOver,
+            CompositionStyle::DestAtop => CompositionOp::DestAtop,
+            CompositionStyle::Copy     => CompositionOp::Source,
+            CompositionStyle::Lighter  => CompositionOp::Add,
+            CompositionStyle::Xor      => CompositionOp::Xor,
+        }
+    }
+
+    pub fn from_str(string: &str) -> Option<CompositionStyle> {
+        match string {
+            "source-in"        => Some(CompositionStyle::SrcIn),
+            "source-out"       => Some(CompositionStyle::SrcOut),
+            "source-over"      => Some(CompositionStyle::SrcOver),
+            "source-atop"      => Some(CompositionStyle::SrcAtop),
+            "destination-in"   => Some(CompositionStyle::DestIn),
+            "destination-out"  => Some(CompositionStyle::DestOut),
+            "destination-over" => Some(CompositionStyle::DestOver),
+            "destination-atop" => Some(CompositionStyle::DestAtop),
+            "copy"             => Some(CompositionStyle::Copy),
+            "lighter"          => Some(CompositionStyle::Lighter),
+            "xor"              => Some(CompositionStyle::Xor),
+            _ => None
+        }
+    }
+
+    pub fn to_str(&self) -> &str {
+        match *self {
+            CompositionStyle::SrcIn    => "source-in",
+            CompositionStyle::SrcOut   => "source-out",
+            CompositionStyle::SrcOver  => "source-over",
+            CompositionStyle::SrcAtop  => "source-atop",
+            CompositionStyle::DestIn   => "destination-in",
+            CompositionStyle::DestOut  => "destination-out",
+            CompositionStyle::DestOver => "destination-over",
+            CompositionStyle::DestAtop => "destination-atop",
+            CompositionStyle::Copy     => "copy",
+            CompositionStyle::Lighter  => "lighter",
+            CompositionStyle::Xor      => "xor",
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum BlendingStyle {
+    Multiply,
+    Screen,
+    Overlay,
+    Darken,
+    Lighten,
+    ColorDodge,
+    ColorBurn,
+    HardLight,
+    SoftLight,
+    Difference,
+    Exclusion,
+    Hue,
+    Saturation,
+    Color,
+    Luminosity,
+}
+
+impl BlendingStyle {
+    pub fn to_azure_style(&self) -> CompositionOp {
+        match *self {
+            BlendingStyle::Multiply   => CompositionOp::Multiply,
+            BlendingStyle::Screen     => CompositionOp::Screen,
+            BlendingStyle::Overlay    => CompositionOp::Overlay,
+            BlendingStyle::Darken     => CompositionOp::Darken,
+            BlendingStyle::Lighten    => CompositionOp::Lighten,
+            BlendingStyle::ColorDodge => CompositionOp::ColorDodge,
+            BlendingStyle::ColorBurn  => CompositionOp::ColorBurn,
+            BlendingStyle::HardLight  => CompositionOp::HardLight,
+            BlendingStyle::SoftLight  => CompositionOp::SoftLight,
+            BlendingStyle::Difference => CompositionOp::Difference,
+            BlendingStyle::Exclusion  => CompositionOp::Exclusion,
+            BlendingStyle::Hue        => CompositionOp::Hue,
+            BlendingStyle::Saturation => CompositionOp::Saturation,
+            BlendingStyle::Color      => CompositionOp::Color,
+            BlendingStyle::Luminosity => CompositionOp::Luminosity,
+        }
+    }
+
+    pub fn from_str(string: &str) -> Option<BlendingStyle> {
+        match string {
+            "multiply"    => Some(BlendingStyle::Multiply),
+            "screen"      => Some(BlendingStyle::Screen),
+            "overlay"     => Some(BlendingStyle::Overlay),
+            "darken"      => Some(BlendingStyle::Darken),
+            "lighten"     => Some(BlendingStyle::Lighten),
+            "color-dodge" => Some(BlendingStyle::ColorDodge),
+            "color-burn"  => Some(BlendingStyle::ColorBurn),
+            "hard-light"  => Some(BlendingStyle::HardLight),
+            "soft-light"  => Some(BlendingStyle::SoftLight),
+            "difference"  => Some(BlendingStyle::Difference),
+            "exclusion"   => Some(BlendingStyle::Exclusion),
+            "hue"         => Some(BlendingStyle::Hue),
+            "saturation"  => Some(BlendingStyle::Saturation),
+            "color"       => Some(BlendingStyle::Color),
+            "luminosity"  => Some(BlendingStyle::Luminosity),
+            _ => None
+        }
+    }
+
+    pub fn to_str(&self) -> &str {
+        match *self {
+            BlendingStyle::Multiply   => "multiply",
+            BlendingStyle::Screen     => "screen",
+            BlendingStyle::Overlay    => "overlay",
+            BlendingStyle::Darken     => "darken",
+            BlendingStyle::Lighten    => "lighten",
+            BlendingStyle::ColorDodge => "color-dodge",
+            BlendingStyle::ColorBurn  => "color-burn",
+            BlendingStyle::HardLight  => "hard-light",
+            BlendingStyle::SoftLight  => "soft-light",
+            BlendingStyle::Difference => "difference",
+            BlendingStyle::Exclusion  => "exclusion",
+            BlendingStyle::Hue        => "hue",
+            BlendingStyle::Saturation => "saturation",
+            BlendingStyle::Color      => "color",
+            BlendingStyle::Luminosity => "luminosity",
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum CompositionOrBlending {
+    Composition(CompositionStyle),
+    Blending(BlendingStyle),
+}
+
+impl CompositionOrBlending {
+    pub fn to_azure_style(&self) -> CompositionOp {
+        match *self {
+            CompositionOrBlending::Composition(op) => op.to_azure_style(),
+            CompositionOrBlending::Blending(op) => op.to_azure_style(),
+        }
+    }
+
+    pub fn default() -> CompositionOrBlending {
+        CompositionOrBlending::Composition(CompositionStyle::SrcOver)
+    }
+
+    pub fn from_str(string: &str) -> Option<CompositionOrBlending> {
+        if let Some(op) = CompositionStyle::from_str(string) {
+            return Some(CompositionOrBlending::Composition(op));
+        }
+
+        if let Some(op) = BlendingStyle::from_str(string) {
+            return Some(CompositionOrBlending::Blending(op));
+        }
+
+        None
+    }
+}
--- a/servo/components/compositing/Cargo.toml
+++ b/servo/components/compositing/Cargo.toml
@@ -5,16 +5,19 @@ authors = ["The Servo Project Developers
 
 [lib]
 name = "compositing"
 path = "lib.rs"
 
 [dependencies.gfx]
 path = "../gfx"
 
+[dependencies.gfx_traits]
+path = "../gfx_traits"
+
 [dependencies.layout_traits]
 path = "../layout_traits"
 
 [dependencies.script_traits]
 path = "../script_traits"
 
 [dependencies.msg]
 path = "../msg"
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -10,17 +10,17 @@ use pipeline::CompositionPipeline;
 use scrolling::ScrollingTimerProxy;
 use windowing;
 use windowing::{MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
 
 use geom::point::{Point2D, TypedPoint2D};
 use geom::rect::{Rect, TypedRect};
 use geom::scale_factor::ScaleFactor;
 use geom::size::{Size2D, TypedSize2D};
-use gfx::color;
+use gfx_traits::color;
 use gfx::paint_task::Msg as PaintMsg;
 use gfx::paint_task::PaintRequest;
 use gleam::gl::types::{GLint, GLsizei};
 use gleam::gl;
 use layers::geometry::{DevicePixel, LayerPixel};
 use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
 use layers::rendergl::RenderContext;
 use layers::rendergl;
--- a/servo/components/compositing/lib.rs
+++ b/servo/components/compositing/lib.rs
@@ -18,16 +18,17 @@ extern crate layers;
 extern crate layout_traits;
 extern crate png;
 extern crate script_traits;
 extern crate msg;
 extern crate net;
 extern crate num;
 extern crate profile_traits;
 extern crate net_traits;
+extern crate gfx_traits;
 extern crate style;
 #[macro_use]
 extern crate util;
 extern crate gleam;
 extern crate webdriver_traits;
 extern crate clipboard;
 
 extern crate libc;
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -6,19 +6,25 @@ authors = ["The Servo Project Developers
 
 [lib]
 name = "gfx"
 path = "lib.rs"
 
 [dependencies.plugins]
 path = "../plugins"
 
+[dependencies.gfx_traits]
+path = "../gfx_traits"
+
 [dependencies.net_traits]
 path = "../net_traits"
 
+[dependencies.canvas_traits]
+path = "../canvas_traits"
+
 [dependencies.util]
 path = "../util"
 
 [dependencies.msg]
 path = "../msg"
 
 [dependencies.profile_traits]
 path = "../profile_traits"
--- a/servo/components/gfx/lib.rs
+++ b/servo/components/gfx/lib.rs
@@ -33,16 +33,19 @@ extern crate util;
 extern crate msg;
 extern crate rand;
 extern crate string_cache;
 extern crate style;
 extern crate skia;
 extern crate time;
 extern crate url;
 
+extern crate gfx_traits;
+extern crate canvas_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;
 
 // Linux and Android-specific library dependencies
 #[cfg(any(target_os="linux", target_os = "android"))]
 extern crate fontconfig;
 
@@ -54,18 +57,16 @@ extern crate freetype;
 #[cfg(target_os="macos")] extern crate core_graphics;
 #[cfg(target_os="macos")] extern crate core_text;
 
 pub use paint_context::PaintContext;
 
 // Private painting modules
 mod paint_context;
 
-// Painting
-pub mod color;
 #[path="display_list/mod.rs"]
 pub mod display_list;
 pub mod paint_task;
 
 // Fonts
 pub mod font;
 pub mod font_context;
 pub mod font_cache_task;
--- a/servo/components/gfx/paint_context.rs
+++ b/servo/components/gfx/paint_context.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/. */
 
 //! Painting of display lists using Moz2D/Azure.
 
-use color;
+use gfx_traits::color;
 use display_list::TextOrientation::{SidewaysLeft, SidewaysRight, Upright};
 use display_list::{BLUR_INFLATION_FACTOR, BorderRadii, BoxShadowClipMode, ClippingRegion};
 use display_list::{TextDisplayItem};
 use filters;
 use font_context::FontContext;
 use text::TextRun;
 use text::glyph::CharIndex;
 
--- a/servo/components/gfx/paint_task.rs
+++ b/servo/components/gfx/paint_task.rs
@@ -15,28 +15,30 @@ use azure::AzFloat;
 use geom::matrix2d::Matrix2D;
 use geom::point::Point2D;
 use geom::rect::Rect;
 use geom::size::Size2D;
 use layers::platform::surface::{NativeGraphicsMetadata, NativePaintingGraphicsContext};
 use layers::platform::surface::NativeSurface;
 use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
 use layers;
+use canvas_traits::CanvasMsg;
 use msg::compositor_msg::{Epoch, FrameTreeId, LayerId};
 use msg::compositor_msg::{LayerProperties, PaintListener, ScrollPolicy};
 use msg::constellation_msg::Msg as ConstellationMsg;
 use msg::constellation_msg::{ConstellationChan, Failure, PipelineId};
 use msg::constellation_msg::PipelineExitType;
 use profile_traits::time::{self, profile};
 use rand::{self, Rng};
 use skia::SkiaGrGLNativeContextRef;
 use std::borrow::ToOwned;
 use std::mem;
-use std::sync::Arc;
+use std::sync::{Arc, Mutex};
 use std::sync::mpsc::{Receiver, Sender, channel};
+use std::collections::HashMap;
 use util::geometry::{Au, ZERO_POINT};
 use util::opts;
 use util::task::spawn_named_with_send_on_failure;
 use util::task_state;
 use util::task::spawn_named;
 
 /// Information about a hardware graphics layer that layout sends to the painting task.
 #[derive(Clone)]
@@ -64,16 +66,17 @@ pub struct PaintRequest {
     pub buffer_requests: Vec<BufferRequest>,
     pub scale: f32,
     pub layer_id: LayerId,
     pub epoch: Epoch,
 }
 
 pub enum Msg {
     PaintInit(Epoch, Arc<StackingContext>),
+    CanvasLayer(LayerId, Arc<Mutex<Sender<CanvasMsg>>>),
     Paint(Vec<PaintRequest>, FrameTreeId),
     UnusedBuffer(Vec<Box<LayerBuffer>>),
     PaintPermissionGranted,
     PaintPermissionRevoked,
     Exit(Option<Sender<()>>, PipelineExitType),
 }
 
 #[derive(Clone)]
@@ -120,16 +123,19 @@ pub struct PaintTask<C> {
     buffer_map: BufferMap,
 
     /// Communication handles to each of the worker threads.
     worker_threads: Vec<WorkerThreadProxy>,
 
     /// Tracks the number of buffers that the compositor currently owns. The
     /// PaintTask waits to exit until all buffers are returned.
     used_buffer_count: usize,
+
+    /// A map to track the canvas specific layers
+    canvas_map: HashMap<LayerId, Arc<Mutex<Sender<CanvasMsg>>>>,
 }
 
 // If we implement this as a function, we get borrowck errors from borrowing
 // the whole PaintTask struct.
 macro_rules! native_graphics_context(
     ($task:expr) => (
         $task.native_graphics_context.as_ref().expect("Need a graphics context to do painting")
     )
@@ -165,16 +171,17 @@ impl<C> PaintTask<C> where C: PaintListe
                     time_profiler_chan: time_profiler_chan,
                     native_graphics_context: native_graphics_context,
                     root_stacking_context: None,
                     paint_permission: false,
                     current_epoch: None,
                     buffer_map: BufferMap::new(10000000),
                     worker_threads: worker_threads,
                     used_buffer_count: 0,
+                    canvas_map: HashMap::new()
                 };
 
                 paint_task.start();
 
                 // Destroy all the buffers.
                 match paint_task.native_graphics_context.as_ref() {
                     Some(ctx) => paint_task.buffer_map.clear(ctx),
                     None => (),
@@ -211,16 +218,21 @@ impl<C> PaintTask<C> where C: PaintListe
 
                     // If waiting to exit, ignore any more paint commands
                     if waiting_for_compositor_buffers_to_exit {
                         continue;
                     }
 
                     self.initialize_layers();
                 }
+                // Inserts a new canvas renderer to the layer map
+                Msg::CanvasLayer(layer_id, canvas_renderer) => {
+                    debug!("Renderer received for canvas with layer {:?}", layer_id);
+                    self.canvas_map.insert(layer_id, canvas_renderer);
+                }
                 Msg::Paint(requests, frame_tree_id) => {
                     if !self.paint_permission {
                         debug!("PaintTask: paint ready msg");
                         let ConstellationChan(ref mut c) = self.constellation_chan;
                         c.send(ConstellationMsg::PainterReady(self.id)).unwrap();
                         continue;
                     }
 
new file mode 100644
--- /dev/null
+++ b/servo/components/gfx_traits/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "gfx_traits"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+
+[lib]
+name = "gfx_traits"
+path = "lib.rs"
+
+[dependencies.azure]
+git = "https://github.com/servo/rust-azure"
rename from servo/components/gfx/color.rs
rename to servo/components/gfx_traits/color.rs
new file mode 100644
--- /dev/null
+++ b/servo/components/gfx_traits/lib.rs
@@ -0,0 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#![crate_name = "gfx_traits"]
+#![crate_type = "rlib"]
+extern crate azure;
+
+pub mod color;
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -8,19 +8,25 @@ name = "layout"
 path = "lib.rs"
 
 [dependencies.azure]
 git = "https://github.com/servo/rust-azure"
 
 [dependencies.canvas]
 path = "../canvas"
 
+[dependencies.canvas_traits]
+path = "../canvas_traits"
+
 [dependencies.gfx]
 path = "../gfx"
 
+[dependencies.gfx_traits]
+path = "../gfx_traits"
+
 [dependencies.msg]
 path = "../msg"
 
 [dependencies.script]
 path = "../script"
 
 [dependencies.layout_traits]
 path = "../layout_traits"
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -3,31 +3,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Data needed by the layout task.
 
 #![allow(unsafe_code)]
 
 use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
 
+use canvas_traits::CanvasMsg;
+use msg::compositor_msg::LayerId;
 use geom::{Rect, Size2D};
 use gfx::display_list::OpaqueNode;
 use gfx::font_cache_task::FontCacheTask;
 use gfx::font_context::FontContext;
-use msg::compositor_msg::LayerId;
 use msg::constellation_msg::ConstellationChan;
 use net_traits::image::base::Image;
 use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState};
 use script::layout_interface::{Animation, LayoutChan, ReflowGoal};
 use std::boxed;
 use std::cell::Cell;
 use std::collections::HashMap;
 use std::collections::hash_state::DefaultState;
 use std::ptr;
-use std::sync::Arc;
+use std::sync::{Arc, Mutex};
 use std::sync::mpsc::{channel, Sender};
 use style::selector_matching::Stylist;
 use url::Url;
 use util::fnv::FnvHasher;
 use util::geometry::Au;
 use util::opts;
 
 struct LocalLayoutContext {
@@ -98,16 +99,19 @@ pub struct SharedLayoutContext {
     /// Starts at zero, and increased by one every time a layout completes.
     /// This can be used to easily check for invalid stale data.
     pub generation: u32,
 
     /// A channel on which new animations that have been triggered by style recalculation can be
     /// sent.
     pub new_animations_sender: Sender<Animation>,
 
+    /// A channel to send canvas renderers to paint task, in order to correctly paint the layers
+    pub canvas_layers_sender: Sender<(LayerId, Option<Arc<Mutex<Sender<CanvasMsg>>>>)>,
+
     /// The visible rects for each layer, as reported to us by the compositor.
     pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
 
     /// Why is this reflow occurring
     pub goal: ReflowGoal,
 }
 
 pub struct SharedLayoutContextWrapper(pub *const SharedLayoutContext);
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -7,60 +7,67 @@
 //! Other browser engines sometimes call this "painting", but it is more accurately called display
 //! list building, as the actual painting does not happen here—only deciding *what* we're going to
 //! paint.
 
 #![deny(unsafe_code)]
 
 use azure::azure_hl::Color;
 use block::BlockFlow;
-use canvas::canvas_msg::{CanvasMsg, CanvasCommonMsg};
 use context::LayoutContext;
 use flow::{self, BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER};
 use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo};
 use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo};
 use inline::InlineFlow;
 use list_item::ListItemFlow;
 use model::{self, MaybeAuto, ToGfxMatrix};
 use table_cell::CollapsedBordersForCell;
 
 use geom::{Matrix2D, Point2D, Rect, Size2D, SideOffsets2D};
-use gfx::color;
+use gfx_traits::color;
 use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
 use gfx::display_list::{DisplayItem, DisplayList, DisplayItemMetadata};
 use gfx::display_list::{GradientDisplayItem};
 use gfx::display_list::{GradientStop, ImageDisplayItem, LineDisplayItem};
 use gfx::display_list::{OpaqueNode, SolidColorDisplayItem};
 use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
 use gfx::paint_task::{PaintLayer, THREAD_TINT_COLORS};
-use msg::compositor_msg::ScrollPolicy;
+use msg::compositor_msg::{ScrollPolicy, LayerId};
 use msg::constellation_msg::ConstellationChan;
 use msg::constellation_msg::Msg as ConstellationMsg;
 use png::{self, PixelsByColorType};
 use std::cmp;
 use std::default::Default;
 use std::iter::repeat;
 use std::sync::Arc;
-use std::sync::mpsc::channel;
 use style::computed_values::filter::Filter;
 use style::computed_values::transform::ComputedMatrix;
 use style::computed_values::{background_attachment, background_clip, background_origin, background_repeat, background_size};
 use style::computed_values::{border_style, image_rendering, overflow_x, position, visibility};
 use style::properties::ComputedValues;
 use style::properties::style_structs::Border;
 use style::values::RGBA;
 use style::values::computed::{Image, LinearGradient, LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
 use url::Url;
 use util::cursor::Cursor;
 use util::geometry::{Au, ZERO_POINT};
 use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
 use util::opts;
 
+use canvas_traits::{CanvasMsg, CanvasCommonMsg};
+use std::sync::mpsc::channel;
+
+/// A possible `PaintLayer` for an stacking context
+pub enum StackingContextLayer {
+    Existing(PaintLayer),
+    IfCanvas(LayerId),
+}
+
 /// The results of display list building for a single flow.
 pub enum DisplayListBuildingResult {
     None,
     StackingContext(Arc<StackingContext>),
     Normal(Box<DisplayList>),
 }
 
 impl DisplayListBuildingResult {
@@ -235,17 +242,18 @@ pub trait FragmentDisplayListBuilding {
                                                   display_list: &mut DisplayList,
                                                   stacking_relative_border_box: &Rect<Au>,
                                                   clip: &ClippingRegion);
 
     /// Creates a stacking context for associated fragment.
     fn create_stacking_context(&self,
                                base_flow: &BaseFlow,
                                display_list: Box<DisplayList>,
-                               layer: Option<Arc<PaintLayer>>)
+                               layout_context: &LayoutContext,
+                               layer: StackingContextLayer)
                                -> Arc<StackingContext>;
 
 }
 
 fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> {
     // No two corners' border radii may add up to more than the length of the edge
     // between them. To prevent that, all radii are scaled down uniformly.
     fn scale_factor(radius_a: Au, radius_b: Au, edge_length: Au) -> f32 {
@@ -1072,61 +1080,59 @@ impl FragmentDisplayListBuilding for Fra
                                                    (*clip).clone()),
                         image: image.clone(),
                         stretch_size: stacking_relative_content_box.size,
                         image_rendering: self.style.get_effects().image_rendering.clone(),
                     }));
                 }
             }
             SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
+                // TODO(ecoal95): make the canvas with a renderer use the custom layer
                 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);
-
                 let (sender, receiver) = channel::<Vec<u8>>();
                 let canvas_data = match canvas_fragment_info.renderer {
                     Some(ref renderer) =>  {
                         renderer.lock().unwrap().send(CanvasMsg::Common(
                                 CanvasCommonMsg::SendPixelContents(sender))).unwrap();
                         receiver.recv().unwrap()
                     },
                     None => repeat(0xFFu8).take(width * height * 4).collect(),
                 };
-
-                let canvas_display_item = box ImageDisplayItem {
+                display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem{
                     base: BaseDisplayItem::new(stacking_relative_content_box,
                                                DisplayItemMetadata::new(self.node,
-                                                                            &*self.style,
-                                                                            Cursor::DefaultCursor),
+                                                                        &*self.style,
+                                                                        Cursor::DefaultCursor),
                                                (*clip).clone()),
                     image: Arc::new(png::Image {
                         width: width as u32,
                         height: height as u32,
                         pixels: PixelsByColorType::RGBA8(canvas_data),
                     }),
                     stretch_size: stacking_relative_content_box.size,
                     image_rendering: image_rendering::T::Auto,
-                };
-
-                display_list.content.push_back(DisplayItem::ImageClass(canvas_display_item));
+                }));
             }
             SpecificFragmentInfo::UnscannedText(_) => {
                 panic!("Shouldn't see unscanned fragments here.")
             }
             SpecificFragmentInfo::TableColumn(_) => {
                 panic!("Shouldn't see table column fragments here.")
             }
         }
     }
 
     fn create_stacking_context(&self,
                                base_flow: &BaseFlow,
                                display_list: Box<DisplayList>,
-                               layer: Option<Arc<PaintLayer>>)
+                               layout_context: &LayoutContext,
+                               layer: StackingContextLayer)
                                -> Arc<StackingContext> {
         let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position,
                                                                &base_flow.absolute_position_info
                                                                .relative_containing_block_size,
                                                                base_flow.absolute_position_info
                                                                .relative_containing_block_mode,
                                                                CoordinateSystem::Parent);
 
@@ -1148,16 +1154,38 @@ impl FragmentDisplayListBuilding for Fra
 
         // Create the filter pipeline.
         let effects = self.style().get_effects();
         let mut filters = effects.filter.clone();
         if effects.opacity != 1.0 {
             filters.push(Filter::Opacity(effects.opacity))
         }
 
+        // Ensure every canvas has a layer
+        let layer = match layer {
+            StackingContextLayer::Existing(existing_layer) => Some(existing_layer),
+            StackingContextLayer::IfCanvas(layer_id) => {
+                if let SpecificFragmentInfo::Canvas(_) = self.specific {
+                    Some(PaintLayer::new(layer_id, color::transparent(), ScrollPolicy::Scrollable))
+                } else {
+                    None
+                }
+            }
+        };
+
+        // If it's a canvas we must propagate the layer and the renderer to the paint
+        // task
+        if let SpecificFragmentInfo::Canvas(ref fragment_info) = self.specific {
+            let layer_id = layer.as_ref().unwrap().id;
+            layout_context.shared.canvas_layers_sender
+                .send((layer_id, fragment_info.renderer.clone())).unwrap();
+        }
+
+        let layer = layer.map(|l| Arc::new(l));
+
         Arc::new(StackingContext::new(display_list,
                                       &border_box,
                                       &overflow,
                                       self.style().get_box().z_index.number_or_zero(),
                                       &transform,
                                       filters,
                                       self.style().get_effects().mix_blend_mode,
                                       layer))
@@ -1414,20 +1442,21 @@ impl BlockFlowDisplayListBuilding for Bl
                                            border_painting_mode: BorderPaintingMode,
                                            background_border_level: BackgroundAndBorderLevel) {
         self.build_display_list_for_block_base(&mut *display_list,
                                                layout_context,
                                                border_painting_mode,
                                                background_border_level);
 
         self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
-            DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
-                    &self.base,
-                    display_list,
-                    None))
+            DisplayListBuildingResult::StackingContext(
+                self.fragment.create_stacking_context(&self.base,
+                                                      display_list,
+                                                      layout_context,
+                                                      StackingContextLayer::IfCanvas(self.layer_id(0))))
         } else {
             match self.fragment.style.get_box().position {
                 position::T::static_ => {}
                 _ => {
                     display_list.form_pseudo_stacking_context_for_positioned_content();
                 }
             }
             DisplayListBuildingResult::Normal(display_list)
@@ -1447,52 +1476,56 @@ impl BlockFlowDisplayListBuilding for Bl
         self.build_display_list_for_block_base(&mut *display_list,
                                                layout_context,
                                                border_painting_mode,
                                                BackgroundAndBorderLevel::RootOfStackingContext);
 
         if !self.will_get_layer() {
             // We didn't need a layer.
             self.base.display_list_building_result =
-                DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
-                        &self.base,
-                        display_list,
-                        None));
+                DisplayListBuildingResult::StackingContext(
+                    self.fragment.create_stacking_context(&self.base,
+                                                          display_list,
+                                                          layout_context,
+                                                          StackingContextLayer::IfCanvas(self.layer_id(0))));
             return
         }
 
         // If we got here, then we need a new layer.
         let scroll_policy = if self.is_fixed() {
             ScrollPolicy::FixedPosition
         } else {
             ScrollPolicy::Scrollable
         };
 
-        let transparent = color::transparent();
-        let stacking_context = self.fragment.create_stacking_context(
-            &self.base,
-            display_list,
-            Some(Arc::new(PaintLayer::new(self.layer_id(0), transparent, scroll_policy))));
+        let paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy);
+        let stacking_context = self.fragment.create_stacking_context(&self.base,
+                                                                     display_list,
+                                                                     layout_context,
+                                                                     StackingContextLayer::Existing(paint_layer));
         self.base.display_list_building_result =
             DisplayListBuildingResult::StackingContext(stacking_context)
     }
 
     fn build_display_list_for_floating_block(&mut self,
                                              mut display_list: Box<DisplayList>,
                                              layout_context: &LayoutContext,
                                              border_painting_mode: BorderPaintingMode) {
         self.build_display_list_for_block_base(&mut *display_list,
                                                layout_context,
                                                border_painting_mode,
                                                BackgroundAndBorderLevel::RootOfStackingContext);
         display_list.form_float_pseudo_stacking_context();
 
         self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
             DisplayListBuildingResult::StackingContext(
-                self.fragment.create_stacking_context(&self.base, display_list, None))
+                self.fragment.create_stacking_context(&self.base,
+                                                      display_list,
+                                                      layout_context,
+                                                      StackingContextLayer::IfCanvas(self.layer_id(0))))
         } else {
             DisplayListBuildingResult::Normal(display_list)
         }
     }
 
     fn build_display_list_for_block(&mut self,
                                     display_list: Box<DisplayList>,
                                     layout_context: &LayoutContext,
@@ -1539,16 +1572,17 @@ impl InlineFlowDisplayListBuilding for I
                                             .absolute_position_info
                                             .relative_containing_block_mode,
                                         BorderPaintingMode::Separate,
                                         BackgroundAndBorderLevel::Content,
                                         &self.base.clip,
                                         &self.base.stacking_relative_position_of_display_port);
 
             has_stacking_context = fragment.establishes_stacking_context();
+
             match fragment.specific {
                 SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
                     let block_flow = &mut *block_flow.flow_ref;
                     flow::mut_base(block_flow).display_list_building_result
                                               .add_to(&mut *display_list)
                 }
                 SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
                     let block_flow = &mut *block_flow.flow_ref;
@@ -1566,27 +1600,33 @@ impl InlineFlowDisplayListBuilding for I
 
         if !self.fragments.fragments.is_empty() {
             self.base.build_display_items_for_debugging_tint(&mut *display_list,
                                                              self.fragments.fragments[0].node);
         }
 
         // FIXME(Savago): fix Fragment::establishes_stacking_context() for absolute positioned item
         // and remove the check for filter presence. Further details on #5812.
-        if has_stacking_context &&
-                !self.fragments.fragments[0].style().get_effects().filter.is_empty() {
-            self.base.display_list_building_result =
-                DisplayListBuildingResult::StackingContext(
-                    self.fragments.fragments[0].create_stacking_context(&self.base,
-                                                                        display_list,
-                                                                        None));
+        has_stacking_context = has_stacking_context && {
+            if let SpecificFragmentInfo::Canvas(_) = self.fragments.fragments[0].specific {
+                true
+            } else {
+                !self.fragments.fragments[0].style().get_effects().filter.is_empty()
+            }
+        };
+
+        self.base.display_list_building_result = if has_stacking_context {
+            DisplayListBuildingResult::StackingContext(
+                self.fragments.fragments[0].create_stacking_context(&self.base,
+                                                                    display_list,
+                                                                    layout_context,
+                                                                    StackingContextLayer::IfCanvas(self.layer_id(0))))
         } else {
-            self.base.display_list_building_result =
-                DisplayListBuildingResult::Normal(display_list);
-        }
+            DisplayListBuildingResult::Normal(display_list)
+        };
 
         if opts::get().validate_display_list_geometry {
             self.base.validate_display_list_geometry();
         }
     }
 }
 
 pub trait ListItemFlowDisplayListBuilding {
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -1,17 +1,17 @@
 /* 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 `Fragment` type, which represents the leaves of the layout tree.
 
 #![deny(unsafe_code)]
 
-use canvas::canvas_msg::CanvasMsg;
+use canvas_traits::CanvasMsg;
 use css::node_style::StyledNode;
 use context::LayoutContext;
 use floats::ClearType;
 use flow;
 use flow::Flow;
 use flow_ref::FlowRef;
 use incremental::{self, RestyleDamage};
 use inline::{InlineFragmentContext, InlineFragmentNodeInfo, InlineMetrics};
@@ -190,19 +190,17 @@ impl SpecificFragmentInfo {
     pub fn get_type(&self) -> &'static str {
         match *self {
             SpecificFragmentInfo::Canvas(_) => "SpecificFragmentInfo::Canvas",
             SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic",
             SpecificFragmentInfo::GeneratedContent(_) => "SpecificFragmentInfo::GeneratedContent",
             SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
             SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
             SpecificFragmentInfo::InlineAbsolute(_) => "SpecificFragmentInfo::InlineAbsolute",
-            SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
-                "SpecificFragmentInfo::InlineAbsoluteHypothetical"
-            }
+            SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => "SpecificFragmentInfo::InlineAbsoluteHypothetical",
             SpecificFragmentInfo::InlineBlock(_) => "SpecificFragmentInfo::InlineBlock",
             SpecificFragmentInfo::ScannedText(_) => "SpecificFragmentInfo::ScannedText",
             SpecificFragmentInfo::Table => "SpecificFragmentInfo::Table",
             SpecificFragmentInfo::TableCell => "SpecificFragmentInfo::TableCell",
             SpecificFragmentInfo::TableColumn(_) => "SpecificFragmentInfo::TableColumn",
             SpecificFragmentInfo::TableRow => "SpecificFragmentInfo::TableRow",
             SpecificFragmentInfo::TableWrapper => "SpecificFragmentInfo::TableWrapper",
             SpecificFragmentInfo::UnscannedText(_) => "SpecificFragmentInfo::UnscannedText",
@@ -1992,16 +1990,23 @@ impl Fragment {
             return true
         }
         if self.style().get_effects().mix_blend_mode != mix_blend_mode::T::normal {
             return true
         }
         if self.style().get_effects().transform.is_some() {
             return true
         }
+
+        // Canvas always layerizes, as an special case
+        // FIXME(pcwalton): Don't unconditionally form stacking contexts for each canvas.
+        if let SpecificFragmentInfo::Canvas(_) = self.specific {
+            return true
+        }
+
         match self.style().get_box().position {
             position::T::absolute | position::T::fixed => {
                 // FIXME(pcwalton): This should only establish a new stacking context when
                 // `z-index` is not `auto`. But this matches what we did before.
                 true
             }
             position::T::relative | position::T::static_ => {
                 // FIXME(pcwalton): `position: relative` establishes a new stacking context if
--- a/servo/components/layout/layout_task.rs
+++ b/servo/components/layout/layout_task.rs
@@ -19,32 +19,33 @@ use fragment::{Fragment, FragmentBorderB
 use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
 use layout_debug;
 use opaque_node::OpaqueNodeMethods;
 use parallel::{self, UnsafeFlow};
 use sequential;
 use wrapper::{LayoutNode, TLayoutNode};
 
 use azure::azure::AzColor;
+use canvas_traits::CanvasMsg;
 use encoding::EncodingRef;
 use encoding::all::UTF_8;
 use geom::matrix2d::Matrix2D;
 use geom::point::Point2D;
 use geom::rect::Rect;
 use geom::scale_factor::ScaleFactor;
 use geom::size::Size2D;
-use gfx::color;
+use gfx_traits::color;
 use gfx::display_list::{ClippingRegion, DisplayItemMetadata, DisplayList, OpaqueNode};
 use gfx::display_list::{StackingContext};
 use gfx::font_cache_task::FontCacheTask;
 use gfx::paint_task::Msg as PaintMsg;
 use gfx::paint_task::{PaintChan, PaintLayer};
 use layout_traits::{LayoutControlMsg, LayoutTaskFactory};
 use log;
-use msg::compositor_msg::{Epoch, LayerId, ScrollPolicy};
+use msg::compositor_msg::{Epoch, ScrollPolicy, LayerId};
 use msg::constellation_msg::Msg as ConstellationMsg;
 use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
 use profile_traits::mem::{self, Report, ReportsChan};
 use profile_traits::time::{self, ProfilerMetadata, profile};
 use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
 use net_traits::{load_bytes_iter, PendingAsyncLoad};
 use net_traits::image_cache_task::{ImageCacheTask, ImageCacheResult, ImageCacheChan};
 use script::dom::bindings::js::LayoutJS;
@@ -129,17 +130,17 @@ pub struct LayoutTaskData {
 
     /// Receives newly-discovered animations.
     pub new_animations_receiver: Receiver<Animation>,
 
     /// A channel on which new animations that have been triggered by style recalculation can be
     /// sent.
     pub new_animations_sender: Sender<Animation>,
 
-    /// A counter for epoch messages.
+    /// A counter for epoch messages
     epoch: Epoch,
 
     /// The position and size of the visible rect for each layer. We do not build display lists
     /// for any areas more than `DISPLAY_PORT_SIZE_FACTOR` screens away from this area.
     pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
 }
 
 /// Information needed by the layout task.
@@ -190,16 +191,21 @@ pub struct LayoutTask {
     pub image_cache_task: ImageCacheTask,
 
     /// Public interface to the font cache task.
     pub font_cache_task: FontCacheTask,
 
     /// Is this the first reflow in this LayoutTask?
     pub first_reflow: Cell<bool>,
 
+    /// To receive a canvas renderer associated to a layer, this message is propagated
+    /// to the paint chan
+    pub canvas_layers_receiver: Receiver<(LayerId, Option<Arc<Mutex<Sender<CanvasMsg>>>>)>,
+    pub canvas_layers_sender: Sender<(LayerId, Option<Arc<Mutex<Sender<CanvasMsg>>>>)>,
+
     /// A mutex to allow for fast, read-only RPC of layout's internal data
     /// structures, while still letting the LayoutTask modify them.
     ///
     /// All the other elements of this struct are read-only.
     pub rw_data: Arc<Mutex<LayoutTaskData>>,
 }
 
 impl LayoutTaskFactory for LayoutTask {
@@ -305,16 +311,17 @@ impl LayoutTask {
         let reporter = box chan.clone();
         let reporter_name = format!("layout-reporter-{}", id.0);
         mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter));
 
 
         // Create the channel on which new animations can be sent.
         let (new_animations_sender, new_animations_receiver) = channel();
         let (image_cache_sender, image_cache_receiver) = channel();
+        let (canvas_layers_sender, canvas_layers_receiver) = channel();
 
         LayoutTask {
             id: id,
             url: url,
             is_iframe: is_iframe,
             port: port,
             pipeline_port: pipeline_port,
             chan: chan,
@@ -324,16 +331,18 @@ impl LayoutTask {
             time_profiler_chan: time_profiler_chan,
             mem_profiler_chan: mem_profiler_chan,
             reporter_name: reporter_name,
             image_cache_task: image_cache_task.clone(),
             font_cache_task: font_cache_task,
             first_reflow: Cell::new(true),
             image_cache_receiver: image_cache_receiver,
             image_cache_sender: ImageCacheChan(image_cache_sender),
+            canvas_layers_receiver: canvas_layers_receiver,
+            canvas_layers_sender: canvas_layers_sender,
             rw_data: Arc::new(Mutex::new(
                 LayoutTaskData {
                     root_flow: None,
                     image_cache_task: image_cache_task,
                     constellation_chan: constellation_chan,
                     screen_size: screen_size,
                     stacking_context: None,
                     stylist: box Stylist::new(device),
@@ -370,16 +379,17 @@ impl LayoutTask {
         SharedLayoutContext {
             image_cache_task: rw_data.image_cache_task.clone(),
             image_cache_sender: self.image_cache_sender.clone(),
             screen_size: rw_data.screen_size.clone(),
             screen_size_changed: screen_size_changed,
             constellation_chan: rw_data.constellation_chan.clone(),
             layout_chan: self.chan.clone(),
             font_cache_task: self.font_cache_task.clone(),
+            canvas_layers_sender: self.canvas_layers_sender.clone(),
             stylist: &*rw_data.stylist,
             url: (*url).clone(),
             reflow_root: reflow_root.map(|node| OpaqueNodeMethods::from_layout_node(node)),
             dirty: Rect::zero(),
             visible_rects: rw_data.visible_rects.clone(),
             generation: rw_data.generation,
             new_animations_sender: rw_data.new_animations_sender.clone(),
             goal: goal,
@@ -955,16 +965,24 @@ impl LayoutTask {
 
             // Retrieve the (possibly rebuilt) root flow.
             rw_data.root_flow = Some(self.get_layout_root((*node).clone()));
 
             // Kick off animations if any were triggered.
             animation::process_new_animations(&mut *rw_data, self.id);
         }
 
+        // Send new canvas renderers to the paint task
+        while let Ok((layer_id, renderer)) = self.canvas_layers_receiver.try_recv() {
+            // Just send if there's an actual renderer
+            if let Some(renderer) = renderer {
+                self.paint_chan.send(PaintMsg::CanvasLayer(layer_id, renderer));
+            }
+        }
+
         // Perform post-style recalculation layout passes.
         self.perform_post_style_recalc_layout_passes(&data.reflow_info,
                                                      &mut rw_data,
                                                      &mut shared_layout_context);
 
         let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone();
         match data.query_type {
             ReflowQueryType::ContentBoxQuery(node) => {
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -34,23 +34,24 @@ extern crate net_traits;
 extern crate profile_traits;
 
 #[macro_use]
 extern crate util;
 
 extern crate rustc_serialize;
 extern crate alloc;
 extern crate azure;
-extern crate canvas;
+extern crate canvas_traits;
 extern crate clock_ticks;
 extern crate collections;
 extern crate cssparser;
 extern crate encoding;
 extern crate geom;
 extern crate gfx;
+extern crate gfx_traits;
 extern crate layout_traits;
 extern crate libc;
 extern crate msg;
 extern crate png;
 extern crate script;
 extern crate script_traits;
 extern crate selectors;
 extern crate string_cache;
--- a/servo/components/layout/wrapper.rs
+++ b/servo/components/layout/wrapper.rs
@@ -27,17 +27,17 @@
 //!
 //!   o Instead of `get_attr()`, use `.get_attr_val_for_layout()`.
 //!
 //!   o Instead of `html_element_in_html_document()`, use
 //!     `html_element_in_html_document_for_layout()`.
 
 #![allow(unsafe_code)]
 
-use canvas::canvas_msg::CanvasMsg;
+use canvas_traits::CanvasMsg;
 use context::SharedLayoutContext;
 use css::node_style::StyledNode;
 use incremental::RestyleDamage;
 use data::{LayoutDataAccess, LayoutDataFlags, LayoutDataWrapper, PrivateLayoutData};
 use opaque_node::OpaqueNodeMethods;
 
 use gfx::display_list::OpaqueNode;
 use script::dom::attr::AttrValue;
--- a/servo/components/msg/Cargo.toml
+++ b/servo/components/msg/Cargo.toml
@@ -1,10 +1,9 @@
 [package]
-
 name = "msg"
 version = "0.0.1"
 authors = ["The Servo Project Developers"]
 
 [lib]
 name = "msg"
 path = "lib.rs"
 
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -37,16 +37,19 @@ path = "../devtools_traits"
 path = "../style"
 
 [dependencies.gfx]
 path = "../gfx"
 
 [dependencies.canvas]
 path = "../canvas"
 
+[dependencies.canvas_traits]
+path = "../canvas_traits"
+
 [dependencies.webdriver_traits]
 path = "../webdriver_traits"
 
 [dependencies.selectors]
 git = "https://github.com/servo/rust-selectors"
 
 [dependencies.geom]
 git = "https://github.com/servo/rust-geom"
--- a/servo/components/script/dom/bindings/trace.rs
+++ b/servo/components/script/dom/bindings/trace.rs
@@ -29,18 +29,18 @@
 //! The `no_jsmanaged_fields!()` macro adds an empty implementation of `JSTraceable` to
 //! a datatype.
 
 use dom::bindings::js::JS;
 use dom::bindings::refcounted::Trusted;
 use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler};
 use script_task::ScriptChan;
 
-use canvas::canvas_paint_task::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle};
-use canvas::canvas_paint_task::{LineCapStyle, LineJoinStyle, CompositionOrBlending};
+use canvas_traits::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle};
+use canvas_traits::{LineCapStyle, LineJoinStyle, CompositionOrBlending};
 use cssparser::RGBA;
 use encoding::types::EncodingRef;
 use geom::matrix2d::Matrix2D;
 use geom::rect::Rect;
 use html5ever::tree_builder::QuirksMode;
 use hyper::header::Headers;
 use hyper::method::Method;
 use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSGCTraceKind};
--- a/servo/components/script/dom/canvasgradient.rs
+++ b/servo/components/script/dom/canvasgradient.rs
@@ -1,14 +1,14 @@
 /* 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 cssparser::RGBA;
-use canvas::canvas_paint_task::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle};
+use canvas_traits::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle};
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::CanvasGradientBinding;
 use dom::bindings::codegen::Bindings::CanvasGradientBinding::CanvasGradientMethods;
 use dom::bindings::global::GlobalRef;
 use dom::bindings::js::{JSRef, Temporary};
 use dom::bindings::num::Finite;
 use dom::bindings::utils::{Reflector, reflect_dom_object};
 use dom::canvasrenderingcontext2d::parse_color;
--- a/servo/components/script/dom/canvasrenderingcontext2d.rs
+++ b/servo/components/script/dom/canvasrenderingcontext2d.rs
@@ -23,20 +23,20 @@ use dom::node::{window_from_node, NodeHe
 
 use cssparser::Color as CSSColor;
 use cssparser::{Parser, RGBA, ToCss};
 use geom::matrix2d::Matrix2D;
 use geom::point::Point2D;
 use geom::rect::Rect;
 use geom::size::Size2D;
 
-use canvas::canvas_msg::{CanvasMsg, Canvas2dMsg, CanvasCommonMsg};
-use canvas::canvas_paint_task::{CanvasPaintTask, FillOrStrokeStyle};
-use canvas::canvas_paint_task::{LinearGradientStyle, RadialGradientStyle};
-use canvas::canvas_paint_task::{LineCapStyle, LineJoinStyle, CompositionOrBlending};
+use canvas_traits::{CanvasMsg, Canvas2dMsg, CanvasCommonMsg};
+use canvas_traits::{FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle};
+use canvas_traits::{LineCapStyle, LineJoinStyle, CompositionOrBlending};
+use canvas::canvas_paint_task::CanvasPaintTask;
 
 use net_traits::image::base::Image;
 use net_traits::image_cache_task::ImageCacheChan;
 use png::PixelsByColorType;
 
 use num::{Float, ToPrimitive};
 use std::borrow::ToOwned;
 use std::cell::RefCell;
--- a/servo/components/script/dom/htmlcanvaselement.rs
+++ b/servo/components/script/dom/htmlcanvaselement.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use canvas::canvas_msg::CanvasMsg;
+use canvas_traits::CanvasMsg;
 use dom::attr::Attr;
 use dom::attr::AttrHelpers;
 use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
 use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
 use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived;
 use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
 use dom::bindings::codegen::UnionTypes::CanvasRenderingContext2DOrWebGLRenderingContext;
 use dom::bindings::global::GlobalRef;
--- a/servo/components/script/dom/webglrenderingcontext.rs
+++ b/servo/components/script/dom/webglrenderingcontext.rs
@@ -1,14 +1,14 @@
 /* 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::webgl_paint_task::WebGLPaintTask;
-use canvas::canvas_msg::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg};
+use canvas_traits::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg};
 use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding;
 use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{ WebGLRenderingContextMethods, WebGLRenderingContextConstants};
 use dom::bindings::global::{GlobalRef, GlobalField};
 use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary};
 use dom::bindings::utils::{Reflector, reflect_dom_object};
 use dom::htmlcanvaselement::{HTMLCanvasElement};
 use dom::webglbuffer::{WebGLBuffer, WebGLBufferHelpers};
 use dom::webglshader::{WebGLShader, WebGLShaderHelpers};
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -35,16 +35,17 @@ extern crate js;
 extern crate libc;
 extern crate msg;
 extern crate net_traits;
 extern crate num;
 extern crate png;
 extern crate rustc_serialize;
 extern crate time;
 extern crate canvas;
+extern crate canvas_traits;
 extern crate profile_traits;
 extern crate script_traits;
 extern crate selectors;
 extern crate util;
 extern crate websocket;
 #[macro_use]
 extern crate style;
 extern crate unicase;
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -64,26 +64,39 @@ name = "byteorder"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "canvas"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+ "canvas_traits 0.0.1",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
- "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.0.1 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
  "util 0.0.1",
 ]
 
 [[package]]
+name = "canvas_traits"
+version = "0.0.1"
+dependencies = [
+ "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+ "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
+ "gfx_traits 0.0.1",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
+]
+
+[[package]]
 name = "cgl"
 version = "0.0.1"
 source = "git+https://github.com/servo/rust-cgl#851ca1b90081d221c3c38d33548d3e22a19db79f"
 dependencies = [
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -110,16 +123,17 @@ version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "clipboard 0.0.1 (git+https://github.com/servo/rust-x11-clipboard)",
  "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
  "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
  "devtools_traits 0.0.1",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "layout_traits 0.0.1",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net 0.0.1",
  "net_traits 0.0.1",
  "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -350,22 +364,24 @@ dependencies = [
 ]
 
 [[package]]
 name = "gfx"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "canvas_traits 0.0.1",
  "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
  "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
  "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
  "fontconfig 0.1.0 (git+https://github.com/servo/rust-fontconfig)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
+ "gfx_traits 0.0.1",
  "harfbuzz 0.1.0 (git+https://github.com/servo/rust-harfbuzz)",
  "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "png 0.1.0 (git+https://github.com/servo/rust-png)",
  "profile_traits 0.0.1",
@@ -384,16 +400,23 @@ dependencies = [
 [[package]]
 name = "gfx_tests"
 version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
 ]
 
 [[package]]
+name = "gfx_traits"
+version = "0.0.1"
+dependencies = [
+ "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+]
+
+[[package]]
 name = "gl"
 version = "0.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_common 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "gl_generator 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "khronos_api 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -642,21 +665,23 @@ dependencies = [
 
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas 0.0.1",
+ "canvas_traits 0.0.1",
  "clock_ticks 0.0.5 (git+https://github.com/tomaka/clock_ticks)",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "layout_traits 0.0.1",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "png 0.1.0 (git+https://github.com/servo/rust-png)",
  "profile_traits 0.0.1",
  "rustc-serialize 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -848,23 +873,24 @@ source = "registry+https://github.com/ru
 dependencies = [
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_buf 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "offscreen_gl_context"
 version = "0.0.1"
-source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#c2b3dfd7fe344384e4206672b99c296141f5b4d6"
+source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#97eacf34b72f69b10130a0de016529e98ee32f04"
 dependencies = [
  "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
  "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "glx 0.0.1 (git+https://github.com/servo/rust-glx)",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
 ]
 
 [[package]]
 name = "openssl"
 version = "0.6.1"
@@ -1016,16 +1042,17 @@ version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "script"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas 0.0.1",
+ "canvas_traits 0.0.1",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "devtools_traits 0.0.1",
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
  "html5ever 0.0.0 (git+https://github.com/servo/html5ever)",
  "hyper 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "js 0.1.0 (git+https://github.com/servo/rust-mozjs)",
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -63,26 +63,39 @@ name = "byteorder"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "canvas"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+ "canvas_traits 0.0.1",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
- "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.0.1 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
  "util 0.0.1",
 ]
 
 [[package]]
+name = "canvas_traits"
+version = "0.0.1"
+dependencies = [
+ "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+ "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
+ "gfx_traits 0.0.1",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
+]
+
+[[package]]
 name = "cgl"
 version = "0.0.1"
 source = "git+https://github.com/servo/rust-cgl#851ca1b90081d221c3c38d33548d3e22a19db79f"
 dependencies = [
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -119,16 +132,17 @@ version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "clipboard 0.0.1 (git+https://github.com/servo/rust-x11-clipboard)",
  "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
  "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
  "devtools_traits 0.0.1",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "layout_traits 0.0.1",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net 0.0.1",
  "net_traits 0.0.1",
  "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -359,22 +373,24 @@ dependencies = [
 ]
 
 [[package]]
 name = "gfx"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "canvas_traits 0.0.1",
  "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
  "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
  "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
  "fontconfig 0.1.0 (git+https://github.com/servo/rust-fontconfig)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
+ "gfx_traits 0.0.1",
  "harfbuzz 0.1.0 (git+https://github.com/servo/rust-harfbuzz)",
  "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "png 0.1.0 (git+https://github.com/servo/rust-png)",
  "profile_traits 0.0.1",
@@ -386,16 +402,23 @@ dependencies = [
  "string_cache 0.1.0 (git+https://github.com/servo/string-cache)",
  "style 0.0.1",
  "time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
 ]
 
 [[package]]
+name = "gfx_traits"
+version = "0.0.1"
+dependencies = [
+ "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+]
+
+[[package]]
 name = "gl"
 version = "0.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_common 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "gl_generator 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "khronos_api 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -644,21 +667,23 @@ dependencies = [
 
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas 0.0.1",
+ "canvas_traits 0.0.1",
  "clock_ticks 0.0.5 (git+https://github.com/tomaka/clock_ticks)",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "layout_traits 0.0.1",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "png 0.1.0 (git+https://github.com/servo/rust-png)",
  "profile_traits 0.0.1",
  "rustc-serialize 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -838,23 +863,24 @@ source = "registry+https://github.com/ru
 dependencies = [
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_buf 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "offscreen_gl_context"
 version = "0.0.1"
-source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#c2b3dfd7fe344384e4206672b99c296141f5b4d6"
+source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#97eacf34b72f69b10130a0de016529e98ee32f04"
 dependencies = [
  "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
  "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "glx 0.0.1 (git+https://github.com/servo/rust-glx)",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
 ]
 
 [[package]]
 name = "openssl"
 version = "0.6.1"
@@ -1006,16 +1032,17 @@ version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "script"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas 0.0.1",
+ "canvas_traits 0.0.1",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "devtools_traits 0.0.1",
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
  "html5ever 0.0.0 (git+https://github.com/servo/html5ever)",
  "hyper 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "js 0.1.0 (git+https://github.com/servo/rust-mozjs)",
--- a/servo/ports/gonk/Cargo.lock
+++ b/servo/ports/gonk/Cargo.lock
@@ -50,26 +50,39 @@ name = "byteorder"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "canvas"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+ "canvas_traits 0.0.1",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
- "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.0.1 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
  "util 0.0.1",
 ]
 
 [[package]]
+name = "canvas_traits"
+version = "0.0.1"
+dependencies = [
+ "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+ "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
+ "gfx_traits 0.0.1",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
+]
+
+[[package]]
 name = "cgl"
 version = "0.0.1"
 source = "git+https://github.com/servo/rust-cgl#851ca1b90081d221c3c38d33548d3e22a19db79f"
 dependencies = [
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -96,16 +109,17 @@ version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "clipboard 0.0.1 (git+https://github.com/servo/rust-x11-clipboard)",
  "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
  "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
  "devtools_traits 0.0.1",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "layout_traits 0.0.1",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net 0.0.1",
  "net_traits 0.0.1",
  "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -338,22 +352,24 @@ dependencies = [
 ]
 
 [[package]]
 name = "gfx"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "canvas_traits 0.0.1",
  "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
  "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
  "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
  "fontconfig 0.1.0 (git+https://github.com/servo/rust-fontconfig)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
+ "gfx_traits 0.0.1",
  "harfbuzz 0.1.0 (git+https://github.com/servo/rust-harfbuzz)",
  "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "png 0.1.0 (git+https://github.com/servo/rust-png)",
  "profile_traits 0.0.1",
@@ -365,16 +381,23 @@ dependencies = [
  "string_cache 0.1.0 (git+https://github.com/servo/string-cache)",
  "style 0.0.1",
  "time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
 ]
 
 [[package]]
+name = "gfx_traits"
+version = "0.0.1"
+dependencies = [
+ "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
+]
+
+[[package]]
 name = "gl_common"
 version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -542,21 +565,23 @@ dependencies = [
 
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas 0.0.1",
+ "canvas_traits 0.0.1",
  "clock_ticks 0.0.5 (git+https://github.com/tomaka/clock_ticks)",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
+ "gfx_traits 0.0.1",
  "layout_traits 0.0.1",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "png 0.1.0 (git+https://github.com/servo/rust-png)",
  "profile_traits 0.0.1",
  "rustc-serialize 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -719,23 +744,24 @@ version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "offscreen_gl_context"
 version = "0.0.1"
-source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#c2b3dfd7fe344384e4206672b99c296141f5b4d6"
+source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#97eacf34b72f69b10130a0de016529e98ee32f04"
 dependencies = [
  "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
  "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gleam 0.0.1 (git+https://github.com/servo/gleam)",
  "glx 0.0.1 (git+https://github.com/servo/rust-glx)",
+ "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
  "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
 ]
 
 [[package]]
 name = "openssl"
 version = "0.6.1"
@@ -877,16 +903,17 @@ version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "script"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas 0.0.1",
+ "canvas_traits 0.0.1",
  "cssparser 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "devtools_traits 0.0.1",
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
  "gfx 0.0.1",
  "html5ever 0.0.0 (git+https://github.com/servo/html5ever)",
  "hyper 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "js 0.1.0 (git+https://github.com/servo/rust-mozjs)",