Bug 1345975 - Sort Webrender binding definitions r?kats draft
authorRyan Hunt <rhunt@eqrion.net>
Thu, 09 Mar 2017 17:39:19 -0500
changeset 496201 93c2cdaf1b9310b0a2218a9f255fe4d2ecae6499
parent 496200 748ca189b70aece54cabd179877ec3852042e355
child 496202 1ff190b22dbe3b5d16c487c210e82c5de352b6a9
push id48552
push userbmo:rhunt@eqrion.net
push dateThu, 09 Mar 2017 23:26:57 +0000
reviewerskats
bugs1345975
milestone55.0a1
Bug 1345975 - Sort Webrender binding definitions r?kats MozReview-Commit-ID: B1Z5IcAq8Qm
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -48,543 +48,16 @@ check_ffi_type!(_image_key_repr struct I
 check_ffi_type!(_font_key_repr struct FontKey as (u32, u32));
 check_ffi_type!(_epoch_repr struct Epoch as (u32));
 check_ffi_type!(_image_format_repr enum ImageFormat as u32);
 check_ffi_type!(_border_style_repr enum BorderStyle as u32);
 check_ffi_type!(_image_rendering_repr enum ImageRendering as u32);
 check_ffi_type!(_namespace_id_repr struct IdNamespace as (u32));
 
 #[repr(C)]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct WrWindowId(u64);
-
-#[repr(C)]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct WrImageDescriptor {
-    pub format: ImageFormat,
-    pub width: u32,
-    pub height: u32,
-    pub stride: u32,
-    pub is_opaque: bool,
-}
-
-impl WrImageDescriptor {
-    pub fn to_descriptor(&self) -> ImageDescriptor {
-        ImageDescriptor {
-            width: self.width,
-            height: self.height,
-            stride: if self.stride != 0 { Some(self.stride) } else { None },
-            format: self.format,
-            is_opaque: self.is_opaque,
-            offset: 0,
-        }
-    }
-}
-
-#[repr(C)]
-pub struct WrVecU8 {
-    ptr: *mut u8,
-    length: usize,
-    capacity: usize
-}
-
-impl WrVecU8 {
-    fn to_vec(self) -> Vec<u8> {
-        unsafe { Vec::from_raw_parts(self.ptr, self.length, self.capacity) }
-    }
-    fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
-        let w = WrVecU8{ptr: v.as_mut_ptr(), length: v.len(), capacity: v.capacity()};
-        mem::forget(v);
-        w
-    }
-}
-
-#[no_mangle]
-pub extern fn wr_vec_u8_free(v: WrVecU8) {
-    v.to_vec();
-}
-
-fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void{
-
-    extern  {
-        fn get_proc_address_from_glcontext(glcontext_ptr: *mut c_void, procname: *const c_char) -> *const c_void;
-    }
-
-    let symbol_name = CString::new(name).unwrap();
-    let symbol = unsafe {
-        get_proc_address_from_glcontext(glcontext_ptr, symbol_name.as_ptr())
-    };
-
-    // For now panic, not sure we should be though or if we can recover
-    if symbol.is_null() {
-        // XXX Bug 1322949 Make whitelist for extensions
-        println!("Could not find symbol {:?} by glcontext", symbol_name);
-    }
-
-    symbol as *const _
-}
-
-extern  {
-    fn is_in_compositor_thread() -> bool;
-    fn is_in_render_thread() -> bool;
-    fn is_in_main_thread() -> bool;
-}
-
-#[no_mangle]
-pub extern fn wr_renderer_update(renderer: &mut Renderer) {
-    renderer.update();
-}
-
-#[no_mangle]
-pub extern fn wr_renderer_render(renderer: &mut Renderer, width: u32, height: u32) {
-    renderer.render(DeviceUintSize::new(width, height));
-}
-
-// Call wr_renderer_render() before calling this function.
-#[no_mangle]
-pub unsafe extern fn wr_renderer_readback(width: u32, height: u32,
-                                          dst_buffer: *mut u8, buffer_size: usize) {
-    assert!(is_in_render_thread());
-
-    gl::flush();
-
-    let mut slice = slice::from_raw_parts_mut(dst_buffer, buffer_size);
-    gl::read_pixels_into_buffer(0, 0,
-                                width as gl::GLsizei,
-                                height as gl::GLsizei,
-                                gl::BGRA,
-                                gl::UNSIGNED_BYTE,
-                                slice);
-}
-
-#[no_mangle]
-pub extern fn wr_renderer_set_profiler_enabled(renderer: &mut Renderer, enabled: bool) {
-    renderer.set_profiler_enabled(enabled);
-}
-
-#[no_mangle]
-pub extern fn wr_renderer_set_external_image_handler(renderer: &mut Renderer,
-                                                     external_image_handler: *mut WrExternalImageHandler) {
-    if !external_image_handler.is_null() {
-        renderer.set_external_image_handler(Box::new(
-            unsafe {
-                WrExternalImageHandler {
-                    external_image_obj: (*external_image_handler).external_image_obj,
-                    lock_func: (*external_image_handler).lock_func,
-                    unlock_func: (*external_image_handler).unlock_func,
-                    release_func: (*external_image_handler).release_func,
-                }
-            }));
-    }
-}
-
-#[no_mangle]
-pub extern fn wr_renderer_current_epoch(renderer: &mut Renderer,
-                                        pipeline_id: PipelineId,
-                                        out_epoch: &mut Epoch) -> bool {
-    if let Some(epoch) = renderer.current_epoch(pipeline_id) {
-        *out_epoch = epoch;
-        return true;
-    }
-    return false;
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_renderer_delete(renderer: *mut Renderer) {
-    Box::from_raw(renderer);
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_api_get_namespace(api: &mut RenderApi) -> IdNamespace
-{
-    api.id_namespace
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_api_delete(api: *mut RenderApi) {
-    let api = Box::from_raw(api);
-    api.shut_down();
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_api_finalize_builder(state: &mut WrState,
-                                             dl_descriptor: &mut BuiltDisplayListDescriptor,
-                                             dl_data: &mut WrVecU8,
-                                             aux_descriptor: &mut AuxiliaryListsDescriptor,
-                                             aux_data: &mut WrVecU8)
-{
-    let frame_builder = mem::replace(&mut state.frame_builder,
-                                     WebRenderFrameBuilder::new(state.pipeline_id));
-    let (_, dl, aux) = frame_builder.dl_builder.finalize();
-    //XXX: get rid of the copies here
-    *dl_data = WrVecU8::from_vec(dl.data().to_owned());
-    *dl_descriptor = dl.descriptor().clone();
-    *aux_data = WrVecU8::from_vec(aux.data().to_owned());
-    *aux_descriptor = aux.descriptor().clone();
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_dp_push_built_display_list(state: &mut WrState,
-                                                   dl_descriptor: BuiltDisplayListDescriptor,
-                                                   dl_data: WrVecU8,
-                                                   aux_descriptor: AuxiliaryListsDescriptor,
-                                                   aux_data: WrVecU8)
-{
-    let dl_vec = dl_data.to_vec();
-    let aux_vec = aux_data.to_vec();
-
-    let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
-    let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
-
-    state.frame_builder.dl_builder.push_built_display_list(dl, aux);
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_api_set_root_display_list(api: &mut RenderApi,
-                                                  epoch: Epoch,
-                                                  viewport_width: f32,
-                                                  viewport_height: f32,
-                                                  pipeline_id: PipelineId,
-                                                  dl_descriptor: BuiltDisplayListDescriptor,
-                                                  dl_data: *mut u8,
-                                                  dl_size: usize,
-                                                  aux_descriptor: AuxiliaryListsDescriptor,
-                                                  aux_data: *mut u8,
-                                                  aux_size: usize) {
-    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
-    // See the documentation of set_root_display_list in api.rs. I don't think
-    // it makes a difference in gecko at the moment(until APZ is figured out)
-    // but I suppose it is a good default.
-    let preserve_frame_state = true;
-
-    let dl_slice = slice::from_raw_parts(dl_data, dl_size);
-    let mut dl_vec = Vec::new();
-    // XXX: see if we can get rid of the copy here
-    dl_vec.extend_from_slice(dl_slice);
-    let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
-
-    let aux_slice = slice::from_raw_parts(aux_data, aux_size);
-    let mut aux_vec = Vec::new();
-    // XXX: see if we can get rid of the copy here
-    aux_vec.extend_from_slice(aux_slice);
-    let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
-
-    api.set_root_display_list(Some(root_background_color),
-                              epoch,
-                              LayoutSize::new(viewport_width, viewport_height),
-                              (pipeline_id, dl, aux),
-                              preserve_frame_state);
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_api_clear_root_display_list(api: &mut RenderApi,
-                                                    epoch: Epoch,
-                                                    pipeline_id: PipelineId) {
-    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
-    let preserve_frame_state = true;
-    let frame_builder = WebRenderFrameBuilder::new(pipeline_id);
-
-    api.set_root_display_list(Some(root_background_color),
-                              epoch,
-                              LayoutSize::new(0.0, 0.0),
-                              frame_builder.dl_builder.finalize(),
-                              preserve_frame_state);
-}
-
-
-#[no_mangle]
-pub extern fn wr_api_set_window_parameters(api: &mut RenderApi,
-                                           width: i32, height: i32)
-{
-    let size = DeviceUintSize::new(width as u32, height as u32);
-    api.set_window_parameters(size,
-                              DeviceUintRect::new(DeviceUintPoint::new(0, 0), size));
-
-}
-
-#[no_mangle]
-pub extern fn wr_api_generate_frame(api: &mut RenderApi) {
-  api.generate_frame(None);
-}
-
-// Call MakeCurrent before this.
-#[no_mangle]
-pub extern fn wr_window_new(window_id: WrWindowId,
-                            window_width: u32,
-                            window_height: u32,
-                            gl_context: *mut c_void,
-                            enable_profiler: bool,
-                            out_api: &mut *mut RenderApi,
-                            out_renderer: &mut *mut Renderer) -> bool {
-    assert!(unsafe { is_in_render_thread() });
-
-    let recorder: Option<Box<ApiRecordingReceiver>> = if ENABLE_RECORDING {
-        let name = format!("wr-record-{}.bin", window_id.0);
-        Some(Box::new(BinaryRecorder::new(&PathBuf::from(name))))
-    } else {
-        None
-    };
-
-    gl::load_with(|symbol| get_proc_address(gl_context, symbol));
-    gl::clear_color(0.3, 0.0, 0.0, 1.0);
-
-    let version = gl::get_string(gl::VERSION);
-
-    println!("WebRender - OpenGL version new {}", version);
-
-    let opts = RendererOptions {
-        enable_aa: true,
-        enable_subpixel_aa: true,
-        enable_profiler: enable_profiler,
-        recorder: recorder,
-        .. Default::default()
-    };
-
-    let window_size = DeviceUintSize::new(window_width, window_height);
-    let (renderer, sender) = match Renderer::new(opts, window_size) {
-        Ok((renderer, sender)) => { (renderer, sender) }
-        Err(e) => {
-            println!(" Failed to create a Renderer: {:?}", e);
-            return false;
-        }
-    };
-
-    renderer.set_render_notifier(Box::new(CppNotifier { window_id: window_id }));
-
-    *out_api = Box::into_raw(Box::new(sender.create_api()));
-    *out_renderer = Box::into_raw(Box::new(renderer));
-
-    return true;
-}
-
-#[no_mangle]
-pub extern fn wr_state_new(pipeline_id: PipelineId) -> *mut WrState {
-    assert!(unsafe { is_in_main_thread() });
-
-    let state = Box::new(WrState {
-        pipeline_id: pipeline_id,
-        z_index: 0,
-        frame_builder: WebRenderFrameBuilder::new(pipeline_id),
-    });
-
-    Box::into_raw(state)
-}
-
-#[no_mangle]
-pub extern fn wr_state_delete(state:*mut WrState) {
-    assert!(unsafe { is_in_main_thread() });
-
-    unsafe {
-        Box::from_raw(state);
-    }
-}
-
-#[no_mangle]
-pub extern fn wr_dp_begin(state: &mut WrState, width: u32, height: u32) {
-    assert!( unsafe { is_in_main_thread() });
-    state.frame_builder.dl_builder.list.clear();
-    state.z_index = 0;
-
-    let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(width as f32, height as f32));
-
-    state.frame_builder.dl_builder.push_stacking_context(
-        webrender_traits::ScrollPolicy::Scrollable,
-        bounds,
-        ClipRegion::simple(&bounds),
-        0,
-        None,
-        None,
-        webrender_traits::MixBlendMode::Normal,
-        Vec::new(),
-    );
-}
-
-#[no_mangle]
-pub extern fn wr_dp_end(state: &mut WrState) {
-    assert!( unsafe { is_in_main_thread() });
-    state.frame_builder.dl_builder.pop_stacking_context();
-}
-
-#[no_mangle]
-pub extern fn wr_dp_new_clip_region(state: &mut WrState,
-                                    main: WrRect,
-                                    complex: *const WrComplexClipRegion, complex_count: usize,
-                                    image_mask: *const WrImageMask) -> WrClipRegion {
-    assert!( unsafe { is_in_main_thread() });
-
-    let main = main.to_rect();
-    let complex = WrComplexClipRegion::to_complex_clip_regions(unsafe {
-        slice::from_raw_parts(complex, complex_count)
-    });
-    let mask = unsafe { image_mask.as_ref().map(|x| x.to_image_mask()) };
-
-    let clip_region = state.frame_builder.dl_builder.new_clip_region(&main, complex, mask);
-
-    clip_region.into()
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_renderer_flush_rendered_epochs(renderer: &mut Renderer) -> *mut Vec<(PipelineId, Epoch)> {
-    let map = renderer.flush_rendered_epochs();
-    let pipeline_epochs = Box::new(map.into_iter().collect());
-    return Box::into_raw(pipeline_epochs);
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_rendered_epochs_next(pipeline_epochs: &mut Vec<(PipelineId, Epoch)>,
-                                             out_pipeline: &mut PipelineId,
-                                             out_epoch: &mut Epoch) -> bool {
-    if let Some((pipeline, epoch)) = pipeline_epochs.pop() {
-        *out_pipeline = pipeline;
-        *out_epoch = epoch;
-        return true;
-    }
-    return false;
-}
-
-#[no_mangle]
-pub unsafe extern fn wr_rendered_epochs_delete(pipeline_epochs: *mut Vec<(PipelineId, Epoch)>) {
-    Box::from_raw(pipeline_epochs);
-}
-
-
-struct CppNotifier {
-    window_id: WrWindowId,
-}
-
-unsafe impl Send for CppNotifier {}
-
-extern {
-    fn wr_notifier_new_frame_ready(window_id: WrWindowId);
-    fn wr_notifier_new_scroll_frame_ready(window_id: WrWindowId, composite_needed: bool);
-    fn wr_notifier_external_event(window_id: WrWindowId, raw_event: usize);
-}
-
-impl webrender_traits::RenderNotifier for CppNotifier {
-    fn new_frame_ready(&mut self) {
-        unsafe {
-            wr_notifier_new_frame_ready(self.window_id);
-        }
-    }
-
-    fn new_scroll_frame_ready(&mut self, composite_needed: bool) {
-        unsafe {
-            wr_notifier_new_scroll_frame_ready(self.window_id, composite_needed);
-        }
-    }
-
-    fn external_event(&mut self, event: ExternalEvent) {
-        unsafe {
-            wr_notifier_external_event(self.window_id, event.unwrap());
-        }
-    }
-}
-
-// RenderThread WIP notes:
-// In order to separate the compositor thread (or ipc receiver) and the render
-// thread, some of the logic below needs to be rewritten. In particular
-// the WrWindowState and Notifier implementations aren't designed to work with
-// a separate render thread.
-// As part of that I am moving the bindings closer to WebRender's API boundary,
-// and moving more of the logic in C++ land.
-// This work is tracked by bug 1328602.
-//
-// See RenderThread.h for some notes about how the pieces fit together.
-
-pub struct WebRenderFrameBuilder {
-    pub root_pipeline_id: PipelineId,
-    pub dl_builder: webrender_traits::DisplayListBuilder,
-}
-
-impl WebRenderFrameBuilder {
-    pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
-        WebRenderFrameBuilder {
-            root_pipeline_id: root_pipeline_id,
-            dl_builder: webrender_traits::DisplayListBuilder::new(root_pipeline_id),
-        }
-    }
-}
-
-pub struct WrState {
-    pipeline_id: PipelineId,
-    z_index: i32,
-    frame_builder: WebRenderFrameBuilder,
-}
-
-#[repr(C)]
-#[allow(dead_code)]
-enum WrExternalImageType {
-    NativeTexture,
-    RawData,
-}
-
-#[repr(C)]
-struct WrExternalImageStruct {
-    image_type: WrExternalImageType,
-
-    // Texture coordinate
-    u0: f32,
-    v0: f32,
-    u1: f32,
-    v1: f32,
-
-    // external buffer handle
-    handle: u32,
-
-    // handle RawData.
-    buff: *const u8,
-    size: usize,
-}
-
-type LockExternalImageCallback = fn(*mut c_void, ExternalImageId) -> WrExternalImageStruct;
-type UnlockExternalImageCallback = fn(*mut c_void, ExternalImageId);
-type ReleaseExternalImageCallback = fn(*mut c_void, ExternalImageId);
-
-#[repr(C)]
-pub struct WrExternalImageHandler {
-    external_image_obj: *mut c_void,
-    lock_func: LockExternalImageCallback,
-    unlock_func: UnlockExternalImageCallback,
-    release_func: ReleaseExternalImageCallback,
-}
-
-impl ExternalImageHandler for WrExternalImageHandler {
-    fn lock(&mut self, id: ExternalImageId) -> ExternalImage {
-        let image = (self.lock_func)(self.external_image_obj, id);
-
-        match image.image_type {
-            WrExternalImageType::NativeTexture =>
-                ExternalImage {
-                    u0: image.u0,
-                    v0: image.v0,
-                    u1: image.u1,
-                    v1: image.v1,
-                    source: ExternalImageSource::NativeTexture(image.handle)
-                },
-            WrExternalImageType::RawData =>
-                ExternalImage {
-                    u0: image.u0,
-                    v0: image.v0,
-                    u1: image.u1,
-                    v1: image.v1,
-                    source: ExternalImageSource::RawData(unsafe { slice::from_raw_parts(image.buff, image.size)})
-                },
-        }
-    }
-
-    fn unlock(&mut self, id: ExternalImageId) {
-        (self.unlock_func)(self.external_image_obj, id);
-    }
-
-    fn release(&mut self, id: ExternalImageId) {
-        (self.release_func)(self.external_image_obj, id);
-    }
-}
-
-#[repr(C)]
 pub enum WrBoxShadowClipMode
 {
     None,
     Outset,
     Inset,
 }
 
 impl WrBoxShadowClipMode
@@ -661,16 +134,851 @@ impl WrGradientExtendMode
         match self
         {
             WrGradientExtendMode::Clamp => ExtendMode::Clamp,
             WrGradientExtendMode::Repeat => ExtendMode::Repeat,
         }
     }
 }
 
+#[repr(C)]
+struct WrItemRange
+{
+    start: usize,
+    length: usize,
+}
+
+impl WrItemRange
+{
+    fn to_item_range(&self) -> ItemRange
+    {
+        ItemRange {
+            start: self.start,
+            length: self.length,
+        }
+    }
+}
+
+impl From<ItemRange> for WrItemRange
+{
+    fn from(item_range: ItemRange) -> Self
+    {
+        WrItemRange {
+            start: item_range.start,
+            length: item_range.length,
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WrPoint
+{
+    x: f32,
+    y: f32
+}
+
+impl WrPoint
+{
+    pub fn to_point(&self) -> TypedPoint2D<f32, LayerPixel>
+    {
+        TypedPoint2D::new(self.x, self.y)
+    }
+}
+
+#[repr(C)]
+pub struct WrSize
+{
+    width: f32,
+    height: f32
+}
+
+impl WrSize
+{
+    pub fn to_size(&self) -> LayoutSize
+    {
+        LayoutSize::new(self.width, self.height)
+    }
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct WrRect
+{
+    x: f32,
+    y: f32,
+    width: f32,
+    height: f32
+}
+
+impl WrRect
+{
+    pub fn to_rect(&self) -> LayoutRect
+    {
+        LayoutRect::new(LayoutPoint::new(self.x, self.y), LayoutSize::new(self.width, self.height))
+    }
+}
+impl From<LayoutRect> for WrRect
+{
+    fn from(rect: LayoutRect) -> Self
+    {
+        WrRect {
+            x: rect.origin.x,
+            y: rect.origin.y,
+            width: rect.size.width,
+            height: rect.size.height,
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WrColor
+{
+    r: f32,
+    g: f32,
+    b: f32,
+    a: f32
+}
+
+impl WrColor
+{
+    pub fn to_color(&self) -> ColorF
+    {
+        ColorF::new(self.r, self.g, self.b, self.a)
+    }
+}
+
+#[repr(C)]
+pub struct WrGradientStop
+{
+    offset: f32,
+    color: WrColor,
+}
+
+impl WrGradientStop
+{
+    pub fn to_gradient_stop(&self) -> GradientStop
+    {
+        GradientStop {
+            offset: self.offset,
+            color: self.color.to_color(),
+        }
+    }
+    pub fn to_gradient_stops(stops: &[WrGradientStop]) -> Vec<GradientStop>
+    {
+        stops.iter().map(|x| x.to_gradient_stop()).collect()
+    }
+}
+
+#[repr(C)]
+pub struct WrBorderSide
+{
+    width: f32,
+    color: WrColor,
+    style: BorderStyle
+}
+
+impl WrBorderSide
+{
+    pub fn to_border_side(&self) -> BorderSide
+    {
+        BorderSide { color: self.color.to_color(), style: self.style }
+    }
+}
+
+#[repr(C)]
+pub struct WrBorderRadius {
+    pub top_left: WrSize,
+    pub top_right: WrSize,
+    pub bottom_left: WrSize,
+    pub bottom_right: WrSize,
+}
+
+impl WrBorderRadius
+{
+    pub fn to_border_radius(&self) -> BorderRadius
+    {
+        BorderRadius { top_left: self.top_left.to_size(),
+                       top_right: self.top_right.to_size(),
+                       bottom_left: self.bottom_left.to_size(),
+                       bottom_right: self.bottom_right.to_size() }
+    }
+}
+
+
+#[repr(C)]
+pub struct WrImageMask
+{
+    image: ImageKey,
+    rect: WrRect,
+    repeat: bool
+}
+
+impl WrImageMask
+{
+    pub fn to_image_mask(&self) -> ImageMask
+    {
+        ImageMask { image: self.image, rect: self.rect.to_rect(), repeat: self.repeat }
+    }
+}
+impl From<ImageMask> for WrImageMask
+{
+    fn from(image_mask: ImageMask) -> Self
+    {
+        WrImageMask {
+            image: image_mask.image,
+            rect: image_mask.rect.into(),
+            repeat: image_mask.repeat,
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WrComplexClipRegion
+{
+  rect: WrRect,
+  radii: WrBorderRadius,
+}
+
+impl WrComplexClipRegion
+{
+    pub fn to_complex_clip_region(&self) -> ComplexClipRegion
+    {
+        ComplexClipRegion {
+            rect: self.rect.to_rect(),
+            radii: self.radii.to_border_radius(),
+        }
+    }
+    pub fn to_complex_clip_regions(complex_clips: &[WrComplexClipRegion]) -> Vec<ComplexClipRegion>
+    {
+        complex_clips.iter().map(|x| x.to_complex_clip_region()).collect()
+    }
+}
+
+#[repr(C)]
+pub struct WrClipRegion
+{
+  main: WrRect,
+  complex: WrItemRange,
+  image_mask: WrImageMask,
+  has_image_mask: bool,
+}
+impl WrClipRegion
+{
+    pub fn to_clip_region(&self) -> ClipRegion
+    {
+        ClipRegion {
+            main: self.main.to_rect(),
+            complex: self.complex.to_item_range(),
+            image_mask: if self.has_image_mask {
+                Some(self.image_mask.to_image_mask())
+            } else {
+                None
+            }
+        }
+    }
+}
+impl From<ClipRegion> for WrClipRegion
+{
+    fn from(clip_region: ClipRegion) -> Self {
+        if let Some(image_mask) = clip_region.image_mask {
+            WrClipRegion {
+                main: clip_region.main.into(),
+                complex: clip_region.complex.into(),
+                image_mask: image_mask.into(),
+                has_image_mask: true,
+            }
+        } else {
+            let blank = WrImageMask {
+                image: ImageKey(0, 0),
+                rect: WrRect { x: 0f32, y: 0f32, width: 0f32, height: 0f32, },
+                repeat: false,
+            };
+
+            WrClipRegion {
+                main: clip_region.main.into(),
+                complex: clip_region.complex.into(),
+                image_mask: blank,
+                has_image_mask: false,
+            }
+        }
+    }
+}
+
+#[repr(C)]
+#[allow(dead_code)]
+enum WrExternalImageType {
+    NativeTexture,
+    RawData,
+}
+
+#[repr(C)]
+struct WrExternalImageStruct {
+    image_type: WrExternalImageType,
+
+    // Texture coordinate
+    u0: f32,
+    v0: f32,
+    u1: f32,
+    v1: f32,
+
+    // external buffer handle
+    handle: u32,
+
+    // handle RawData.
+    buff: *const u8,
+    size: usize,
+}
+
+type LockExternalImageCallback = fn(*mut c_void, ExternalImageId) -> WrExternalImageStruct;
+type UnlockExternalImageCallback = fn(*mut c_void, ExternalImageId);
+type ReleaseExternalImageCallback = fn(*mut c_void, ExternalImageId);
+
+#[repr(C)]
+pub struct WrExternalImageHandler {
+    external_image_obj: *mut c_void,
+    lock_func: LockExternalImageCallback,
+    unlock_func: UnlockExternalImageCallback,
+    release_func: ReleaseExternalImageCallback,
+}
+
+impl ExternalImageHandler for WrExternalImageHandler {
+    fn lock(&mut self, id: ExternalImageId) -> ExternalImage {
+        let image = (self.lock_func)(self.external_image_obj, id);
+
+        match image.image_type {
+            WrExternalImageType::NativeTexture =>
+                ExternalImage {
+                    u0: image.u0,
+                    v0: image.v0,
+                    u1: image.u1,
+                    v1: image.v1,
+                    source: ExternalImageSource::NativeTexture(image.handle)
+                },
+            WrExternalImageType::RawData =>
+                ExternalImage {
+                    u0: image.u0,
+                    v0: image.v0,
+                    u1: image.u1,
+                    v1: image.v1,
+                    source: ExternalImageSource::RawData(unsafe { slice::from_raw_parts(image.buff, image.size)})
+                },
+        }
+    }
+
+    fn unlock(&mut self, id: ExternalImageId) {
+        (self.unlock_func)(self.external_image_obj, id);
+    }
+
+    fn release(&mut self, id: ExternalImageId) {
+        (self.release_func)(self.external_image_obj, id);
+    }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct WrWindowId(u64);
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct WrImageDescriptor {
+    pub format: ImageFormat,
+    pub width: u32,
+    pub height: u32,
+    pub stride: u32,
+    pub is_opaque: bool,
+}
+
+impl WrImageDescriptor {
+    pub fn to_descriptor(&self) -> ImageDescriptor {
+        ImageDescriptor {
+            width: self.width,
+            height: self.height,
+            stride: if self.stride != 0 { Some(self.stride) } else { None },
+            format: self.format,
+            is_opaque: self.is_opaque,
+            offset: 0,
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WrVecU8 {
+    ptr: *mut u8,
+    length: usize,
+    capacity: usize
+}
+
+impl WrVecU8 {
+    fn to_vec(self) -> Vec<u8> {
+        unsafe { Vec::from_raw_parts(self.ptr, self.length, self.capacity) }
+    }
+    fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
+        let w = WrVecU8{ptr: v.as_mut_ptr(), length: v.len(), capacity: v.capacity()};
+        mem::forget(v);
+        w
+    }
+}
+
+#[no_mangle]
+pub extern fn wr_vec_u8_free(v: WrVecU8) {
+    v.to_vec();
+}
+
+fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void{
+
+    extern  {
+        fn get_proc_address_from_glcontext(glcontext_ptr: *mut c_void, procname: *const c_char) -> *const c_void;
+    }
+
+    let symbol_name = CString::new(name).unwrap();
+    let symbol = unsafe {
+        get_proc_address_from_glcontext(glcontext_ptr, symbol_name.as_ptr())
+    };
+
+    // For now panic, not sure we should be though or if we can recover
+    if symbol.is_null() {
+        // XXX Bug 1322949 Make whitelist for extensions
+        println!("Could not find symbol {:?} by glcontext", symbol_name);
+    }
+
+    symbol as *const _
+}
+
+extern  {
+    fn is_in_compositor_thread() -> bool;
+    fn is_in_render_thread() -> bool;
+    fn is_in_main_thread() -> bool;
+}
+
+struct CppNotifier {
+    window_id: WrWindowId,
+}
+
+unsafe impl Send for CppNotifier {}
+
+extern {
+    fn wr_notifier_new_frame_ready(window_id: WrWindowId);
+    fn wr_notifier_new_scroll_frame_ready(window_id: WrWindowId, composite_needed: bool);
+    fn wr_notifier_external_event(window_id: WrWindowId, raw_event: usize);
+}
+
+impl webrender_traits::RenderNotifier for CppNotifier {
+    fn new_frame_ready(&mut self) {
+        unsafe {
+            wr_notifier_new_frame_ready(self.window_id);
+        }
+    }
+
+    fn new_scroll_frame_ready(&mut self, composite_needed: bool) {
+        unsafe {
+            wr_notifier_new_scroll_frame_ready(self.window_id, composite_needed);
+        }
+    }
+
+    fn external_event(&mut self, event: ExternalEvent) {
+        unsafe {
+            wr_notifier_external_event(self.window_id, event.unwrap());
+        }
+    }
+}
+
+#[no_mangle]
+pub extern fn wr_renderer_set_external_image_handler(renderer: &mut Renderer,
+                                                     external_image_handler: *mut WrExternalImageHandler) {
+    if !external_image_handler.is_null() {
+        renderer.set_external_image_handler(Box::new(
+            unsafe {
+                WrExternalImageHandler {
+                    external_image_obj: (*external_image_handler).external_image_obj,
+                    lock_func: (*external_image_handler).lock_func,
+                    unlock_func: (*external_image_handler).unlock_func,
+                    release_func: (*external_image_handler).release_func,
+                }
+            }));
+    }
+}
+
+#[no_mangle]
+pub extern fn wr_renderer_update(renderer: &mut Renderer) {
+    renderer.update();
+}
+
+#[no_mangle]
+pub extern fn wr_renderer_render(renderer: &mut Renderer, width: u32, height: u32) {
+    renderer.render(DeviceUintSize::new(width, height));
+}
+
+// Call wr_renderer_render() before calling this function.
+#[no_mangle]
+pub unsafe extern fn wr_renderer_readback(width: u32, height: u32,
+                                          dst_buffer: *mut u8, buffer_size: usize) {
+    assert!(is_in_render_thread());
+
+    gl::flush();
+
+    let mut slice = slice::from_raw_parts_mut(dst_buffer, buffer_size);
+    gl::read_pixels_into_buffer(0, 0,
+                                width as gl::GLsizei,
+                                height as gl::GLsizei,
+                                gl::BGRA,
+                                gl::UNSIGNED_BYTE,
+                                slice);
+}
+
+#[no_mangle]
+pub extern fn wr_renderer_set_profiler_enabled(renderer: &mut Renderer, enabled: bool) {
+    renderer.set_profiler_enabled(enabled);
+}
+
+#[no_mangle]
+pub extern fn wr_renderer_current_epoch(renderer: &mut Renderer,
+                                        pipeline_id: PipelineId,
+                                        out_epoch: &mut Epoch) -> bool {
+    if let Some(epoch) = renderer.current_epoch(pipeline_id) {
+        *out_epoch = epoch;
+        return true;
+    }
+    return false;
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_renderer_delete(renderer: *mut Renderer) {
+    Box::from_raw(renderer);
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_renderer_flush_rendered_epochs(renderer: &mut Renderer) -> *mut Vec<(PipelineId, Epoch)> {
+    let map = renderer.flush_rendered_epochs();
+    let pipeline_epochs = Box::new(map.into_iter().collect());
+    return Box::into_raw(pipeline_epochs);
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_rendered_epochs_next(pipeline_epochs: &mut Vec<(PipelineId, Epoch)>,
+                                             out_pipeline: &mut PipelineId,
+                                             out_epoch: &mut Epoch) -> bool {
+    if let Some((pipeline, epoch)) = pipeline_epochs.pop() {
+        *out_pipeline = pipeline;
+        *out_epoch = epoch;
+        return true;
+    }
+    return false;
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_rendered_epochs_delete(pipeline_epochs: *mut Vec<(PipelineId, Epoch)>) {
+    Box::from_raw(pipeline_epochs);
+}
+
+// Call MakeCurrent before this.
+#[no_mangle]
+pub extern fn wr_window_new(window_id: WrWindowId,
+                            window_width: u32,
+                            window_height: u32,
+                            gl_context: *mut c_void,
+                            enable_profiler: bool,
+                            out_api: &mut *mut RenderApi,
+                            out_renderer: &mut *mut Renderer) -> bool {
+    assert!(unsafe { is_in_render_thread() });
+
+    let recorder: Option<Box<ApiRecordingReceiver>> = if ENABLE_RECORDING {
+        let name = format!("wr-record-{}.bin", window_id.0);
+        Some(Box::new(BinaryRecorder::new(&PathBuf::from(name))))
+    } else {
+        None
+    };
+
+    gl::load_with(|symbol| get_proc_address(gl_context, symbol));
+    gl::clear_color(0.3, 0.0, 0.0, 1.0);
+
+    let version = gl::get_string(gl::VERSION);
+
+    println!("WebRender - OpenGL version new {}", version);
+
+    let opts = RendererOptions {
+        enable_aa: true,
+        enable_subpixel_aa: true,
+        enable_profiler: enable_profiler,
+        recorder: recorder,
+        .. Default::default()
+    };
+
+    let window_size = DeviceUintSize::new(window_width, window_height);
+    let (renderer, sender) = match Renderer::new(opts, window_size) {
+        Ok((renderer, sender)) => { (renderer, sender) }
+        Err(e) => {
+            println!(" Failed to create a Renderer: {:?}", e);
+            return false;
+        }
+    };
+
+    renderer.set_render_notifier(Box::new(CppNotifier { window_id: window_id }));
+
+    *out_api = Box::into_raw(Box::new(sender.create_api()));
+    *out_renderer = Box::into_raw(Box::new(renderer));
+
+    return true;
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_api_delete(api: *mut RenderApi) {
+    let api = Box::from_raw(api);
+    api.shut_down();
+}
+
+#[no_mangle]
+pub extern fn wr_api_add_image(api: &mut RenderApi, image_key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
+    assert!( unsafe { is_in_compositor_thread() });
+    let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
+    api.add_image(
+        image_key,
+        descriptor.to_descriptor(),
+        ImageData::new(bytes),
+        None
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_api_add_external_image_handle(api: &mut RenderApi, image_key: ImageKey, width: u32, height: u32, format: ImageFormat, external_image_id: u64) {
+    assert!( unsafe { is_in_compositor_thread() });
+    api.add_image(image_key,
+                  ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false, offset: 0},
+                  ImageData::ExternalHandle(ExternalImageId(external_image_id)),
+                  None
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_api_add_external_image_buffer(api: &mut RenderApi, image_key: ImageKey, descriptor: &WrImageDescriptor, external_image_id: u64) {
+    assert!( unsafe { is_in_compositor_thread() });
+    api.add_image(image_key,
+                  descriptor.to_descriptor(),
+                  ImageData::ExternalBuffer(ExternalImageId(external_image_id)),
+                  None
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_api_update_image(api: &mut RenderApi, key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
+    assert!( unsafe { is_in_compositor_thread() });
+    let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
+
+    api.update_image(
+        key,
+        descriptor.to_descriptor(),
+        bytes
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_api_delete_image(api: &mut RenderApi, key: ImageKey) {
+    assert!( unsafe { is_in_compositor_thread() });
+    api.delete_image(key)
+}
+
+#[no_mangle]
+pub extern fn wr_api_set_root_pipeline(api: &mut RenderApi, pipeline_id: PipelineId) {
+    api.set_root_pipeline(pipeline_id);
+    api.generate_frame(None);
+}
+
+#[no_mangle]
+pub extern fn wr_api_set_window_parameters(api: &mut RenderApi,
+                                           width: i32, height: i32)
+{
+    let size = DeviceUintSize::new(width as u32, height as u32);
+    api.set_window_parameters(size,
+                              DeviceUintRect::new(DeviceUintPoint::new(0, 0), size));
+
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_api_set_root_display_list(api: &mut RenderApi,
+                                                  epoch: Epoch,
+                                                  viewport_width: f32,
+                                                  viewport_height: f32,
+                                                  pipeline_id: PipelineId,
+                                                  dl_descriptor: BuiltDisplayListDescriptor,
+                                                  dl_data: *mut u8,
+                                                  dl_size: usize,
+                                                  aux_descriptor: AuxiliaryListsDescriptor,
+                                                  aux_data: *mut u8,
+                                                  aux_size: usize) {
+    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
+    // See the documentation of set_root_display_list in api.rs. I don't think
+    // it makes a difference in gecko at the moment(until APZ is figured out)
+    // but I suppose it is a good default.
+    let preserve_frame_state = true;
+
+    let dl_slice = slice::from_raw_parts(dl_data, dl_size);
+    let mut dl_vec = Vec::new();
+    // XXX: see if we can get rid of the copy here
+    dl_vec.extend_from_slice(dl_slice);
+    let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
+
+    let aux_slice = slice::from_raw_parts(aux_data, aux_size);
+    let mut aux_vec = Vec::new();
+    // XXX: see if we can get rid of the copy here
+    aux_vec.extend_from_slice(aux_slice);
+    let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
+
+    api.set_root_display_list(Some(root_background_color),
+                              epoch,
+                              LayoutSize::new(viewport_width, viewport_height),
+                              (pipeline_id, dl, aux),
+                              preserve_frame_state);
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_api_clear_root_display_list(api: &mut RenderApi,
+                                                    epoch: Epoch,
+                                                    pipeline_id: PipelineId) {
+    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
+    let preserve_frame_state = true;
+    let frame_builder = WebRenderFrameBuilder::new(pipeline_id);
+
+    api.set_root_display_list(Some(root_background_color),
+                              epoch,
+                              LayoutSize::new(0.0, 0.0),
+                              frame_builder.dl_builder.finalize(),
+                              preserve_frame_state);
+}
+
+#[no_mangle]
+pub extern fn wr_api_generate_frame(api: &mut RenderApi) {
+  api.generate_frame(None);
+}
+
+#[no_mangle]
+pub extern fn wr_api_send_external_event(api: &mut RenderApi, evt: usize) {
+    assert!(unsafe { is_in_compositor_thread() });
+
+    api.send_external_event(ExternalEvent::from_raw(evt));
+}
+
+#[no_mangle]
+pub extern fn wr_api_add_raw_font(api: &mut RenderApi,
+                                  key: FontKey,
+                                  font_buffer: *mut u8,
+                                  buffer_size: usize)
+{
+    assert!( unsafe { is_in_compositor_thread() });
+
+    let font_slice = unsafe {
+        slice::from_raw_parts(font_buffer, buffer_size as usize)
+    };
+    let mut font_vector = Vec::new();
+    font_vector.extend_from_slice(font_slice);
+
+    api.add_raw_font(key, font_vector);
+}
+
+#[no_mangle]
+pub unsafe extern fn wr_api_get_namespace(api: &mut RenderApi) -> IdNamespace
+{
+    api.id_namespace
+}
+
+// RenderThread WIP notes:
+// In order to separate the compositor thread (or ipc receiver) and the render
+// thread, some of the logic below needs to be rewritten. In particular
+// the WrWindowState and Notifier implementations aren't designed to work with
+// a separate render thread.
+// As part of that I am moving the bindings closer to WebRender's API boundary,
+// and moving more of the logic in C++ land.
+// This work is tracked by bug 1328602.
+//
+// See RenderThread.h for some notes about how the pieces fit together.
+
+pub struct WebRenderFrameBuilder {
+    pub root_pipeline_id: PipelineId,
+    pub dl_builder: webrender_traits::DisplayListBuilder,
+}
+
+impl WebRenderFrameBuilder {
+    pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
+        WebRenderFrameBuilder {
+            root_pipeline_id: root_pipeline_id,
+            dl_builder: webrender_traits::DisplayListBuilder::new(root_pipeline_id),
+        }
+    }
+}
+
+pub struct WrState {
+    pipeline_id: PipelineId,
+    z_index: i32,
+    frame_builder: WebRenderFrameBuilder,
+}
+
+#[no_mangle]
+pub extern fn wr_state_new(pipeline_id: PipelineId) -> *mut WrState {
+    assert!(unsafe { is_in_main_thread() });
+
+    let state = Box::new(WrState {
+        pipeline_id: pipeline_id,
+        z_index: 0,
+        frame_builder: WebRenderFrameBuilder::new(pipeline_id),
+    });
+
+    Box::into_raw(state)
+}
+
+#[no_mangle]
+pub extern fn wr_state_delete(state:*mut WrState) {
+    assert!(unsafe { is_in_main_thread() });
+
+    unsafe {
+        Box::from_raw(state);
+    }
+}
+
+#[no_mangle]
+pub extern fn wr_dp_begin(state: &mut WrState, width: u32, height: u32) {
+    assert!( unsafe { is_in_main_thread() });
+    state.frame_builder.dl_builder.list.clear();
+    state.z_index = 0;
+
+    let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(width as f32, height as f32));
+
+    state.frame_builder.dl_builder.push_stacking_context(
+        webrender_traits::ScrollPolicy::Scrollable,
+        bounds,
+        ClipRegion::simple(&bounds),
+        0,
+        None,
+        None,
+        webrender_traits::MixBlendMode::Normal,
+        Vec::new(),
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_dp_end(state: &mut WrState) {
+    assert!( unsafe { is_in_main_thread() });
+    state.frame_builder.dl_builder.pop_stacking_context();
+}
+
+#[no_mangle]
+pub extern fn wr_dp_new_clip_region(state: &mut WrState,
+                                    main: WrRect,
+                                    complex: *const WrComplexClipRegion, complex_count: usize,
+                                    image_mask: *const WrImageMask) -> WrClipRegion {
+    assert!( unsafe { is_in_main_thread() });
+
+    let main = main.to_rect();
+    let complex = WrComplexClipRegion::to_complex_clip_regions(unsafe {
+        slice::from_raw_parts(complex, complex_count)
+    });
+    let mask = unsafe { image_mask.as_ref().map(|x| x.to_image_mask()) };
+
+    let clip_region = state.frame_builder.dl_builder.new_clip_region(&main, complex, mask);
+
+    clip_region.into()
+}
+
 #[no_mangle]
 pub extern fn wr_dp_push_stacking_context(state:&mut WrState, bounds: WrRect, overflow: WrRect, mask: *const WrImageMask, opacity: f32, transform: &LayoutTransform, mix_blend_mode: WrMixBlendMode)
 {
     assert!( unsafe { is_in_main_thread() });
     state.z_index += 1;
 
     let bounds = bounds.to_rect();
     let overflow = overflow.to_rect();
@@ -721,110 +1029,79 @@ pub extern fn wr_dp_push_scroll_layer(st
 #[no_mangle]
 pub extern fn wr_dp_pop_scroll_layer(state: &mut WrState)
 {
     assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
 }
 
 #[no_mangle]
-pub extern fn wr_api_set_root_pipeline(api: &mut RenderApi, pipeline_id: PipelineId) {
-    api.set_root_pipeline(pipeline_id);
-    api.generate_frame(None);
-}
-
-#[no_mangle]
-pub extern fn wr_api_generate_image_key(api: &mut RenderApi) -> ImageKey
-{
-    api.generate_image_key()
-}
-
-#[no_mangle]
-pub extern fn wr_api_add_image(api: &mut RenderApi, image_key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
-    assert!( unsafe { is_in_compositor_thread() });
-    let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
-    api.add_image(
-        image_key,
-        descriptor.to_descriptor(),
-        ImageData::new(bytes),
-        None
-    );
-}
-
-#[no_mangle]
-pub extern fn wr_api_add_external_image_handle(api: &mut RenderApi, image_key: ImageKey, width: u32, height: u32, format: ImageFormat, external_image_id: u64) {
-    assert!( unsafe { is_in_compositor_thread() });
-    api.add_image(image_key,
-                  ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false, offset: 0},
-                  ImageData::ExternalHandle(ExternalImageId(external_image_id)),
-                  None
-    );
-}
+pub extern fn wr_dp_push_iframe(state: &mut WrState, rect: WrRect, clip: WrClipRegion, pipeline_id: PipelineId) {
+    assert!( unsafe { is_in_main_thread() });
 
-#[no_mangle]
-pub extern fn wr_api_add_external_image_buffer(api: &mut RenderApi, image_key: ImageKey, descriptor: &WrImageDescriptor, external_image_id: u64) {
-    assert!( unsafe { is_in_compositor_thread() });
-    api.add_image(image_key,
-                  descriptor.to_descriptor(),
-                  ImageData::ExternalBuffer(ExternalImageId(external_image_id)),
-                  None
-    );
+    state.frame_builder.dl_builder.push_iframe(rect.to_rect(),
+                                               clip.to_clip_region(),
+                                               pipeline_id);
 }
 
 #[no_mangle]
-pub extern fn wr_api_update_image(api: &mut RenderApi, key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
-    assert!( unsafe { is_in_compositor_thread() });
-    let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
-
-    api.update_image(
-        key,
-        descriptor.to_descriptor(),
-        bytes
-    );
-}
-#[no_mangle]
-pub extern fn wr_api_delete_image(api: &mut RenderApi, key: ImageKey) {
-    assert!( unsafe { is_in_compositor_thread() });
-    api.delete_image(key)
-}
-
-#[no_mangle]
-pub extern fn wr_api_send_external_event(api: &mut RenderApi, evt: usize) {
-    assert!(unsafe { is_in_compositor_thread() });
-
-    api.send_external_event(ExternalEvent::from_raw(evt));
-}
-
-
-#[no_mangle]
 pub extern fn wr_dp_push_rect(state: &mut WrState, rect: WrRect, clip: WrClipRegion, color: WrColor) {
     assert!( unsafe { is_in_main_thread() });
 
     state.frame_builder.dl_builder.push_rect(
                                     rect.to_rect(),
                                     clip.to_clip_region(),
                                     color.to_color());
 }
 
 #[no_mangle]
-pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrClipRegion,
-                                    box_bounds: WrRect, offset: WrPoint, color: WrColor,
-                                    blur_radius: f32, spread_radius: f32, border_radius: f32,
-                                    clip_mode: WrBoxShadowClipMode) {
+pub extern fn wr_dp_push_image(state:&mut WrState, bounds: WrRect, clip: WrClipRegion, image_rendering: ImageRendering, key: ImageKey) {
     assert!( unsafe { is_in_main_thread() });
 
-    state.frame_builder.dl_builder.push_box_shadow(rect.to_rect(),
-                                                   clip.to_clip_region(),
-                                                   box_bounds.to_rect(),
-                                                   offset.to_point(),
-                                                   color.to_color(),
-                                                   blur_radius,
-                                                   spread_radius,
-                                                   border_radius,
-                                                   clip_mode.to_box_shadow_clip_mode());
+    let bounds = bounds.to_rect();
+
+    state.frame_builder.dl_builder.push_image(
+        bounds,
+        clip.to_clip_region(),
+        bounds.size,
+        bounds.size,
+        image_rendering,
+        key
+    );
+}
+
+#[no_mangle]
+pub extern fn wr_dp_push_text(state: &mut WrState,
+                              bounds: WrRect,
+                              clip: WrClipRegion,
+                              color: WrColor,
+                              font_key: FontKey,
+                              glyphs: *mut GlyphInstance,
+                              glyph_count: u32,
+                              glyph_size: f32)
+{
+    assert!( unsafe { is_in_main_thread() });
+
+    let glyph_slice = unsafe {
+        slice::from_raw_parts(glyphs, glyph_count as usize)
+    };
+    let mut glyph_vector = Vec::new();
+    glyph_vector.extend_from_slice(&glyph_slice);
+
+    let colorf = ColorF::new(color.r, color.g, color.b, color.a);
+
+    let glyph_options = None; // TODO
+    state.frame_builder.dl_builder.push_text(bounds.to_rect(),
+                                             clip.to_clip_region(),
+                                             glyph_vector,
+                                             font_key,
+                                             colorf,
+                                             Au::from_f32_px(glyph_size),
+                                             Au::from_px(0),
+                                             glyph_options);
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_border(state: &mut WrState, rect: WrRect, clip: WrClipRegion,
                                 top: WrBorderSide, right: WrBorderSide, bottom: WrBorderSide, left: WrBorderSide,
                                 radius: WrBorderRadius) {
     assert!( unsafe { is_in_main_thread() });
 
@@ -885,345 +1162,57 @@ pub extern fn wr_dp_push_radial_gradient
                                     end_center.to_point(),
                                     end_radius,
                                     stops,
                                     extend_mode.to_gradient_extend_mode()
                                     );
 }
 
 #[no_mangle]
-pub extern fn wr_dp_push_iframe(state: &mut WrState, rect: WrRect, clip: WrClipRegion, pipeline_id: PipelineId) {
+pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrClipRegion,
+                                    box_bounds: WrRect, offset: WrPoint, color: WrColor,
+                                    blur_radius: f32, spread_radius: f32, border_radius: f32,
+                                    clip_mode: WrBoxShadowClipMode) {
     assert!( unsafe { is_in_main_thread() });
 
-    state.frame_builder.dl_builder.push_iframe(rect.to_rect(),
-                                               clip.to_clip_region(),
-                                               pipeline_id);
-}
-
-#[repr(C)]
-struct WrItemRange
-{
-    start: usize,
-    length: usize,
-}
-impl WrItemRange
-{
-    fn to_item_range(&self) -> ItemRange
-    {
-        ItemRange {
-            start: self.start,
-            length: self.length,
-        }
-    }
-}
-impl From<ItemRange> for WrItemRange
-{
-    fn from(item_range: ItemRange) -> Self
-    {
-        WrItemRange {
-            start: item_range.start,
-            length: item_range.length,
-        }
-    }
-}
-
-#[repr(C)]
-pub struct WrColor
-{
-    r: f32,
-    g: f32,
-    b: f32,
-    a: f32
-}
-
-impl WrColor
-{
-    pub fn to_color(&self) -> ColorF
-    {
-        ColorF::new(self.r, self.g, self.b, self.a)
-    }
-}
-
-#[repr(C)]
-pub struct WrBorderRadius {
-    pub top_left: WrSize,
-    pub top_right: WrSize,
-    pub bottom_left: WrSize,
-    pub bottom_right: WrSize,
-}
-
-impl WrBorderRadius
-{
-    pub fn to_border_radius(&self) -> BorderRadius
-    {
-        BorderRadius { top_left: self.top_left.to_size(),
-                       top_right: self.top_right.to_size(),
-                       bottom_left: self.bottom_left.to_size(),
-                       bottom_right: self.bottom_right.to_size() }
-    }
-}
-
-#[repr(C)]
-pub struct WrBorderSide
-{
-    width: f32,
-    color: WrColor,
-    style: BorderStyle
-}
-
-impl WrBorderSide
-{
-    pub fn to_border_side(&self) -> BorderSide
-    {
-        BorderSide { color: self.color.to_color(), style: self.style }
-    }
-}
-
-#[repr(C)]
-pub struct WrGradientStop
-{
-    offset: f32,
-    color: WrColor,
-}
-
-impl WrGradientStop
-{
-    pub fn to_gradient_stop(&self) -> GradientStop
-    {
-        GradientStop {
-            offset: self.offset,
-            color: self.color.to_color(),
-        }
-    }
-    pub fn to_gradient_stops(stops: &[WrGradientStop]) -> Vec<GradientStop>
-    {
-        stops.iter().map(|x| x.to_gradient_stop()).collect()
-    }
-}
-
-#[repr(C)]
-pub struct WrSize
-{
-    width: f32,
-    height: f32
-}
-
-impl WrSize
-{
-    pub fn to_size(&self) -> LayoutSize
-    {
-        LayoutSize::new(self.width, self.height)
-    }
-}
-
-#[repr(C)]
-#[derive(Debug)]
-pub struct WrRect
-{
-    x: f32,
-    y: f32,
-    width: f32,
-    height: f32
-}
-
-impl WrRect
-{
-    pub fn to_rect(&self) -> LayoutRect
-    {
-        LayoutRect::new(LayoutPoint::new(self.x, self.y), LayoutSize::new(self.width, self.height))
-    }
-}
-impl From<LayoutRect> for WrRect
-{
-    fn from(rect: LayoutRect) -> Self
-    {
-        WrRect {
-            x: rect.origin.x,
-            y: rect.origin.y,
-            width: rect.size.width,
-            height: rect.size.height,
-        }
-    }
-}
-
-#[repr(C)]
-pub struct WrPoint
-{
-    x: f32,
-    y: f32
-}
-
-impl WrPoint
-{
-    pub fn to_point(&self) -> TypedPoint2D<f32, LayerPixel>
-    {
-        TypedPoint2D::new(self.x, self.y)
-    }
-}
-
-#[repr(C)]
-pub struct WrImageMask
-{
-    image: ImageKey,
-    rect: WrRect,
-    repeat: bool
-}
-
-impl WrImageMask
-{
-    pub fn to_image_mask(&self) -> ImageMask
-    {
-        ImageMask { image: self.image, rect: self.rect.to_rect(), repeat: self.repeat }
-    }
-}
-impl From<ImageMask> for WrImageMask
-{
-    fn from(image_mask: ImageMask) -> Self
-    {
-        WrImageMask {
-            image: image_mask.image,
-            rect: image_mask.rect.into(),
-            repeat: image_mask.repeat,
-        }
-    }
-}
-
-#[repr(C)]
-pub struct WrComplexClipRegion
-{
-  rect: WrRect,
-  radii: WrBorderRadius,
-}
-impl WrComplexClipRegion
-{
-    pub fn to_complex_clip_region(&self) -> ComplexClipRegion
-    {
-        ComplexClipRegion {
-            rect: self.rect.to_rect(),
-            radii: self.radii.to_border_radius(),
-        }
-    }
-    pub fn to_complex_clip_regions(complex_clips: &[WrComplexClipRegion]) -> Vec<ComplexClipRegion>
-    {
-        complex_clips.iter().map(|x| x.to_complex_clip_region()).collect()
-    }
-}
-
-#[repr(C)]
-pub struct WrClipRegion
-{
-  main: WrRect,
-  complex: WrItemRange,
-  image_mask: WrImageMask,
-  has_image_mask: bool,
-}
-impl WrClipRegion
-{
-    pub fn to_clip_region(&self) -> ClipRegion
-    {
-        ClipRegion {
-            main: self.main.to_rect(),
-            complex: self.complex.to_item_range(),
-            image_mask: if self.has_image_mask {
-                Some(self.image_mask.to_image_mask())
-            } else {
-                None
-            }
-        }
-    }
-}
-impl From<ClipRegion> for WrClipRegion
-{
-    fn from(clip_region: ClipRegion) -> Self {
-        if let Some(image_mask) = clip_region.image_mask {
-            WrClipRegion {
-                main: clip_region.main.into(),
-                complex: clip_region.complex.into(),
-                image_mask: image_mask.into(),
-                has_image_mask: true,
-            }
-        } else {
-            let blank = WrImageMask {
-                image: ImageKey(0, 0),
-                rect: WrRect { x: 0f32, y: 0f32, width: 0f32, height: 0f32, },
-                repeat: false,
-            };
-
-            WrClipRegion {
-                main: clip_region.main.into(),
-                complex: clip_region.complex.into(),
-                image_mask: blank,
-                has_image_mask: false,
-            }
-        }
-    }
+    state.frame_builder.dl_builder.push_box_shadow(rect.to_rect(),
+                                                   clip.to_clip_region(),
+                                                   box_bounds.to_rect(),
+                                                   offset.to_point(),
+                                                   color.to_color(),
+                                                   blur_radius,
+                                                   spread_radius,
+                                                   border_radius,
+                                                   clip_mode.to_box_shadow_clip_mode());
 }
 
 #[no_mangle]
-pub extern fn wr_dp_push_image(state:&mut WrState, bounds: WrRect, clip: WrClipRegion, image_rendering: ImageRendering, key: ImageKey) {
-    assert!( unsafe { is_in_main_thread() });
-
-    let bounds = bounds.to_rect();
-
-    state.frame_builder.dl_builder.push_image(
-        bounds,
-        clip.to_clip_region(),
-        bounds.size,
-        bounds.size,
-        image_rendering,
-        key
-    );
-}
-#[no_mangle]
-pub extern fn wr_api_generate_font_key(api: &mut RenderApi) -> FontKey
+pub unsafe extern fn wr_api_finalize_builder(state: &mut WrState,
+                                             dl_descriptor: &mut BuiltDisplayListDescriptor,
+                                             dl_data: &mut WrVecU8,
+                                             aux_descriptor: &mut AuxiliaryListsDescriptor,
+                                             aux_data: &mut WrVecU8)
 {
-    api.generate_font_key()
+    let frame_builder = mem::replace(&mut state.frame_builder,
+                                     WebRenderFrameBuilder::new(state.pipeline_id));
+    let (_, dl, aux) = frame_builder.dl_builder.finalize();
+    //XXX: get rid of the copies here
+    *dl_data = WrVecU8::from_vec(dl.data().to_owned());
+    *dl_descriptor = dl.descriptor().clone();
+    *aux_data = WrVecU8::from_vec(aux.data().to_owned());
+    *aux_descriptor = aux.descriptor().clone();
 }
 
 #[no_mangle]
-pub extern fn wr_api_add_raw_font(api: &mut RenderApi,
-                                  key: FontKey,
-                                  font_buffer: *mut u8,
-                                  buffer_size: usize)
+pub unsafe extern fn wr_dp_push_built_display_list(state: &mut WrState,
+                                                   dl_descriptor: BuiltDisplayListDescriptor,
+                                                   dl_data: WrVecU8,
+                                                   aux_descriptor: AuxiliaryListsDescriptor,
+                                                   aux_data: WrVecU8)
 {
-    assert!( unsafe { is_in_compositor_thread() });
-
-    let font_slice = unsafe {
-        slice::from_raw_parts(font_buffer, buffer_size as usize)
-    };
-    let mut font_vector = Vec::new();
-    font_vector.extend_from_slice(font_slice);
-
-    api.add_raw_font(key, font_vector);
-}
-
+    let dl_vec = dl_data.to_vec();
+    let aux_vec = aux_data.to_vec();
 
-#[no_mangle]
-pub extern fn wr_dp_push_text(state: &mut WrState,
-                              bounds: WrRect,
-                              clip: WrClipRegion,
-                              color: WrColor,
-                              font_key: FontKey,
-                              glyphs: *mut GlyphInstance,
-                              glyph_count: u32,
-                              glyph_size: f32)
-{
-    assert!( unsafe { is_in_main_thread() });
+    let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
+    let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
 
-    let glyph_slice = unsafe {
-        slice::from_raw_parts(glyphs, glyph_count as usize)
-    };
-    let mut glyph_vector = Vec::new();
-    glyph_vector.extend_from_slice(&glyph_slice);
-
-    let colorf = ColorF::new(color.r, color.g, color.b, color.a);
-
-    let glyph_options = None; // TODO
-    state.frame_builder.dl_builder.push_text(bounds.to_rect(),
-                                             clip.to_clip_region(),
-                                             glyph_vector,
-                                             font_key,
-                                             colorf,
-                                             Au::from_f32_px(glyph_size),
-                                             Au::from_px(0),
-                                             glyph_options);
+    state.frame_builder.dl_builder.push_built_display_list(dl, aux);
 }
-
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -168,24 +168,61 @@ typedef uint64_t WrImageIdType;
 
 struct WrItemRange
 {
   size_t start;
   size_t length;
 };
 
 struct WrBuiltDisplayListDescriptor {
-    size_t display_list_items_size;
+  size_t display_list_items_size;
 };
 
 struct WrAuxiliaryListsDescriptor {
-    size_t gradient_stops_size;
-    size_t complex_clip_regions_size;
-    size_t filters_size;
-    size_t glyph_instances_size;
+  size_t gradient_stops_size;
+  size_t complex_clip_regions_size;
+  size_t filters_size;
+  size_t glyph_instances_size;
+};
+
+struct WrPoint
+{
+  float x;
+  float y;
+
+  bool operator==(const WrPoint& aRhs) const {
+    return x == aRhs.x && y == aRhs.y;
+  }
+
+  operator mozilla::gfx::Point() const { return mozilla::gfx::Point(x, y); }
+};
+
+struct WrSize
+{
+  float width;
+  float height;
+
+  bool operator==(const WrSize& aRhs) const
+  {
+    return width == aRhs.width && height == aRhs.height;
+  }
+};
+
+struct WrRect
+{
+  float x;
+  float y;
+  float width;
+  float height;
+
+  bool operator==(const WrRect& aRhs) const
+  {
+    return x == aRhs.x && y == aRhs.y &&
+           width == aRhs.width && height == aRhs.height;
+  }
 };
 
 struct WrColor
 {
   float r;
   float g;
   float b;
   float a;
@@ -254,66 +291,29 @@ struct WrBorderSide {
 
   bool operator==(const WrBorderSide& aRhs) const
   {
     return width == aRhs.width && color == aRhs.color &&
            style == aRhs.style;
   }
 };
 
-struct WrSize
-{
-  float width;
-  float height;
-
-  bool operator==(const WrSize& aRhs) const
-  {
-    return width == aRhs.width && height == aRhs.height;
-  }
-};
-
 struct WrBorderRadius {
   WrSize top_left;
   WrSize top_right;
   WrSize bottom_left;
   WrSize bottom_right;
 
   bool operator==(const WrBorderRadius& aRhs) const
   {
     return top_left == aRhs.top_left && top_right == aRhs.top_right &&
            bottom_left == aRhs.bottom_left && bottom_right == aRhs.bottom_right;
   }
 };
 
-struct WrRect
-{
-  float x;
-  float y;
-  float width;
-  float height;
-
-  bool operator==(const WrRect& aRhs) const
-  {
-    return x == aRhs.x && y == aRhs.y &&
-           width == aRhs.width && height == aRhs.height;
-  }
-};
-
-struct WrPoint
-{
-  float x;
-  float y;
-
-  bool operator==(const WrPoint& aRhs) const {
-    return x == aRhs.x && y == aRhs.y;
-  }
-
-  operator mozilla::gfx::Point() const { return mozilla::gfx::Point(x, y); }
-};
-
 struct WrImageMask
 {
   WrImageKey image;
   WrRect rect;
   bool repeat;
 
   bool operator==(const WrImageMask& aRhs) const
   {
@@ -417,16 +417,23 @@ WR_FUNC;
 WR_INLINE void
 wr_renderer_update(WrRenderer* renderer)
 WR_FUNC;
 
 WR_INLINE void
 wr_renderer_render(WrRenderer* renderer, uint32_t width, uint32_t height)
 WR_FUNC;
 
+// It is the responsibility of the caller to manage the dst_buffer memory
+// and also free it at the proper time.
+WR_INLINE const uint8_t*
+wr_renderer_readback(uint32_t width, uint32_t height,
+                     uint8_t* dst_buffer, size_t buffer_length)
+WR_FUNC;
+
 WR_INLINE void
 wr_renderer_set_profiler_enabled(WrRenderer* renderer, bool enabled)
 WR_FUNC;
 
 WR_INLINE bool
 wr_renderer_current_epoch(WrRenderer* renderer, WrPipelineId pipeline_id,
                           WrEpoch* out_epoch)
 WR_FUNC;
@@ -515,25 +522,44 @@ WR_FUNC;
 WR_INLINE void
 wr_api_send_external_event(WrAPI* api, uintptr_t evt)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE void
 wr_api_add_raw_font(WrAPI* api, WrFontKey key, uint8_t* font_buffer, size_t buffer_size)
 WR_FUNC;
 
+WR_INLINE WrIdNamespace
+wr_api_get_namespace(WrAPI* api)
+WR_FUNC;
+
 WR_INLINE WrState*
 wr_state_new(WrPipelineId pipeline_id)
 WR_FUNC;
 
 WR_INLINE void
 wr_state_delete(WrState* state)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE void
+wr_dp_begin(WrState* wrState, uint32_t width, uint32_t height)
+WR_FUNC;
+
+WR_INLINE void
+wr_dp_end(WrState* wrState)
+WR_FUNC;
+
+WR_INLINE WrClipRegion
+wr_dp_new_clip_region(WrState* wrState,
+                      WrRect main,
+                      const WrComplexClipRegion* complex, size_t complexCount,
+                      const WrImageMask* image_mask)
+WR_FUNC;
+
+WR_INLINE void
 wr_dp_push_stacking_context(WrState *wrState, WrRect bounds,
                             WrRect overflow, const WrImageMask *mask,
                             float opacity, const float* matrix,
                             WrMixBlendMode mixBlendMode)
 WR_FUNC;
 
 //XXX: matrix should use a proper type
 WR_INLINE void
@@ -544,38 +570,31 @@ WR_INLINE void
 wr_dp_push_scroll_layer(WrState *wrState, WrRect bounds,
                         WrRect overflow, const WrImageMask *mask)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_pop_scroll_layer(WrState *wrState)
 WR_FUNC;
 
-
 WR_INLINE void
-wr_dp_begin(WrState* wrState, uint32_t width, uint32_t height)
-WR_FUNC;
-
-WR_INLINE void
-wr_dp_end(WrState* wrState)
-WR_FUNC;
-
-WR_INLINE WrClipRegion
-wr_dp_new_clip_region(WrState* wrState,
-                      WrRect main,
-                      const WrComplexClipRegion* complex, size_t complexCount,
-                      const WrImageMask* image_mask)
+wr_dp_push_iframe(WrState* wrState, WrRect bounds, WrClipRegion clip, WrPipelineId layers_id)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_rect(WrState* wrState, WrRect bounds, WrClipRegion clip,
                 WrColor color)
 WR_FUNC;
 
 WR_INLINE void
+wr_dp_push_image(WrState* wrState, WrRect bounds, WrClipRegion clip,
+                 WrImageRendering filter, WrImageKey key)
+WR_FUNC;
+
+WR_INLINE void
 wr_dp_push_text(WrState* wrState, WrRect bounds, WrClipRegion clip, WrColor color,
                 WrFontKey font_Key, const WrGlyphInstance* glyphs,
                 uint32_t glyph_count, float glyph_size)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_border(WrState* wrState, WrRect bounds, WrClipRegion clip,
                   WrBorderSide top, WrBorderSide right, WrBorderSide bottom, WrBorderSide left,
@@ -593,42 +612,22 @@ WR_INLINE void
 wr_dp_push_radial_gradient(WrState* wrState, WrRect bounds, WrClipRegion clip,
                            WrPoint startCenter, WrPoint endCenter,
                            float startRadius, float endRadius,
                            const WrGradientStop* stops, size_t stopsCount,
                            WrGradientExtendMode extendMode)
 WR_FUNC;
 
 WR_INLINE void
-wr_dp_push_image(WrState* wrState, WrRect bounds, WrClipRegion clip,
-                 WrImageRendering filter, WrImageKey key)
-WR_FUNC;
-
-WR_INLINE void
-wr_dp_push_iframe(WrState* wrState, WrRect bounds, WrClipRegion clip, WrPipelineId layers_id)
-WR_FUNC;
-
-// It is the responsibility of the caller to manage the dst_buffer memory
-// and also free it at the proper time.
-WR_INLINE const uint8_t*
-wr_renderer_readback(uint32_t width, uint32_t height,
-                     uint8_t* dst_buffer, size_t buffer_length)
-WR_FUNC;
-
-WR_INLINE void
 wr_dp_push_box_shadow(WrState* wrState, WrRect rect, WrClipRegion clip,
                       WrRect box_bounds, WrPoint offset, WrColor color,
                       float blur_radius, float spread_radius, float border_radius,
                       WrBoxShadowClipMode clip_mode)
 WR_FUNC;
 
-WR_INLINE WrIdNamespace
-wr_api_get_namespace(WrAPI* api)
-WR_FUNC;
-
 WR_INLINE void
 wr_api_finalize_builder(WrState* wrState,
                         WrBuiltDisplayListDescriptor& dl_descriptor,
                         WrVecU8& dl_data,
                         WrAuxiliaryListsDescriptor& aux_descriptor,
                         WrVecU8& aux_data)
 WR_FUNC;