Bug 1546371 - Switch render backend and API away from FramebufferPixel r=gw
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Thu, 25 Apr 2019 13:02:47 +0000
changeset 471328 bc316493ddae00897a98f9a0601f9764e7c4daa9
parent 471327 5c2540f3ed73ff48f6f523c7e67f9ce2da38dfa1
child 471329 dc38b66e235646ca9230acda946ecf0f8b018742
push id112913
push useropoprus@mozilla.com
push dateThu, 25 Apr 2019 22:21:16 +0000
treeherdermozilla-inbound@5279ac14ae48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1546371
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1546371 - Switch render backend and API away from FramebufferPixel r=gw The gist of the problem I introduced with the framebuffer coordinate system is that we provided the window rect (effectively) twice: 1. when computing the document rectangle (and Y-inverting it) 2. when rendering If between these points the window got resized (during scene building), we end up with our document aligned to bottom left corner. The user expects content to still be aligned to the top left, so that's what is visible as a bug. The change here switched scene building to only care about device coordinate space, restraining the framebuffer coordinates to be mostly an implementation detail of the renderer/device (the way it was originally meant to be, when introduced). This way the current window size is only considered once during rendering. Differential Revision: https://phabricator.services.mozilla.com/D28731
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/Cargo.lock
gfx/wr/direct-composition/src/main_windows.rs
gfx/wr/examples/alpha_perf.rs
gfx/wr/examples/animation.rs
gfx/wr/examples/basic.rs
gfx/wr/examples/blob.rs
gfx/wr/examples/common/boilerplate.rs
gfx/wr/examples/document.rs
gfx/wr/examples/frame_output.rs
gfx/wr/examples/iframe.rs
gfx/wr/examples/image_resize.rs
gfx/wr/examples/multiwindow.rs
gfx/wr/examples/scrolling.rs
gfx/wr/examples/texture_cache_stress.rs
gfx/wr/examples/yuv.rs
gfx/wr/webrender/src/debug_render.rs
gfx/wr/webrender/src/device/gl.rs
gfx/wr/webrender/src/display_list_flattener.rs
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender/src/resource_cache.rs
gfx/wr/webrender/src/texture_cache.rs
gfx/wr/webrender/src/tiling.rs
gfx/wr/webrender_api/src/api.rs
gfx/wr/wrench/src/main.rs
gfx/wr/wrench/src/png.rs
gfx/wr/wrench/src/rawtest.rs
gfx/wr/wrench/src/reftest.rs
gfx/wr/wrench/src/wrench.rs
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -931,17 +931,17 @@ bool WebRenderBridgeParent::SetDisplayLi
         // XXX: If we can't have multiple documents, just use the
         // pre-document- splitting behavior of directly applying the client
         // size. This is a speculative and temporary attempt to address bug
         // 1538540, as an incorrect rect supplied to SetDocumentView can cause
         // us to not build a frame and potentially render with stale texture
         // cache items.
         rect = LayoutDeviceIntRect(LayoutDeviceIntPoint(), widgetSize);
       }
-      aTxn.SetDocumentView(rect, widgetSize);
+      aTxn.SetDocumentView(rect);
     }
     gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
     aTxn.SetDisplayList(clearColor, aWrEpoch,
                         wr::ToLayoutSize(RoundedToInt(aRect).Size()),
                         mPipelineId, aContentSize, aDLDesc, dlData);
 
     if (aObserveLayersUpdate) {
       aTxn.Notify(wr::Checkpoint::SceneBuilt,
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -204,22 +204,20 @@ bool TransactionBuilder::IsResourceUpdat
   return wr_transaction_resource_updates_is_empty(mTxn);
 }
 
 bool TransactionBuilder::IsRenderedFrameInvalidated() const {
   return wr_transaction_is_rendered_frame_invalidated(mTxn);
 }
 
 void TransactionBuilder::SetDocumentView(
-    const LayoutDeviceIntRect& aDocumentRect,
-    const LayoutDeviceIntSize& aWidgetSize) {
-  wr::FramebufferIntRect wrDocRect;
+    const LayoutDeviceIntRect& aDocumentRect) {
+  wr::DeviceIntRect wrDocRect;
   wrDocRect.origin.x = aDocumentRect.x;
-  wrDocRect.origin.y =
-      aWidgetSize.height - aDocumentRect.y - aDocumentRect.height;
+  wrDocRect.origin.y = aDocumentRect.y;
   wrDocRect.size.width = aDocumentRect.width;
   wrDocRect.size.height = aDocumentRect.height;
   wr_transaction_set_document_view(mTxn, &wrDocRect);
 }
 
 void TransactionBuilder::UpdateScrollPosition(
     const wr::WrPipelineId& aPipelineId,
     const layers::ScrollableLayerGuid::ViewID& aScrollId,
@@ -296,17 +294,17 @@ already_AddRefed<WebRenderAPI> WebRender
                        mUseTripleBuffering, mSyncHandle, mRenderRoot);
   renderApi->mRootApi = this;  // Hold root api
   renderApi->mRootDocumentApi = this;
   return renderApi.forget();
 }
 
 already_AddRefed<WebRenderAPI> WebRenderAPI::CreateDocument(
     LayoutDeviceIntSize aSize, int8_t aLayerIndex, wr::RenderRoot aRenderRoot) {
-  wr::FramebufferIntSize wrSize;
+  wr::DeviceIntSize wrSize;
   wrSize.width = aSize.width;
   wrSize.height = aSize.height;
   wr::DocumentHandle* newDoc;
 
   wr_api_create_document(mDocHandle, &newDoc, wrSize, aLayerIndex,
                          (uint32_t)aRenderRoot);
 
   RefPtr<WebRenderAPI> api(
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -99,18 +99,17 @@ class TransactionBuilder final {
   void GenerateFrame();
 
   void InvalidateRenderedFrame();
 
   void UpdateDynamicProperties(
       const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
       const nsTArray<wr::WrTransformProperty>& aTransformArray);
 
-  void SetDocumentView(const LayoutDeviceIntRect& aDocRect,
-                       const LayoutDeviceIntSize& aWidgetSize);
+  void SetDocumentView(const LayoutDeviceIntRect& aDocRect);
 
   void UpdateScrollPosition(
       const wr::WrPipelineId& aPipelineId,
       const layers::ScrollableLayerGuid::ViewID& aScrollId,
       const wr::LayoutPoint& aScrollPosition);
 
   bool IsEmpty() const;
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -204,25 +204,25 @@ unsafe fn make_slice_mut<'a, T>(ptr: *mu
 }
 
 pub struct DocumentHandle {
     api: RenderApi,
     document_id: DocumentId,
 }
 
 impl DocumentHandle {
-    pub fn new(api: RenderApi, size: FramebufferIntSize, layer: i8) -> DocumentHandle {
+    pub fn new(api: RenderApi, size: DeviceIntSize, layer: i8) -> DocumentHandle {
         let doc = api.add_document(size, layer);
         DocumentHandle {
             api: api,
             document_id: doc
         }
     }
 
-    pub fn new_with_id(api: RenderApi, size: FramebufferIntSize, layer: i8, id: u32) -> DocumentHandle {
+    pub fn new_with_id(api: RenderApi, size: DeviceIntSize, layer: i8, id: u32) -> DocumentHandle {
         let doc = api.add_document_with_id(size, layer, id);
         DocumentHandle {
             api: api,
             document_id: doc
         }
     }
 }
 
@@ -654,17 +654,17 @@ pub extern "C" fn wr_renderer_update(ren
 pub extern "C" fn wr_renderer_render(renderer: &mut Renderer,
                                      width: i32,
                                      height: i32,
                                      had_slow_frame: bool,
                                      out_stats: &mut RendererStats) -> bool {
     if had_slow_frame {
       renderer.notify_slow_frame();
     }
-    match renderer.render(FramebufferIntSize::new(width, height)) {
+    match renderer.render(DeviceIntSize::new(width, height)) {
         Ok(results) => {
             *out_stats = results.stats;
             true
         }
         Err(errors) => {
             for e in errors {
                 warn!(" Failed to render: {:?}", e);
                 let msg = CString::new(format!("wr_renderer_render: {:?}", e)).unwrap();
@@ -1221,17 +1221,17 @@ pub extern "C" fn wr_window_new(window_i
         enable_picture_caching,
         allow_pixel_local_storage_support: false,
         ..Default::default()
     };
 
     // Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
     set_profiler_hooks(Some(&PROFILER_HOOKS));
 
-    let window_size = FramebufferIntSize::new(window_width, window_height);
+    let window_size = DeviceIntSize::new(window_width, window_height);
     let notifier = Box::new(CppNotifier {
         window_id: window_id,
     });
     let (renderer, sender) = match Renderer::new(gl, notifier, opts, shaders, window_size) {
         Ok((renderer, sender)) => (renderer, sender),
         Err(e) => {
             warn!(" Failed to create a Renderer: {:?}", e);
             let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
@@ -1253,17 +1253,17 @@ pub extern "C" fn wr_window_new(window_i
 
     return true;
 }
 
 #[no_mangle]
 pub extern "C" fn wr_api_create_document(
     root_dh: &mut DocumentHandle,
     out_handle: &mut *mut DocumentHandle,
-    doc_size: FramebufferIntSize,
+    doc_size: DeviceIntSize,
     layer: i8,
     document_id: u32
 ) {
     assert!(unsafe { is_in_compositor_thread() });
 
     *out_handle = Box::into_raw(Box::new(DocumentHandle::new_with_id(
         root_dh.api.clone_sender().create_api_by_client(next_namespace_id()),
         doc_size,
@@ -1440,17 +1440,17 @@ pub extern "C" fn wr_transaction_set_dis
         (pipeline_id, content_size, dl),
         preserve_frame_state,
     );
 }
 
 #[no_mangle]
 pub extern "C" fn wr_transaction_set_document_view(
     txn: &mut Transaction,
-    doc_rect: &FramebufferIntRect,
+    doc_rect: &DeviceIntRect,
 ) {
     txn.set_document_view(
         *doc_rect,
         1.0,
     );
 }
 
 #[no_mangle]
--- a/gfx/wr/Cargo.lock
+++ b/gfx/wr/Cargo.lock
@@ -366,17 +366,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "direct-composition"
 version = "0.1.0"
 dependencies = [
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dlib"
 version = "0.4.1"
@@ -860,17 +860,17 @@ dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mozangle"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1641,17 +1641,17 @@ dependencies = [
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "pathfinder_font_renderer 0.5.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)",
  "pathfinder_gfx_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)",
  "pathfinder_partitioner 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)",
  "pathfinder_path_utils 0.2.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)",
  "plane-split 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1793,17 +1793,17 @@ dependencies = [
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
  "webrender_api 0.60.0",
@@ -1970,17 +1970,17 @@ dependencies = [
 "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
 "checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
 "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
 "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
 "checksum mio 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "75f72a93f046f1517e3cfddc0a096eb756a2ba727d36edc8227dee769a50a9b0"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
-"checksum mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f0583e6792917f498bb3a7440f777a59353102063445ab7f5e9d1dc4ed593aa"
+"checksum mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "45a8a18a41cfab0fde25cc2f43ea89064d211a0fbb33225b8ff93ab20406e0e7"
 "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0"
 "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d"
 "checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45"
 "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
 "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
 "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
--- a/gfx/wr/direct-composition/src/main_windows.rs
+++ b/gfx/wr/direct-composition/src/main_windows.rs
@@ -90,23 +90,23 @@ fn direct_composition_from_window(window
     }
 }
 
 struct Rectangle {
     visual: direct_composition::AngleVisual,
     renderer: Option<webrender::Renderer>,
     api: api::RenderApi,
     document_id: api::DocumentId,
-    size: api::units::FramebufferIntSize,
+    size: api::units::DeviceIntSize,
     color: api::ColorF,
 }
 
 impl Rectangle {
     fn new(composition: &DirectComposition, notifier: &Box<Notifier>,
-           device_pixel_ratio: f32, size: api::units::FramebufferIntSize, r: f32, g: f32, b: f32, a: f32)
+           device_pixel_ratio: f32, size: api::units::DeviceIntSize, r: f32, g: f32, b: f32, a: f32)
            -> Self {
         let visual = composition.create_angle_visual(size.width as u32, size.height as u32);
         visual.make_current();
 
         let (renderer, sender) = webrender::Renderer::new(
             composition.gleam.clone(),
             notifier.clone(),
             webrender::RendererOptions {
--- a/gfx/wr/examples/alpha_perf.rs
+++ b/gfx/wr/examples/alpha_perf.rs
@@ -9,30 +9,30 @@ extern crate webrender;
 extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use std::cmp;
 use webrender::api::*;
-use webrender::api::units::FramebufferIntSize;
+use webrender::api::units::DeviceIntSize;
 
 
 struct App {
     rect_count: usize,
 }
 
 impl Example for App {
     fn render(
         &mut self,
         _api: &RenderApi,
         builder: &mut DisplayListBuilder,
         _txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let bounds = (0, 0).to(1920, 1080);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
--- a/gfx/wr/examples/animation.rs
+++ b/gfx/wr/examples/animation.rs
@@ -106,17 +106,17 @@ impl Example for App {
     const WIDTH: u32 = 2048;
     const HEIGHT: u32 = 1536;
 
     fn render(
         &mut self,
         _api: &RenderApi,
         builder: &mut DisplayListBuilder,
         _txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let opacity_key = self.opacity_key;
 
         let bounds = (150, 150).to(250, 250);
         let key0 = self.property_key0;
         self.add_rounded_rect(bounds, ColorF::new(1.0, 0.0, 0.0, 0.5), builder, pipeline_id, key0, Some(opacity_key));
--- a/gfx/wr/examples/basic.rs
+++ b/gfx/wr/examples/basic.rs
@@ -181,17 +181,17 @@ impl Example for App {
     // Make this the only example to test all shaders for compile errors.
     const PRECACHE_SHADER_FLAGS: ShaderPrecacheFlags = ShaderPrecacheFlags::FULL_COMPILE;
 
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
-        _: FramebufferIntSize,
+        _: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let content_bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
         let spatial_id = root_space_and_clip.spatial_id;
 
         builder.push_simple_stacking_context(
--- a/gfx/wr/examples/blob.rs
+++ b/gfx/wr/examples/blob.rs
@@ -195,17 +195,17 @@ impl api::AsyncBlobImageRasterizer for R
 struct App {}
 
 impl Example for App {
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let blob_img1 = api.generate_blob_image_key();
         txn.add_blob_image(
             blob_img1,
             api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true, false),
             serialize_blob(api::ColorU::new(50, 50, 150, 255)),
--- a/gfx/wr/examples/common/boilerplate.rs
+++ b/gfx/wr/examples/common/boilerplate.rs
@@ -75,17 +75,17 @@ pub trait Example {
     const WIDTH: u32 = 1920;
     const HEIGHT: u32 = 1080;
 
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         document_id: DocumentId,
     );
     fn on_event(
         &mut self,
         winit::WindowEvent,
         &RenderApi,
         DocumentId,
@@ -155,55 +155,55 @@ pub fn main_wrapper<E: Example>(
         precache_flags: E::PRECACHE_SHADER_FLAGS,
         device_pixel_ratio,
         clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
         //scatter_gpu_cache_updates: false,
         debug_flags,
         ..options.unwrap_or(webrender::RendererOptions::default())
     };
 
-    let framebuffer_size = {
+    let device_size = {
         let size = window
             .get_inner_size()
             .unwrap()
             .to_physical(device_pixel_ratio as f64);
-        FramebufferIntSize::new(size.width as i32, size.height as i32)
+        DeviceIntSize::new(size.width as i32, size.height as i32)
     };
     let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
     let (mut renderer, sender) = webrender::Renderer::new(
         gl.clone(),
         notifier,
         opts,
         None,
-        framebuffer_size,
+        device_size,
     ).unwrap();
     let api = sender.create_api();
-    let document_id = api.add_document(framebuffer_size, 0);
+    let document_id = api.add_document(device_size, 0);
 
     let (external, output) = example.get_image_handlers(&*gl);
 
     if let Some(output_image_handler) = output {
         renderer.set_output_image_handler(output_image_handler);
     }
 
     if let Some(external_image_handler) = external {
         renderer.set_external_image_handler(external_image_handler);
     }
 
     let epoch = Epoch(0);
     let pipeline_id = PipelineId(0, 0);
-    let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
+    let layout_size = device_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
     let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
     let mut txn = Transaction::new();
 
     example.render(
         &api,
         &mut builder,
         &mut txn,
-        framebuffer_size,
+        device_size,
         pipeline_id,
         document_id,
     );
     txn.set_display_list(
         epoch,
         Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
         layout_size,
         builder.finalize(),
@@ -245,21 +245,21 @@ pub fn main_wrapper<E: Example>(
                 winit::VirtualKeyCode::Q => debug_flags.toggle(
                     DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES
                 ),
                 winit::VirtualKeyCode::F => debug_flags.toggle(
                     DebugFlags::NEW_FRAME_INDICATOR | DebugFlags::NEW_SCENE_INDICATOR
                 ),
                 winit::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
                 winit::VirtualKeyCode::Key1 => txn.set_document_view(
-                    framebuffer_size.into(),
+                    device_size.into(),
                     1.0
                 ),
                 winit::VirtualKeyCode::Key2 => txn.set_document_view(
-                    framebuffer_size.into(),
+                    device_size.into(),
                     2.0
                 ),
                 winit::VirtualKeyCode::M => api.notify_memory_pressure(),
                 winit::VirtualKeyCode::C => {
                     let path: PathBuf = "../captures/example".into();
                     //TODO: switch between SCENE/FRAME capture types
                     // based on "shift" modifier, when `glutin` is updated.
                     let bits = CaptureBits::all();
@@ -286,33 +286,33 @@ pub fn main_wrapper<E: Example>(
 
         if custom_event {
             let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
 
             example.render(
                 &api,
                 &mut builder,
                 &mut txn,
-                framebuffer_size,
+                device_size,
                 pipeline_id,
                 document_id,
             );
             txn.set_display_list(
                 epoch,
                 Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
                 layout_size,
                 builder.finalize(),
                 true,
             );
             txn.generate_frame();
         }
         api.send_transaction(document_id, txn);
 
         renderer.update();
-        renderer.render(framebuffer_size).unwrap();
+        renderer.render(device_size).unwrap();
         let _ = renderer.flush_pipeline_info();
         example.draw_custom(&*gl);
         window.swap_buffers().ok();
 
         winit::ControlFlow::Continue
     });
 
     renderer.deinit();
--- a/gfx/wr/examples/document.rs
+++ b/gfx/wr/examples/document.rs
@@ -34,43 +34,43 @@ impl App {
     fn init(
         &mut self,
         api: &RenderApi,
         device_pixel_ratio: f32,
     ) {
         let init_data = vec![
             (
                 PipelineId(1, 0),
-                1,
+                -2,
                 ColorF::new(0.0, 1.0, 0.0, 1.0),
-                FramebufferIntPoint::new(0, 400),
+                DeviceIntPoint::new(0, 0),
             ),
             (
                 PipelineId(2, 0),
-                2,
+                -1,
                 ColorF::new(1.0, 1.0, 0.0, 1.0),
-                FramebufferIntPoint::new(200, 400),
+                DeviceIntPoint::new(200, 0),
             ),
             (
                 PipelineId(3, 0),
-                3,
+                0,
                 ColorF::new(1.0, 0.0, 0.0, 1.0),
-                FramebufferIntPoint::new(200, 600),
+                DeviceIntPoint::new(200, 200),
             ),
             (
                 PipelineId(4, 0),
-                4,
+                1,
                 ColorF::new(1.0, 0.0, 1.0, 1.0),
-                FramebufferIntPoint::new(0, 600),
+                DeviceIntPoint::new(0, 200),
             ),
         ];
 
         for (pipeline_id, layer, color, offset) in init_data {
-            let size = FramebufferIntSize::new(250, 250);
-            let bounds = FramebufferIntRect::new(offset, size);
+            let size = DeviceIntSize::new(250, 250);
+            let bounds = DeviceIntRect::new(offset, size);
 
             let document_id = api.add_document(size, layer);
             let mut txn = Transaction::new();
             txn.set_document_view(bounds, device_pixel_ratio);
             txn.set_root_pipeline(pipeline_id);
             api.send_transaction(document_id, txn);
 
             self.documents.push(Document {
@@ -87,22 +87,22 @@ impl App {
 }
 
 impl Example for App {
     fn render(
         &mut self,
         api: &RenderApi,
         base_builder: &mut DisplayListBuilder,
         _txn: &mut Transaction,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
         _pipeline_id: PipelineId,
         _: DocumentId,
     ) {
         if self.documents.is_empty() {
-            let device_pixel_ratio = framebuffer_size.width as f32 /
+            let device_pixel_ratio = device_size.width as f32 /
                 base_builder.content_size().width;
             // this is the first run, hack around the boilerplate,
             // which assumes an example only needs one document
             self.init(api,  device_pixel_ratio);
         }
 
         for doc in &self.documents {
             let space_and_clip = SpaceAndClipInfo::root_scroll(doc.pipeline_id);
--- a/gfx/wr/examples/frame_output.rs
+++ b/gfx/wr/examples/frame_output.rs
@@ -65,42 +65,39 @@ impl webrender::ExternalImageHandler for
     }
     fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {}
 }
 
 impl App {
     fn init_output_document(
         &mut self,
         api: &RenderApi,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
         device_pixel_ratio: f32,
     ) {
         // Generate the external image key that will be used to render the output document to the root document.
         self.external_image_key = Some(api.generate_image_key());
 
         let pipeline_id = PipelineId(1, 0);
         let layer = 1;
         let color = ColorF::new(1., 1., 0., 1.);
-        let document_id = api.add_document(framebuffer_size, layer);
+        let document_id = api.add_document(device_size, layer);
         api.enable_frame_output(document_id, pipeline_id, true);
         api.set_document_view(
             document_id,
-            FramebufferIntRect::new(
-                FramebufferIntPoint::new(0, 1000),
-                framebuffer_size,
-            ),
+            device_size.into(),
             device_pixel_ratio,
         );
 
         let document = Document {
             id: document_id,
             pipeline_id,
             content_rect: LayoutRect::new(
                 LayoutPoint::zero(),
-                framebuffer_size.to_f32() / TypedScale::new(device_pixel_ratio),
+                device_size.to_f32() / TypedScale::new(device_pixel_ratio),
             ),
             color,
         };
 
         let mut txn = Transaction::new();
 
         txn.add_image(
             self.external_image_key.unwrap(),
@@ -146,24 +143,24 @@ impl App {
 }
 
 impl Example for App {
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         _txn: &mut Transaction,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         if self.output_document.is_none() {
-            let device_pixel_ratio = framebuffer_size.width as f32 /
+            let device_pixel_ratio = device_size.width as f32 /
                 builder.content_size().width;
-            self.init_output_document(api, FramebufferIntSize::new(200, 200), device_pixel_ratio);
+            self.init_output_document(api, DeviceIntSize::new(200, 200), device_pixel_ratio);
         }
 
         let bounds = (100, 100).to(200, 200);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
--- a/gfx/wr/examples/iframe.rs
+++ b/gfx/wr/examples/iframe.rs
@@ -21,17 +21,17 @@ use webrender::api::units::*;
 struct App {}
 
 impl Example for App {
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         _txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         document_id: DocumentId,
     ) {
         // All the sub_* things are for the nested pipeline
         let sub_size = DeviceIntSize::new(100, 100);
         let sub_bounds = (0, 0).to(sub_size.width as i32, sub_size.height as i32);
 
         let sub_pipeline_id = PipelineId(pipeline_id.0, 42);
--- a/gfx/wr/examples/image_resize.rs
+++ b/gfx/wr/examples/image_resize.rs
@@ -21,17 +21,17 @@ struct App {
 }
 
 impl Example for App {
     fn render(
         &mut self,
         _api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let (image_descriptor, image_data) = image_helper::make_checkerboard(32, 32);
         txn.add_image(
             self.image_key,
             image_descriptor,
             image_data,
--- a/gfx/wr/examples/multiwindow.rs
+++ b/gfx/wr/examples/multiwindow.rs
@@ -92,27 +92,27 @@ impl Window {
         let device_pixel_ratio = window.get_hidpi_factor() as f32;
 
         let opts = webrender::RendererOptions {
             device_pixel_ratio,
             clear_color: Some(clear_color),
             ..webrender::RendererOptions::default()
         };
 
-        let framebuffer_size = {
+        let device_size = {
             let size = window
                 .get_inner_size()
                 .unwrap()
                 .to_physical(device_pixel_ratio as f64);
-            FramebufferIntSize::new(size.width as i32, size.height as i32)
+            DeviceIntSize::new(size.width as i32, size.height as i32)
         };
         let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
-        let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None, framebuffer_size).unwrap();
+        let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None, device_size).unwrap();
         let api = sender.create_api();
-        let document_id = api.add_document(framebuffer_size, 0);
+        let document_id = api.add_document(device_size, 0);
 
         let epoch = Epoch(0);
         let pipeline_id = PipelineId(0, 0);
         let mut txn = Transaction::new();
 
         let font_key = api.generate_font_key();
         let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
         txn.add_raw_font(font_key, font_bytes, 0);
@@ -171,24 +171,24 @@ impl Window {
             }
             _ => {}
         });
         if do_exit {
             return true
         }
 
         let device_pixel_ratio = self.window.get_hidpi_factor() as f32;
-        let framebuffer_size = {
+        let device_size = {
             let size = self.window
                 .get_inner_size()
                 .unwrap()
                 .to_physical(device_pixel_ratio as f64);
-            FramebufferIntSize::new(size.width as i32, size.height as i32)
+            DeviceIntSize::new(size.width as i32, size.height as i32)
         };
-        let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
+        let layout_size = device_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
         let mut txn = Transaction::new();
         let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);
         let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id);
 
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
@@ -281,17 +281,17 @@ impl Window {
             builder.finalize(),
             true,
         );
         txn.set_root_pipeline(self.pipeline_id);
         txn.generate_frame();
         api.send_transaction(self.document_id, txn);
 
         renderer.update();
-        renderer.render(framebuffer_size).unwrap();
+        renderer.render(device_size).unwrap();
         self.window.swap_buffers().ok();
 
         false
     }
 
     fn deinit(self) {
         self.renderer.deinit();
     }
--- a/gfx/wr/examples/scrolling.rs
+++ b/gfx/wr/examples/scrolling.rs
@@ -23,17 +23,17 @@ struct App {
 }
 
 impl Example for App {
     fn render(
         &mut self,
         _api: &RenderApi,
         builder: &mut DisplayListBuilder,
         _txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
         builder.push_simple_stacking_context(
             LayoutPoint::zero(),
             root_space_and_clip.spatial_id,
             true,
--- a/gfx/wr/examples/texture_cache_stress.rs
+++ b/gfx/wr/examples/texture_cache_stress.rs
@@ -87,17 +87,17 @@ struct App {
 }
 
 impl Example for App {
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let bounds = (0, 0).to(512, 512);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
--- a/gfx/wr/examples/yuv.rs
+++ b/gfx/wr/examples/yuv.rs
@@ -84,17 +84,17 @@ struct App {
 }
 
 impl Example for App {
     fn render(
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
-        _framebuffer_size: FramebufferIntSize,
+        _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
--- a/gfx/wr/webrender/src/debug_render.rs
+++ b/gfx/wr/webrender/src/debug_render.rs
@@ -307,17 +307,17 @@ impl DebugRenderer {
         self.add_line(p1.x, p0.y, color, p1.x, p1.y, color);
         self.add_line(p1.x, p1.y, color, p0.x, p1.y, color);
         self.add_line(p0.x, p1.y, color, p0.x, p0.y, color);
     }
 
     pub fn render(
         &mut self,
         device: &mut Device,
-        viewport_size: Option<FramebufferIntSize>,
+        viewport_size: Option<DeviceIntSize>,
         scale: f32,
     ) {
         if let Some(viewport_size) = viewport_size {
             device.disable_depth();
             device.set_blend(true);
             device.set_blend_mode_premultiplied_alpha();
 
             let projection = Transform3D::ortho(
--- a/gfx/wr/webrender/src/device/gl.rs
+++ b/gfx/wr/webrender/src/device/gl.rs
@@ -1028,20 +1028,21 @@ pub enum DrawTarget<'a> {
     /// Use an FBO attached to an external texture.
     External {
         fbo: FBOId,
         size: FramebufferIntSize,
     },
 }
 
 impl<'a> DrawTarget<'a> {
-    pub fn new_default(size: FramebufferIntSize) -> Self {
+    pub fn new_default(size: DeviceIntSize) -> Self {
+        let total_size = FramebufferIntSize::from_untyped(&size.to_untyped());
         DrawTarget::Default {
-            rect: size.into(),
-            total_size: size,
+            rect: total_size.into(),
+            total_size,
         }
     }
 
     /// Returns true if this draw target corresponds to the default framebuffer.
     pub fn is_default(&self) -> bool {
         match *self {
             DrawTarget::Default {..} => true,
             _ => false,
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -338,17 +338,17 @@ impl<'a> DisplayListFlattener<'a> {
 
         debug_assert!(flattener.sc_stack.is_empty());
 
         new_scene.root_pipeline_id = Some(root_pipeline_id);
         new_scene.pipeline_epochs = scene.pipeline_epochs.clone();
         new_scene.pipelines = scene.pipelines.clone();
 
         FrameBuilder::with_display_list_flattener(
-            DeviceIntSize::from_untyped(&view.framebuffer_rect.size.to_untyped()).into(),
+            view.device_rect.size.into(),
             background_color,
             flattener,
         )
     }
 
     /// Retrieve the current offset to allow converting a stacking context
     /// relative coordinate to be relative to the owing reference frame,
     /// also considering any external scroll offset on the provided
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -488,17 +488,17 @@ impl FrameBuilder {
         &mut self,
         resource_cache: &mut ResourceCache,
         gpu_cache: &mut GpuCache,
         stamp: FrameStamp,
         clip_scroll_tree: &mut ClipScrollTree,
         pipelines: &FastHashMap<PipelineId, Arc<ScenePipeline>>,
         global_device_pixel_scale: DevicePixelScale,
         layer: DocumentLayer,
-        framebuffer_origin: FramebufferIntPoint,
+        device_origin: DeviceIntPoint,
         pan: WorldPoint,
         texture_cache_profile: &mut TextureCacheProfileCounters,
         gpu_cache_profile: &mut GpuCacheProfileCounters,
         scene_properties: &SceneProperties,
         data_stores: &mut DataStores,
         scratch: &mut PrimitiveScratchBuffer,
         render_task_counters: &mut RenderTaskTreeCounters,
         debug_flags: DebugFlags,
@@ -639,19 +639,19 @@ impl FrameBuilder {
         let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile).frame_id();
 
         render_tasks.write_task_data();
         *render_task_counters = render_tasks.counters();
         resource_cache.end_frame(texture_cache_profile);
 
         Frame {
             content_origin: self.output_rect.origin,
-            framebuffer_rect: FramebufferIntRect::new(
-                framebuffer_origin,
-                FramebufferIntSize::from_untyped(&self.output_rect.size.to_untyped()),
+            device_rect: DeviceIntRect::new(
+                device_origin,
+                self.output_rect.size,
             ),
             background_color: self.background_color,
             layer,
             profile_counters,
             passes,
             transform_palette: transform_palette.transforms,
             render_tasks,
             deferred_resolves,
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -63,17 +63,17 @@ use tiling::Frame;
 use time::precise_time_ns;
 use util::{Recycler, VecHelper, drain_filter};
 
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone)]
 pub struct DocumentView {
-    pub framebuffer_rect: FramebufferIntRect,
+    pub device_rect: DeviceIntRect,
     pub layer: DocumentLayer,
     pub pan: DeviceIntPoint,
     pub device_pixel_ratio: f32,
     pub page_zoom_factor: f32,
     pub pinch_zoom_factor: f32,
 }
 
 impl DocumentView {
@@ -354,26 +354,26 @@ struct Document {
     /// Keep track of the size of render task tree to pre-allocate memory up-front
     /// the next frame.
     render_task_counters: RenderTaskTreeCounters,
 }
 
 impl Document {
     pub fn new(
         id: DocumentId,
-        size: FramebufferIntSize,
+        size: DeviceIntSize,
         layer: DocumentLayer,
         default_device_pixel_ratio: f32,
     ) -> Self {
         Document {
             id,
             scene: Scene::new(),
             removed_pipelines: Vec::new(),
             view: DocumentView {
-                framebuffer_rect: FramebufferIntRect::new(FramebufferIntPoint::zero(), size),
+                device_rect: size.into(),
                 layer,
                 pan: DeviceIntPoint::zero(),
                 page_zoom_factor: 1.0,
                 pinch_zoom_factor: 1.0,
                 device_pixel_ratio: default_device_pixel_ratio,
             },
             clip_scroll_tree: ClipScrollTree::new(),
             stamp: FrameStamp::first(id),
@@ -391,17 +391,17 @@ impl Document {
         }
     }
 
     fn can_render(&self) -> bool {
         self.frame_builder.is_some() && self.scene.has_root_pipeline()
     }
 
     fn has_pixels(&self) -> bool {
-        !self.view.framebuffer_rect.size.is_empty_or_negative()
+        !self.view.device_rect.size.is_empty_or_negative()
     }
 
     fn process_frame_msg(
         &mut self,
         message: FrameMsg,
     ) -> DocumentOps {
         match message {
             FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
@@ -512,17 +512,17 @@ impl Document {
             let frame = frame_builder.build(
                 resource_cache,
                 gpu_cache,
                 self.stamp,
                 &mut self.clip_scroll_tree,
                 &self.scene.pipelines,
                 accumulated_scale_factor,
                 self.view.layer,
-                self.view.framebuffer_rect.origin,
+                self.view.device_rect.origin,
                 pan,
                 &mut resource_profile.texture_cache,
                 &mut resource_profile.gpu_cache,
                 &self.dynamic_properties,
                 &mut self.data_stores,
                 &mut self.scratch,
                 &mut self.render_task_counters,
                 debug_flags,
@@ -751,20 +751,20 @@ impl RenderBackend {
         match message {
             SceneMsg::UpdateEpoch(pipeline_id, epoch) => {
                 txn.epoch_updates.push((pipeline_id, epoch));
             }
             SceneMsg::SetPageZoom(factor) => {
                 doc.view.page_zoom_factor = factor.get();
             }
             SceneMsg::SetDocumentView {
-                framebuffer_rect,
+                device_rect,
                 device_pixel_ratio,
             } => {
-                doc.view.framebuffer_rect = framebuffer_rect;
+                doc.view.device_rect = device_rect;
                 doc.view.device_pixel_ratio = device_pixel_ratio;
             }
             SceneMsg::SetDisplayList {
                 epoch,
                 pipeline_id,
                 background,
                 viewport_size,
                 content_size,
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -1930,17 +1930,17 @@ pub struct Renderer {
     /// List of profile results from previous frames. Can be retrieved
     /// via get_frame_profiles().
     cpu_profiles: VecDeque<CpuProfile>,
     gpu_profiles: VecDeque<GpuProfile>,
 
     /// Notification requests to be fulfilled after rendering.
     notifications: Vec<NotificationRequest>,
 
-    framebuffer_size: Option<FramebufferIntSize>,
+    device_size: Option<DeviceIntSize>,
 
     /// A lazily created texture for the zoom debugging widget.
     zoom_debug_texture: Option<Texture>,
 
     /// The current mouse position. This is used for debugging
     /// functionality only, such as the debug zoom widget.
     cursor_position: DeviceIntPoint,
 
@@ -1994,17 +1994,17 @@ impl Renderer {
     /// let (renderer, sender) = Renderer::new(opts);
     /// ```
     /// [rendereroptions]: struct.RendererOptions.html
     pub fn new(
         gl: Rc<gl::Gl>,
         notifier: Box<RenderNotifier>,
         mut options: RendererOptions,
         shaders: Option<&mut WrShaders>,
-        start_size: FramebufferIntSize,
+        start_size: DeviceIntSize,
     ) -> Result<(Self, RenderApiSender), RendererError> {
         HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
 
         let (api_tx, api_rx) = channel::msg_channel()?;
         let (payload_tx, payload_rx) = channel::payload_channel()?;
         let (result_tx, result_rx) = channel();
         let gl_type = gl.get_type();
 
@@ -2413,31 +2413,31 @@ impl Renderer {
             texture_resolver,
             renderer_errors: Vec::new(),
             async_screenshots: None,
             #[cfg(feature = "capture")]
             read_fbo,
             #[cfg(feature = "replay")]
             owned_external_images: FastHashMap::default(),
             notifications: Vec::new(),
-            framebuffer_size: None,
+            device_size: None,
             zoom_debug_texture: None,
             cursor_position: DeviceIntPoint::zero(),
         };
 
         // We initially set the flags to default and then now call set_debug_flags
         // to ensure any potential transition when enabling a flag is run.
         renderer.set_debug_flags(debug_flags);
 
         let sender = RenderApiSender::new(api_tx, payload_tx);
         Ok((renderer, sender))
     }
 
-    pub fn framebuffer_size(&self) -> Option<FramebufferIntSize> {
-        self.framebuffer_size
+    pub fn device_size(&self) -> Option<DeviceIntSize> {
+        self.device_size
     }
 
     /// Update the current position of the debug cursor.
     pub fn set_cursor_position(
         &mut self,
         position: DeviceIntPoint,
     ) {
         self.cursor_position = position;
@@ -2492,18 +2492,18 @@ impl Renderer {
                     // Add a new document to the active set, expressed as a `Vec` in order
                     // to re-order based on `DocumentLayer` during rendering.
                     match self.active_documents.iter().position(|&(id, _)| id == document_id) {
                         Some(pos) => {
                             // If the document we are replacing must be drawn
                             // (in order to update the texture cache), issue
                             // a render just to off-screen targets.
                             if self.active_documents[pos].1.frame.must_be_drawn() {
-                                let framebuffer_size = self.framebuffer_size;
-                                self.render_impl(framebuffer_size).ok();
+                                let device_size = self.device_size;
+                                self.render_impl(device_size).ok();
                             }
                             self.active_documents[pos].1 = doc;
                         }
                         None => self.active_documents.push((document_id, doc)),
                     }
 
                     // IMPORTANT: The pending texture cache updates must be applied
                     //            *after* the previous frame has been rendered above
@@ -2928,43 +2928,43 @@ impl Renderer {
         self.slow_frame_indicator.changed();
     }
 
     /// Renders the current frame.
     ///
     /// A Frame is supplied by calling [`generate_frame()`][webrender_api::Transaction::generate_frame].
     pub fn render(
         &mut self,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
     ) -> Result<RenderResults, Vec<RendererError>> {
-        self.framebuffer_size = Some(framebuffer_size);
-
-        let result = self.render_impl(Some(framebuffer_size));
+        self.device_size = Some(device_size);
+
+        let result = self.render_impl(Some(device_size));
 
         drain_filter(
             &mut self.notifications,
             |n| { n.when() == Checkpoint::FrameRendered },
             |n| { n.notify(); },
         );
 
         // This is the end of the rendering pipeline. If some notifications are is still there,
         // just clear them and they will autimatically fire the Checkpoint::TransactionDropped
         // event. Otherwise they would just pile up in this vector forever.
         self.notifications.clear();
 
         result
     }
 
-    // If framebuffer_size is None, don't render
+    // If device_size is None, don't render
     // to the main frame buffer. This is useful
     // to update texture cache render tasks but
     // avoid doing a full frame render.
     fn render_impl(
         &mut self,
-        framebuffer_size: Option<FramebufferIntSize>,
+        device_size: Option<DeviceIntSize>,
     ) -> Result<RenderResults, Vec<RendererError>> {
         profile_scope!("render");
         let mut results = RenderResults::default();
         if self.active_documents.is_empty() {
             self.last_time = precise_time_ns();
             return Ok(results);
         }
 
@@ -3028,23 +3028,23 @@ impl Renderer {
                 frame.profile_counters.reset_targets();
                 self.prepare_gpu_cache(frame);
                 assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id,
                     "Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})",
                     frame.gpu_cache_frame_id, self.gpu_cache_frame_id);
 
                 self.draw_tile_frame(
                     frame,
-                    framebuffer_size,
+                    device_size,
                     cpu_frame_id,
                     &mut results.stats,
                     doc_index == 0,
                 );
 
-                if let Some(_) = framebuffer_size {
+                if let Some(_) = device_size {
                     self.draw_frame_debug_items(&frame.debug_items);
                 }
                 if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
                     frame_profiles.push(frame.profile_counters.clone());
                 }
 
                 let dirty_regions =
                     mem::replace(&mut frame.recorded_dirty_regions, Vec::new());
@@ -3058,26 +3058,26 @@ impl Renderer {
                     self.texture_resolver.end_pass(&mut self.device, None, None);
                 }
             }
 
             self.unlock_external_images();
             self.active_documents = active_documents;
         });
 
-        if let Some(framebuffer_size) = framebuffer_size {
-            self.draw_render_target_debug(framebuffer_size);
-            self.draw_texture_cache_debug(framebuffer_size);
-            self.draw_gpu_cache_debug(framebuffer_size);
-            self.draw_zoom_debug(framebuffer_size);
+        if let Some(device_size) = device_size {
+            self.draw_render_target_debug(device_size);
+            self.draw_texture_cache_debug(device_size);
+            self.draw_gpu_cache_debug(device_size);
+            self.draw_zoom_debug(device_size);
             self.draw_epoch_debug();
         }
 
         let current_time = precise_time_ns();
-        if framebuffer_size.is_some() {
+        if device_size.is_some() {
             let ns = current_time - self.last_time;
             self.profile_counters.frame_time.set(ns);
         }
 
         if self.max_recorded_profiles > 0 {
             while self.cpu_profiles.len() >= self.max_recorded_profiles {
                 self.cpu_profiles.pop_front();
             }
@@ -3086,20 +3086,20 @@ impl Renderer {
                 self.backend_profile_counters.total_time.get(),
                 profile_timers.cpu_time.get(),
                 self.profile_counters.draw_calls.get(),
             );
             self.cpu_profiles.push_back(cpu_profile);
         }
 
         if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
-            if let Some(framebuffer_size) = framebuffer_size {
+            if let Some(device_size) = device_size {
                 //TODO: take device/pixel ratio into equation?
                 if let Some(debug_renderer) = self.debug.get_mut(&mut self.device) {
-                    let screen_fraction = 1.0 / framebuffer_size.to_f32().area();
+                    let screen_fraction = 1.0 / device_size.to_f32().area();
                     self.profiler.draw_profile(
                         &frame_profiles,
                         &self.backend_profile_counters,
                         &self.profile_counters,
                         &mut profile_timers,
                         &profile_samplers,
                         screen_fraction,
                         debug_renderer,
@@ -3157,28 +3157,28 @@ impl Renderer {
         self.gpu_cache_upload_time = 0;
 
         profile_timers.cpu_time.profile(|| {
             let _gm = self.gpu_profile.start_marker("end frame");
             self.gpu_profile.end_frame();
             if let Some(debug_renderer) = self.debug.try_get_mut() {
                 let small_screen = self.debug_flags.contains(DebugFlags::SMALL_SCREEN);
                 let scale = if small_screen { 1.6 } else { 1.0 };
-                debug_renderer.render(&mut self.device, framebuffer_size, scale);
+                debug_renderer.render(&mut self.device, device_size, scale);
             }
             // See comment for texture_resolver.begin_frame() for explanation
             // of why this must be done after all rendering, including debug
             // overlays. The end_frame() call implicitly calls end_pass(), which
             // should ensure any left over render targets get invalidated and
             // returned to the pool correctly.
             self.texture_resolver.end_frame(&mut self.device, cpu_frame_id);
             self.device.end_frame();
         });
 
-        if framebuffer_size.is_some() {
+        if device_size.is_some() {
             self.last_time = current_time;
         }
 
         if self.renderer_errors.is_empty() {
             Ok(results)
         } else {
             Err(mem::replace(&mut self.renderer_errors, Vec::new()))
         }
@@ -4625,47 +4625,28 @@ impl Renderer {
 
         debug_assert!(self.texture_resolver.prev_pass_alpha.is_none());
         debug_assert!(self.texture_resolver.prev_pass_color.is_none());
     }
 
     fn draw_tile_frame(
         &mut self,
         frame: &mut Frame,
-        framebuffer_size: Option<FramebufferIntSize>,
+        device_size: Option<DeviceIntSize>,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
         clear_framebuffer: bool,
     ) {
         let _gm = self.gpu_profile.start_marker("tile frame draw");
 
         if frame.passes.is_empty() {
             frame.has_been_rendered = true;
             return;
         }
 
-        // TODO(gw): This is a hack / workaround for a resizing glitch. What
-        //           happens is that the framebuffer rect / content origin are
-        //           determined during frame building, rather than at render
-        //           time (which is what used to happen). This means that the
-        //           framebuffer rect/origin can be wrong by the time a frame
-        //           is drawn, if resizing is occurring. This hack just makes
-        //           the framebuffer rect/origin be hard coded to the current
-        //           framebuffer size at render time. It seems like this probably
-        //           breaks some assumptions elsewhere, but it seems to fix the
-        //           bug and I haven't noticed any other issues so far. We will
-        //           need to investigate this further and make a "proper" fix.
-        if let Some(framebuffer_size) = framebuffer_size {
-            frame.framebuffer_rect = FramebufferIntRect::new(
-                FramebufferIntPoint::zero(),
-                framebuffer_size,
-            );
-            frame.content_origin = DeviceIntPoint::zero();
-        }
-
         self.device.disable_depth_write();
         self.set_blend(false, FramebufferKind::Other);
         self.device.disable_stencil();
 
         self.bind_frame_data(frame);
 
         for (pass_index, pass) in frame.passes.iter_mut().enumerate() {
             let _gm = self.gpu_profile.start_marker(&format!("pass {}", pass_index));
@@ -4678,33 +4659,37 @@ impl Renderer {
             self.texture_resolver.bind(
                 &TextureSource::PrevPassColor,
                 TextureSampler::PrevPassColor,
                 &mut self.device,
             );
 
             match pass.kind {
                 RenderPassKind::MainFramebuffer(ref target) => {
-                    if let Some(framebuffer_size) = framebuffer_size {
+                    if let Some(device_size) = device_size {
                         stats.color_target_count += 1;
 
                         let offset = frame.content_origin.to_f32();
-                        let size = frame.framebuffer_rect.size.to_f32();
+                        let size = frame.device_rect.size.to_f32();
                         let projection = Transform3D::ortho(
                             offset.x,
                             offset.x + size.width,
                             offset.y + size.height,
                             offset.y,
                             ORTHO_NEAR_PLANE,
                             ORTHO_FAR_PLANE,
                         );
 
+                        let fb_scale = TypedScale::<_, _, FramebufferPixel>::new(1i32);
+                        let mut fb_rect = frame.device_rect * fb_scale;
+                        fb_rect.origin.y = device_size.height - fb_rect.origin.y - fb_rect.size.height;
+
                         let draw_target = DrawTarget::Default {
-                            rect: frame.framebuffer_rect,
-                            total_size: framebuffer_size,
+                            rect: fb_rect,
+                            total_size: device_size * fb_scale,
                         };
                         if clear_framebuffer {
                             self.device.bind_draw_target(draw_target);
                             self.device.enable_depth_write();
                             self.device.clear_target(self.clear_color.map(|color| color.to_array()),
                                                      Some(1.0),
                                                      None);
                         }
@@ -4812,22 +4797,22 @@ impl Renderer {
                         &mut self.device,
                         alpha_tex,
                         color_tex,
                     );
                 }
             }
         }
 
-        if let Some(framebuffer_size) = framebuffer_size {
+        if let Some(device_size) = device_size {
             self.draw_frame_debug_items(&frame.debug_items);
-            self.draw_render_target_debug(framebuffer_size);
-            self.draw_texture_cache_debug(framebuffer_size);
-            self.draw_gpu_cache_debug(framebuffer_size);
-            self.draw_zoom_debug(framebuffer_size);
+            self.draw_render_target_debug(device_size);
+            self.draw_texture_cache_debug(device_size);
+            self.draw_gpu_cache_debug(device_size);
+            self.draw_zoom_debug(device_size);
         }
         self.draw_epoch_debug();
 
         // Garbage collect any frame outputs that weren't used this frame.
         let device = &mut self.device;
         self.output_targets
             .retain(|_, target| if target.last_access != frame_id {
                 device.delete_fbo(target.fbo_id);
@@ -4968,73 +4953,73 @@ impl Renderer {
                         (*color).into(),
                         None,
                     );
                 }
             }
         }
     }
 
-    fn draw_render_target_debug(&mut self, framebuffer_size: FramebufferIntSize) {
+    fn draw_render_target_debug(&mut self, device_size: DeviceIntSize) {
         if !self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) {
             return;
         }
 
         let debug_renderer = match self.debug.get_mut(&mut self.device) {
             Some(render) => render,
             None => return,
         };
 
         let textures =
             self.texture_resolver.render_target_pool.iter().collect::<Vec<&Texture>>();
 
         Self::do_debug_blit(
             &mut self.device,
             debug_renderer,
             textures,
-            framebuffer_size,
+            device_size,
             0,
             &|_| [0.0, 1.0, 0.0, 1.0], // Use green for all RTs.
         );
     }
 
     fn draw_zoom_debug(
         &mut self,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
     ) {
         if !self.debug_flags.contains(DebugFlags::ZOOM_DBG) {
             return;
         }
 
         let debug_renderer = match self.debug.get_mut(&mut self.device) {
             Some(render) => render,
             None => return,
         };
 
         let source_size = DeviceIntSize::new(64, 64);
         let target_size = DeviceIntSize::new(1024, 1024);
 
         let source_origin = DeviceIntPoint::new(
             (self.cursor_position.x - source_size.width / 2)
-                .min(framebuffer_size.width - source_size.width)
+                .min(device_size.width - source_size.width)
                 .max(0),
             (self.cursor_position.y - source_size.height / 2)
-                .min(framebuffer_size.height - source_size.height)
+                .min(device_size.height - source_size.height)
                 .max(0),
         );
 
         let source_rect = DeviceIntRect::new(
             source_origin,
             source_size,
         );
 
         let target_rect = DeviceIntRect::new(
             DeviceIntPoint::new(
-                framebuffer_size.width - target_size.width - 64,
-                framebuffer_size.height - target_size.height - 64,
+                device_size.width - target_size.width - 64,
+                device_size.height - target_size.height - 64,
             ),
             target_size,
         );
 
         let texture_rect = FramebufferIntRect::new(
             FramebufferIntPoint::zero(),
             FramebufferIntSize::from_untyped(&source_rect.size.to_untyped()),
         );
@@ -5054,17 +5039,17 @@ impl Renderer {
                 Some(RenderTargetInfo { has_depth: false }),
                 1,
             );
 
             self.zoom_debug_texture = Some(texture);
         }
 
         // Copy frame buffer into the zoom texture
-        let read_target = DrawTarget::new_default(framebuffer_size);
+        let read_target = DrawTarget::new_default(device_size);
         self.device.blit_render_target(
             read_target.into(),
             read_target.to_framebuffer_rect(source_rect),
             DrawTarget::Texture {
                 texture: self.zoom_debug_texture.as_ref().unwrap(),
                 layer: 0,
                 with_depth: false,
             },
@@ -5080,17 +5065,17 @@ impl Renderer {
             },
             texture_rect,
             read_target,
             read_target.to_framebuffer_rect(target_rect),
             TextureFilter::Nearest,
         );
     }
 
-    fn draw_texture_cache_debug(&mut self, framebuffer_size: FramebufferIntSize) {
+    fn draw_texture_cache_debug(&mut self, device_size: DeviceIntSize) {
         if !self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
             return;
         }
 
         let debug_renderer = match self.debug.get_mut(&mut self.device) {
             Some(render) => render,
             None => return,
         };
@@ -5105,35 +5090,35 @@ impl Renderer {
                 [1.0, 0.0, 1.0, 1.0] // Fuchsia for standalone.
             }
         }
 
         Self::do_debug_blit(
             &mut self.device,
             debug_renderer,
             textures,
-            framebuffer_size,
+            device_size,
             if self.debug_flags.contains(DebugFlags::RENDER_TARGET_DBG) { 544 } else { 0 },
             &select_color,
         );
     }
 
     fn do_debug_blit(
         device: &mut Device,
         debug_renderer: &mut DebugRenderer,
         mut textures: Vec<&Texture>,
-        framebuffer_size: FramebufferIntSize,
+        device_size: DeviceIntSize,
         bottom: i32,
         select_color: &Fn(&Texture) -> [f32; 4],
     ) {
         let mut spacing = 16;
         let mut size = 512;
 
-        let fb_width = framebuffer_size.width as i32;
-        let fb_height = framebuffer_size.height as i32;
+        let fb_width = device_size.width;
+        let fb_height = device_size.height;
         let num_layers: i32 = textures.iter()
             .map(|texture| texture.get_layer_count())
             .sum();
 
         if num_layers * (size + spacing) > fb_width {
             let factor = fb_width as f32 / (num_layers * (size + spacing)) as f32;
             size = (size as f32 * factor) as i32;
             spacing = (spacing as f32 * factor) as i32;
@@ -5193,17 +5178,17 @@ impl Renderer {
 
                 // Blit the contents of the layer. We need to invert Y because
                 // we're blitting from a texture to the main framebuffer, which
                 // use different conventions.
                 let dest_rect = rect(x, y + tag_height, size, size);
                 device.blit_render_target_invert_y(
                     ReadTarget::Texture { texture, layer },
                     src_rect,
-                    DrawTarget::new_default(framebuffer_size),
+                    DrawTarget::new_default(device_size),
                     FramebufferIntRect::from_untyped(&dest_rect),
                 );
                 i += 1;
             }
         }
     }
 
     fn draw_epoch_debug(&mut self) {
@@ -5238,30 +5223,30 @@ impl Renderer {
             y0 - margin,
             x0 + text_width + margin,
             y + margin,
             ColorU::new(25, 25, 25, 200),
             ColorU::new(51, 51, 51, 200),
         );
     }
 
-    fn draw_gpu_cache_debug(&mut self, framebuffer_size: FramebufferIntSize) {
+    fn draw_gpu_cache_debug(&mut self, device_size: DeviceIntSize) {
         if !self.debug_flags.contains(DebugFlags::GPU_CACHE_DBG) {
             return;
         }
 
         let debug_renderer = match self.debug.get_mut(&mut self.device) {
             Some(render) => render,
             None => return,
         };
 
         let (x_off, y_off) = (30f32, 30f32);
         let height = self.gpu_cache_texture.texture
             .as_ref().map_or(0, |t| t.get_dimensions().height)
-            .min(framebuffer_size.height - (y_off as i32) * 2) as usize;
+            .min(device_size.height - (y_off as i32) * 2) as usize;
         debug_renderer.add_quad(
             x_off,
             y_off,
             x_off + MAX_VERTEX_TEXTURE_WIDTH as f32,
             y_off + height as f32,
             ColorU::new(80, 80, 80, 80),
             ColorU::new(80, 80, 80, 80),
         );
@@ -5286,30 +5271,30 @@ impl Renderer {
     }
 
     pub fn read_pixels_rgba8(&mut self, rect: FramebufferIntRect) -> Vec<u8> {
         let mut pixels = vec![0; (rect.size.width * rect.size.height * 4) as usize];
         self.device.read_pixels_into(rect, ReadPixelsFormat::Rgba8, &mut pixels);
         pixels
     }
 
-    pub fn read_gpu_cache(&mut self) -> (FramebufferIntSize, Vec<u8>) {
+    pub fn read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>) {
         let texture = self.gpu_cache_texture.texture.as_ref().unwrap();
         let size = FramebufferIntSize::from_untyped(&texture.get_dimensions().to_untyped());
         let mut texels = vec![0; (size.width * size.height * 16) as usize];
         self.device.begin_frame();
         self.device.bind_read_target(ReadTarget::Texture { texture, layer: 0 });
         self.device.read_pixels_into(
             size.into(),
             ReadPixelsFormat::Standard(ImageFormat::RGBAF32),
             &mut texels,
         );
         self.device.reset_read_target();
         self.device.end_frame();
-        (size, texels)
+        (texture.get_dimensions(), texels)
     }
 
     // De-initialize the Renderer safely, assuming the GL is still alive and active.
     pub fn deinit(mut self) {
         //Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
         self.device.begin_frame();
         self.gpu_cache_texture.deinit(&mut self.device);
         if let Some(dither_matrix_texture) = self.dither_matrix_texture {
@@ -5699,17 +5684,17 @@ struct PlainTexture {
     filter: TextureFilter,
 }
 
 
 #[cfg(any(feature = "capture", feature = "replay"))]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct PlainRenderer {
-    framebuffer_size: Option<FramebufferIntSize>,
+    device_size: Option<DeviceIntSize>,
     gpu_cache: PlainTexture,
     gpu_cache_frame_id: FrameId,
     textures: FastHashMap<CacheTextureId, PlainTexture>,
     external_images: Vec<ExternalCaptureImage>
 }
 
 #[cfg(feature = "replay")]
 enum CapturedExternalImageData {
@@ -5934,17 +5919,17 @@ impl Renderer {
             let path_textures = config.root.join("textures");
             if !path_textures.is_dir() {
                 fs::create_dir(&path_textures).unwrap();
             }
 
             info!("saving GPU cache");
             self.update_gpu_cache(); // flush pending updates
             let mut plain_self = PlainRenderer {
-                framebuffer_size: self.framebuffer_size,
+                device_size: self.device_size,
                 gpu_cache: Self::save_texture(
                     &self.gpu_cache_texture.texture.as_ref().unwrap(),
                     "gpu", &config.root, &mut self.device,
                 ),
                 gpu_cache_frame_id: self.gpu_cache_frame_id,
                 textures: FastHashMap::default(),
                 external_images: deferred_images,
             };
@@ -5997,17 +5982,17 @@ impl Renderer {
             };
             let ext = plain_ext.external;
             let value = (CapturedExternalImageData::Buffer(data), plain_ext.uv);
             image_handler.data.insert((ext.id, ext.channel_index), value);
         }
 
         if let Some(renderer) = CaptureConfig::deserialize::<PlainRenderer, _>(&root, "renderer") {
             info!("loading cached textures");
-            self.framebuffer_size = renderer.framebuffer_size;
+            self.device_size = renderer.device_size;
             self.device.begin_frame();
 
             for (_id, texture) in self.texture_resolver.texture_cache_map.drain() {
                 self.device.delete_texture(texture);
             }
             for (id, texture) in renderer.textures {
                 info!("\t{}", texture.data);
                 let t = Self::load_texture(
--- a/gfx/wr/webrender/src/resource_cache.rs
+++ b/gfx/wr/webrender/src/resource_cache.rs
@@ -2203,17 +2203,17 @@ impl ResourceCache {
                 self.cached_glyphs.clear();
                 self.cached_glyph_dimensions.clear();
                 self.cached_images.clear();
                 self.cached_render_tasks.clear();
                 self.texture_cache = TextureCache::new(
                     self.texture_cache.max_texture_size(),
                     self.texture_cache.max_texture_layers(),
                     self.texture_cache.picture_tile_size(),
-                    FramebufferIntSize::zero(),
+                    DeviceIntSize::zero(),
                 );
             }
         }
 
         self.glyph_rasterizer.reset();
         let res = &mut self.resources;
         res.font_templates.clear();
         *res.font_instances.write().unwrap() = resources.font_instances;
--- a/gfx/wr/webrender/src/texture_cache.rs
+++ b/gfx/wr/webrender/src/texture_cache.rs
@@ -522,17 +522,17 @@ pub struct TextureCache {
     require_frame_build: bool,
 }
 
 impl TextureCache {
     pub fn new(
         max_texture_size: i32,
         mut max_texture_layers: usize,
         picture_tile_size: Option<DeviceIntSize>,
-        initial_size: FramebufferIntSize,
+        initial_size: DeviceIntSize,
     ) -> Self {
         if cfg!(target_os = "macos") {
             // On MBP integrated Intel GPUs, texture arrays appear to be
             // implemented as a single texture of stacked layers, and that
             // texture appears to be subject to the texture size limit. As such,
             // allocating more than 32 512x512 regions results in a dimension
             // longer than 16k (the max texture size), causing incorrect behavior.
             //
@@ -593,17 +593,17 @@ impl TextureCache {
         }
     }
 
     /// Creates a TextureCache and sets it up with a valid `FrameStamp`, which
     /// is useful for avoiding panics when instantiating the `TextureCache`
     /// directly from unit test code.
     #[cfg(test)]
     pub fn new_for_testing(max_texture_size: i32, max_texture_layers: usize) -> Self {
-        let mut cache = Self::new(max_texture_size, max_texture_layers, None, FramebufferIntSize::zero());
+        let mut cache = Self::new(max_texture_size, max_texture_layers, None, DeviceIntSize::zero());
         let mut now = FrameStamp::first(DocumentId::new(IdNamespace(1), 1));
         now.advance();
         cache.begin_frame(now);
         cache
     }
 
     pub fn set_debug_flags(&mut self, flags: DebugFlags) {
         self.debug_flags = flags;
--- a/gfx/wr/webrender/src/tiling.rs
+++ b/gfx/wr/webrender/src/tiling.rs
@@ -1167,17 +1167,17 @@ impl CompositeOps {
 /// A rendering-oriented representation of the frame built by the render backend
 /// and presented to the renderer.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct Frame {
     /// The origin on content produced by the render tasks.
     pub content_origin: DeviceIntPoint,
     /// The rectangle to show the frame in, on screen.
-    pub framebuffer_rect: FramebufferIntRect,
+    pub device_rect: DeviceIntRect,
     pub background_color: Option<ColorF>,
     pub layer: DocumentLayer,
     pub passes: Vec<RenderPass>,
     #[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
     pub profile_counters: FrameProfileCounters,
 
     pub transform_palette: Vec<TransformData>,
     pub render_tasks: RenderTaskTree,
--- a/gfx/wr/webrender_api/src/api.rs
+++ b/gfx/wr/webrender_api/src/api.rs
@@ -197,22 +197,22 @@ impl Transaction {
     /// affect the WebRender's state.
     pub fn notify(&mut self, event: NotificationRequest) {
         self.notifications.push(event);
     }
 
     /// Setup the output region in the framebuffer for a given document.
     pub fn set_document_view(
         &mut self,
-        framebuffer_rect: FramebufferIntRect,
+        device_rect: DeviceIntRect,
         device_pixel_ratio: f32,
     ) {
         self.scene_ops.push(
             SceneMsg::SetDocumentView {
-                framebuffer_rect,
+                device_rect,
                 device_pixel_ratio,
             },
         );
     }
 
     /// Enable copying of the output of this pipeline id to
     /// an external texture for callers to consume.
     pub fn enable_frame_output(&mut self, pipeline_id: PipelineId, enable: bool) {
@@ -595,17 +595,17 @@ pub enum SceneMsg {
         epoch: Epoch,
         pipeline_id: PipelineId,
         background: Option<ColorF>,
         viewport_size: LayoutSize,
         content_size: LayoutSize,
         preserve_frame_state: bool,
     },
     SetDocumentView {
-        framebuffer_rect: FramebufferIntRect,
+        device_rect: DeviceIntRect,
         device_pixel_ratio: f32,
     },
 }
 
 // Frame messages affect frame generation (applied after building the scene).
 #[derive(Clone, Deserialize, Serialize)]
 pub enum FrameMsg {
     UpdateEpoch(PipelineId, Epoch),
@@ -724,17 +724,17 @@ pub enum ApiMsg {
     ),
     /// Gets the glyph indices from a string
     GetGlyphIndices(font::FontKey, String, MsgSender<Vec<Option<u32>>>),
     /// Adds a new document namespace.
     CloneApi(MsgSender<IdNamespace>),
     /// Adds a new document namespace.
     CloneApiByClient(IdNamespace),
     /// Adds a new document with given initial size.
-    AddDocument(DocumentId, FramebufferIntSize, DocumentLayer),
+    AddDocument(DocumentId, DeviceIntSize, DocumentLayer),
     /// A message targeted at a particular document.
     UpdateDocuments(Vec<DocumentId>, Vec<TransactionMsg>),
     /// Deletes an existing document.
     DeleteDocument(DocumentId),
     /// An opaque handle that must be passed to the render notifier. It is used by Gecko
     /// to forward gecko-specific messages to the render thread preserving the ordering
     /// within the other messages.
     ExternalEvent(ExternalEvent),
@@ -1073,23 +1073,23 @@ impl RenderApi {
     pub fn get_namespace_id(&self) -> IdNamespace {
         self.namespace_id
     }
 
     pub fn clone_sender(&self) -> RenderApiSender {
         RenderApiSender::new(self.api_sender.clone(), self.payload_sender.clone())
     }
 
-    pub fn add_document(&self, initial_size: FramebufferIntSize, layer: DocumentLayer) -> DocumentId {
+    pub fn add_document(&self, initial_size: DeviceIntSize, layer: DocumentLayer) -> DocumentId {
         let new_id = self.next_unique_id();
         self.add_document_with_id(initial_size, layer, new_id)
     }
 
     pub fn add_document_with_id(&self,
-                                initial_size: FramebufferIntSize,
+                                initial_size: DeviceIntSize,
                                 layer: DocumentLayer,
                                 id: u32) -> DocumentId {
         let document_id = DocumentId::new(self.namespace_id, id);
 
         let msg = ApiMsg::AddDocument(document_id, initial_size, layer);
         self.api_sender.send(msg).unwrap();
 
         document_id
@@ -1279,22 +1279,22 @@ impl RenderApi {
         );
         rx.recv().unwrap()
     }
 
     /// Setup the output region in the framebuffer for a given document.
     pub fn set_document_view(
         &self,
         document_id: DocumentId,
-        framebuffer_rect: FramebufferIntRect,
+        device_rect: DeviceIntRect,
         device_pixel_ratio: f32,
     ) {
         self.send_scene_msg(
             document_id,
-            SceneMsg::SetDocumentView { framebuffer_rect, device_pixel_ratio },
+            SceneMsg::SetDocumentView { device_rect, device_pixel_ratio },
         );
     }
 
     /// Setup the output region in the framebuffer for a given document.
     /// Enable copying of the output of this pipeline id to
     /// an external texture for callers to consume.
     pub fn enable_frame_output(
         &self,
--- a/gfx/wr/wrench/src/main.rs
+++ b/gfx/wr/wrench/src/main.rs
@@ -175,40 +175,40 @@ impl WindowWrapper {
     fn swap_buffers(&self) {
         match *self {
             WindowWrapper::Window(ref window, _) => window.swap_buffers().unwrap(),
             WindowWrapper::Angle(_, ref context, _) => context.swap_buffers().unwrap(),
             WindowWrapper::Headless(_, _) => {}
         }
     }
 
-    fn get_inner_size(&self) -> FramebufferIntSize {
-        fn inner_size(window: &winit::Window) -> FramebufferIntSize {
+    fn get_inner_size(&self) -> DeviceIntSize {
+        fn inner_size(window: &winit::Window) -> DeviceIntSize {
             let size = window
                 .get_inner_size()
                 .unwrap()
                 .to_physical(window.get_hidpi_factor());
-            FramebufferIntSize::new(size.width as i32, size.height as i32)
+            DeviceIntSize::new(size.width as i32, size.height as i32)
         }
         match *self {
             WindowWrapper::Window(ref window, _) => inner_size(window.window()),
             WindowWrapper::Angle(ref window, ..) => inner_size(window),
-            WindowWrapper::Headless(ref context, _) => FramebufferIntSize::new(context.width, context.height),
+            WindowWrapper::Headless(ref context, _) => DeviceIntSize::new(context.width, context.height),
         }
     }
 
     fn hidpi_factor(&self) -> f32 {
         match *self {
             WindowWrapper::Window(ref window, _) => window.get_hidpi_factor() as f32,
             WindowWrapper::Angle(ref window, ..) => window.get_hidpi_factor() as f32,
             WindowWrapper::Headless(_, _) => 1.0,
         }
     }
 
-    fn resize(&mut self, size: FramebufferIntSize) {
+    fn resize(&mut self, size: DeviceIntSize) {
         match *self {
             WindowWrapper::Window(ref mut window, _) => {
                 window.set_inner_size(LogicalSize::new(size.width as f64, size.height as f64))
             },
             WindowWrapper::Angle(ref mut window, ..) => {
                 window.set_inner_size(LogicalSize::new(size.width as f64, size.height as f64))
             },
             WindowWrapper::Headless(_, _) => unimplemented!(), // requites Glutin update
@@ -236,17 +236,17 @@ impl WindowWrapper {
             WindowWrapper::Window(_, ref gl) |
             WindowWrapper::Angle(_, _, ref gl) |
             WindowWrapper::Headless(_, ref gl) => gl.clone(),
         }
     }
 }
 
 fn make_window(
-    size: FramebufferIntSize,
+    size: DeviceIntSize,
     dp_ratio: Option<f32>,
     vsync: bool,
     events_loop: &Option<winit::EventsLoop>,
     angle: bool,
 ) -> WindowWrapper {
     let wrapper = match *events_loop {
         Some(ref events_loop) => {
             let context_builder = glutin::ContextBuilder::new()
@@ -422,30 +422,30 @@ fn main() {
         "yaml" => wrench::SaveType::Yaml,
         "json" => wrench::SaveType::Json,
         "ron" => wrench::SaveType::Ron,
         "binary" => wrench::SaveType::Binary,
         _ => panic!("Save type must be json, ron, yaml, or binary")
     });
     let size = args.value_of("size")
         .map(|s| if s == "720p" {
-            FramebufferIntSize::new(1280, 720)
+            DeviceIntSize::new(1280, 720)
         } else if s == "1080p" {
-            FramebufferIntSize::new(1920, 1080)
+            DeviceIntSize::new(1920, 1080)
         } else if s == "4k" {
-            FramebufferIntSize::new(3840, 2160)
+            DeviceIntSize::new(3840, 2160)
         } else {
             let x = s.find('x').expect(
                 "Size must be specified exactly as 720p, 1080p, 4k, or width x height",
             );
             let w = s[0 .. x].parse::<i32>().expect("Invalid size width");
             let h = s[x + 1 ..].parse::<i32>().expect("Invalid size height");
-            FramebufferIntSize::new(w, h)
+            DeviceIntSize::new(w, h)
         })
-        .unwrap_or(FramebufferIntSize::new(1920, 1080));
+        .unwrap_or(DeviceIntSize::new(1920, 1080));
     let zoom_factor = args.value_of("zoom").map(|z| z.parse::<f32>().unwrap());
     let chase_primitive = match args.value_of("chase") {
         Some(s) => {
             let mut items = s
                 .split(',')
                 .map(|s| s.parse::<f32>().unwrap())
                 .collect::<Vec<_>>();
             let rect = LayoutRect::new(
@@ -540,28 +540,28 @@ fn main() {
     };
 
     wrench.renderer.deinit();
 }
 
 fn render<'a>(
     wrench: &mut Wrench,
     window: &mut WindowWrapper,
-    size: FramebufferIntSize,
+    size: DeviceIntSize,
     events_loop: &mut Option<winit::EventsLoop>,
     subargs: &clap::ArgMatches<'a>,
 ) {
     let input_path = subargs.value_of("INPUT").map(PathBuf::from).unwrap();
 
     // If the input is a directory, we are looking at a capture.
     let mut thing = if input_path.as_path().is_dir() {
         let mut documents = wrench.api.load_capture(input_path);
         println!("loaded {:?}", documents.iter().map(|cd| cd.document_id).collect::<Vec<_>>());
         let captured = documents.swap_remove(0);
-        if let Some(fb_size) = wrench.renderer.framebuffer_size() {
+        if let Some(fb_size) = wrench.renderer.device_size() {
             window.resize(fb_size);
         }
         wrench.document_id = captured.document_id;
         Box::new(captured) as Box<WrenchThing>
     } else {
         let extension = input_path
             .extension()
             .expect("Tried to render with an unknown file type.")
@@ -782,17 +782,18 @@ fn render<'a>(
         }
 
         winit::ControlFlow::Continue
     };
 
     match *events_loop {
         None => {
             while body(wrench, vec![winit::Event::Awakened]) == winit::ControlFlow::Continue {}
-            let pixels = wrench.renderer.read_pixels_rgba8(size.into());
+            let fb_rect = FramebufferIntSize::new(size.width, size.height).into();
+            let pixels = wrench.renderer.read_pixels_rgba8(fb_rect);
             save_flipped("screenshot.png", pixels, size);
         }
         Some(ref mut events_loop) => {
             // We want to ensure that we:
             //
             // (a) Block the thread when no events are present (for CPU/battery purposes)
             // (b) Don't lag the input events by having the event queue back up.
             loop {
--- a/gfx/wr/wrench/src/png.rs
+++ b/gfx/wr/wrench/src/png.rs
@@ -20,17 +20,17 @@ pub enum ReadSurface {
 pub struct SaveSettings {
     pub flip_vertical: bool,
     pub try_crop: bool,
 }
 
 pub fn save<P: Clone + AsRef<Path>>(
     path: P,
     orig_pixels: Vec<u8>,
-    size: FramebufferIntSize,
+    size: DeviceIntSize,
     settings: SaveSettings
 ) {
     let mut width = size.width as u32;
     let mut height = size.height as u32;
     let mut buffer = image::RgbaImage::from_raw(
         width,
         height,
         orig_pixels,
@@ -61,17 +61,17 @@ pub fn save<P: Clone + AsRef<Path>>(
     encoder
         .encode(&buffer, width, height, ColorType::RGBA(8))
         .expect("Unable to encode PNG!");
 }
 
 pub fn save_flipped<P: Clone + AsRef<Path>>(
     path: P,
     orig_pixels: Vec<u8>,
-    size: FramebufferIntSize,
+    size: DeviceIntSize,
 ) {
     save(path, orig_pixels, size, SaveSettings {
         flip_vertical: true,
         try_crop: true,
     })
 }
 
 pub fn png(
@@ -86,18 +86,18 @@ pub fn png(
 
     // wait for the frame
     rx.recv().unwrap();
     wrench.render();
 
     let (fb_size, data, settings) = match surface {
         ReadSurface::Screen => {
             let dim = window.get_inner_size();
-            let data = wrench.renderer
-                .read_pixels_rgba8(dim.into());
+            let rect = FramebufferIntSize::new(dim.width, dim.height).into();
+            let data = wrench.renderer.read_pixels_rgba8(rect);
             (dim, data, SaveSettings {
                 flip_vertical: true,
                 try_crop: true,
             })
         }
         ReadSurface::GpuCache => {
             let (size, data) = wrench.renderer
                 .read_gpu_cache();
--- a/gfx/wr/wrench/src/rawtest.rs
+++ b/gfx/wr/wrench/src/rawtest.rs
@@ -1138,17 +1138,17 @@ impl<'a> RawtestHarness<'a> {
         let pixels2 = self.render_and_get_pixels(window_rect);
         assert!(pixels0 == pixels2);
     }
 
     fn test_zero_height_window(&mut self) {
         println!("\tzero height test...");
 
         let layout_size = LayoutSize::new(120.0, 0.0);
-        let window_size = FramebufferIntSize::new(layout_size.width as i32, layout_size.height as i32);
+        let window_size = DeviceIntSize::new(layout_size.width as i32, layout_size.height as i32);
         let doc_id = self.wrench.api.add_document(window_size, 1);
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         let info = self.make_common_properties(LayoutRect::new(LayoutPoint::zero(),
                                                             LayoutSize::new(100.0, 100.0)));
         builder.push_rect(
             &info,
             ColorF::new(0.0, 1.0, 0.0, 1.0),
--- a/gfx/wr/wrench/src/reftest.rs
+++ b/gfx/wr/wrench/src/reftest.rs
@@ -118,17 +118,17 @@ impl Display for Reftest {
             self.op,
             self.reference.display()
         )
     }
 }
 
 struct ReftestImage {
     data: Vec<u8>,
-    size: FramebufferIntSize,
+    size: DeviceIntSize,
 }
 enum ReftestImageComparison {
     Equal,
     NotEqual {
         max_difference: usize,
         count_different: usize,
     },
 }
@@ -515,24 +515,24 @@ impl<'a> ReftestHarness<'a> {
 
     fn load_image(&mut self, filename: &Path, format: ImageFormat) -> ReftestImage {
         let file = BufReader::new(File::open(filename).unwrap());
         let img_raw = load_piston_image(file, format).unwrap();
         let img = img_raw.flipv().to_rgba();
         let size = img.dimensions();
         ReftestImage {
             data: img.into_raw(),
-            size: FramebufferIntSize::new(size.0 as i32, size.1 as i32),
+            size: DeviceIntSize::new(size.0 as i32, size.1 as i32),
         }
     }
 
     fn render_yaml(
         &mut self,
         filename: &Path,
-        size: FramebufferIntSize,
+        size: DeviceIntSize,
         font_render_mode: Option<FontRenderMode>,
         allow_mipmaps: bool,
     ) -> YamlRenderOutput {
         let mut reader = YamlFrameReader::new(filename);
         reader.set_font_render_mode(font_render_mode);
         reader.allow_mipmaps(allow_mipmaps);
         reader.do_frame(self.wrench);
 
@@ -547,17 +547,17 @@ impl<'a> ReftestHarness<'a> {
             size.width <= window_size.width &&
             size.height <= window_size.height,
             format!("size={:?} ws={:?}", size, window_size)
         );
 
         // taking the bottom left sub-rectangle
         let rect = FramebufferIntRect::new(
             FramebufferIntPoint::new(0, window_size.height - size.height),
-            size,
+            FramebufferIntSize::new(size.width, size.height),
         );
         let pixels = self.wrench.renderer.read_pixels_rgba8(rect);
         self.window.swap_buffers();
 
         let write_debug_images = false;
         if write_debug_images {
             let debug_path = filename.with_extension("yaml.png");
             save_flipped(debug_path, pixels.clone(), size);
--- a/gfx/wr/wrench/src/wrench.rs
+++ b/gfx/wr/wrench/src/wrench.rs
@@ -138,17 +138,17 @@ impl WrenchThing for CapturedDocument {
                 wrench.refresh();
             }
         }
         0
     }
 }
 
 pub struct Wrench {
-    window_size: FramebufferIntSize,
+    window_size: DeviceIntSize,
     pub device_pixel_ratio: f32,
     page_zoom_factor: ZoomFactor,
 
     pub renderer: webrender::Renderer,
     pub api: RenderApi,
     pub document_id: DocumentId,
     pub root_pipeline_id: PipelineId,
 
@@ -166,17 +166,17 @@ pub struct Wrench {
 
 impl Wrench {
     pub fn new(
         window: &mut WindowWrapper,
         proxy: Option<EventsLoopProxy>,
         shader_override_path: Option<PathBuf>,
         dp_ratio: f32,
         save_type: Option<SaveType>,
-        size: FramebufferIntSize,
+        size: DeviceIntSize,
         do_rebuild: bool,
         no_subpixel_aa: bool,
         verbose: bool,
         no_scissor: bool,
         no_batch: bool,
         precache_shaders: bool,
         disable_dual_source_blending: bool,
         zoom_factor: f32,
@@ -512,17 +512,17 @@ impl Wrench {
 
     #[allow(dead_code)]
     pub fn delete_font_instance(&mut self, key: FontInstanceKey) {
         let mut txn = Transaction::new();
         txn.delete_font_instance(key);
         self.api.update_resources(txn.resource_updates);
     }
 
-    pub fn update(&mut self, dim: FramebufferIntSize) {
+    pub fn update(&mut self, dim: DeviceIntSize) {
         if dim != self.window_size {
             self.window_size = dim;
         }
     }
 
     pub fn begin_frame(&mut self) {
         self.frame_start_sender.push(time::SteadyTime::now());
     }