Bug 1507140 - Update webrender to commit dc442bfe38dcd9fc5033d2191b04c6242d167f05 (WR PR #3291). r=kats
authorWR Updater Bot <graphics-team@mozilla.staktrace.com>
Fri, 16 Nov 2018 17:13:07 +0000
changeset 503228 efa160d5e7d6a69c69815903c137039a50a96fd0
parent 503227 96d08f7859d163479054a2835df1bf7d23a06916
child 503229 59d8473f176488a5e8aa95b8ca34d0ac4f0e0840
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1507140
milestone65.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 1507140 - Update webrender to commit dc442bfe38dcd9fc5033d2191b04c6242d167f05 (WR PR #3291). r=kats Differential Revision: https://phabricator.services.mozilla.com/D12149
gfx/webrender/src/batch.rs
gfx/webrender/src/capture.rs
gfx/webrender/src/clip.rs
gfx/webrender/src/debug_font_data.rs
gfx/webrender/src/debug_render.rs
gfx/webrender/src/debug_server.rs
gfx/webrender/src/device/gl.rs
gfx/webrender/src/frame_builder.rs
gfx/webrender/src/glyph_rasterizer/mod.rs
gfx/webrender/src/gpu_cache.rs
gfx/webrender/src/gpu_glyph_renderer.rs
gfx/webrender/src/image.rs
gfx/webrender/src/internal_types.rs
gfx/webrender/src/platform/macos/font.rs
gfx/webrender/src/platform/unix/font.rs
gfx/webrender/src/platform/windows/font.rs
gfx/webrender/src/prim_store.rs
gfx/webrender/src/render_backend.rs
gfx/webrender/src/render_task.rs
gfx/webrender/src/renderer.rs
gfx/webrender/src/resource_cache.rs
gfx/webrender/src/texture_allocator.rs
gfx/webrender/src/texture_cache.rs
gfx/webrender/src/tiling.rs
gfx/webrender_api/src/api.rs
gfx/webrender_api/src/display_item.rs
gfx/webrender_api/src/font.rs
gfx/webrender_api/src/image.rs
gfx/webrender_api/src/units.rs
gfx/webrender_bindings/revision.txt
gfx/wrench/src/blob.rs
gfx/wrench/src/json_frame_writer.rs
gfx/wrench/src/main.rs
gfx/wrench/src/png.rs
gfx/wrench/src/rawtest.rs
gfx/wrench/src/reftest.rs
gfx/wrench/src/ron_frame_writer.rs
gfx/wrench/src/wrench.rs
gfx/wrench/src/yaml_frame_reader.rs
gfx/wrench/src/yaml_frame_writer.rs
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize};
-use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering};
-use api::{YuvColorSpace, YuvFormat, ColorDepth, PictureRect};
+use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntPoint, DeviceIntSize};
+use api::{ExternalImageType, FilterOp, ImageRendering};
+use api::{YuvColorSpace, YuvFormat, PictureRect, ColorDepth};
 use clip::{ClipDataStore, ClipNodeFlags, ClipNodeRange, ClipItem, ClipStore};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
 use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator};
 use gpu_types::{ClipMaskInstance, SplitCompositeInstance};
 use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
 use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
@@ -1990,18 +1990,18 @@ pub fn resolve_image(
                 Some(external_image) => {
                     // This is an external texture - we will add it to
                     // the deferred resolves list to be patched by
                     // the render thread...
                     let cache_handle = gpu_cache.push_deferred_per_frame_blocks(BLOCKS_PER_UV_RECT);
                     let cache_item = CacheItem {
                         texture_id: TextureSource::External(external_image),
                         uv_rect_handle: cache_handle,
-                        uv_rect: DeviceUintRect::new(
-                            DeviceUintPoint::zero(),
+                        uv_rect: DeviceIntRect::new(
+                            DeviceIntPoint::zero(),
                             image_properties.descriptor.size,
                         ),
                         texture_layer: 0,
                     };
 
                     deferred_resolves.push(DeferredResolve {
                         image_properties,
                         address: gpu_cache.get_address(&cache_handle),
--- a/gfx/webrender/src/capture.rs
+++ b/gfx/webrender/src/capture.rs
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use std::fs::File;
 use std::path::{Path, PathBuf};
 
 use api::{CaptureBits, ExternalImageData, ImageDescriptor, TexelRect};
 #[cfg(feature = "png")]
 use device::ReadPixelsFormat;
+#[cfg(feature = "png")]
+use api::DeviceIntSize;
 use ron;
 use serde;
 
 
 #[derive(Clone)]
 pub struct CaptureConfig {
     pub root: PathBuf,
     pub bits: CaptureBits,
@@ -72,17 +74,17 @@ impl CaptureConfig {
         match ron::de::from_str(&string) {
             Ok(out) => Some(out),
             Err(e) => panic!("File {:?} deserialization failed: {:?}", name.as_ref(), e),
         }
     }
 
     #[cfg(feature = "png")]
     pub fn save_png(
-        path: PathBuf, size: (u32, u32), format: ReadPixelsFormat, data: &[u8],
+        path: PathBuf, size: DeviceIntSize, format: ReadPixelsFormat, data: &[u8],
     ) {
         use api::ImageFormat;
         use png::{BitDepth, ColorType, Encoder, HasParameters};
         use std::io::BufWriter;
 
         let color_type = match format {
             ReadPixelsFormat::Rgba8 => ColorType::RGBA,
             ReadPixelsFormat::Standard(ImageFormat::BGRA8) => {
@@ -92,17 +94,17 @@ impl CaptureConfig {
             ReadPixelsFormat::Standard(ImageFormat::R8) => ColorType::Grayscale,
             ReadPixelsFormat::Standard(ImageFormat::RG8) => ColorType::GrayscaleAlpha,
             ReadPixelsFormat::Standard(fm) => {
                 error!("Unable to save PNG of {:?}", fm);
                 return;
             }
         };
         let w = BufWriter::new(File::create(path).unwrap());
-        let mut enc = Encoder::new(w, size.0, size.1);
+        let mut enc = Encoder::new(w, size.width as u32, size.height as u32);
         enc
             .set(color_type)
             .set(BitDepth::Eight);
         enc
             .write_header()
             .unwrap()
             .write_image_data(&data)
             .unwrap();
--- a/gfx/webrender/src/clip.rs
+++ b/gfx/webrender/src/clip.rs
@@ -295,17 +295,17 @@ impl ClipNode {
                             let image_rect = LayoutRect {
                                 origin,
                                 size: mask.rect.size,
                             };
                             let tiles = image::tiles(
                                 &image_rect,
                                 &visible_rect,
                                 &device_image_size,
-                                tile_size as u32,
+                                tile_size as i32,
                             );
                             for tile in tiles {
                                 resource_cache.request_image(
                                     request.with_tile(tile.offset),
                                     gpu_cache,
                                 );
                                 let mut handle = GpuCacheHandle::new();
                                 if let Some(request) = gpu_cache.request(&mut handle) {
--- a/gfx/webrender/src/debug_font_data.rs
+++ b/gfx/webrender/src/debug_font_data.rs
@@ -8,20 +8,20 @@ pub struct BakedGlyph {
     pub y0: u32,
     pub x1: u32,
     pub y1: u32,
     pub xo: f32,
     pub yo: f32,
     pub xa: f32,
 }
 
-pub const FIRST_GLYPH_INDEX: u32 = 32;
-pub const BMP_WIDTH: u32 = 128;
-pub const BMP_HEIGHT: u32 = 128;
-pub const FONT_SIZE: u32 = 19;
+pub const FIRST_GLYPH_INDEX: i32 = 32;
+pub const BMP_WIDTH: i32 = 128;
+pub const BMP_HEIGHT: i32 = 128;
+pub const FONT_SIZE: i32 = 19;
 
 pub const GLYPHS: [BakedGlyph; 96] = [
     BakedGlyph {
         x0: 1,
         y0: 1,
         x1: 1,
         y1: 1,
         xo: 0.000000,
--- a/gfx/webrender/src/debug_render.rs
+++ b/gfx/webrender/src/debug_render.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ColorU, ImageFormat, TextureTarget};
-use api::{DeviceIntRect, DeviceRect, DevicePoint, DeviceSize, DeviceUintSize};
+use api::{DeviceIntRect, DeviceRect, DevicePoint, DeviceSize, DeviceIntSize};
 use debug_font_data;
 use device::{Device, Program, Texture, TextureSlot, VertexDescriptor, ShaderError, VAO};
 use device::{TextureFilter, VertexAttribute, VertexAttributeKind, VertexUsageHint};
 use euclid::{Point2D, Rect, Size2D, Transform3D};
 use internal_types::{ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE};
 use std::f32;
 
 #[derive(Debug, Copy, Clone)]
@@ -293,17 +293,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<DeviceUintSize>,
+        viewport_size: Option<DeviceIntSize>,
     ) {
         if let Some(viewport_size) = viewport_size {
             device.disable_depth();
             device.set_blend(true);
             device.set_blend_mode_premultiplied_alpha();
 
             let projection = Transform3D::ortho(
                 0.0,
--- a/gfx/webrender/src/debug_server.rs
+++ b/gfx/webrender/src/debug_server.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{ApiMsg, DebugCommand};
+use api::{ApiMsg, DebugCommand, DeviceIntSize};
 use api::channel::MsgSender;
 use print_tree::PrintTreePrinter;
 use std::sync::mpsc::{channel, Receiver};
 use std::sync::mpsc::Sender;
 use std::thread;
 use ws;
 use base64::encode;
 use image_loader;
@@ -271,21 +271,26 @@ impl DocumentList {
 
 #[derive(Serialize)]
 pub struct Screenshot {
     kind: &'static str,
     data: String
 }
 
 impl Screenshot {
-    pub fn new(width: u32, height: u32, data: Vec<u8>) -> Self {
-        let mut output = Vec::with_capacity((width * height) as usize);
+    pub fn new(size: DeviceIntSize, data: Vec<u8>) -> Self {
+        let mut output = Vec::with_capacity((size.width * size.height) as usize);
         {
             let encoder = image_loader::png::PNGEncoder::new(&mut output);
-            encoder.encode(&data, width, height, image_loader::ColorType::RGBA(8)).unwrap();
+            encoder.encode(
+                &data,
+                size.width as u32,
+                size.height as u32,
+                image_loader::ColorType::RGBA(8),
+            ).unwrap();
         }
 
         let data = encode(&output);
         Screenshot {
             kind: "screenshot",
             data
         }
     }
--- a/gfx/webrender/src/device/gl.rs
+++ b/gfx/webrender/src/device/gl.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use super::super::shader_source;
 use api::{ColorF, ImageFormat, MemoryReport};
-use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize};
+use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::TextureTarget;
 #[cfg(any(feature = "debug_renderer", feature="capture"))]
 use api::ImageDescriptor;
 use euclid::Transform3D;
 use gleam::gl;
 use internal_types::{FastHashMap, LayerIndex, RenderTargetInfo};
 use log::Level;
 use smallvec::SmallVec;
@@ -140,17 +140,17 @@ pub enum UploadMethod {
 }
 
 /// Plain old data that can be used to initialize a texture.
 pub unsafe trait Texel: Copy {}
 unsafe impl Texel for u8 {}
 unsafe impl Texel for f32 {}
 
 /// Returns the size in bytes of a depth target with the given dimensions.
-fn depth_target_size_in_bytes(dimensions: &DeviceUintSize) -> usize {
+fn depth_target_size_in_bytes(dimensions: &DeviceIntSize) -> usize {
     // DEPTH24 textures generally reserve 3 bytes for depth and 1 byte
     // for stencil, so we measure them as 32 bits.
     let pixels = dimensions.width * dimensions.height;
     (pixels as usize) * 4
 }
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum ReadPixelsFormat {
@@ -478,18 +478,17 @@ bitflags! {
 /// Because freeing a texture requires various device handles that are not
 /// reachable from this struct, manual destruction via `Device` is required.
 /// Our `Drop` implementation asserts that this has happened.
 pub struct Texture {
     id: gl::GLuint,
     target: gl::GLuint,
     layer_count: i32,
     format: ImageFormat,
-    width: u32,
-    height: u32,
+    size: DeviceIntSize,
     filter: TextureFilter,
     flags: TextureFlags,
     /// Framebuffer Objects, one for each layer of the texture, allowing this
     /// texture to be rendered to. Empty if this texture is not used as a render
     /// target.
     fbos: Vec<FBOId>,
     /// Same as the above, but with a depth buffer attached.
     ///
@@ -508,18 +507,18 @@ pub struct Texture {
     /// or the other, but not both, unless they were actually used in both
     /// configurations). But that would complicate a lot of logic in this module,
     /// and FBOs are cheap enough to create.
     fbos_with_depth: Vec<FBOId>,
     last_frame_used: GpuFrameId,
 }
 
 impl Texture {
-    pub fn get_dimensions(&self) -> DeviceUintSize {
-        DeviceUintSize::new(self.width, self.height)
+    pub fn get_dimensions(&self) -> DeviceIntSize {
+        self.size
     }
 
     pub fn get_layer_count(&self) -> i32 {
         self.layer_count
     }
 
     pub fn get_format(&self) -> ImageFormat {
         self.format
@@ -552,20 +551,20 @@ impl Texture {
     /// Returns a mutable borrow of the flags for this texture.
     pub fn flags_mut(&mut self) -> &mut TextureFlags {
         &mut self.flags
     }
 
     /// Returns the number of bytes (generally in GPU memory) that each layer of
     /// this texture consumes.
     pub fn layer_size_in_bytes(&self) -> usize {
-        assert!(self.layer_count > 0 || self.width + self.height == 0);
+        assert!(self.layer_count > 0 || self.size.width + self.size.height == 0);
         let bpp = self.format.bytes_per_pixel() as usize;
-        let w = self.width as usize;
-        let h = self.height as usize;
+        let w = self.size.width as usize;
+        let h = self.size.height as usize;
         bpp * w * h
     }
 
     /// Returns the number of bytes (generally in GPU memory) that this texture
     /// consumes.
     pub fn size_in_bytes(&self) -> usize {
         self.layer_size_in_bytes() * (self.layer_count as usize)
     }
@@ -829,25 +828,25 @@ pub struct Device {
 
     bgra_format_internal: gl::GLuint,
     bgra_format_external: gl::GLuint,
 
     /// Map from texture dimensions to shared depth buffers for render targets.
     ///
     /// Render targets often have the same width/height, so we can save memory
     /// by sharing these across targets.
-    depth_targets: FastHashMap<DeviceUintSize, SharedDepthTarget>,
+    depth_targets: FastHashMap<DeviceIntSize, SharedDepthTarget>,
 
     // debug
     inside_frame: bool,
 
     // resources
     resource_override_path: Option<PathBuf>,
 
-    max_texture_size: u32,
+    max_texture_size: i32,
     max_texture_layers: u32,
     renderer_name: String,
     cached_programs: Option<Rc<ProgramCache>>,
 
     // Frame counter. This is used to map between CPU
     // frames and GPU frames.
     frame_id: GpuFrameId,
 
@@ -862,17 +861,17 @@ pub struct Device {
     extensions: Vec<String>,
 }
 
 /// Contains the parameters necessary to bind a draw target.
 #[derive(Clone, Copy)]
 pub enum DrawTarget<'a> {
     /// Use the device's default draw target, with the provided dimensions,
     /// which are used to set the viewport.
-    Default(DeviceUintSize),
+    Default(DeviceIntSize),
     /// Use the provided texture.
     Texture {
         /// The target texture.
         texture: &'a Texture,
         /// The slice within the texture array to draw to.
         layer: LayerIndex,
         /// Whether to draw with the texture's associated depth target.
         with_depth: bool,
@@ -884,17 +883,17 @@ impl<'a> DrawTarget<'a> {
     pub fn is_default(&self) -> bool {
         match *self {
             DrawTarget::Default(..) => true,
             _ => false,
         }
     }
 
     /// Returns the dimensions of this draw-target.
-    pub fn dimensions(&self) -> DeviceUintSize {
+    pub fn dimensions(&self) -> DeviceIntSize {
         match *self {
             DrawTarget::Default(d) => d,
             DrawTarget::Texture { texture, .. } => texture.get_dimensions(),
         }
     }
 }
 
 /// Contains the parameters necessary to bind a texture-backed read target.
@@ -929,17 +928,18 @@ impl Device {
         cached_programs: Option<Rc<ProgramCache>>,
     ) -> Device {
         let mut max_texture_size = [0];
         let mut max_texture_layers = [0];
         unsafe {
             gl.get_integer_v(gl::MAX_TEXTURE_SIZE, &mut max_texture_size);
             gl.get_integer_v(gl::MAX_ARRAY_TEXTURE_LAYERS, &mut max_texture_layers);
         }
-        let max_texture_size = max_texture_size[0] as u32;
+
+        let max_texture_size = max_texture_size[0];
         let max_texture_layers = max_texture_layers[0] as u32;
         let renderer_name = gl.get_string(gl::RENDERER);
 
         let mut extension_count = [0];
         unsafe {
             gl.get_integer_v(gl::NUM_EXTENSIONS, &mut extension_count);
         }
         let extension_count = extension_count[0] as gl::GLuint;
@@ -1074,22 +1074,22 @@ impl Device {
 
     pub fn update_program_cache(&mut self, cached_programs: Rc<ProgramCache>) {
         self.cached_programs = Some(cached_programs);
     }
 
     /// Ensures that the maximum texture size is less than or equal to the
     /// provided value. If the provided value is less than the value supported
     /// by the driver, the latter is used.
-    pub fn clamp_max_texture_size(&mut self, size: u32) {
+    pub fn clamp_max_texture_size(&mut self, size: i32) {
         self.max_texture_size = self.max_texture_size.min(size);
     }
 
     /// Returns the limit on texture dimensions (width or height).
-    pub fn max_texture_size(&self) -> u32 {
+    pub fn max_texture_size(&self) -> i32 {
         self.max_texture_size
     }
 
     /// Returns the limit on texture array layers.
     pub fn max_texture_layers(&self) -> usize {
         self.max_texture_layers as usize
     }
 
@@ -1448,36 +1448,35 @@ impl Device {
             self.program_mode_id = UniformLocation(program.u_mode);
         }
     }
 
     pub fn create_texture(
         &mut self,
         target: TextureTarget,
         format: ImageFormat,
-        mut width: u32,
-        mut height: u32,
+        mut width: i32,
+        mut height: i32,
         filter: TextureFilter,
         render_target: Option<RenderTargetInfo>,
         layer_count: i32,
     ) -> Texture {
         debug_assert!(self.inside_frame);
 
         if width > self.max_texture_size || height > self.max_texture_size {
             error!("Attempting to allocate a texture of size {}x{} above the limit, trimming", width, height);
             width = width.min(self.max_texture_size);
             height = height.min(self.max_texture_size);
         }
 
         // Set up the texture book-keeping.
         let mut texture = Texture {
             id: self.gl.gen_textures(1)[0],
             target: get_gl_target(target),
-            width,
-            height,
+            size: DeviceIntSize::new(width, height),
             layer_count,
             format,
             filter,
             fbos: vec![],
             fbos_with_depth: vec![],
             last_frame_used: self.frame_id,
             flags: TextureFlags::default(),
         };
@@ -1512,48 +1511,48 @@ impl Device {
             TexStorageUsage::Never => false,
         };
         match (use_texture_storage, is_array) {
             (true, true) =>
                 self.gl.tex_storage_3d(
                     gl::TEXTURE_2D_ARRAY,
                     mipmap_levels,
                     desc.internal,
-                    texture.width as gl::GLint,
-                    texture.height as gl::GLint,
+                    texture.size.width as gl::GLint,
+                    texture.size.height as gl::GLint,
                     texture.layer_count,
                 ),
             (true, false) =>
                 self.gl.tex_storage_2d(
                     texture.target,
                     mipmap_levels,
                     desc.internal,
-                    texture.width as gl::GLint,
-                    texture.height as gl::GLint,
+                    texture.size.width as gl::GLint,
+                    texture.size.height as gl::GLint,
                 ),
             (false, true) =>
                 self.gl.tex_image_3d(
                     gl::TEXTURE_2D_ARRAY,
                     0,
                     desc.internal as gl::GLint,
-                    texture.width as gl::GLint,
-                    texture.height as gl::GLint,
+                    texture.size.width as gl::GLint,
+                    texture.size.height as gl::GLint,
                     texture.layer_count,
                     0,
                     desc.external,
                     desc.pixel_type,
                     None,
                 ),
             (false, false) =>
                 self.gl.tex_image_2d(
                     texture.target,
                     0,
                     desc.internal as gl::GLint,
-                    texture.width as gl::GLint,
-                    texture.height as gl::GLint,
+                    texture.size.width as gl::GLint,
+                    texture.size.height as gl::GLint,
                     0,
                     desc.external,
                     desc.pixel_type,
                     None,
                 ),
         }
 
         // Set up FBOs, if required.
@@ -1594,18 +1593,18 @@ impl Device {
 
     /// Copies the contents from one renderable texture to another.
     pub fn blit_renderable_texture(
         &mut self,
         dst: &mut Texture,
         src: &Texture,
     ) {
         debug_assert!(self.inside_frame);
-        debug_assert!(dst.width >= src.width);
-        debug_assert!(dst.height >= src.height);
+        debug_assert!(dst.size.width >= src.size.width);
+        debug_assert!(dst.size.height >= src.size.height);
         debug_assert!(dst.layer_count >= src.layer_count);
 
         // Note that zip() truncates to the shorter of the two iterators.
         let rect = DeviceIntRect::new(DeviceIntPoint::zero(), src.get_dimensions().to_i32());
         for (read_fbo, draw_fbo) in src.fbos.iter().zip(&dst.fbos) {
             self.bind_read_target_impl(*read_fbo);
             self.bind_draw_target_impl(*draw_fbo);
             self.blit_render_target(rect, rect);
@@ -1709,17 +1708,17 @@ impl Device {
             let fbo_ids: SmallVec<[gl::GLuint; 8]> = fbos
                 .drain(..)
                 .map(|FBOId(fbo_id)| fbo_id)
                 .collect();
             self.gl.delete_framebuffers(&fbo_ids[..]);
         }
     }
 
-    fn acquire_depth_target(&mut self, dimensions: DeviceUintSize) -> RBOId {
+    fn acquire_depth_target(&mut self, dimensions: DeviceIntSize) -> RBOId {
         let gl = &self.gl;
         let target = self.depth_targets.entry(dimensions).or_insert_with(|| {
             let renderbuffer_ids = gl.gen_renderbuffers(1);
             let depth_rb = renderbuffer_ids[0];
             gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
             gl.renderbuffer_storage(
                 gl::RENDERBUFFER,
                 gl::DEPTH_COMPONENT24,
@@ -1733,17 +1732,17 @@ impl Device {
         });
         if target.refcount == 0 {
             record_gpu_alloc(depth_target_size_in_bytes(&dimensions));
         }
         target.refcount += 1;
         target.rbo_id
     }
 
-    fn release_depth_target(&mut self, dimensions: DeviceUintSize) {
+    fn release_depth_target(&mut self, dimensions: DeviceIntSize) {
         let mut entry = match self.depth_targets.entry(dimensions) {
             Entry::Occupied(x) => x,
             Entry::Vacant(..) => panic!("Releasing unknown depth target"),
         };
         debug_assert!(entry.get().refcount != 0);
         entry.get_mut().refcount -= 1;
         if entry.get().refcount == 0 {
             let (dimensions, target) = entry.remove_entry();
@@ -1981,31 +1980,31 @@ impl Device {
         let desc = self.gl_describe_format(texture.format);
         match texture.target {
             gl::TEXTURE_2D | gl::TEXTURE_RECTANGLE | gl::TEXTURE_EXTERNAL_OES =>
                 self.gl.tex_sub_image_2d(
                     texture.target,
                     0,
                     0,
                     0,
-                    texture.width as gl::GLint,
-                    texture.height as gl::GLint,
+                    texture.size.width as gl::GLint,
+                    texture.size.height as gl::GLint,
                     desc.external,
                     desc.pixel_type,
                     texels_to_u8_slice(pixels),
                 ),
             gl::TEXTURE_2D_ARRAY =>
                 self.gl.tex_sub_image_3d(
                     texture.target,
                     0,
                     0,
                     0,
                     0,
-                    texture.width as gl::GLint,
-                    texture.height as gl::GLint,
+                    texture.size.width as gl::GLint,
+                    texture.size.height as gl::GLint,
                     texture.layer_count as gl::GLint,
                     desc.external,
                     desc.pixel_type,
                     texels_to_u8_slice(pixels),
                 ),
             _ => panic!("BUG: Unexpected texture target!"),
         }
     }
@@ -2020,17 +2019,17 @@ impl Device {
             desc.external,
             desc.pixel_type,
         )
     }
 
     /// Read rectangle of pixels into the specified output slice.
     pub fn read_pixels_into(
         &mut self,
-        rect: DeviceUintRect,
+        rect: DeviceIntRect,
         format: ReadPixelsFormat,
         output: &mut [u8],
     ) {
         let (bytes_per_pixel, desc) = match format {
             ReadPixelsFormat::Standard(imf) => {
                 (imf.bytes_per_pixel(), self.gl_describe_format(imf))
             }
             ReadPixelsFormat::Rgba8 => {
@@ -2641,19 +2640,19 @@ impl Device {
 
 struct FormatDesc {
     internal: gl::GLenum,
     external: gl::GLuint,
     pixel_type: gl::GLuint,
 }
 
 struct UploadChunk {
-    rect: DeviceUintRect,
+    rect: DeviceIntRect,
     layer_index: i32,
-    stride: Option<u32>,
+    stride: Option<i32>,
     offset: usize,
 }
 
 struct PixelBuffer {
     usage: gl::GLenum,
     size_allocated: usize,
     size_used: usize,
     // small vector avoids heap allocation for a single chunk
@@ -2695,19 +2694,19 @@ impl<'a, T> Drop for TextureUploader<'a,
             self.target.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
         }
     }
 }
 
 impl<'a, T> TextureUploader<'a, T> {
     pub fn upload(
         &mut self,
-        rect: DeviceUintRect,
+        rect: DeviceIntRect,
         layer_index: i32,
-        stride: Option<u32>,
+        stride: Option<i32>,
         data: &[T],
     ) -> usize {
         let bytes_pp = self.target.texture.format.bytes_per_pixel();
         let upload_size = match stride {
             Some(stride) => ((rect.size.height - 1) * stride + rect.size.width * bytes_pp) as usize,
             None => (rect.size.area() * bytes_pp) as usize,
         };
         assert!(upload_size <= data.len() * mem::size_of::<T>());
@@ -2769,17 +2768,17 @@ impl<'a> UploadTarget<'a> {
             ImageFormat::BGRA8 => (self.bgra_format, 4, gl::UNSIGNED_BYTE),
             ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
             ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
             ImageFormat::RGBAI32 => (gl::RGBA_INTEGER, 16, gl::INT),
         };
 
         let row_length = match chunk.stride {
             Some(value) => value / bpp,
-            None => self.texture.width,
+            None => self.texture.size.width,
         };
 
         if chunk.stride.is_some() {
             self.gl.pixel_store_i(
                 gl::UNPACK_ROW_LENGTH,
                 row_length as _,
             );
         }
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ColorF, DeviceIntPoint, DevicePixelScale, LayoutPixel, PicturePixel, RasterPixel};
-use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode};
+use api::{DeviceIntRect, DeviceIntSize, DocumentLayer, FontRenderMode};
 use api::{LayoutPoint, LayoutRect, LayoutSize, PipelineId, RasterSpace, WorldPoint, WorldRect, WorldPixel};
 use clip::{ClipDataStore, ClipStore};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use display_list_flattener::{DisplayListFlattener};
 use gpu_cache::GpuCache;
 use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind, ZBufferIdGenerator};
 use hit_test::{HitTester, HitTestingRun};
 use internal_types::{FastHashMap, PlaneSplitter};
@@ -49,19 +49,19 @@ pub struct FrameBuilderConfig {
     pub default_font_render_mode: FontRenderMode,
     pub dual_source_blending_is_supported: bool,
     pub dual_source_blending_is_enabled: bool,
     pub chase_primitive: ChasePrimitive,
 }
 
 /// A builder structure for `tiling::Frame`
 pub struct FrameBuilder {
-    screen_rect: DeviceUintRect,
+    screen_rect: DeviceIntRect,
     background_color: Option<ColorF>,
-    window_size: DeviceUintSize,
+    window_size: DeviceIntSize,
     root_pic_index: PictureIndex,
     pub prim_store: PrimitiveStore,
     pub clip_store: ClipStore,
     pub hit_testing_runs: Vec<HitTestingRun>,
     pub config: FrameBuilderConfig,
 }
 
 pub struct FrameBuildingContext<'a> {
@@ -134,33 +134,33 @@ impl<'a> PrimitiveContext<'a> {
 
 impl FrameBuilder {
     #[cfg(feature = "replay")]
     pub fn empty() -> Self {
         FrameBuilder {
             hit_testing_runs: Vec::new(),
             prim_store: PrimitiveStore::new(),
             clip_store: ClipStore::new(),
-            screen_rect: DeviceUintRect::zero(),
-            window_size: DeviceUintSize::zero(),
+            screen_rect: DeviceIntRect::zero(),
+            window_size: DeviceIntSize::zero(),
             background_color: None,
             root_pic_index: PictureIndex(0),
             config: FrameBuilderConfig {
                 default_font_render_mode: FontRenderMode::Mono,
                 dual_source_blending_is_enabled: true,
                 dual_source_blending_is_supported: false,
                 chase_primitive: ChasePrimitive::Nothing,
             },
         }
     }
 
     pub fn with_display_list_flattener(
-        screen_rect: DeviceUintRect,
+        screen_rect: DeviceIntRect,
         background_color: Option<ColorF>,
-        window_size: DeviceUintSize,
+        window_size: DeviceIntSize,
         flattener: DisplayListFlattener,
     ) -> Self {
         FrameBuilder {
             hit_testing_runs: flattener.hit_testing_runs,
             prim_store: flattener.prim_store,
             clip_store: flattener.clip_store,
             root_pic_index: flattener.root_pic_index,
             screen_rect,
@@ -316,17 +316,17 @@ impl FrameBuilder {
         pan: WorldPoint,
         texture_cache_profile: &mut TextureCacheProfileCounters,
         gpu_cache_profile: &mut GpuCacheProfileCounters,
         scene_properties: &SceneProperties,
         resources: &mut FrameResources,
     ) -> Frame {
         profile_scope!("build");
         debug_assert!(
-            DeviceUintRect::new(DeviceUintPoint::zero(), self.window_size)
+            DeviceIntRect::new(DeviceIntPoint::zero(), self.window_size)
                 .contains_rect(&self.screen_rect)
         );
 
         let mut profile_counters = FrameProfileCounters::new();
         profile_counters
             .total_primitives
             .set(self.prim_store.prim_count());
 
--- a/gfx/webrender/src/glyph_rasterizer/mod.rs
+++ b/gfx/webrender/src/glyph_rasterizer/mod.rs
@@ -428,18 +428,18 @@ impl GlyphFormat {
             _ => self,
         }
     }
 }
 
 pub struct RasterizedGlyph {
     pub top: f32,
     pub left: f32,
-    pub width: u32,
-    pub height: u32,
+    pub width: i32,
+    pub height: i32,
     pub scale: f32,
     pub format: GlyphFormat,
     pub bytes: Vec<u8>,
 }
 
 pub struct FontContexts {
     // These worker are mostly accessed from their corresponding worker threads.
     // The goal is that there should be no noticeable contention on the mutexes.
--- a/gfx/webrender/src/gpu_cache.rs
+++ b/gfx/webrender/src/gpu_cache.rs
@@ -30,19 +30,19 @@ use euclid::TypedRect;
 use profiler::GpuCacheProfileCounters;
 use render_backend::FrameId;
 use renderer::MAX_VERTEX_TEXTURE_WIDTH;
 use std::{mem, u16, u32};
 use std::ops::Add;
 use std::os::raw::c_void;
 
 
-pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512;
+pub const GPU_CACHE_INITIAL_HEIGHT: i32 = 512;
 const FRAMES_BEFORE_EVICTION: usize = 10;
-const NEW_ROWS_PER_RESIZE: u32 = 512;
+const NEW_ROWS_PER_RESIZE: i32 = 512;
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct Epoch(u32);
 
 impl Epoch {
     fn next(&mut self) {
@@ -242,17 +242,17 @@ pub struct GpuDebugChunk {
 #[must_use]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct GpuCacheUpdateList {
     /// The frame current update list was generated from.
     pub frame_id: FrameId,
     /// The current height of the texture. The render thread
     /// should resize the texture if required.
-    pub height: u32,
+    pub height: i32,
     /// List of updates to apply.
     pub updates: Vec<GpuCacheUpdate>,
     /// A flat list of GPU blocks that are pending upload
     /// to GPU memory.
     pub blocks: Vec<GpuBlockData>,
     /// Whole state GPU block metadata for debugging.
     #[cfg_attr(feature = "serde", serde(skip))]
     pub debug_chunks: Vec<GpuDebugChunk>,
@@ -311,17 +311,17 @@ impl FreeBlockLists {
     }
 }
 
 // CPU-side representation of the GPU resource cache texture.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct Texture {
     // Current texture height
-    height: u32,
+    height: i32,
     // All blocks that have been created for this texture
     blocks: Vec<Block>,
     // Metadata about each allocated row.
     rows: Vec<Row>,
     // Free lists of available blocks for each supported
     // block size in the texture. These are intrusive
     // linked lists.
     free_lists: FreeBlockLists,
@@ -374,17 +374,17 @@ impl Texture {
         frame_id: FrameId,
     ) -> CacheLocation {
         // Find the appropriate free list to use based on the block size.
         let (alloc_size, free_list) = self.free_lists
             .get_actual_block_count_and_free_list(block_count);
 
         // See if we need a new row (if free-list has nothing available)
         if free_list.is_none() {
-            if self.rows.len() as u32 == self.height {
+            if self.rows.len() as i32 == self.height {
                 self.height += NEW_ROWS_PER_RESIZE;
             }
 
             // Create a new row.
             let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / alloc_size;
             let row_index = self.rows.len();
             self.rows.push(Row::new(alloc_size));
 
--- a/gfx/webrender/src/gpu_glyph_renderer.rs
+++ b/gfx/webrender/src/gpu_glyph_renderer.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! GPU glyph rasterization using Pathfinder.
 
-use api::{DeviceIntPoint, DeviceIntRect, DeviceUintSize, FontRenderMode};
+use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, FontRenderMode};
 use api::{ImageFormat, TextureTarget};
 use debug_colors;
 use device::{DrawTarget, Device, Texture, TextureFilter, VAO};
 use euclid::{Point2D, Size2D, Transform3D, TypedVector2D, Vector2D};
 use internal_types::RenderTargetInfo;
 use pathfinder_gfx_utils::ShelfBinPacker;
 use profiler::GpuProfileTag;
 use renderer::{self, ImageBufferKind, Renderer, RendererError, RendererStats};
@@ -52,18 +52,18 @@ impl GpuGlyphRenderer {
         let area_lut_height = (AREA_LUT_TGA_BYTES[14] as u32) |
             ((AREA_LUT_TGA_BYTES[15] as u32) << 8);
         let area_lut_pixels =
             &AREA_LUT_TGA_BYTES[18..(18 + area_lut_width * area_lut_height) as usize];
 
         let area_lut_texture = device.create_texture(
             TextureTarget::Default,
             ImageFormat::R8,
-            area_lut_width,
-            area_lut_height,
+            area_lut_width as i32,
+            area_lut_height as i32,
             TextureFilter::Linear,
             None,
             1,
         );
         device.upload_texture_immediate(&area_lut_texture, area_lut_pixels);
 
         let vector_stencil_vao =
             device.create_vao_with_new_instances(&renderer::desc::VECTOR_STENCIL, prim_vao);
@@ -96,17 +96,17 @@ impl GpuGlyphRenderer {
     }
 }
 
 impl Renderer {
     /// Renders glyphs using the vector graphics shaders (Pathfinder).
     pub fn stencil_glyphs(&mut self,
                           glyphs: &[GlyphJob],
                           projection: &Transform3D<f32>,
-                          target_size: &DeviceUintSize,
+                          target_size: &DeviceIntSize,
                           stats: &mut RendererStats)
                           -> Option<StenciledGlyphPage> {
         if glyphs.is_empty() {
             return None
         }
 
         let _timer = self.gpu_profile.start_timer(GPU_TAG_GLYPH_STENCIL);
 
@@ -178,17 +178,17 @@ impl Renderer {
             ]);
         }
 
         // TODO(pcwalton): Cache this texture!
         let path_info_texture = self.device.create_texture(
             TextureTarget::Default,
             ImageFormat::RGBAF32,
             3,
-            glyphs.len() as u32,
+            glyphs.len() as i32,
             TextureFilter::Nearest,
             None,
             1,
         );
         self.device.upload_texture_immediate(&path_info_texture, &path_info_texels);
 
         self.gpu_glyph_renderer.vector_stencil.bind(&mut self.device,
                                                     projection,
--- a/gfx/webrender/src/image.rs
+++ b/gfx/webrender/src/image.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{TileOffset, TileRange, LayoutRect, LayoutSize, LayoutPoint};
-use api::{DeviceUintSize, DeviceUintRect};
+use api::{DeviceIntSize, DeviceIntRect};
 use euclid::{vec2, point2};
 use prim_store::EdgeAaSegmentMask;
 
 /// If repetitions are far enough apart that only one is within
 /// the primitive rect, then we can simplify the parameters and
 /// treat the primitive as not repeated.
 /// This can let us avoid unnecessary work later to handle some
 /// of the parameters.
@@ -151,20 +151,20 @@ pub fn repetitions(
 #[derive(Debug)]
 pub struct Tile {
     pub rect: LayoutRect,
     pub offset: TileOffset,
     pub edge_flags: EdgeAaSegmentMask,
 }
 
 pub struct TileIterator {
-    current_x: u32,
-    x_count: u32,
-    current_y: u32,
-    y_count: u32,
+    current_x: i32,
+    x_count: i32,
+    current_y: i32,
+    y_count: i32,
     origin: TileOffset,
     tile_size: LayoutSize,
     leftover_offset: TileOffset,
     leftover_size: LayoutSize,
     local_origin: LayoutPoint,
     row_flags: EdgeAaSegmentMask,
 }
 
@@ -220,18 +220,18 @@ impl Iterator for TileIterator {
         self.current_x += 1;
         Some(tile)
     }
 }
 
 pub fn tiles(
     prim_rect: &LayoutRect,
     visible_rect: &LayoutRect,
-    device_image_size: &DeviceUintSize,
-    device_tile_size: u32,
+    device_image_size: &DeviceIntSize,
+    device_tile_size: i32,
 ) -> TileIterator {
     // The image resource is tiled. We have to generate an image primitive
     // for each tile.
     // We need to do this because the image is broken up into smaller tiles in the texture
     // cache and the image shader is not able to work with this type of sparse representation.
 
     // The tiling logic works as follows:
     //
@@ -284,60 +284,60 @@ pub fn tiles(
     let layer_tile_size = LayoutSize::new(
         tile_dw * prim_rect.size.width,
         tile_dh * prim_rect.size.height,
     );
 
     // The size in pixels of the tiles on the right and bottom edges, smaller
     // than the regular tile size if the image is not a multiple of the tile size.
     // Zero means the image size is a multiple of the tile size.
-    let leftover_device_size = DeviceUintSize::new(
+    let leftover_device_size = DeviceIntSize::new(
         device_image_size.width % device_tile_size,
         device_image_size.height % device_tile_size
     );
 
     // The size in layer space of the tiles on the right and bottom edges.
     let leftover_layer_size = LayoutSize::new(
         layer_tile_size.width * leftover_device_size.width as f32 / device_tile_size_f32,
         layer_tile_size.height * leftover_device_size.height as f32 / device_tile_size_f32,
     );
 
     // Offset of the row and column of tiles with leftover size.
     let leftover_offset = TileOffset::new(
-        (device_image_size.width / device_tile_size) as u32,
-        (device_image_size.height / device_tile_size) as u32,
+        device_image_size.width / device_tile_size,
+        device_image_size.height / device_tile_size,
     );
 
     // Number of culled out tiles to skip before the first visible tile.
     let t0 = TileOffset::new(
         if visible_rect.origin.x > prim_rect.origin.x {
-            f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as u32
+            f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as i32
         } else {
             0
         },
         if visible_rect.origin.y > prim_rect.origin.y {
-            f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as u32
+            f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as i32
         } else {
             0
         },
     );
 
     // Since we're working in layer space, we can end up computing leftover tiles with an empty
     // size due to floating point precision issues. Detect this case so that we don't return
     // tiles with an empty size.
     let x_max = {
-        let result = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u32;
+        let result = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as i32;
         if result == leftover_offset.x + 1 && leftover_layer_size.width == 0.0f32 {
             leftover_offset.x
         } else {
             result
         }
     };
     let y_max = {
-        let result = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u32;
+        let result = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as i32;
         if result == leftover_offset.y + 1 && leftover_layer_size.height == 0.0f32 {
             leftover_offset.y
         } else {
             result
         }
     };
 
     let mut row_flags = EdgeAaSegmentMask::TOP;
@@ -354,32 +354,32 @@ pub fn tiles(
         tile_size: layer_tile_size,
         leftover_offset,
         leftover_size: leftover_layer_size,
         local_origin: prim_rect.origin,
     }
 }
 
 pub fn compute_tile_range(
-    visible_area: &DeviceUintRect,
+    visible_area: &DeviceIntRect,
     tile_size: u16,
 ) -> TileRange {
     // Tile dimensions in normalized coordinates.
     let tw = 1. / (tile_size as f32);
     let th = 1. / (tile_size as f32);
 
     let t0 = point2(
         f32::floor(visible_area.origin.x as f32 * tw),
         f32::floor(visible_area.origin.y as f32 * th),
-    ).try_cast::<u32>().unwrap_or_else(|| panic!("compute_tile_range bad values {:?} {:?}", visible_area, tile_size));
+    ).try_cast::<i32>().unwrap_or_else(|| panic!("compute_tile_range bad values {:?} {:?}", visible_area, tile_size));
 
     let t1 = point2(
         f32::ceil(visible_area.max_x() as f32 * tw),
         f32::ceil(visible_area.max_y() as f32 * th),
-    ).try_cast::<u32>().unwrap_or_else(|| panic!("compute_tile_range bad values {:?} {:?}", visible_area, tile_size));
+    ).try_cast::<i32>().unwrap_or_else(|| panic!("compute_tile_range bad values {:?} {:?}", visible_area, tile_size));
 
     TileRange {
         origin: t0,
         size: (t1 - t0).to_size(),
     }
 }
 
 pub fn for_each_tile_in_range(
@@ -392,25 +392,25 @@ pub fn for_each_tile_in_range(
         }
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
     use std::collections::HashSet;
-    use api::{LayoutRect, DeviceUintSize};
+    use api::{LayoutRect, DeviceIntSize};
     use euclid::{rect, size2};
 
     // this checks some additional invariants
     fn checked_for_each_tile(
         prim_rect: &LayoutRect,
         visible_rect: &LayoutRect,
-        device_image_size: &DeviceUintSize,
-        device_tile_size: u32,
+        device_image_size: &DeviceIntSize,
+        device_tile_size: i32,
         callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
     ) {
         let mut coverage = LayoutRect::zero();
         let mut seen_tiles = HashSet::new();
         for tile in tiles(
             prim_rect,
             visible_rect,
             device_image_size,
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{DebugCommand, DeviceUintRect, DocumentId, ExternalImageData, ExternalImageId};
+use api::{DebugCommand, DeviceIntRect, DocumentId, ExternalImageData, ExternalImageId};
 use api::{ImageFormat, WorldPixel, NotificationRequest};
 use device::TextureFilter;
 use renderer::PipelineInfo;
 use gpu_cache::GpuCacheUpdateList;
 use fxhash::FxHasher;
 use plane_split::BspSplitter;
 use profiler::BackendProfileCounters;
 use std::{usize, i32};
@@ -117,18 +117,18 @@ pub struct TextureCacheAllocation {
     pub id: CacheTextureId,
     /// Details corresponding to the operation in question.
     pub kind: TextureCacheAllocationKind,
 }
 
 /// Information used when allocating / reallocating.
 #[derive(Debug)]
 pub struct TextureCacheAllocInfo {
-    pub width: u32,
-    pub height: u32,
+    pub width: i32,
+    pub height: i32,
     pub layer_count: i32,
     pub format: ImageFormat,
     pub filter: TextureFilter,
     /// Indicates whether this corresponds to one of the shared texture caches.
     pub is_shared_cache: bool,
 }
 
 /// Sub-operation-specific information for allocation operations.
@@ -143,19 +143,19 @@ pub enum TextureCacheAllocationKind {
     /// Frees the texture and the corresponding cache ID.
     Free,
 }
 
 /// Command to update the contents of the texture cache.
 #[derive(Debug)]
 pub struct TextureCacheUpdate {
     pub id: CacheTextureId,
-    pub rect: DeviceUintRect,
-    pub stride: Option<u32>,
-    pub offset: u32,
+    pub rect: DeviceIntRect,
+    pub stride: Option<i32>,
+    pub offset: i32,
     pub layer_index: i32,
     pub source: TextureUpdateSource,
 }
 
 /// Atomic set of commands to manipulate the texture cache, generated on the
 /// RenderBackend thread and executed on the Renderer thread.
 ///
 /// The list of allocation operations is processed before the updates. This is
--- a/gfx/webrender/src/platform/macos/font.rs
+++ b/gfx/webrender/src/platform/macos/font.rs
@@ -50,18 +50,18 @@ pub struct FontContext {
 // all hidden inside their font context.
 unsafe impl Send for FontContext {}
 
 struct GlyphMetrics {
     rasterized_left: i32,
     #[allow(dead_code)]
     rasterized_descent: i32,
     rasterized_ascent: i32,
-    rasterized_width: u32,
-    rasterized_height: u32,
+    rasterized_width: i32,
+    rasterized_height: i32,
     advance: f32,
 }
 
 // According to the Skia source code, there's no public API to
 // determine if subpixel AA is supported. So jrmuizel ported
 // this function from Skia which is used to check if a glyph
 // can be rendered with subpixel AA.
 fn supports_subpixel_aa() -> bool {
@@ -151,18 +151,18 @@ fn get_glyph_metrics(
     right += 1;
     top += 1;
 
     let width = right - left;
     let height = top - bottom;
 
     GlyphMetrics {
         rasterized_left: left,
-        rasterized_width: width as u32,
-        rasterized_height: height as u32,
+        rasterized_width: width,
+        rasterized_height: height,
         rasterized_ascent: top,
         rasterized_descent: -bottom,
         advance: advance.width as f32,
     }
 }
 
 #[link(name = "ApplicationServices", kind = "framework")]
 extern {
@@ -416,18 +416,18 @@ impl FontContext {
                     extra_strikes as f64,
                 );
                 if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 {
                     None
                 } else {
                     Some(GlyphDimensions {
                         left: metrics.rasterized_left,
                         top: metrics.rasterized_ascent,
-                        width: metrics.rasterized_width as u32,
-                        height: metrics.rasterized_height as u32,
+                        width: metrics.rasterized_width,
+                        height: metrics.rasterized_height,
                         advance: metrics.advance,
                     })
                 }
             })
     }
 
     // Assumes the pixels here are linear values from CG
     #[cfg(not(feature = "pathfinder"))]
@@ -560,17 +560,20 @@ impl FontContext {
             x_offset,
             y_offset,
             extra_strikes as f64 * pixel_step,
         );
         if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 {
             return GlyphRasterResult::LoadFailed
         }
 
-        let raster_size = Size2D::new(metrics.rasterized_width, metrics.rasterized_height);
+        let raster_size = Size2D::new(
+            metrics.rasterized_width as u32,
+            metrics.rasterized_height as u32
+        );
 
         // If the font render mode is Alpha, we support two different ways to
         // compute the grayscale mask, depending on the value of the platform
         // options' font_smoothing flag:
         //  - Alpha + smoothing:
         //    We will recover a grayscale mask from a subpixel rasterization, in
         //    such a way that the result looks as close to subpixel text
         //    blending as we can make it. This involves gamma correction,
--- a/gfx/webrender/src/platform/unix/font.rs
+++ b/gfx/webrender/src/platform/unix/font.rs
@@ -427,57 +427,57 @@ impl FontContext {
         font: &FontInstance,
         glyph: &GlyphKey,
         use_transform: Option<f32>,
     ) -> Option<GlyphDimensions> {
         let format = unsafe { (*slot).format };
         let (mut left, mut top, mut width, mut height) = match format {
             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
                 unsafe { (
-                    (*slot).bitmap_left,
-                    (*slot).bitmap_top,
-                    (*slot).bitmap.width,
-                    (*slot).bitmap.rows,
+                    (*slot).bitmap_left as i32,
+                    (*slot).bitmap_top as i32,
+                    (*slot).bitmap.width as i32,
+                    (*slot).bitmap.rows as i32,
                 ) }
             }
             FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
                 let cbox = self.get_bounding_box(slot, font, glyph);
                 (
                     (cbox.xMin >> 6) as i32,
                     (cbox.yMax >> 6) as i32,
-                    ((cbox.xMax - cbox.xMin) >> 6) as u32,
-                    ((cbox.yMax - cbox.yMin) >> 6) as u32,
+                    ((cbox.xMax - cbox.xMin) >> 6) as i32,
+                    ((cbox.yMax - cbox.yMin) >> 6) as i32,
                 )
             }
             _ => return None,
         };
         let mut advance = unsafe { (*slot).metrics.horiAdvance as f32 / 64.0 };
         if let Some(scale) = use_transform {
             if scale != 1.0 {
                 let x0 = left as f32 * scale;
                 let x1 = width as f32 * scale + x0;
                 let y1 = top as f32 * scale;
                 let y0 = y1 - height as f32 * scale;
                 left = x0.round() as i32;
                 top = y1.round() as i32;
-                width = (x1.ceil() - x0.floor()) as u32;
-                height = (y1.ceil() - y0.floor()) as u32;
+                width = (x1.ceil() - x0.floor()) as i32;
+                height = (y1.ceil() - y0.floor()) as i32;
                 advance *= scale;
             }
             // An outline glyph's cbox would have already been transformed inside FT_Load_Glyph,
             // so only handle bitmap glyphs which are not handled by FT_Load_Glyph.
             if format == FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP {
                 if font.synthetic_italics.is_enabled() {
                     let (skew_min, skew_max) = get_skew_bounds(
                         top - height as i32,
                         top,
                         font.synthetic_italics.to_skew(),
                     );
                     left += skew_min as i32;
-                    width += (skew_max - skew_min) as u32;
+                    width += (skew_max - skew_min) as i32;
                 }
                 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
                     mem::swap(&mut width, &mut height);
                     mem::swap(&mut left, &mut top);
                     left -= width as i32;
                     top += height as i32;
                 }
                 if font.flags.contains(FontInstanceFlags::FLIP_X) {
@@ -799,18 +799,18 @@ impl FontContext {
             (FT_Pixel_Mode::FT_PIXEL_MODE_BGRA, _) => GlyphFormat::ColorBitmap,
             (_, FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP) => GlyphFormat::Bitmap,
             _ => font.get_alpha_glyph_format(),
         };
 
         GlyphRasterResult::Bitmap(RasterizedGlyph {
             left: left as f32,
             top: top as f32,
-            width: actual_width as u32,
-            height: actual_height as u32,
+            width: actual_width as i32,
+            height: actual_height as i32,
             scale,
             format: glyph_format,
             bytes: final_buffer,
         })
     }
 }
 
 impl Drop for FontContext {
--- a/gfx/webrender/src/platform/windows/font.rs
+++ b/gfx/webrender/src/platform/windows/font.rs
@@ -327,18 +327,18 @@ impl FontContext {
             None
         };
         let analysis = self.create_glyph_analysis(font, key, size, transform, bitmaps);
 
         let texture_type = dwrite_texture_type(font.render_mode);
 
         let bounds = analysis.get_alpha_texture_bounds(texture_type);
 
-        let width = (bounds.right - bounds.left) as u32;
-        let height = (bounds.bottom - bounds.top) as u32;
+        let width = (bounds.right - bounds.left) as i32;
+        let height = (bounds.bottom - bounds.top) as i32;
 
         // Alpha texture bounds can sometimes return an empty rect
         // Such as for spaces
         if width == 0 || height == 0 {
             return None;
         }
 
         let face = self.get_font_face(font);
@@ -459,18 +459,18 @@ impl FontContext {
         } else {
             None
         };
 
         let analysis = self.create_glyph_analysis(font, key, size, transform, bitmaps);
         let texture_type = dwrite_texture_type(font.render_mode);
 
         let bounds = analysis.get_alpha_texture_bounds(texture_type);
-        let width = (bounds.right - bounds.left) as u32;
-        let height = (bounds.bottom - bounds.top) as u32;
+        let width = (bounds.right - bounds.left) as i32;
+        let height = (bounds.bottom - bounds.top) as i32;
 
         // Alpha texture bounds can sometimes return an empty rect
         // Such as for spaces
         if width == 0 || height == 0 {
             return GlyphRasterResult::LoadFailed;
         }
 
         let pixels = analysis.create_alpha_texture(texture_type, bounds);
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -3199,17 +3199,17 @@ impl PrimitiveInstance {
                                         origin,
                                         size: stretch_size,
                                     };
 
                                     let tiles = image::tiles(
                                         &image_rect,
                                         &visible_rect,
                                         &device_image_size,
-                                        tile_size as u32,
+                                        tile_size as i32,
                                     );
 
                                     for tile in tiles {
                                         frame_state.resource_cache.request_image(
                                             request.with_tile(tile.offset),
                                             frame_state.gpu_cache,
                                         );
 
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -6,17 +6,17 @@
 //! commands to be issued by the `Renderer`.
 //!
 //! See the comment at the top of the `renderer` module for a description of
 //! how these two pieces interact.
 
 use api::{ApiMsg, BuiltDisplayList, ClearCache, DebugCommand};
 #[cfg(feature = "debugger")]
 use api::{BuiltDisplayListIter, SpecificDisplayItem};
-use api::{DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
+use api::{DevicePixelScale, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{DocumentId, DocumentLayer, ExternalScrollId, FrameMsg, HitTestFlags, HitTestResult};
 use api::{IdNamespace, LayoutPoint, PipelineId, RenderNotifier, SceneMsg, ScrollClamping};
 use api::{MemoryReport, VoidPtrToSizeFn};
 use api::{ScrollLocation, ScrollNodeState, TransactionMsg, ResourceUpdate, ImageKey};
 use api::{NotificationRequest, Checkpoint};
 use api::channel::{MsgReceiver, Payload};
 #[cfg(feature = "capture")]
 use api::CaptureBits;
@@ -56,18 +56,18 @@ use std::u32;
 use tiling::Frame;
 use time::precise_time_ns;
 use util::drain_filter;
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone)]
 pub struct DocumentView {
-    pub window_size: DeviceUintSize,
-    pub inner_rect: DeviceUintRect,
+    pub window_size: DeviceIntSize,
+    pub inner_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 {
@@ -192,26 +192,26 @@ struct Document {
     // renderer.
     has_built_scene: bool,
 
     resources: FrameResources,
 }
 
 impl Document {
     pub fn new(
-        window_size: DeviceUintSize,
+        window_size: DeviceIntSize,
         layer: DocumentLayer,
         default_device_pixel_ratio: f32,
     ) -> Self {
         Document {
             scene: Scene::new(),
             removed_pipelines: Vec::new(),
             view: DocumentView {
                 window_size,
-                inner_rect: DeviceUintRect::new(DeviceUintPoint::zero(), window_size),
+                inner_rect: DeviceIntRect::new(DeviceIntPoint::zero(), window_size),
                 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(),
             frame_id: FrameId::first(),
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -1208,18 +1208,18 @@ impl RenderTaskCache {
 
                 // Select the right texture page to allocate from.
                 let image_format = match target_kind {
                     RenderTargetKind::Color => ImageFormat::BGRA8,
                     RenderTargetKind::Alpha => ImageFormat::R8,
                 };
 
                 let descriptor = ImageDescriptor::new(
-                    size.width as u32,
-                    size.height as u32,
+                    size.width,
+                    size.height,
                     image_format,
                     entry.is_opaque,
                     false,
                 );
 
                 // Allocate space in the texture cache, but don't supply
                 // and CPU-side data to be uploaded.
                 //
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -18,17 +18,17 @@
 //! initial entry point into WebRender, and is responsible for spawning the
 //! various other threads discussed above. That said, WebRender initialization
 //! returns both the `Renderer` instance as well as a channel for communicating
 //! directly with the `RenderBackend`. Aside from a few high-level operations
 //! like 'render now', most of interesting commands from the consumer go over
 //! that channel and operate on the `RenderBackend`.
 
 use api::{BlobImageHandler, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
-use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, Epoch, ExternalImageId};
+use api::{DocumentId, Epoch, ExternalImageId};
 use api::{ExternalImageType, FontRenderMode, FrameMsg, ImageFormat, PipelineId};
 use api::{ImageRendering, Checkpoint, NotificationRequest};
 use api::{MemoryReport, VoidPtrToSizeFn};
 use api::{RenderApiSender, RenderNotifier, TexelRect, TextureTarget};
 use api::{channel};
 use api::DebugCommand;
 use api::channel::PayloadReceiverHelperMethods;
 use batch::{BatchKind, BatchTextures, BrushBatchKind};
@@ -1075,30 +1075,30 @@ struct GpuCacheTexture {
     texture: Option<Texture>,
     bus: GpuCacheBus,
 }
 
 impl GpuCacheTexture {
 
     /// Ensures that we have an appropriately-sized texture. Returns true if a
     /// new texture was created.
-    fn ensure_texture(&mut self, device: &mut Device, height: u32) -> bool {
+    fn ensure_texture(&mut self, device: &mut Device, height: i32) -> bool {
         // If we already have a texture that works, we're done.
         if self.texture.as_ref().map_or(false, |t| t.get_dimensions().height >= height) {
             if GPU_CACHE_RESIZE_TEST && self.bus.uses_render_target() {
                 // Special debug mode - resize the texture even though it's fine.
             } else {
                 return false;
             }
         }
 
         // Compute a few parameters for the new texture. We round the height up to
         // a multiple of 256 to avoid many small resizes.
         let new_height = (height + 255) & !255;
-        let new_size = DeviceUintSize::new(MAX_VERTEX_TEXTURE_WIDTH as _, new_height);
+        let new_size = DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as _, new_height);
         let rt_info = if self.bus.uses_render_target() {
             Some(RenderTargetInfo { has_depth: false })
         } else {
             None
         };
 
         // Take the old texture, if any, and deinitialize it unless we're going
         // to blit it's contents to the new one.
@@ -1181,25 +1181,25 @@ impl GpuCacheTexture {
                 device.delete_program(program);
                 device.delete_custom_vao(vao);
                 device.delete_vbo(buf_position);
                 device.delete_vbo(buf_value);
             }
         }
     }
 
-    fn get_height(&self) -> u32 {
+    fn get_height(&self) -> i32 {
         self.texture.as_ref().map_or(0, |t| t.get_dimensions().height)
     }
 
     fn prepare_for_updates(
         &mut self,
         device: &mut Device,
         total_block_count: usize,
-        max_height: u32,
+        max_height: i32,
     ) {
         let allocated_new_texture = self.ensure_texture(device, max_height);
         match self.bus {
             GpuCacheBus::PixelBuffer { ref mut rows, .. } => {
                 if allocated_new_texture {
                     // If we had to resize the texture, just mark all rows
                     // as dirty so they will be uploaded to the texture
                     // during the next flush.
@@ -1315,19 +1315,19 @@ impl GpuCacheTexture {
                 for (row_index, row) in rows.iter_mut().enumerate() {
                     if !row.is_dirty {
                         continue;
                     }
 
                     let block_index = row_index * MAX_VERTEX_TEXTURE_WIDTH;
                     let cpu_blocks =
                         &cpu_blocks[block_index .. (block_index + MAX_VERTEX_TEXTURE_WIDTH)];
-                    let rect = DeviceUintRect::new(
-                        DeviceUintPoint::new(0, row_index as u32),
-                        DeviceUintSize::new(MAX_VERTEX_TEXTURE_WIDTH as u32, 1),
+                    let rect = DeviceIntRect::new(
+                        DeviceIntPoint::new(0, row_index as i32),
+                        DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as i32, 1),
                     );
 
                     uploader.upload(rect, 0, None, cpu_blocks);
 
                     row.is_dirty = false;
                 }
 
                 rows_dirty
@@ -1394,18 +1394,18 @@ impl VertexDataTexture {
         // OpenGL to upload to the GPU.
         if items_per_row != 0 {
             while data.len() % items_per_row != 0 {
                 data.push(unsafe { mem::uninitialized() });
             }
         }
 
         let width =
-            (MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item)) as u32;
-        let needed_height = (data.len() / items_per_row) as u32;
+            (MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % texels_per_item)) as i32;
+        let needed_height = (data.len() / items_per_row) as i32;
         let existing_height = self.texture.as_ref().map_or(0, |t| t.get_dimensions().height);
 
         // Create a new texture if needed.
         if needed_height > existing_height {
             // Drop the existing texture, if any.
             if let Some(t) = self.texture.take() {
                 device.delete_texture(t);
             }
@@ -1418,19 +1418,19 @@ impl VertexDataTexture {
                 new_height,
                 TextureFilter::Nearest,
                 None,
                 1,
             );
             self.texture = Some(texture);
         }
 
-        let rect = DeviceUintRect::new(
-            DeviceUintPoint::zero(),
-            DeviceUintSize::new(width, needed_height),
+        let rect = DeviceIntRect::new(
+            DeviceIntPoint::zero(),
+            DeviceIntSize::new(width, needed_height),
         );
         device
             .upload_texture(self.texture(), &self.pbo, 0)
             .upload(rect, 0, None, data);
     }
 
     fn deinit(mut self, device: &mut Device) {
         device.delete_pbo(self.pbo);
@@ -1442,17 +1442,17 @@ impl VertexDataTexture {
 
 struct FrameOutput {
     last_access: GpuFrameId,
     fbo_id: FBOId,
 }
 
 #[derive(PartialEq)]
 struct TargetSelector {
-    size: DeviceUintSize,
+    size: DeviceIntSize,
     num_layers: usize,
     format: ImageFormat,
 }
 
 #[cfg(feature = "debug_renderer")]
 struct LazyInitializedDebugRenderer {
     debug_renderer: Option<DebugRenderer>,
     failed: bool,
@@ -1666,17 +1666,17 @@ impl Renderer {
             options.cached_programs.take(),
         );
 
         let ext_dual_source_blending = !options.disable_dual_source_blending &&
             device.supports_extension("GL_ARB_blend_func_extended") &&
             device.supports_extension("GL_ARB_explicit_attrib_location");
 
         // 512 is the minimum that the texture cache can work with.
-        const MIN_TEXTURE_SIZE: u32 = 512;
+        const MIN_TEXTURE_SIZE: i32 = 512;
         if let Some(user_limit) = options.max_texture_size {
             assert!(user_limit >= MIN_TEXTURE_SIZE);
             device.clamp_max_texture_size(user_limit);
         }
         if device.max_texture_size() < MIN_TEXTURE_SIZE {
             // Broken GL contexts can return a max texture size of zero (See #1260).
             // Better to gracefully fail now than panic as soon as a texture is allocated.
             error!(
@@ -2039,17 +2039,17 @@ impl Renderer {
         };
 
         renderer.set_debug_flags(options.debug_flags);
 
         let sender = RenderApiSender::new(api_tx, payload_tx);
         Ok((renderer, sender))
     }
 
-    pub fn get_max_texture_size(&self) -> u32 {
+    pub fn get_max_texture_size(&self) -> i32 {
         self.device.max_texture_size()
     }
 
     pub fn get_graphics_api_info(&self) -> GraphicsApiInfo {
         GraphicsApiInfo {
             kind: GraphicsApi::OpenGL,
             version: self.device.gl().get_string(gl::VERSION),
             renderer: self.device.gl().get_string(gl::RENDERER),
@@ -2203,17 +2203,17 @@ impl Renderer {
 
 
     #[cfg(feature = "debugger")]
     fn get_screenshot_for_debugger(&mut self) -> String {
         use api::ImageDescriptor;
 
         let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, true, false);
         let data = self.device.read_pixels(&desc);
-        let screenshot = debug_server::Screenshot::new(desc.size.width, desc.size.height, data);
+        let screenshot = debug_server::Screenshot::new(desc.size, data);
 
         serde_json::to_string(&screenshot).unwrap()
     }
 
     #[cfg(not(feature = "debugger"))]
     fn get_passes_for_debugger(&self) -> String {
         // Avoid unused param warning.
         let _ = &self.debug_server;
@@ -2488,17 +2488,17 @@ impl Renderer {
     }
 
     /// Renders the current frame.
     ///
     /// A Frame is supplied by calling [`generate_frame()`][genframe].
     /// [genframe]: ../../webrender_api/struct.DocumentApi.html#method.generate_frame
     pub fn render(
         &mut self,
-        framebuffer_size: DeviceUintSize,
+        framebuffer_size: DeviceIntSize,
     ) -> Result<RendererStats, Vec<RendererError>> {
         let result = self.render_impl(Some(framebuffer_size));
 
         drain_filter(
             &mut self.notifications,
             |n| { n.when() == Checkpoint::FrameRendered },
             |n| { n.notify(); },
         );
@@ -2512,17 +2512,17 @@ impl Renderer {
     }
 
     // If framebuffer_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<DeviceUintSize>,
+        framebuffer_size: Option<DeviceIntSize>,
     ) -> Result<RendererStats, Vec<RendererError>> {
         profile_scope!("render");
         if self.active_documents.is_empty() {
             self.last_time = precise_time_ns();
             return Ok(RendererStats::empty());
         }
 
         let mut stats = RendererStats::empty();
@@ -2576,17 +2576,17 @@ impl Renderer {
             active_documents.sort_by_key(|&(_, ref render_doc)| render_doc.frame.layer);
 
             // don't clear the framebuffer if one of the rendered documents will overwrite it
             if let Some(framebuffer_size) = framebuffer_size {
                 let needs_color_clear = !active_documents
                     .iter()
                     .any(|&(_, RenderedDocument { ref frame, .. })| {
                         frame.background_color.is_some() &&
-                        frame.inner_rect.origin == DeviceUintPoint::zero() &&
+                        frame.inner_rect.origin == DeviceIntPoint::zero() &&
                         frame.inner_rect.size == framebuffer_size
                     });
 
                 if needs_color_clear || clear_depth_value.is_some() {
                     let clear_color = if needs_color_clear {
                         self.clear_color.map(|color| color.to_array())
                     } else {
                         None
@@ -3122,17 +3122,17 @@ impl Renderer {
             stats,
         );
     }
 
     fn draw_color_target(
         &mut self,
         draw_target: DrawTarget,
         target: &ColorRenderTarget,
-        framebuffer_target_rect: DeviceUintRect,
+        framebuffer_target_rect: DeviceIntRect,
         depth_is_ready: bool,
         clear_color: Option<[f32; 4]>,
         render_tasks: &RenderTaskTree,
         projection: &Transform3D<f32>,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
     ) {
         self.profile_counters.color_targets.inc();
@@ -3173,17 +3173,17 @@ impl Renderer {
                     // Note: The above measurements were taken when render
                     // target slices were minimum 2048x2048. Now that we size
                     // them adaptively, this may be less of a win (except perhaps
                     // on a mostly-unused last slice of a large texture array).
                     Some(target.used_rect())
                 } else {
                     None
                 }
-            } else if framebuffer_target_rect == DeviceUintRect::new(DeviceUintPoint::zero(), draw_target.dimensions()) {
+            } else if framebuffer_target_rect == DeviceIntRect::new(DeviceIntPoint::zero(), draw_target.dimensions()) {
                 // whole screen is covered, no need for scissor
                 None
             } else {
                 let mut rect = framebuffer_target_rect.to_i32();
                 // Note: `framebuffer_target_rect` needs a Y-flip before going to GL
                 // Note: at this point, the target rectangle is not guaranteed to be within the main framebuffer bounds
                 // but `clear_target_rect` is totally fine with negative origin, as long as width & height are positive
                 rect.origin.y = draw_target.dimensions().height as i32 - rect.origin.y - rect.size.height;
@@ -3737,17 +3737,17 @@ impl Renderer {
             self.cover_glyphs(stencil_page, &projection, stats);
         }
     }
 
     #[cfg(not(feature = "pathfinder"))]
     fn stencil_glyphs(&mut self,
                       _: &[GlyphJob],
                       _: &Transform3D<f32>,
-                      _: &DeviceUintSize,
+                      _: &DeviceIntSize,
                       _: &mut RendererStats)
                       -> Option<StenciledGlyphPage> {
         None
     }
 
     #[cfg(not(feature = "pathfinder"))]
     fn cover_glyphs(&mut self,
                     _: StenciledGlyphPage,
@@ -3867,19 +3867,19 @@ impl Renderer {
         // of 256. This improves render target reuse when resizing the window,
         // since we don't need to create a new render target for each slightly-
         // larger frame.
         let mut bounding_rect = DeviceIntRect::zero();
         for t in list.targets.iter() {
             bounding_rect = t.used_rect().union(&bounding_rect);
         }
         debug_assert_eq!(bounding_rect.origin, DeviceIntPoint::zero());
-        let dimensions = DeviceUintSize::new(
-            (bounding_rect.size.width as u32 + 255) & !255,
-            (bounding_rect.size.height as u32 + 255) & !255,
+        let dimensions = DeviceIntSize::new(
+            (bounding_rect.size.width + 255) & !255,
+            (bounding_rect.size.height + 255) & !255,
         );
 
         counters.targets_used.inc();
 
         // Try finding a match in the existing pool. If there's no match, we'll
         // create a new texture.
         let selector = TargetSelector {
             size: dimensions,
@@ -3961,17 +3961,17 @@ 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<DeviceUintSize>,
+        framebuffer_size: Option<DeviceIntSize>,
         framebuffer_depth_is_ready: bool,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
     ) {
         let _gm = self.gpu_profile.start_marker("tile frame draw");
 
         if frame.passes.is_empty() {
             frame.has_been_rendered = true;
@@ -4180,17 +4180,17 @@ impl Renderer {
         self.set_debug_flags(new_flags);
     }
 
     pub fn save_cpu_profile(&self, filename: &str) {
         write_profile(filename);
     }
 
     #[cfg(feature = "debug_renderer")]
-    fn draw_render_target_debug(&mut self, framebuffer_size: DeviceUintSize) {
+    fn draw_render_target_debug(&mut self, framebuffer_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,
         };
@@ -4204,17 +4204,17 @@ impl Renderer {
             textures,
             framebuffer_size,
             0,
             &|_| [0.0, 1.0, 0.0, 1.0], // Use green for all RTs.
         );
     }
 
     #[cfg(feature = "debug_renderer")]
-    fn draw_texture_cache_debug(&mut self, framebuffer_size: DeviceUintSize) {
+    fn draw_texture_cache_debug(&mut self, framebuffer_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,
         };
@@ -4240,17 +4240,17 @@ impl Renderer {
         );
     }
 
     #[cfg(feature = "debug_renderer")]
     fn do_debug_blit(
         device: &mut Device,
         debug_renderer: &mut DebugRenderer,
         mut textures: Vec<&Texture>,
-        framebuffer_size: DeviceUintSize,
+        framebuffer_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;
@@ -4356,17 +4356,17 @@ impl Renderer {
             x0 + text_width + margin,
             y + margin,
             ColorU::new(25, 25, 25, 200),
             ColorU::new(51, 51, 51, 200),
         );
     }
 
     #[cfg(feature = "debug_renderer")]
-    fn draw_gpu_cache_debug(&mut self, framebuffer_size: DeviceUintSize) {
+    fn draw_gpu_cache_debug(&mut self, framebuffer_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,
         };
@@ -4394,34 +4394,34 @@ impl Renderer {
                 y_off + chunk.address.v as f32 + 1.0,
                 color,
                 color,
             );
         }
     }
 
     /// Pass-through to `Device::read_pixels_into`, used by Gecko's WR bindings.
-    pub fn read_pixels_into(&mut self, rect: DeviceUintRect, format: ReadPixelsFormat, output: &mut [u8]) {
+    pub fn read_pixels_into(&mut self, rect: DeviceIntRect, format: ReadPixelsFormat, output: &mut [u8]) {
         self.device.read_pixels_into(rect, format, output);
     }
 
-    pub fn read_pixels_rgba8(&mut self, rect: DeviceUintRect) -> Vec<u8> {
+    pub fn read_pixels_rgba8(&mut self, rect: DeviceIntRect) -> 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) -> (DeviceUintSize, Vec<u8>) {
+    pub fn read_gpu_cache(&mut self) -> (DeviceIntSize, Vec<u8>) {
         let texture = self.gpu_cache_texture.texture.as_ref().unwrap();
         let size = texture.get_dimensions();
         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(
-            DeviceUintRect::new(DeviceUintPoint::zero(), size),
+            DeviceIntRect::new(DeviceIntPoint::zero(), size),
             ReadPixelsFormat::Standard(ImageFormat::RGBAF32),
             &mut texels,
         );
         self.device.reset_read_target();
         self.device.end_frame();
         (size, texels)
     }
 
@@ -4673,17 +4673,17 @@ pub struct RendererOptions {
     pub enable_aa: bool,
     pub enable_dithering: bool,
     pub max_recorded_profiles: usize,
     pub precache_flags: ShaderPrecacheFlags,
     pub renderer_kind: RendererKind,
     pub enable_subpixel_aa: bool,
     pub clear_color: Option<ColorF>,
     pub enable_clear_scissor: bool,
-    pub max_texture_size: Option<u32>,
+    pub max_texture_size: Option<i32>,
     pub scatter_gpu_cache_updates: bool,
     pub upload_method: UploadMethod,
     pub workers: Option<Arc<ThreadPool>>,
     pub blob_image_handler: Option<Box<BlobImageHandler>>,
     pub recorder: Option<Box<ApiRecordingReceiver>>,
     pub thread_listener: Option<Box<ThreadListener + Send + Sync>>,
     pub size_of_op: Option<VoidPtrToSizeFn>,
     pub cached_programs: Option<Rc<ProgramCache>>,
@@ -4775,17 +4775,17 @@ impl RendererStats {
 
 
 
 #[cfg(any(feature = "capture", feature = "replay"))]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct PlainTexture {
     data: String,
-    size: (u32, u32, i32),
+    size: (DeviceIntSize, i32),
     format: ImageFormat,
     filter: TextureFilter,
 }
 
 
 #[cfg(any(feature = "capture", feature = "replay"))]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -4845,18 +4845,18 @@ impl Renderer {
     ) -> PlainTexture {
         use std::fs;
         use std::io::Write;
 
         let short_path = format!("textures/{}.raw", name);
 
         let bytes_per_pixel = texture.get_format().bytes_per_pixel();
         let read_format = ReadPixelsFormat::Standard(texture.get_format());
-        let rect = DeviceUintRect::new(
-            DeviceUintPoint::zero(),
+        let rect = DeviceIntRect::new(
+            DeviceIntPoint::zero(),
             texture.get_dimensions(),
         );
 
         let mut file = fs::File::create(root.join(&short_path))
             .expect(&format!("Unable to create {}", short_path));
         let bytes_per_layer = (rect.size.width * rect.size.height * bytes_per_pixel) as usize;
         let mut data = vec![0; bytes_per_layer];
 
@@ -4873,28 +4873,28 @@ impl Renderer {
                         png_data = vec![0; (rect.size.width * rect.size.height * 4) as usize];
                         device.read_pixels_into(rect, ReadPixelsFormat::Rgba8, &mut png_data);
                         (&png_data, ReadPixelsFormat::Rgba8)
                     }
                     fm => (&data, ReadPixelsFormat::Standard(fm)),
                 };
                 CaptureConfig::save_png(
                     root.join(format!("textures/{}-{}.png", name, layer_id)),
-                    (rect.size.width, rect.size.height), format,
+                    rect.size, format,
                     data_ref,
                 );
             }
             device.read_pixels_into(rect, read_format, &mut data);
             file.write_all(&data)
                 .unwrap();
         }
 
         PlainTexture {
             data: short_path,
-            size: (rect.size.width, rect.size.height, texture.get_layer_count()),
+            size: (rect.size, texture.get_layer_count()),
             format: texture.get_format(),
             filter: texture.get_filter(),
         }
     }
 
     #[cfg(feature = "replay")]
     fn load_texture(
         target: TextureTarget,
@@ -4911,21 +4911,21 @@ impl Renderer {
         File::open(root.join(&plain.data))
             .expect(&format!("Unable to open texture at {}", plain.data))
             .read_to_end(&mut texels)
             .unwrap();
 
         let texture = device.create_texture(
             target,
             plain.format,
-            plain.size.0,
-            plain.size.1,
+            plain.size.0.width,
+            plain.size.0.height,
             plain.filter,
             rt_info,
-            plain.size.2,
+            plain.size.1,
         );
         device.upload_texture_immediate(&texture, &texels);
 
         (texture, texels)
     }
 
     #[cfg(feature = "capture")]
     fn save_capture(
@@ -5141,17 +5141,17 @@ impl Renderer {
 
                 let tid = match native_map.entry(plain_ext.data) {
                     Entry::Occupied(e) => e.get().clone(),
                     Entry::Vacant(e) => {
                         //TODO: provide a way to query both the layer count and the filter from external images
                         let (layer_count, filter) = (1, TextureFilter::Linear);
                         let plain_tex = PlainTexture {
                             data: e.key().clone(),
-                            size: (descriptor.size.width, descriptor.size.height, layer_count),
+                            size: (descriptor.size, layer_count),
                             format: descriptor.format,
                             filter,
                         };
                         let t = Self::load_texture(
                             target,
                             &plain_tex,
                             None,
                             &root,
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AddFont, BlobImageResources, AsyncBlobImageRasterizer, ResourceUpdate};
 use api::{BlobImageDescriptor, BlobImageHandler, BlobImageRequest, RasterizedBlobImage};
-use api::{ClearCache, ColorF, DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
+use api::{ClearCache, ColorF, DevicePoint, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
 use api::{ExternalImageData, ExternalImageType, BlobImageResult, BlobImageParams};
 use api::{FontInstanceData, FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
 use api::{GlyphDimensions, IdNamespace};
 use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
 use api::{MemoryReport, VoidPtrToSizeFn};
 use api::{TileOffset, TileSize, TileRange, BlobImageData};
 use app_units::Au;
@@ -64,26 +64,26 @@ pub struct GlyphFetchResult {
 // atlas can grow). When this happens, by
 // storing the coordinates as texel values
 // we don't need to go through and update
 // various CPU-side structures.
 #[derive(Debug, Clone)]
 pub struct CacheItem {
     pub texture_id: TextureSource,
     pub uv_rect_handle: GpuCacheHandle,
-    pub uv_rect: DeviceUintRect,
+    pub uv_rect: DeviceIntRect,
     pub texture_layer: i32,
 }
 
 impl CacheItem {
     pub fn invalid() -> Self {
         CacheItem {
             texture_id: TextureSource::Invalid,
             uv_rect_handle: GpuCacheHandle::new(),
-            uv_rect: DeviceUintRect::zero(),
+            uv_rect: DeviceIntRect::zero(),
             texture_layer: 0,
         }
     }
 }
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -106,30 +106,30 @@ enum RasterizedBlob {
     NonTiled(Vec<RasterizedBlobImage>),
 }
 
 /// Pre scene building state.
 /// We use this to generate the async blob rendering requests.
 struct BlobImageTemplate {
     descriptor: ImageDescriptor,
     tiling: Option<TileSize>,
-    dirty_rect: Option<DeviceUintRect>,
+    dirty_rect: Option<DeviceIntRect>,
     viewport_tiles: Option<TileRange>,
 }
 
 struct ImageResource {
     data: ImageData,
     descriptor: ImageDescriptor,
     tiling: Option<TileSize>,
     viewport_tiles: Option<TileRange>,
 }
 
 #[derive(Clone, Debug)]
 pub struct ImageTiling {
-    pub image_size: DeviceUintSize,
+    pub image_size: DeviceIntSize,
     pub tile_size: TileSize,
 }
 
 #[derive(Default)]
 struct ImageTemplates {
     images: FastHashMap<ImageKey, ImageResource>,
 }
 
@@ -150,17 +150,17 @@ impl ImageTemplates {
         self.images.get_mut(&key)
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct CachedImageInfo {
     texture_cache_handle: TextureCacheHandle,
-    dirty_rect: Option<DeviceUintRect>,
+    dirty_rect: Option<DeviceIntRect>,
     manual_eviction: bool,
 }
 
 #[cfg(debug_assertions)]
 impl Drop for CachedImageInfo {
     fn drop(&mut self) {
         debug_assert!(!self.manual_eviction, "Manual eviction requires cleanup");
     }
@@ -169,41 +169,41 @@ impl Drop for CachedImageInfo {
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ResourceClassCache<K: Hash + Eq, V, U: Default> {
     resources: FastHashMap<K, V>,
     pub user_data: U,
 }
 
 pub fn intersect_for_tile(
-    dirty: DeviceUintRect,
-    clipped_tile_size: DeviceUintSize,
+    dirty: DeviceIntRect,
+    clipped_tile_size: DeviceIntSize,
     tile_size: TileSize,
     tile_offset: TileOffset,
 
-) -> Option<DeviceUintRect> {
-    dirty.intersection(&DeviceUintRect::new(
-        DeviceUintPoint::new(
-            tile_offset.x as u32 * tile_size as u32,
-            tile_offset.y as u32 * tile_size as u32
+) -> Option<DeviceIntRect> {
+    dirty.intersection(&DeviceIntRect::new(
+        DeviceIntPoint::new(
+            tile_offset.x as i32 * tile_size as i32,
+            tile_offset.y as i32 * tile_size as i32
         ),
         clipped_tile_size,
     )).map(|mut r| {
         // we can't translate by a negative size so do it manually
-        r.origin.x -= tile_offset.x as u32 * tile_size as u32;
-        r.origin.y -= tile_offset.y as u32 * tile_size as u32;
+        r.origin.x -= tile_offset.x as i32 * tile_size as i32;
+        r.origin.y -= tile_offset.y as i32 * tile_size as i32;
         r
     })
 }
 
 fn merge_dirty_rect(
-    prev_dirty_rect: &Option<DeviceUintRect>,
-    dirty_rect: &Option<DeviceUintRect>,
+    prev_dirty_rect: &Option<DeviceIntRect>,
+    dirty_rect: &Option<DeviceIntRect>,
     descriptor: &ImageDescriptor,
-) -> Option<DeviceUintRect> {
+) -> Option<DeviceIntRect> {
     // It is important to never assume an empty dirty rect implies a full reupload here,
     // although we are able to do so elsewhere. We store the descriptor's full rect instead
     // There are update sequences which could cause us to forget the correct dirty regions
     // regions if we cleared the dirty rect when we received None, e.g.:
     //      1) Update with no dirty rect. We want to reupload everything.
     //      2) Update with dirty rect B. We still want to reupload everything, not just B.
     //      3) Perform the upload some time later.
     match (dirty_rect, prev_dirty_rect) {
@@ -450,21 +450,21 @@ impl ResourceCache {
             blob_image_handler,
             rasterized_blob_images: FastHashMap::default(),
             blob_image_templates: FastHashMap::default(),
             missing_blob_images: Vec::new(),
             blob_image_rasterizer: None,
         }
     }
 
-    pub fn max_texture_size(&self) -> u32 {
+    pub fn max_texture_size(&self) -> i32 {
         self.texture_cache.max_texture_size()
     }
 
-    fn should_tile(limit: u32, descriptor: &ImageDescriptor, data: &ImageData) -> bool {
+    fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &ImageData) -> bool {
         let size_check = descriptor.size.width > limit || descriptor.size.height > limit;
         match *data {
             ImageData::Raw(_) | ImageData::Blob(_) => size_check,
             ImageData::External(info) => {
                 // External handles already represent existing textures so it does
                 // not make sense to tile them into smaller ones.
                 info.image_type == ExternalImageType::Buffer && size_check
             }
@@ -747,17 +747,17 @@ impl ResourceCache {
         self.resources.image_templates.insert(image_key, resource);
     }
 
     pub fn update_image_template(
         &mut self,
         image_key: ImageKey,
         descriptor: ImageDescriptor,
         data: ImageData,
-        dirty_rect: Option<DeviceUintRect>,
+        dirty_rect: Option<DeviceIntRect>,
     ) {
         let max_texture_size = self.max_texture_size();
         let image = match self.resources.image_templates.get_mut(image_key) {
             Some(res) => res,
             None => panic!("Attempt to update non-existent image"),
         };
 
         let mut tiling = image.tiling;
@@ -775,18 +775,18 @@ impl ResourceCache {
                 for (key, entry) in entries.iter_mut() {
                     let merged_rect = merge_dirty_rect(&entry.dirty_rect, &dirty_rect, &descriptor);
 
                     entry.dirty_rect = match (key.tile, merged_rect) {
                         (Some(tile), Some(rect)) => {
                             let tile_size = image.tiling.unwrap();
                             let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
 
-                            rect.intersection(&DeviceUintRect::new(
-                                DeviceUintPoint::new(tile.x as u32, tile.y as u32) * tile_size as u32,
+                            rect.intersection(&DeviceIntRect::new(
+                                DeviceIntPoint::new(tile.x as i32, tile.y as i32) * tile_size as i32,
                                 clipped_tile_size,
                             ))
                         }
                         _ => merged_rect,
                     };
                 }
             }
             _ => {}
@@ -814,32 +814,32 @@ impl ResourceCache {
         self.blob_image_handler.as_mut().unwrap().add(key, data, tiling);
 
         self.blob_image_templates.insert(
             key,
             BlobImageTemplate {
                 descriptor: *descriptor,
                 tiling,
                 dirty_rect: Some(
-                    DeviceUintRect::new(
-                        DeviceUintPoint::zero(),
+                    DeviceIntRect::new(
+                        DeviceIntPoint::zero(),
                         descriptor.size,
                     )
                 ),
                 viewport_tiles: None,
             },
         );
     }
 
     // Happens before scene building.
     pub fn update_blob_image(
         &mut self,
         key: ImageKey,
         descriptor: &ImageDescriptor,
-        dirty_rect: &Option<DeviceUintRect>,
+        dirty_rect: &Option<DeviceIntRect>,
         data: Arc<BlobImageData>,
     ) {
         self.blob_image_handler.as_mut().unwrap().update(key, data, *dirty_rect);
 
         let max_texture_size = self.max_texture_size();
 
         let image = self.blob_image_templates
             .get_mut(&key)
@@ -899,17 +899,17 @@ impl ResourceCache {
 
         // Images that don't use the texture cache can early out.
         if !template.data.uses_texture_cache() {
             return;
         }
 
         let side_size =
             template.tiling.map_or(cmp::max(template.descriptor.size.width, template.descriptor.size.height),
-                                   |tile_size| tile_size as u32);
+                                   |tile_size| tile_size as i32);
         if side_size > self.texture_cache.max_texture_size() {
             // The image or tiling size is too big for hardware texture size.
             warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
                   template.descriptor.size.width, template.descriptor.size.height, template.tiling.unwrap_or(0));
             self.cached_images.insert(request.key, ImageResult::Err(ImageCacheError::OverLimitSize));
             return;
         }
 
@@ -1044,27 +1044,27 @@ impl ResourceCache {
             let template = self.blob_image_templates.get_mut(key).unwrap();
 
             if let Some(tile_size) = template.tiling {
                 // If we know that only a portion of the blob image is in the viewport,
                 // only request these visible tiles since blob images can be huge.
                 let mut tiles = template.viewport_tiles.unwrap_or_else(|| {
                     // Default to requesting the full range of tiles.
                     compute_tile_range(
-                        &DeviceUintRect {
+                        &DeviceIntRect {
                             origin: point2(0, 0),
                             size: template.descriptor.size,
                         },
                         tile_size,
                     )
                 });
 
                 // Don't request tiles that weren't invalidated.
                 if let Some(dirty_rect) = template.dirty_rect {
-                    let dirty_rect = DeviceUintRect {
+                    let dirty_rect = DeviceIntRect {
                         origin: point2(
                             dirty_rect.origin.x,
                             dirty_rect.origin.y,
                         ),
                         size: size2(
                             dirty_rect.size.width,
                             dirty_rect.size.height,
                         ),
@@ -1075,18 +1075,18 @@ impl ResourceCache {
                     );
 
                     tiles = tiles.intersection(&dirty_tiles).unwrap_or(TileRange::zero());
                 }
 
                 // This code tries to keep things sane if Gecko sends
                 // nonsensical blob image requests.
                 // Constant here definitely needs to be tweaked.
-                const MAX_TILES_PER_REQUEST: u32 = 64;
-                while tiles.size.width as u32 * tiles.size.height as u32 > MAX_TILES_PER_REQUEST {
+                const MAX_TILES_PER_REQUEST: i32 = 64;
+                while tiles.size.width as i32 * tiles.size.height as i32 > MAX_TILES_PER_REQUEST {
                     // Remove tiles in the largest dimension.
                     if tiles.size.width > tiles.size.height {
                         tiles.size.width -= 2;
                         tiles.origin.x += 1;
                     } else {
                         tiles.size.height -= 2;
                         tiles.origin.y += 1;
                     }
@@ -1174,17 +1174,17 @@ impl ResourceCache {
         let handler = self.blob_image_handler.as_mut().unwrap();
         handler.prepare_resources(&self.resources, &blob_request_params);
         (Some(handler.create_blob_rasterizer()), blob_request_params)
     }
 
     fn discard_tiles_outside_visible_area(
         &mut self,
         key: ImageKey,
-        area: &DeviceUintRect
+        area: &DeviceIntRect
     ) {
         let template = match self.blob_image_templates.get(&key) {
             Some(template) => template,
             None => {
                 //println!("Missing image template (key={:?})!", key);
                 return;
             }
         };
@@ -1478,17 +1478,17 @@ impl ResourceCache {
         self.missing_blob_images.clear();
     }
 
     fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
         for request in self.pending_image_requests.drain() {
             let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
             debug_assert!(image_template.data.uses_texture_cache());
 
-            let mut updates: SmallVec<[(ImageData, Option<DeviceUintRect>); 1]> = SmallVec::new();
+            let mut updates: SmallVec<[(ImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
 
             match image_template.data {
                 ImageData::Raw(..) | ImageData::External(..) => {
                     // Safe to clone here since the Raw image data is an
                     // Arc, and the external image data is small.
                     updates.push((image_template.data.clone(), None));
                 }
                 ImageData::Blob(..) => {
@@ -1547,18 +1547,18 @@ impl ResourceCache {
                     // already broken up into tiles. This affects the way we compute the stride
                     // and offset.
                     let tiled_on_cpu = image_template.data.is_blob();
                     if !tiled_on_cpu {
                         let bpp = descriptor.format.bytes_per_pixel();
                         let stride = descriptor.compute_stride();
                         descriptor.stride = Some(stride);
                         descriptor.offset +=
-                            tile.y as u32 * tile_size as u32 * stride +
-                            tile.x as u32 * tile_size as u32 * bpp;
+                            tile.y as i32 * tile_size as i32 * stride +
+                            tile.x as i32 * tile_size as i32 * bpp;
                     }
 
                     descriptor.size = clipped_tile_size;
                 } else {
                     local_dirty_rect = entry.dirty_rect.take();
                 }
 
                 // If we are uploading the dirty region of a blob image we might have several
@@ -1727,45 +1727,45 @@ impl Drop for ResourceCache {
     fn drop(&mut self) {
         self.clear_images(|_| true);
     }
 }
 
 pub fn get_blob_tiling(
     tiling: Option<TileSize>,
     descriptor: &ImageDescriptor,
-    max_texture_size: u32,
+    max_texture_size: i32,
 ) -> Option<TileSize> {
     if tiling.is_none() &&
         (descriptor.size.width > max_texture_size ||
          descriptor.size.height > max_texture_size) {
         return Some(DEFAULT_TILE_SIZE);
     }
 
     tiling
 }
 
 
 // Compute the width and height of a tile depending on its position in the image.
 pub fn compute_tile_size(
     descriptor: &ImageDescriptor,
     base_size: TileSize,
     tile: TileOffset,
-) -> DeviceUintSize {
-    let base_size = base_size as u32;
+) -> DeviceIntSize {
+    let base_size = base_size as i32;
     // Most tiles are going to have base_size as width and height,
     // except for tiles around the edges that are shrunk to fit the mage data
     // (See decompose_tiled_image in frame.rs).
-    let actual_width = if (tile.x as u32) < descriptor.size.width / base_size {
+    let actual_width = if (tile.x as i32) < descriptor.size.width / base_size {
         base_size
     } else {
         descriptor.size.width % base_size
     };
 
-    let actual_height = if (tile.y as u32) < descriptor.size.height / base_size {
+    let actual_height = if (tile.y as i32) < descriptor.size.height / base_size {
         base_size
     } else {
         descriptor.size.height % base_size
     };
 
     size2(actual_width, actual_height)
 }
 
@@ -1886,17 +1886,17 @@ impl ResourceCache {
                     let entry = match image_paths.entry(arc.as_ptr()) {
                         Entry::Occupied(_) => continue,
                         Entry::Vacant(e) => e,
                     };
 
                     #[cfg(feature = "png")]
                     CaptureConfig::save_png(
                         root.join(format!("images/{}.png", image_id)),
-                        (desc.size.width, desc.size.height),
+                        desc.size,
                         ReadPixelsFormat::Standard(desc.format),
                         &arc,
                     );
                     let file_name = format!("{}.raw", image_id);
                     let short_path = format!("images/{}", file_name);
                     fs::File::create(path_images.join(file_name))
                         .expect(&format!("Unable to create {}", short_path))
                         .write_all(&*arc)
@@ -1930,17 +1930,17 @@ impl ResourceCache {
 
                     assert_eq!(result.rasterized_rect.size, desc.size);
                     assert_eq!(result.data.len(), desc.compute_total_size() as usize);
 
                     num_blobs += 1;
                     #[cfg(feature = "png")]
                     CaptureConfig::save_png(
                         root.join(format!("blobs/{}.png", num_blobs)),
-                        (desc.size.width, desc.size.height),
+                        desc.size,
                         ReadPixelsFormat::Standard(desc.format),
                         &result.data,
                     );
                     let file_name = format!("{}.raw", num_blobs);
                     let short_path = format!("blobs/{}", file_name);
                     let full_path = path_blobs.clone().join(&file_name);
                     fs::File::create(full_path)
                         .expect(&format!("Unable to create {}", short_path))
--- a/gfx/webrender/src/texture_allocator.rs
+++ b/gfx/webrender/src/texture_allocator.rs
@@ -1,57 +1,57 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize};
+use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use std::slice::Iter;
 use util;
 
 /// The minimum number of pixels on each side that we require for rects to be classified as
 /// "medium" within the free list.
-const MINIMUM_MEDIUM_RECT_SIZE: u32 = 16;
+const MINIMUM_MEDIUM_RECT_SIZE: i32 = 16;
 
 /// The minimum number of pixels on each side that we require for rects to be classified as
 /// "large" within the free list.
-const MINIMUM_LARGE_RECT_SIZE: u32 = 32;
+const MINIMUM_LARGE_RECT_SIZE: i32 = 32;
 
 /// A texture allocator using the guillotine algorithm with the rectangle merge improvement. See
 /// sections 2.2 and 2.2.5 in "A Thousand Ways to Pack the Bin - A Practical Approach to Two-
 /// Dimensional Rectangle Bin Packing":
 ///
 ///    http://clb.demon.fi/files/RectangleBinPack.pdf
 ///
 /// This approach was chosen because of its simplicity, good performance, and easy support for
 /// dynamic texture deallocation.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct GuillotineAllocator {
-    texture_size: DeviceUintSize,
+    texture_size: DeviceIntSize,
     free_list: FreeRectList,
     allocations: u32,
     dirty: bool,
 }
 
 impl GuillotineAllocator {
-    pub fn new(texture_size: DeviceUintSize) -> GuillotineAllocator {
+    pub fn new(texture_size: DeviceIntSize) -> GuillotineAllocator {
         let mut page = GuillotineAllocator {
             texture_size,
             free_list: FreeRectList::new(),
             allocations: 0,
             dirty: false,
         };
         page.clear();
         page
     }
 
     fn find_index_of_best_rect_in_bin(
         &self,
         bin: FreeListBin,
-        requested_dimensions: &DeviceUintSize,
+        requested_dimensions: &DeviceIntSize,
     ) -> Option<FreeListIndex> {
         let mut smallest_index_and_area = None;
         for (candidate_index, candidate_rect) in self.free_list.iter(bin).enumerate() {
             if !requested_dimensions.fits_inside(&candidate_rect.size) {
                 continue;
             }
 
             let candidate_area = candidate_rect.size.width * candidate_rect.size.height;
@@ -61,85 +61,85 @@ impl GuillotineAllocator {
 
         smallest_index_and_area.map(|(index, _)| FreeListIndex(bin, index))
     }
 
     /// Find a suitable rect in the free list. We choose the smallest such rect
     /// in terms of area (Best-Area-Fit, BAF).
     fn find_index_of_best_rect(
         &self,
-        requested_dimensions: &DeviceUintSize,
+        requested_dimensions: &DeviceIntSize,
     ) -> Option<FreeListIndex> {
         let bin = FreeListBin::for_size(requested_dimensions);
         for &target_bin in &[FreeListBin::Small, FreeListBin::Medium, FreeListBin::Large] {
             if bin <= target_bin {
                 if let Some(index) =
                     self.find_index_of_best_rect_in_bin(target_bin, requested_dimensions)
                 {
                     return Some(index);
                 }
             }
         }
         None
     }
 
-    pub fn allocate(&mut self, requested_dimensions: &DeviceUintSize) -> Option<DeviceUintPoint> {
+    pub fn allocate(&mut self, requested_dimensions: &DeviceIntSize) -> Option<DeviceIntPoint> {
         if requested_dimensions.width == 0 || requested_dimensions.height == 0 {
-            return Some(DeviceUintPoint::new(0, 0));
+            return Some(DeviceIntPoint::new(0, 0));
         }
         let index = match self.find_index_of_best_rect(requested_dimensions) {
             None => return None,
             Some(index) => index,
         };
 
         // Remove the rect from the free list and decide how to guillotine it. We choose the split
         // that results in the single largest area (Min Area Split Rule, MINAS).
         let chosen_rect = self.free_list.remove(index);
-        let candidate_free_rect_to_right = DeviceUintRect::new(
-            DeviceUintPoint::new(
+        let candidate_free_rect_to_right = DeviceIntRect::new(
+            DeviceIntPoint::new(
                 chosen_rect.origin.x + requested_dimensions.width,
                 chosen_rect.origin.y,
             ),
-            DeviceUintSize::new(
+            DeviceIntSize::new(
                 chosen_rect.size.width - requested_dimensions.width,
                 requested_dimensions.height,
             ),
         );
-        let candidate_free_rect_to_bottom = DeviceUintRect::new(
-            DeviceUintPoint::new(
+        let candidate_free_rect_to_bottom = DeviceIntRect::new(
+            DeviceIntPoint::new(
                 chosen_rect.origin.x,
                 chosen_rect.origin.y + requested_dimensions.height,
             ),
-            DeviceUintSize::new(
+            DeviceIntSize::new(
                 requested_dimensions.width,
                 chosen_rect.size.height - requested_dimensions.height,
             ),
         );
         let candidate_free_rect_to_right_area =
             candidate_free_rect_to_right.size.width * candidate_free_rect_to_right.size.height;
         let candidate_free_rect_to_bottom_area =
             candidate_free_rect_to_bottom.size.width * candidate_free_rect_to_bottom.size.height;
 
         // Guillotine the rectangle.
         let new_free_rect_to_right;
         let new_free_rect_to_bottom;
         if candidate_free_rect_to_right_area > candidate_free_rect_to_bottom_area {
-            new_free_rect_to_right = DeviceUintRect::new(
+            new_free_rect_to_right = DeviceIntRect::new(
                 candidate_free_rect_to_right.origin,
-                DeviceUintSize::new(
+                DeviceIntSize::new(
                     candidate_free_rect_to_right.size.width,
                     chosen_rect.size.height,
                 ),
             );
             new_free_rect_to_bottom = candidate_free_rect_to_bottom
         } else {
             new_free_rect_to_right = candidate_free_rect_to_right;
-            new_free_rect_to_bottom = DeviceUintRect::new(
+            new_free_rect_to_bottom = DeviceIntRect::new(
                 candidate_free_rect_to_bottom.origin,
-                DeviceUintSize::new(
+                DeviceIntSize::new(
                     chosen_rect.size.width,
                     candidate_free_rect_to_bottom.size.height,
                 ),
             )
         }
 
         // Add the guillotined rects back to the free list. If any changes were made, we're now
         // dirty since coalescing might be able to defragment.
@@ -156,61 +156,61 @@ impl GuillotineAllocator {
         self.allocations += 1;
 
         // Return the result.
         Some(chosen_rect.origin)
     }
 
     fn clear(&mut self) {
         self.free_list = FreeRectList::new();
-        self.free_list.push(&DeviceUintRect::new(
-            DeviceUintPoint::zero(),
+        self.free_list.push(&DeviceIntRect::new(
+            DeviceIntPoint::zero(),
             self.texture_size,
         ));
         self.allocations = 0;
         self.dirty = false;
     }
 }
 
 /// A binning free list. Binning is important to avoid sifting through lots of small strips when
 /// allocating many texture items.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct FreeRectList {
-    small: Vec<DeviceUintRect>,
-    medium: Vec<DeviceUintRect>,
-    large: Vec<DeviceUintRect>,
+    small: Vec<DeviceIntRect>,
+    medium: Vec<DeviceIntRect>,
+    large: Vec<DeviceIntRect>,
 }
 
 impl FreeRectList {
     fn new() -> Self {
         FreeRectList {
             small: vec![],
             medium: vec![],
             large: vec![],
         }
     }
 
-    fn push(&mut self, rect: &DeviceUintRect) {
+    fn push(&mut self, rect: &DeviceIntRect) {
         match FreeListBin::for_size(&rect.size) {
             FreeListBin::Small => self.small.push(*rect),
             FreeListBin::Medium => self.medium.push(*rect),
             FreeListBin::Large => self.large.push(*rect),
         }
     }
 
-    fn remove(&mut self, index: FreeListIndex) -> DeviceUintRect {
+    fn remove(&mut self, index: FreeListIndex) -> DeviceIntRect {
         match index.0 {
             FreeListBin::Small => self.small.swap_remove(index.1),
             FreeListBin::Medium => self.medium.swap_remove(index.1),
             FreeListBin::Large => self.large.swap_remove(index.1),
         }
     }
 
-    fn iter(&self, bin: FreeListBin) -> Iter<DeviceUintRect> {
+    fn iter(&self, bin: FreeListBin) -> Iter<DeviceIntRect> {
         match bin {
             FreeListBin::Small => self.small.iter(),
             FreeListBin::Medium => self.medium.iter(),
             FreeListBin::Large => self.large.iter(),
         }
     }
 }
 
@@ -220,30 +220,30 @@ struct FreeListIndex(FreeListBin, usize)
 #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
 enum FreeListBin {
     Small,
     Medium,
     Large,
 }
 
 impl FreeListBin {
-    fn for_size(size: &DeviceUintSize) -> FreeListBin {
+    fn for_size(size: &DeviceIntSize) -> FreeListBin {
         if size.width >= MINIMUM_LARGE_RECT_SIZE && size.height >= MINIMUM_LARGE_RECT_SIZE {
             FreeListBin::Large
         } else if size.width >= MINIMUM_MEDIUM_RECT_SIZE && size.height >= MINIMUM_MEDIUM_RECT_SIZE
         {
             FreeListBin::Medium
         } else {
             debug_assert!(size.width > 0 && size.height > 0);
             FreeListBin::Small
         }
     }
 }
 
 trait FitsInside {
     fn fits_inside(&self, other: &Self) -> bool;
 }
 
-impl FitsInside for DeviceUintSize {
-    fn fits_inside(&self, other: &DeviceUintSize) -> bool {
+impl FitsInside for DeviceIntSize {
+    fn fits_inside(&self, other: &DeviceIntSize) -> bool {
         self.width <= other.width && self.height <= other.height
     }
 }
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize};
+use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{ExternalImageType, ImageData, ImageFormat};
 use api::ImageDescriptor;
 use device::{TextureFilter, total_gpu_bytes_allocated};
 use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle};
 use gpu_cache::{GpuCache, GpuCacheHandle};
 use gpu_types::{ImageSource, UvRectKind};
 use internal_types::{CacheTextureId, LayerIndex, TextureUpdateList, TextureUpdateSource};
 use internal_types::{TextureSource, TextureCacheAllocInfo, TextureCacheUpdate};
@@ -15,28 +15,28 @@ use profiler::{ResourceProfileCounter, T
 use render_backend::FrameId;
 use resource_cache::CacheItem;
 use std::cell::Cell;
 use std::cmp;
 use std::mem;
 use std::rc::Rc;
 
 /// The size of each region/layer in shared cache texture arrays.
-const TEXTURE_REGION_DIMENSIONS: u32 = 512;
+const TEXTURE_REGION_DIMENSIONS: i32 = 512;
 
 /// Items in the texture cache can either be standalone textures,
 /// or a sub-rect inside the shared cache.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 enum EntryDetails {
     Standalone,
     Cache {
         // Origin within the texture layer where this item exists.
-        origin: DeviceUintPoint,
+        origin: DeviceIntPoint,
         // The layer index of the texture array.
         layer_index: usize,
     },
 }
 
 impl EntryDetails {
     /// Returns the kind associated with the details.
     fn kind(&self) -> EntryKind {
@@ -60,17 +60,17 @@ pub enum CacheEntryMarker {}
 // Stores information related to a single entry in the texture
 // cache. This is stored for each item whether it's in the shared
 // cache or a standalone texture.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct CacheEntry {
     /// Size the requested item, in device pixels.
-    size: DeviceUintSize,
+    size: DeviceIntSize,
     /// Details specific to standalone or shared items.
     details: EntryDetails,
     /// Arbitrary user data associated with this item.
     user_data: [f32; 3],
     /// The last frame this item was requested for rendering.
     last_access: FrameId,
     /// Handle to the resource rect in the GPU cache.
     uv_rect_handle: GpuCacheHandle,
@@ -111,17 +111,17 @@ impl CacheEntry {
 
     // Update the GPU cache for this texture cache entry.
     // This ensures that the UV rect, and texture layer index
     // are up to date in the GPU cache for vertex shaders
     // to fetch from.
     fn update_gpu_cache(&mut self, gpu_cache: &mut GpuCache) {
         if let Some(mut request) = gpu_cache.request(&mut self.uv_rect_handle) {
             let (origin, layer_index) = match self.details {
-                EntryDetails::Standalone { .. } => (DeviceUintPoint::zero(), 0.0),
+                EntryDetails::Standalone { .. } => (DeviceIntPoint::zero(), 0.0),
                 EntryDetails::Cache {
                     origin,
                     layer_index,
                     ..
                 } => (origin, layer_index as f32),
             };
             let image_source = ImageSource {
                 p0: origin.to_f32(),
@@ -309,17 +309,17 @@ struct CacheAllocParams {
 /// live view of its contents in Firefox.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct TextureCache {
     /// Set of texture arrays in different formats used for the shared cache.
     shared_textures: SharedTextures,
 
     /// Maximum texture size supported by hardware.
-    max_texture_size: u32,
+    max_texture_size: i32,
 
     /// Maximum number of texture layers supported by hardware.
     max_texture_layers: usize,
 
     /// The next unused virtual texture ID. Monotonically increasing.
     next_id: CacheTextureId,
 
     /// A list of allocations and updates that need to be applied to the texture
@@ -336,17 +336,17 @@ pub struct TextureCache {
     /// Maintains the list of all current items in the texture cache.
     entries: FreeList<CacheEntry, CacheEntryMarker>,
 
     /// Strong handles for all entries allocated from the above `FreeList`.
     handles: EntryHandles,
 }
 
 impl TextureCache {
-    pub fn new(max_texture_size: u32, mut max_texture_layers: usize) -> Self {
+    pub fn new(max_texture_size: i32, mut max_texture_layers: usize) -> 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.
             //
             // So we clamp the number of layers on mac. This results in maximum
@@ -362,16 +362,17 @@ impl TextureCache {
             //   * The bug we're working around is likely specific to a single
             //     driver family, and those drivers are also likely to share
             //     the same max texture size of 16k. If we do encounter a driver
             //     with the same bug but a lower max texture size, we might need
             //     to rethink our strategy anyway, since a limit below 32MB might
             //     start to introduce performance issues.
             max_texture_layers = max_texture_layers.min(32);
         }
+
         TextureCache {
             shared_textures: SharedTextures::new(),
             max_texture_size,
             max_texture_layers,
             next_id: CacheTextureId(1),
             pending_updates: TextureUpdateList::new(),
             frame_id: FrameId::INVALID,
             last_shared_cache_expiration: FrameId::INVALID,
@@ -448,17 +449,17 @@ impl TextureCache {
 
     // Returns true if the image needs to be uploaded to the
     // texture cache (either never uploaded, or has been
     // evicted on a previous frame).
     pub fn needs_upload(&self, handle: &TextureCacheHandle) -> bool {
         self.entries.get_opt(handle).is_none()
     }
 
-    pub fn max_texture_size(&self) -> u32 {
+    pub fn max_texture_size(&self) -> i32 {
         self.max_texture_size
     }
 
     #[allow(dead_code)]
     pub fn max_texture_layers(&self) -> usize {
         self.max_texture_layers
     }
 
@@ -469,17 +470,17 @@ impl TextureCache {
     // Update the data stored by a given texture cache handle.
     pub fn update(
         &mut self,
         handle: &mut TextureCacheHandle,
         descriptor: ImageDescriptor,
         filter: TextureFilter,
         data: Option<ImageData>,
         user_data: [f32; 3],
-        mut dirty_rect: Option<DeviceUintRect>,
+        mut dirty_rect: Option<DeviceIntRect>,
         gpu_cache: &mut GpuCache,
         eviction_notice: Option<&EvictionNotice>,
         uv_rect_kind: UvRectKind,
         eviction: Eviction,
     ) {
         // Determine if we need to allocate texture cache memory
         // for this item. We need to reallocate if any of the following
         // is true:
@@ -520,17 +521,17 @@ impl TextureCache {
 
         entry.eviction = eviction;
 
         // Create an update command, which the render thread processes
         // to upload the new image data into the correct location
         // in GPU memory.
         if let Some(data) = data {
             let (layer_index, origin) = match entry.details {
-                EntryDetails::Standalone { .. } => (0, DeviceUintPoint::zero()),
+                EntryDetails::Standalone { .. } => (0, DeviceIntPoint::zero()),
                 EntryDetails::Cache {
                     layer_index,
                     origin,
                     ..
                 } => (layer_index, origin),
             };
 
             let op = TextureCacheUpdate::new_update(
@@ -569,57 +570,57 @@ impl TextureCache {
     // tries to get a handle that was not requested this frame.
     pub fn get(&self, handle: &TextureCacheHandle) -> CacheItem {
         let entry = self.entries
             .get_opt(handle)
             .expect("BUG: was dropped from cache or not updated!");
         debug_assert_eq!(entry.last_access, self.frame_id);
         let (layer_index, origin) = match entry.details {
             EntryDetails::Standalone { .. } => {
-                (0, DeviceUintPoint::zero())
+                (0, DeviceIntPoint::zero())
             }
             EntryDetails::Cache {
                 layer_index,
                 origin,
                 ..
             } => (layer_index, origin),
         };
         CacheItem {
             uv_rect_handle: entry.uv_rect_handle,
             texture_id: TextureSource::TextureCache(entry.texture_id),
-            uv_rect: DeviceUintRect::new(origin, entry.size),
+            uv_rect: DeviceIntRect::new(origin, entry.size),
             texture_layer: layer_index as i32,
         }
     }
 
     /// A more detailed version of get(). This allows access to the actual
     /// device rect of the cache allocation.
     ///
     /// Returns a tuple identifying the texture, the layer, and the region.
     pub fn get_cache_location(
         &self,
         handle: &TextureCacheHandle,
-    ) -> (CacheTextureId, LayerIndex, DeviceUintRect) {
+    ) -> (CacheTextureId, LayerIndex, DeviceIntRect) {
         let entry = self.entries
             .get_opt(handle)
             .expect("BUG: was dropped from cache or not updated!");
         debug_assert_eq!(entry.last_access, self.frame_id);
         let (layer_index, origin) = match entry.details {
             EntryDetails::Standalone { .. } => {
-                (0, DeviceUintPoint::zero())
+                (0, DeviceIntPoint::zero())
             }
             EntryDetails::Cache {
                 layer_index,
                 origin,
                 ..
             } => (layer_index, origin),
         };
         (entry.texture_id,
          layer_index as usize,
-         DeviceUintRect::new(origin, entry.size))
+         DeviceIntRect::new(origin, entry.size))
     }
 
     pub fn mark_unused(&mut self, handle: &TextureCacheHandle) {
         if let Some(entry) = self.entries.get_opt_mut(handle) {
             // Set last accessed frame to invalid to ensure it gets cleaned up
             // next time we expire entries.
             entry.last_access = FrameId::INVALID;
             entry.eviction = Eviction::Auto;
@@ -915,22 +916,22 @@ impl TextureCache {
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Copy, Clone, PartialEq)]
 struct SlabSize {
-    width: u32,
-    height: u32,
+    width: i32,
+    height: i32,
 }
 
 impl SlabSize {
-    fn new(size: DeviceUintSize) -> SlabSize {
+    fn new(size: DeviceIntSize) -> SlabSize {
         let x_size = quantize_dimension(size.width);
         let y_size = quantize_dimension(size.height);
 
         assert!(x_size > 0 && x_size <= TEXTURE_REGION_DIMENSIONS);
         assert!(y_size > 0 && y_size <= TEXTURE_REGION_DIMENSIONS);
 
         let (width, height) = match (x_size, y_size) {
             // Special cased rectangular slab pages.
@@ -963,18 +964,18 @@ impl SlabSize {
 }
 
 // The x/y location within a texture region of an allocation.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct TextureLocation(u8, u8);
 
 impl TextureLocation {
-    fn new(x: u32, y: u32) -> Self {
-        debug_assert!(x < 0x100 && y < 0x100);
+    fn new(x: i32, y: i32) -> Self {
+        debug_assert!(x >= 0 && y >= 0 && x < 0x100 && y < 0x100);
         TextureLocation(x as u8, y as u8)
     }
 }
 
 /// A region corresponds to a layer in a shared cache texture.
 ///
 /// All allocations within a region are of the same size.
 #[cfg_attr(feature = "capture", derive(Serialize))]
@@ -1023,29 +1024,29 @@ impl TextureRegion {
         self.total_slot_count = 0;
     }
 
     fn is_empty(&self) -> bool {
         self.slab_size == SlabSize::invalid()
     }
 
     // Attempt to allocate a fixed size block from this region.
-    fn alloc(&mut self) -> Option<DeviceUintPoint> {
+    fn alloc(&mut self) -> Option<DeviceIntPoint> {
         debug_assert!(self.slab_size != SlabSize::invalid());
 
         self.free_slots.pop().map(|location| {
-            DeviceUintPoint::new(
-                self.slab_size.width * location.0 as u32,
-                self.slab_size.height * location.1 as u32,
+            DeviceIntPoint::new(
+                self.slab_size.width * location.0 as i32,
+                self.slab_size.height * location.1 as i32,
             )
         })
     }
 
     // Free a block in this region.
-    fn free(&mut self, point: DeviceUintPoint) {
+    fn free(&mut self, point: DeviceIntPoint) {
         let x = point.x / self.slab_size.width;
         let y = point.y / self.slab_size.height;
         self.free_slots.push(TextureLocation::new(x, y));
 
         // If this region is completely unused, deinit it
         // so that it can become a different slab size
         // as required.
         if self.free_slots.len() == self.total_slot_count {
@@ -1083,17 +1084,17 @@ impl TextureArray {
         if let Some(id) = self.texture_id.take() {
             updates.push_free(id);
         }
     }
 
     fn update_profile(&self, counter: &mut ResourceProfileCounter) {
         let layer_count = self.regions.len();
         if layer_count != 0 {
-            let size = layer_count as u32 * TEXTURE_REGION_DIMENSIONS *
+            let size = layer_count as i32 * TEXTURE_REGION_DIMENSIONS *
                 TEXTURE_REGION_DIMENSIONS * self.format.bytes_per_pixel();
             counter.set(layer_count as usize, size as usize);
         } else {
             counter.set(0, 0);
         }
     }
 
     /// Allocate space in this texture array.
@@ -1167,21 +1168,21 @@ impl TextureArray {
 
 impl TextureCacheUpdate {
     // Constructs a TextureCacheUpdate operation to be passed to the
     // rendering thread in order to do an upload to the right
     // location in the texture cache.
     fn new_update(
         data: ImageData,
         descriptor: &ImageDescriptor,
-        origin: DeviceUintPoint,
-        size: DeviceUintSize,
+        origin: DeviceIntPoint,
+        size: DeviceIntSize,
         texture_id: CacheTextureId,
         layer_index: i32,
-        dirty_rect: Option<DeviceUintRect>,
+        dirty_rect: Option<DeviceIntRect>,
     ) -> TextureCacheUpdate {
         let source = match data {
             ImageData::Blob(..) => {
                 panic!("The vector image should have been rasterized.");
             }
             ImageData::External(ext_image) => match ext_image.image_type {
                 ExternalImageType::TextureHandle(_) => {
                     panic!("External texture handle should not go through texture_cache.");
@@ -1204,46 +1205,46 @@ impl TextureCacheUpdate {
         let update_op = match dirty_rect {
             Some(dirty) => {
                 // the dirty rectangle doesn't have to be within the area but has to intersect it, at least
                 let stride = descriptor.compute_stride();
                 let offset = descriptor.offset + dirty.origin.y * stride + dirty.origin.x * descriptor.format.bytes_per_pixel();
 
                 TextureCacheUpdate {
                     id: texture_id,
-                    rect: DeviceUintRect::new(
-                        DeviceUintPoint::new(origin.x + dirty.origin.x, origin.y + dirty.origin.y),
-                        DeviceUintSize::new(
+                    rect: DeviceIntRect::new(
+                        DeviceIntPoint::new(origin.x + dirty.origin.x, origin.y + dirty.origin.y),
+                        DeviceIntSize::new(
                             dirty.size.width.min(size.width - dirty.origin.x),
                             dirty.size.height.min(size.height - dirty.origin.y),
                         ),
                     ),
                     source,
                     stride: Some(stride),
                     offset,
                     layer_index,
                 }
             }
             None => {
                 TextureCacheUpdate {
                     id: texture_id,
-                    rect: DeviceUintRect::new(origin, size),
+                    rect: DeviceIntRect::new(origin, size),
                     source,
                     stride: descriptor.stride,
                     offset: descriptor.offset,
                     layer_index,
                 }
             }
         };
 
         update_op
     }
 }
 
-fn quantize_dimension(size: u32) -> u32 {
+fn quantize_dimension(size: i32) -> i32 {
     match size {
         0 => unreachable!(),
         1...16 => 16,
         17...32 => 32,
         33...64 => 64,
         65...128 => 128,
         129...256 => 256,
         257...512 => 512,
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ColorF, BorderStyle, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
-use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FilterOp, ImageFormat};
+use api::{DocumentLayer, FilterOp, ImageFormat};
 use api::{MixBlendMode, PipelineId, DeviceRect, LayoutSize};
 use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image};
 use clip::ClipStore;
 use clip_scroll_tree::{ClipScrollTree};
 use device::{Texture};
 #[cfg(feature = "pathfinder")]
 use euclid::{TypedPoint2D, TypedVector2D};
 use gpu_cache::{GpuCache};
@@ -31,17 +31,17 @@ use webrender_api::{DevicePixel, FontRen
 
 const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
 const STYLE_MASK: i32 = 0x00FF_FF00;
 
 /// According to apitrace, textures larger than 2048 break fast clear
 /// optimizations on some intel drivers. We sometimes need to go larger, but
 /// we try to avoid it. This can go away when proper tiling support lands,
 /// since we can then split large primitives across multiple textures.
-const IDEAL_MAX_TEXTURE_DIMENSION: u32 = 2048;
+const IDEAL_MAX_TEXTURE_DIMENSION: i32 = 2048;
 
 /// Identifies a given `RenderTarget` in a `RenderTargetList`.
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTargetIndex(pub usize);
 
 pub struct RenderTargetContext<'a, 'rc> {
@@ -65,30 +65,30 @@ struct TextureAllocator {
 
     // Track the used rect of the render target, so that
     // we can set a scissor rect and only clear to the
     // used portion of the target as an optimization.
     used_rect: DeviceIntRect,
 }
 
 impl TextureAllocator {
-    fn new(size: DeviceUintSize) -> Self {
+    fn new(size: DeviceIntSize) -> Self {
         TextureAllocator {
             allocator: GuillotineAllocator::new(size),
             used_rect: DeviceIntRect::zero(),
         }
     }
 
-    fn allocate(&mut self, size: &DeviceUintSize) -> Option<DeviceUintPoint> {
+    fn allocate(&mut self, size: &DeviceIntSize) -> Option<DeviceIntPoint> {
         let origin = self.allocator.allocate(size);
 
         if let Some(origin) = origin {
             // TODO(gw): We need to make all the device rects
             //           be consistent in the use of the
-            //           DeviceIntRect and DeviceUintRect types!
+            //           DeviceIntRect and DeviceIntRect types!
             let origin = DeviceIntPoint::new(origin.x as i32, origin.y as i32);
             let size = DeviceIntSize::new(size.width as i32, size.height as i32);
             let rect = DeviceIntRect::new(origin, size);
             self.used_rect = rect.union(&self.used_rect);
         }
 
         origin
     }
@@ -105,26 +105,26 @@ impl TextureAllocator {
 /// into draw commands on that surface.
 ///
 /// We express this as a trait to generalize over color and alpha surfaces.
 /// a given `RenderTask` will draw to one or the other, depending on its type
 /// and sometimes on its parameters. See `RenderTask::target_kind`.
 pub trait RenderTarget {
     /// Creates a new RenderTarget of the given type.
     fn new(
-        size: Option<DeviceUintSize>,
+        size: Option<DeviceIntSize>,
         screen_size: DeviceIntSize,
     ) -> Self;
 
     /// Allocates a region of the given size in this target, and returns either
     /// the offset of that region or `None` if it won't fit.
     ///
     /// If a non-`None` result is returned, that value is generally stored in
     /// a task which is then added to this target via `add_task()`.
-    fn allocate(&mut self, size: DeviceUintSize) -> Option<DeviceUintPoint>;
+    fn allocate(&mut self, size: DeviceIntSize) -> Option<DeviceIntPoint>;
 
     /// Optional hook to provide additional processing for the target at the
     /// end of the build phase.
     fn build(
         &mut self,
         _ctx: &mut RenderTargetContext,
         _gpu_cache: &mut GpuCache,
         _render_tasks: &mut RenderTaskTree,
@@ -199,30 +199,30 @@ pub struct RenderTargetList<T> {
     pub format: ImageFormat,
     /// The maximum width and height of any single primitive we've encountered
     /// that will be drawn to a dynamic location.
     ///
     /// We initially create our per-slice allocators with a width and height of
     /// IDEAL_MAX_TEXTURE_DIMENSION. If we encounter a larger primitive, the
     /// allocation will fail, but we'll bump max_dynamic_size, which will cause the
     /// allocator for the next slice to be just large enough to accomodate it.
-    pub max_dynamic_size: DeviceUintSize,
+    pub max_dynamic_size: DeviceIntSize,
     pub targets: Vec<T>,
     pub saved_index: Option<SavedTargetIndex>,
 }
 
 impl<T: RenderTarget> RenderTargetList<T> {
     fn new(
         screen_size: DeviceIntSize,
         format: ImageFormat,
     ) -> Self {
         RenderTargetList {
             screen_size,
             format,
-            max_dynamic_size: DeviceUintSize::new(0, 0),
+            max_dynamic_size: DeviceIntSize::new(0, 0),
             targets: Vec::new(),
             saved_index: None,
         }
     }
 
     fn build(
         &mut self,
         ctx: &mut RenderTargetContext,
@@ -268,29 +268,29 @@ impl<T: RenderTarget> RenderTargetList<T
             clip_store,
             transforms,
             deferred_resolves,
         );
     }
 
     fn allocate(
         &mut self,
-        alloc_size: DeviceUintSize,
-    ) -> (DeviceUintPoint, RenderTargetIndex) {
+        alloc_size: DeviceIntSize,
+    ) -> (DeviceIntPoint, RenderTargetIndex) {
         let existing_origin = self.targets
             .last_mut()
             .and_then(|target| target.allocate(alloc_size));
 
         let origin = match existing_origin {
             Some(origin) => origin,
             None => {
                 // Have the allocator restrict slice sizes to our max ideal
                 // dimensions, unless we've already gone bigger on a previous
                 // slice.
-                let allocator_dimensions = DeviceUintSize::new(
+                let allocator_dimensions = DeviceIntSize::new(
                     cmp::max(IDEAL_MAX_TEXTURE_DIMENSION, self.max_dynamic_size.width),
                     cmp::max(IDEAL_MAX_TEXTURE_DIMENSION, self.max_dynamic_size.height),
                 );
                 let mut new_target = T::new(Some(allocator_dimensions), self.screen_size);
                 let origin = new_target.allocate(alloc_size).expect(&format!(
                     "Each render task must allocate <= size of one target! ({})",
                     alloc_size
                 ));
@@ -387,25 +387,25 @@ pub struct ColorRenderTarget {
     // List of frame buffer outputs for this render target.
     pub outputs: Vec<FrameOutput>,
     allocator: Option<TextureAllocator>,
     alpha_tasks: Vec<RenderTaskId>,
     screen_size: DeviceIntSize,
 }
 
 impl RenderTarget for ColorRenderTarget {
-    fn allocate(&mut self, size: DeviceUintSize) -> Option<DeviceUintPoint> {
+    fn allocate(&mut self, size: DeviceIntSize) -> Option<DeviceIntPoint> {
         self.allocator
             .as_mut()
             .expect("bug: calling allocate on framebuffer")
             .allocate(&size)
     }
 
     fn new(
-        size: Option<DeviceUintSize>,
+        size: Option<DeviceIntSize>,
         screen_size: DeviceIntSize,
     ) -> Self {
         ColorRenderTarget {
             alpha_batch_containers: Vec::new(),
             vertical_blurs: Vec::new(),
             horizontal_blurs: Vec::new(),
             readbacks: Vec::new(),
             scalings: Vec::new(),
@@ -539,19 +539,16 @@ impl RenderTarget for ColorRenderTarget 
                             key.request,
                             ctx.resource_cache,
                             gpu_cache,
                             deferred_resolves,
                         );
 
                         // Work out a source rect to copy from the texture, depending on whether
                         // a sub-rect is present or not.
-                        // TODO(gw): We have much type confusion below - f32, i32 and u32 for
-                        //           various representations of the texel rects. We should make
-                        //           this consistent!
                         let source_rect = key.texel_rect.map_or(cache_item.uv_rect.to_i32(), |sub_rect| {
                             DeviceIntRect::new(
                                 DeviceIntPoint::new(
                                     cache_item.uv_rect.origin.x as i32 + sub_rect.origin.x,
                                     cache_item.uv_rect.origin.y as i32 + sub_rect.origin.y,
                                 ),
                                 sub_rect.size,
                             )
@@ -603,22 +600,22 @@ pub struct AlphaRenderTarget {
     pub vertical_blurs: Vec<BlurInstance>,
     pub horizontal_blurs: Vec<BlurInstance>,
     pub scalings: Vec<ScalingInstance>,
     pub zero_clears: Vec<RenderTaskId>,
     allocator: TextureAllocator,
 }
 
 impl RenderTarget for AlphaRenderTarget {
-    fn allocate(&mut self, size: DeviceUintSize) -> Option<DeviceUintPoint> {
+    fn allocate(&mut self, size: DeviceIntSize) -> Option<DeviceIntPoint> {
         self.allocator.allocate(&size)
     }
 
     fn new(
-        size: Option<DeviceUintSize>,
+        size: Option<DeviceIntSize>,
         _: DeviceIntSize,
     ) -> Self {
         AlphaRenderTarget {
             clip_batcher: ClipBatcher::new(),
             vertical_blurs: Vec::new(),
             horizontal_blurs: Vec::new(),
             scalings: Vec::new(),
             zero_clears: Vec::new(),
@@ -903,18 +900,18 @@ impl RenderPass {
             // off-screen render target, update the max-encountered size. We don't
             // need to do this for things drawn to the texture cache, since those
             // don't affect our render target allocation.
             if location.is_dynamic() {
                 let max_size = match target_kind {
                     RenderTargetKind::Color => &mut color.max_dynamic_size,
                     RenderTargetKind::Alpha => &mut alpha.max_dynamic_size,
                 };
-                max_size.width = cmp::max(max_size.width, size.width as u32);
-                max_size.height = cmp::max(max_size.height, size.height as u32);
+                max_size.width = cmp::max(max_size.width, size.width);
+                max_size.height = cmp::max(max_size.height, size.height);
             }
         }
 
         self.tasks.push(task_id);
     }
 
     /// Processes this pass to prepare it for rendering.
     ///
@@ -987,22 +984,21 @@ impl RenderPass {
                         let texture_target = match task.location {
                             RenderTaskLocation::TextureCache { texture, layer, .. } => {
                                 Some((texture, layer))
                             }
                             RenderTaskLocation::Fixed(..) => {
                                 None
                             }
                             RenderTaskLocation::Dynamic(ref mut origin, size) => {
-                                let alloc_size = DeviceUintSize::new(size.width as u32, size.height as u32);
                                 let (alloc_origin, target_index) =  match target_kind {
-                                    RenderTargetKind::Color => color.allocate(alloc_size),
-                                    RenderTargetKind::Alpha => alpha.allocate(alloc_size),
+                                    RenderTargetKind::Color => color.allocate(size),
+                                    RenderTargetKind::Alpha => alpha.allocate(size),
                                 };
-                                *origin = Some((alloc_origin.to_i32(), target_index));
+                                *origin = Some((alloc_origin, target_index));
                                 None
                             }
                         };
 
                         // Replace the pending saved index with a real one
                         if let Some(index) = task.saved_index {
                             assert_eq!(index, SavedTargetIndex::PENDING);
                             task.saved_index = match target_kind {
@@ -1100,18 +1096,18 @@ 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 {
     //TODO: share the fields with DocumentView struct
-    pub window_size: DeviceUintSize,
-    pub inner_rect: DeviceUintRect,
+    pub window_size: DeviceIntSize,
+    pub inner_rect: DeviceIntRect,
     pub background_color: Option<ColorF>,
     pub layer: DocumentLayer,
     pub device_pixel_ratio: f32,
     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>,
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -7,32 +7,32 @@ extern crate serde_bytes;
 use app_units::Au;
 use channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethods};
 use std::cell::Cell;
 use std::fmt;
 use std::marker::PhantomData;
 use std::os::raw::c_void;
 use std::path::PathBuf;
 use std::u32;
-use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, DeviceUintRect};
-use {DeviceUintSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
+use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, DeviceIntRect};
+use {DeviceIntSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
 use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphIndex, ImageData};
 use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
 use {NativeFontHandle, WorldPoint};
 
 pub type TileSize = u16;
 /// Documents are rendered in the ascending order of their associated layer values.
 pub type DocumentLayer = i8;
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum ResourceUpdate {
     AddImage(AddImage),
     UpdateImage(UpdateImage),
     DeleteImage(ImageKey),
-    SetImageVisibleArea(ImageKey, DeviceUintRect),
+    SetImageVisibleArea(ImageKey, DeviceIntRect),
     AddFont(AddFont),
     DeleteFont(FontKey),
     AddFontInstance(AddFontInstance),
     DeleteFontInstance(FontInstanceKey),
 }
 
 /// A Transaction is a group of commands to apply atomically to a document.
 ///
@@ -112,17 +112,17 @@ impl Transaction {
         // proper times, but it wouldn't make things simpler.
     }
 
     /// Sets the root pipeline.
     ///
     /// # Examples
     ///
     /// ```
-    /// # use webrender_api::{DeviceUintSize, PipelineId, RenderApiSender, Transaction};
+    /// # use webrender_api::{DeviceIntSize, PipelineId, RenderApiSender, Transaction};
     /// # fn example() {
     /// let pipeline_id = PipelineId(0, 0);
     /// let mut txn = Transaction::new();
     /// txn.set_root_pipeline(pipeline_id);
     /// # }
     /// ```
     pub fn set_root_pipeline(&mut self, pipeline_id: PipelineId) {
         self.scene_ops.push(SceneMsg::SetRootPipeline(pipeline_id));
@@ -192,18 +192,18 @@ impl Transaction {
     /// best to use them for synchronization purposes and not for things that could
     /// affect the WebRender's state.
     pub fn notify(&mut self, event: NotificationRequest) {
         self.notifications.push(event);
     }
 
     pub fn set_window_parameters(
         &mut self,
-        window_size: DeviceUintSize,
-        inner_rect: DeviceUintRect,
+        window_size: DeviceIntSize,
+        inner_rect: DeviceIntRect,
         device_pixel_ratio: f32,
     ) {
         self.scene_ops.push(
             SceneMsg::SetWindowParameters {
                 window_size,
                 inner_rect,
                 device_pixel_ratio,
             },
@@ -316,31 +316,31 @@ impl Transaction {
         }));
     }
 
     pub fn update_image(
         &mut self,
         key: ImageKey,
         descriptor: ImageDescriptor,
         data: ImageData,
-        dirty_rect: Option<DeviceUintRect>,
+        dirty_rect: Option<DeviceIntRect>,
     ) {
         self.resource_updates.push(ResourceUpdate::UpdateImage(UpdateImage {
             key,
             descriptor,
             data,
             dirty_rect,
         }));
     }
 
     pub fn delete_image(&mut self, key: ImageKey) {
         self.resource_updates.push(ResourceUpdate::DeleteImage(key));
     }
 
-    pub fn set_image_visible_area(&mut self, key: ImageKey, area: DeviceUintRect) {
+    pub fn set_image_visible_area(&mut self, key: ImageKey, area: DeviceIntRect) {
         self.resource_updates.push(ResourceUpdate::SetImageVisibleArea(key, area))
     }
 
     pub fn add_raw_font(&mut self, key: FontKey, bytes: Vec<u8>, index: u32) {
         self.resource_updates
             .push(ResourceUpdate::AddFont(AddFont::Raw(key, bytes, index)));
     }
 
@@ -459,17 +459,17 @@ pub struct AddImage {
     pub tiling: Option<TileSize>,
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub struct UpdateImage {
     pub key: ImageKey,
     pub descriptor: ImageDescriptor,
     pub data: ImageData,
-    pub dirty_rect: Option<DeviceUintRect>,
+    pub dirty_rect: Option<DeviceIntRect>,
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum AddFont {
     Raw(
         FontKey,
         #[serde(with = "serde_bytes")] Vec<u8>,
         u32
@@ -530,18 +530,18 @@ pub enum SceneMsg {
         epoch: Epoch,
         pipeline_id: PipelineId,
         background: Option<ColorF>,
         viewport_size: LayoutSize,
         content_size: LayoutSize,
         preserve_frame_state: bool,
     },
     SetWindowParameters {
-        window_size: DeviceUintSize,
-        inner_rect: DeviceUintRect,
+        window_size: DeviceIntSize,
+        inner_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),
@@ -610,17 +610,17 @@ bitflags!{
 }
 
 /// Information about a loaded capture of each document
 /// that is returned by `RenderBackend`.
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct CapturedDocument {
     pub document_id: DocumentId,
     pub root_pipeline_id: Option<PipelineId>,
-    pub window_size: DeviceUintSize,
+    pub window_size: DeviceIntSize,
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum DebugCommand {
     /// Display the frame profiler on screen.
     EnableProfiler(bool),
     /// Display all texture cache pages on screen.
     EnableTextureCacheDebug(bool),
@@ -678,17 +678,17 @@ pub enum ApiMsg {
     ),
     /// Gets the glyph indices from a string
     GetGlyphIndices(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, DeviceUintSize, DocumentLayer),
+    AddDocument(DocumentId, DeviceIntSize, DocumentLayer),
     /// A message targeted at a particular document.
     UpdateDocument(DocumentId, 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),
@@ -927,17 +927,17 @@ 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: DeviceUintSize, layer: DocumentLayer) -> DocumentId {
+    pub fn add_document(&self, initial_size: DeviceIntSize, layer: DocumentLayer) -> DocumentId {
         let new_id = self.next_unique_id();
         let document_id = DocumentId(self.namespace_id, new_id);
 
         let msg = ApiMsg::AddDocument(document_id, initial_size, layer);
         self.api_sender.send(msg).unwrap();
 
         document_id
     }
@@ -1098,18 +1098,18 @@ impl RenderApi {
             FrameMsg::HitTest(pipeline_id, point, flags, tx)
         );
         rx.recv().unwrap()
     }
 
     pub fn set_window_parameters(
         &self,
         document_id: DocumentId,
-        window_size: DeviceUintSize,
-        inner_rect: DeviceUintRect,
+        window_size: DeviceIntSize,
+        inner_rect: DeviceIntRect,
         device_pixel_ratio: f32,
     ) {
         self.send_scene_msg(
             document_id,
             SceneMsg::SetWindowParameters { window_size, inner_rect, device_pixel_ratio, },
         );
     }
 
--- a/gfx/webrender_api/src/display_item.rs
+++ b/gfx/webrender_api/src/display_item.rs
@@ -345,29 +345,29 @@ pub enum NinePatchBorderSource {
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct NinePatchBorder {
     /// Describes what to use as the 9-patch source image. If this is an image,
     /// it will be stretched to fill the size given by width x height.
     pub source: NinePatchBorderSource,
 
     /// The width of the 9-part image.
-    pub width: u32,
+    pub width: i32,
 
     /// The height of the 9-part image.
-    pub height: u32,
+    pub height: i32,
 
     /// Distances from each edge where the image should be sliced up. These
     /// values are in 9-part-image space (the same space as width and height),
     /// and the resulting image parts will be used to fill the corresponding
     /// parts of the border as given by the border widths. This can lead to
     /// stretching.
     /// Slices can be overlapping. In that case, the same pixels from the
     /// 9-part image will show up in multiple parts of the resulting border.
-    pub slice: SideOffsets2D<u32>,
+    pub slice: SideOffsets2D<i32>,
 
     /// Controls whether the center of the 9 patch image is rendered or
     /// ignored. The center is never rendered if the slices are overlapping.
     pub fill: bool,
 
     /// Determines what happens if the horizontal side parts of the 9-part
     /// image have a different size than the horizontal parts of the border.
     pub repeat_horizontal: RepeatMode,
--- a/gfx/webrender_api/src/font.rs
+++ b/gfx/webrender_api/src/font.rs
@@ -60,18 +60,18 @@ impl<'de> Deserialize<'de> for NativeFon
     }
 }
 
 #[repr(C)]
 #[derive(Copy, Clone, Deserialize, Serialize, Debug)]
 pub struct GlyphDimensions {
     pub left: i32,
     pub top: i32,
-    pub width: u32,
-    pub height: u32,
+    pub width: i32,
+    pub height: i32,
     pub advance: f32,
 }
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
 pub struct FontKey(pub IdNamespace, pub u32);
 
 impl FontKey {
--- a/gfx/webrender_api/src/image.rs
+++ b/gfx/webrender_api/src/image.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![deny(missing_docs)]
 
 extern crate serde_bytes;
 
 use font::{FontInstanceKey, FontInstanceData, FontKey, FontTemplate};
 use std::sync::Arc;
-use {DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
+use {DevicePoint, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use {IdNamespace, TileOffset, TileSize};
 use euclid::size2;
 
 /// An opaque identifier describing an image registered with WebRender.
 /// This is used as a handle to reference images, and is used as the
 /// hash map key for the actual image storage in the `ResourceCache`.
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
@@ -100,17 +100,17 @@ pub enum ImageFormat {
     /// "two channels" rather than "red and green".
     RG8 = 5,
     /// Four channels, signed integer storage.
     RGBAI32 = 6,
 }
 
 impl ImageFormat {
     /// Returns the number of bytes per pixel for the given format.
-    pub fn bytes_per_pixel(self) -> u32 {
+    pub fn bytes_per_pixel(self) -> i32 {
         match self {
             ImageFormat::R8 => 1,
             ImageFormat::R16 => 2,
             ImageFormat::BGRA8 => 4,
             ImageFormat::RGBAF32 => 16,
             ImageFormat::RG8 => 2,
             ImageFormat::RGBAI32 => 16,
         }
@@ -154,73 +154,73 @@ impl ColorDepth {
 }
 
 /// Metadata (but not storage) describing an image In WebRender.
 #[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ImageDescriptor {
     /// Format of the image data.
     pub format: ImageFormat,
     /// Width and length of the image data, in pixels.
-    pub size: DeviceUintSize,
+    pub size: DeviceIntSize,
     /// The number of bytes from the start of one row to the next. If non-None,
     /// `compute_stride` will return this value, otherwise it returns
     /// `width * bpp`. Different source of images have different alignment
     /// constraints for rows, so the stride isn't always equal to width * bpp.
-    pub stride: Option<u32>,
+    pub stride: Option<i32>,
     /// Offset in bytes of the first pixel of this image in its backing buffer.
     /// This is used for tiling, wherein WebRender extracts chunks of input images
     /// in order to cache, manipulate, and render them individually. This offset
     /// tells the texture upload machinery where to find the bytes to upload for
     /// this tile. Non-tiled images generally set this to zero.
-    pub offset: u32,
+    pub offset: i32,
     /// Whether this image is opaque, or has an alpha channel. Avoiding blending
     /// for opaque surfaces is an important optimization.
     pub is_opaque: bool,
     /// Whether to allow the driver to automatically generate mipmaps. If images
     /// are already downscaled appropriately, mipmap generation can be wasted
     /// work, and cause performance problems on some cards/drivers.
     ///
     /// See https://github.com/servo/webrender/pull/2555/
     pub allow_mipmaps: bool,
 }
 
 impl ImageDescriptor {
     /// Mints a new ImageDescriptor.
     pub fn new(
-        width: u32,
-        height: u32,
+        width: i32,
+        height: i32,
         format: ImageFormat,
         is_opaque: bool,
         allow_mipmaps: bool,
     ) -> Self {
         ImageDescriptor {
             size: size2(width, height),
             format,
             stride: None,
             offset: 0,
             is_opaque,
             allow_mipmaps,
         }
     }
 
     /// Returns the stride, either via an explicit stride stashed on the object
     /// or by the default computation.
-    pub fn compute_stride(&self) -> u32 {
+    pub fn compute_stride(&self) -> i32 {
         self.stride.unwrap_or(self.size.width * self.format.bytes_per_pixel())
     }
 
     /// Computes the total size of the image, in bytes.
-    pub fn compute_total_size(&self) -> u32 {
+    pub fn compute_total_size(&self) -> i32 {
         self.compute_stride() * self.size.height
     }
 
     /// Computes the bounding rectangle for the image, rooted at (0, 0).
-    pub fn full_rect(&self) -> DeviceUintRect {
-        DeviceUintRect::new(
-            DeviceUintPoint::zero(),
+    pub fn full_rect(&self) -> DeviceIntRect {
+        DeviceIntRect::new(
+            DeviceIntPoint::zero(),
             self.size,
         )
     }
 }
 
 /// Represents the backing store of an arbitrary series of pixels for display by
 /// WebRender. This storage can take several forms.
 #[derive(Clone, Debug, Serialize, Deserialize)]
@@ -317,17 +317,17 @@ pub trait BlobImageHandler: Send {
         services: &BlobImageResources,
         requests: &[BlobImageParams],
     );
 
     /// Register a blob image.
     fn add(&mut self, key: ImageKey, data: Arc<BlobImageData>, tiling: Option<TileSize>);
 
     /// Update an already registered blob image.
-    fn update(&mut self, key: ImageKey, data: Arc<BlobImageData>, dirty_rect: Option<DeviceUintRect>);
+    fn update(&mut self, key: ImageKey, data: Arc<BlobImageData>, dirty_rect: Option<DeviceIntRect>);
 
     /// Delete an already registered blob image.
     fn delete(&mut self, key: ImageKey);
 
     /// A hook to let the handler clean up any state related to a font which the resource
     /// cache is about to delete.
     fn delete_font(&mut self, key: FontKey);
 
@@ -360,43 +360,43 @@ pub struct BlobImageParams {
     /// A key that identifies the blob image rasterization request.
     pub request: BlobImageRequest,
     /// Description of the format of the blob's output image.
     pub descriptor: BlobImageDescriptor,
     /// An optional sub-rectangle of the image to avoid re-rasterizing
     /// the entire image when only a portion is updated.
     ///
     /// If set to None the entire image is rasterized.
-    pub dirty_rect: Option<DeviceUintRect>,
+    pub dirty_rect: Option<DeviceIntRect>,
 }
 
 /// Backing store for blob image command streams.
 pub type BlobImageData = Vec<u8>;
 
 /// Result type for blob raserization.
 pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;
 
 /// Metadata (but not storage) for a blob image.
 #[repr(C)]
 #[derive(Copy, Clone, Debug)]
 pub struct BlobImageDescriptor {
     /// Size in device pixels of the blob's output image.
-    pub size: DeviceUintSize,
+    pub size: DeviceIntSize,
     /// When tiling, offset point in device pixels of this tile in the full
     /// image. Generally (0, 0) outside of tiling.
     pub offset: DevicePoint,
     /// Format for the data in the backing store.
     pub format: ImageFormat,
 }
 
 /// Representation of a rasterized blob image. This is obtained by passing
 /// `BlobImageData` to the embedding via the rasterization callback.
 pub struct RasterizedBlobImage {
     /// The bounding rectangle for this blob image.
-    pub rasterized_rect: DeviceUintRect,
+    pub rasterized_rect: DeviceIntRect,
     /// Backing store. The format is stored out of band in `BlobImageDescriptor`.
     pub data: Arc<Vec<u8>>,
 }
 
 /// Error code for when blob rasterization failed.
 #[derive(Clone, Debug)]
 pub enum BlobImageError {
     /// Out of memory.
--- a/gfx/webrender_api/src/units.rs
+++ b/gfx/webrender_api/src/units.rs
@@ -22,20 +22,16 @@ use euclid::{TypedPoint2D, TypedPoint3D,
 pub struct DevicePixel;
 
 pub type DeviceIntRect = TypedRect<i32, DevicePixel>;
 pub type DeviceIntPoint = TypedPoint2D<i32, DevicePixel>;
 pub type DeviceIntSize = TypedSize2D<i32, DevicePixel>;
 pub type DeviceIntLength = Length<i32, DevicePixel>;
 pub type DeviceIntSideOffsets = TypedSideOffsets2D<i32, DevicePixel>;
 
-pub type DeviceUintRect = TypedRect<u32, DevicePixel>;
-pub type DeviceUintPoint = TypedPoint2D<u32, DevicePixel>;
-pub type DeviceUintSize = TypedSize2D<u32, DevicePixel>;
-
 pub type DeviceRect = TypedRect<f32, DevicePixel>;
 pub type DevicePoint = TypedPoint2D<f32, DevicePixel>;
 pub type DeviceVector2D = TypedVector2D<f32, DevicePixel>;
 pub type DeviceSize = TypedSize2D<f32, DevicePixel>;
 
 /// Geometry in the coordinate system of a Picture (intermediate
 /// surface) in physical pixels.
 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
@@ -88,18 +84,18 @@ pub type WorldPoint = TypedPoint2D<f32, 
 pub type WorldSize = TypedSize2D<f32, WorldPixel>;
 pub type WorldPoint3D = TypedPoint3D<f32, WorldPixel>;
 pub type WorldVector2D = TypedVector2D<f32, WorldPixel>;
 pub type WorldVector3D = TypedVector3D<f32, WorldPixel>;
 
 /// Offset in number of tiles.
 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Tiles;
-pub type TileOffset = TypedPoint2D<u32, Tiles>;
-pub type TileRange = TypedRect<u32, Tiles>;
+pub type TileOffset = TypedPoint2D<i32, Tiles>;
+pub type TileRange = TypedRect<i32, Tiles>;
 
 /// Scaling ratio from world pixels to device pixels.
 pub type DevicePixelScale = TypedScale<f32, WorldPixel, DevicePixel>;
 /// Scaling ratio from layout to world. Used for cases where we know the layout
 /// is in world space, or specifically want to treat it this way.
 pub type LayoutToWorldScale = TypedScale<f32, LayoutPixel, WorldPixel>;
 /// A complete scaling ratio from layout space to device pixel space.
 pub type LayoutToDeviceScale = TypedScale<f32, LayoutPixel, DevicePixel>;
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,2 +1,1 @@
-9ec08a4cf0ce6762a98ddd4df34611dbf0694703
-plus servo/webrender#3316 cherry-picked
+dc442bfe38dcd9fc5033d2191b04c6242d167f05
--- a/gfx/wrench/src/blob.rs
+++ b/gfx/wrench/src/blob.rs
@@ -33,49 +33,49 @@ fn premul(x: u8, a: u8) -> u8 {
 }
 
 // This is the function that applies the deserialized drawing commands and generates
 // actual image data.
 fn render_blob(
     color: ColorU,
     descriptor: &BlobImageDescriptor,
     tile: Option<(TileSize, TileOffset)>,
-    dirty_rect: Option<DeviceUintRect>,
+    dirty_rect: Option<DeviceIntRect>,
 ) -> BlobImageResult {
     // Allocate storage for the result. Right now the resource cache expects the
     // tiles to have have no stride or offset.
     let buf_size = descriptor.size.width *
         descriptor.size.height *
         descriptor.format.bytes_per_pixel();
     let mut texels = vec![0u8; (buf_size) as usize];
 
     // Generate a per-tile pattern to see it in the demo. For a real use case it would not
     // make sense for the rendered content to depend on its tile.
     let tile_checker = match tile {
         Some((_, tile)) => (tile.x % 2 == 0) != (tile.y % 2 == 0),
         None => true,
     };
 
-    let mut dirty_rect = dirty_rect.unwrap_or(DeviceUintRect::new(
-        descriptor.offset.to_u32(),
+    let mut dirty_rect = dirty_rect.unwrap_or(DeviceIntRect::new(
+        descriptor.offset.to_i32(),
         descriptor.size,
     ));
 
     if let Some((tile_size, tile)) = tile {
-        dirty_rect = intersect_for_tile(dirty_rect, size2(tile_size as u32, tile_size as u32),
+        dirty_rect = intersect_for_tile(dirty_rect, size2(tile_size as i32, tile_size as i32),
                                         tile_size, tile)
             .expect("empty rects should be culled by webrender");
     }
 
     for y in dirty_rect.min_y() .. dirty_rect.max_y() {
         for x in dirty_rect.min_x() .. dirty_rect.max_x() {
             // Apply the tile's offset. This is important: all drawing commands should be
             // translated by this offset to give correct results with tiled blob images.
-            let x2 = x + descriptor.offset.x as u32;
-            let y2 = y + descriptor.offset.y as u32;
+            let x2 = x + descriptor.offset.x as i32;
+            let y2 = y + descriptor.offset.y as i32;
 
             // Render a simple checkerboard pattern
             let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) {
                 1
             } else {
                 0
             };
             // ..nested in the per-tile checkerboard pattern
@@ -134,17 +134,17 @@ impl CheckerboardRenderer {
 }
 
 impl BlobImageHandler for CheckerboardRenderer {
     fn add(&mut self, key: ImageKey, cmds: Arc<BlobImageData>, tile_size: Option<TileSize>) {
         self.image_cmds
             .insert(key, (deserialize_blob(&cmds[..]).unwrap(), tile_size));
     }
 
-    fn update(&mut self, key: ImageKey, cmds: Arc<BlobImageData>, _dirty_rect: Option<DeviceUintRect>) {
+    fn update(&mut self, key: ImageKey, cmds: Arc<BlobImageData>, _dirty_rect: Option<DeviceIntRect>) {
         // Here, updating is just replacing the current version of the commands with
         // the new one (no incremental updates).
         self.image_cmds.get_mut(&key).unwrap().0 = deserialize_blob(&cmds[..]).unwrap();
     }
 
     fn delete(&mut self, key: ImageKey) {
         self.image_cmds.remove(&key);
     }
@@ -170,17 +170,17 @@ impl BlobImageHandler for CheckerboardRe
     }
 }
 
 struct Command {
     request: BlobImageRequest,
     color: ColorU,
     descriptor: BlobImageDescriptor,
     tile: Option<(TileSize, TileOffset)>,
-    dirty_rect: Option<DeviceUintRect>
+    dirty_rect: Option<DeviceIntRect>
 }
 
 struct Rasterizer {
     image_cmds: HashMap<ImageKey, (ColorU, Option<TileSize>)>,
 }
 
 impl AsyncBlobImageRasterizer for Rasterizer {
     fn rasterize(
--- a/gfx/wrench/src/json_frame_writer.rs
+++ b/gfx/wrench/src/json_frame_writer.rs
@@ -26,19 +26,19 @@ enum CachedFont {
 }
 
 struct CachedFontInstance {
     font_key: FontKey,
     glyph_size: Au,
 }
 
 struct CachedImage {
-    width: u32,
-    height: u32,
-    stride: u32,
+    width: i32,
+    height: i32,
+    stride: i32,
     format: ImageFormat,
     bytes: Option<Vec<u8>>,
     path: Option<PathBuf>,
 }
 
 pub struct JsonFrameWriter {
     frame_base: PathBuf,
     rsrc_base: PathBuf,
@@ -222,30 +222,30 @@ impl JsonFrameWriter {
         );
 
         let ok = match data.format {
             ImageFormat::BGRA8 => if data.stride == data.width * 4 {
                 unpremultiply(bytes.as_mut_slice());
                 save_buffer(
                     &path_file,
                     &bytes,
-                    data.width,
-                    data.height,
+                    data.width as u32,
+                    data.height as u32,
                     ColorType::RGBA(8),
                 ).unwrap();
                 true
             } else {
                 false
             },
             ImageFormat::R8 => if data.stride == data.width {
                 save_buffer(
                     &path_file,
                     &bytes,
-                    data.width,
-                    data.height,
+                    data.width as u32,
+                    data.height as u32,
                     ColorType::Gray(8),
                 ).unwrap();
                 true
             } else {
                 false
             },
             _ => false,
         };
--- a/gfx/wrench/src/main.rs
+++ b/gfx/wrench/src/main.rs
@@ -87,31 +87,31 @@ use yaml_frame_reader::YamlFrameReader;
 lazy_static! {
     static ref PLATFORM_DEFAULT_FACE_NAME: String = String::from("Arial");
 }
 
 pub static mut CURRENT_FRAME_NUMBER: u32 = 0;
 
 #[cfg(feature = "headless")]
 pub struct HeadlessContext {
-    width: u32,
-    height: u32,
+    width: i32,
+    height: i32,
     _context: osmesa_sys::OSMesaContext,
     _buffer: Vec<u32>,
 }
 
 #[cfg(not(feature = "headless"))]
 pub struct HeadlessContext {
-    width: u32,
-    height: u32,
+    width: i32,
+    height: i32,
 }
 
 impl HeadlessContext {
     #[cfg(feature = "headless")]
-    fn new(width: u32, height: u32) -> Self {
+    fn new(width: i32, height: i32) -> Self {
         let mut attribs = Vec::new();
 
         attribs.push(osmesa_sys::OSMESA_PROFILE);
         attribs.push(osmesa_sys::OSMESA_CORE_PROFILE);
         attribs.push(osmesa_sys::OSMESA_CONTEXT_MAJOR_VERSION);
         attribs.push(3);
         attribs.push(osmesa_sys::OSMESA_CONTEXT_MINOR_VERSION);
         attribs.push(3);
@@ -126,32 +126,32 @@ impl HeadlessContext {
 
         let mut buffer = vec![0; (width * height) as usize];
 
         unsafe {
             let ret = osmesa_sys::OSMesaMakeCurrent(
                 context,
                 buffer.as_mut_ptr() as *mut _,
                 gl::UNSIGNED_BYTE,
-                width as i32,
-                height as i32,
+                width,
+                height,
             );
             assert!(ret != 0);
         };
 
         HeadlessContext {
             width,
             height,
             _context: context,
             _buffer: buffer,
         }
     }
 
     #[cfg(not(feature = "headless"))]
-    fn new(width: u32, height: u32) -> Self {
+    fn new(width: i32, height: i32) -> Self {
         HeadlessContext { width, height }
     }
 
     #[cfg(feature = "headless")]
     fn get_proc_address(s: &str) -> *const c_void {
         let c_str = CString::new(s).expect("Unable to create CString");
         unsafe { mem::transmute(osmesa_sys::OSMesaGetProcAddress(c_str.as_ptr())) }
     }
@@ -174,40 +174,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) -> DeviceUintSize {
-        fn inner_size(window: &winit::Window) -> DeviceUintSize {
+    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());
-            DeviceUintSize::new(size.width as u32, size.height as u32)
+            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, _) => DeviceUintSize::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: DeviceUintSize) {
+    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
@@ -235,17 +235,17 @@ impl WindowWrapper {
             WindowWrapper::Window(_, ref gl) |
             WindowWrapper::Angle(_, _, ref gl) |
             WindowWrapper::Headless(_, ref gl) => gl.clone(),
         }
     }
 }
 
 fn make_window(
-    size: DeviceUintSize,
+    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()
@@ -406,30 +406,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" {
-            DeviceUintSize::new(1280, 720)
+            DeviceIntSize::new(1280, 720)
         } else if s == "1080p" {
-            DeviceUintSize::new(1920, 1080)
+            DeviceIntSize::new(1920, 1080)
         } else if s == "4k" {
-            DeviceUintSize::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::<u32>().expect("Invalid size width");
-            let h = s[x + 1 ..].parse::<u32>().expect("Invalid size height");
-            DeviceUintSize::new(w, h)
+            let w = s[0 .. x].parse::<i32>().expect("Invalid size width");
+            let h = s[x + 1 ..].parse::<i32>().expect("Invalid size height");
+            DeviceIntSize::new(w, h)
         })
-        .unwrap_or(DeviceUintSize::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(
@@ -523,17 +523,17 @@ fn main() {
     };
 
     wrench.renderer.deinit();
 }
 
 fn render<'a>(
     wrench: &mut Wrench,
     window: &mut WindowWrapper,
-    size: DeviceUintSize,
+    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);
@@ -739,15 +739,15 @@ fn render<'a>(
         }
 
         winit::ControlFlow::Continue
     };
 
     match *events_loop {
         None => {
             while body(wrench, winit::Event::Awakened) == winit::ControlFlow::Continue {}
-            let rect = DeviceUintRect::new(DeviceUintPoint::zero(), size);
+            let rect = DeviceIntRect::new(DeviceIntPoint::zero(), size);
             let pixels = wrench.renderer.read_pixels_rgba8(rect);
             save_flipped("screenshot.png", pixels, size);
         }
         Some(ref mut events_loop) => events_loop.run_forever(|event| body(wrench, event)),
     }
 }
--- a/gfx/wrench/src/png.rs
+++ b/gfx/wrench/src/png.rs
@@ -20,56 +20,58 @@ 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>,
-    mut size: DeviceUintSize,
+    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(
-        size.width,
-        size.height,
+        width,
+        height,
         orig_pixels,
     ).expect("bug: unable to construct image buffer");
 
     if settings.flip_vertical {
         // flip image vertically (texture is upside down)
         buffer = image::imageops::flip_vertical(&buffer);
     }
 
     if settings.try_crop {
         if let Ok(existing_image) = image::open(path.clone()) {
             let old_dims = existing_image.dimensions();
             println!("Crop from {:?} to {:?}", size, old_dims);
-            size.width = old_dims.0;
-            size.height = old_dims.1;
+            width = old_dims.0;
+            height = old_dims.1;
             buffer = image::imageops::crop(
                 &mut buffer,
                 0,
                 0,
-                size.width,
-                size.height
+                width,
+                height
             ).to_image();
         }
     }
 
     let encoder = PNGEncoder::new(File::create(path).unwrap());
     encoder
-        .encode(&buffer, size.width, size.height, ColorType::RGBA(8))
+        .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: DeviceUintSize,
+    size: DeviceIntSize,
 ) {
     save(path, orig_pixels, size, SaveSettings {
         flip_vertical: true,
         try_crop: true,
     })
 }
 
 pub fn png(
@@ -83,17 +85,17 @@ pub fn png(
 
     // wait for the frame
     rx.recv().unwrap();
     wrench.render();
 
     let (device_size, data, settings) = match surface {
         ReadSurface::Screen => {
             let dim = window.get_inner_size();
-            let rect = DeviceUintRect::new(DeviceUintPoint::zero(), dim);
+            let rect = DeviceIntRect::new(DeviceIntPoint::zero(), dim);
             let data = wrench.renderer
                 .read_pixels_rgba8(rect);
             (rect.size, data, SaveSettings {
                 flip_vertical: true,
                 try_crop: true,
             })
         }
         ReadSurface::GpuCache => {
--- a/gfx/wrench/src/rawtest.rs
+++ b/gfx/wrench/src/rawtest.rs
@@ -50,17 +50,17 @@ impl<'a> RawtestHarness<'a> {
         self.test_insufficient_blob_visible_area();
         self.test_offscreen_blob();
         self.test_save_restore();
         self.test_blur_cache();
         self.test_capture();
         self.test_zero_height_window();
     }
 
-    fn render_and_get_pixels(&mut self, window_rect: DeviceUintRect) -> Vec<u8> {
+    fn render_and_get_pixels(&mut self, window_rect: DeviceIntRect) -> Vec<u8> {
         self.rx.recv().unwrap();
         self.wrench.render();
         self.wrench.renderer.read_pixels_rgba8(window_rect)
     }
 
     fn submit_dl(
         &mut self,
         epoch: &mut Epoch,
@@ -133,20 +133,20 @@ impl<'a> RawtestHarness<'a> {
 
     fn test_very_large_blob(&mut self) {
         println!("\tvery large blob...");
 
         assert_eq!(self.wrench.device_pixel_ratio, 1.);
 
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(800, 800);
+        let test_size = DeviceIntSize::new(800, 800);
 
-        let window_rect = DeviceUintRect::new(
-            DeviceUintPoint::new(0, window_size.height - test_size.height),
+        let window_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(0, window_size.height - test_size.height),
             test_size,
         );
 
         // This exposes a crash in tile decomposition
         let layout_size = LayoutSize::new(800., 800.);
         let mut txn = Transaction::new();
 
         let blob_img = self.wrench.api.generate_image_key();
@@ -180,17 +180,17 @@ impl<'a> RawtestHarness<'a> {
             image_size,
             ImageRendering::Auto,
             AlphaType::PremultipliedAlpha,
             blob_img,
             ColorF::WHITE,
         );
         txn.set_image_visible_area(
             blob_img,
-            DeviceUintRect {
+            DeviceIntRect {
                 origin: point2(0, 111256 / 30),
                 size: size2(1510, 111256 / 30),
             }
         );
 
         builder.pop_clip_id();
 
         let mut epoch = Epoch(0);
@@ -248,34 +248,34 @@ impl<'a> RawtestHarness<'a> {
         // image. The only difference is that one of the display lists specifies a visible
         // area for its blob image which is too small, causing frame building to run into
         // missing tiles, and forcing it to exercise the code path where missing tiles are
         // rendered synchronously on demand.
 
         assert_eq!(self.wrench.device_pixel_ratio, 1.);
 
         let window_size = self.window.get_inner_size();
-        let test_size = DeviceUintSize::new(800, 800);
-        let window_rect = DeviceUintRect::new(
-            DeviceUintPoint::new(0, window_size.height - test_size.height),
+        let test_size = DeviceIntSize::new(800, 800);
+        let window_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(0, window_size.height - test_size.height),
             test_size,
         );
         let layout_size = LayoutSize::new(800.0, 800.0);
         let image_size = size(800.0, 800.0);
         let info = LayoutPrimitiveInfo::new(rect(0.0, 0.0, 800.0, 800.0));
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         let mut txn = Transaction::new();
 
         let blob_img1 = self.wrench.api.generate_image_key();
         txn.add_image(
             blob_img1,
             ImageDescriptor::new(
-                image_size.width as u32,
-                image_size.height as u32,
+                image_size.width as i32,
+                image_size.height as i32,
                 ImageFormat::BGRA8,
                 false,
                 false
             ),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
             Some(100),
         );
 
@@ -294,28 +294,28 @@ impl<'a> RawtestHarness<'a> {
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         let mut txn = Transaction::new();
 
         let blob_img2 = self.wrench.api.generate_image_key();
         txn.add_image(
             blob_img2,
             ImageDescriptor::new(
-                image_size.width as u32,
-                image_size.height as u32,
+                image_size.width as i32,
+                image_size.height as i32,
                 ImageFormat::BGRA8,
                 false,
                 false
             ),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
             Some(100),
         );
         // Set a visible rectangle that is too small.
         // This will force sync rasterization of the missing tiles during frame building.
-        txn.set_image_visible_area(blob_img2, DeviceUintRect {
+        txn.set_image_visible_area(blob_img2, DeviceIntRect {
             origin: point2(200, 200),
             size: size2(80, 80),
         });
 
         builder.push_image(
             &info,
             image_size,
             image_size,
@@ -338,20 +338,20 @@ impl<'a> RawtestHarness<'a> {
 
     fn test_offscreen_blob(&mut self) {
         println!("\toffscreen blob update.");
 
         assert_eq!(self.wrench.device_pixel_ratio, 1.);
 
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(800, 800);
+        let test_size = DeviceIntSize::new(800, 800);
 
-        let window_rect = DeviceUintRect::new(
-            DeviceUintPoint::new(0, window_size.height - test_size.height),
+        let window_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(0, window_size.height - test_size.height),
             test_size,
         );
 
         // This exposes a crash in tile decomposition
         let mut txn = Transaction::new();
         let layout_size = LayoutSize::new(800., 800.);
 
         let blob_img = self.wrench.api.generate_image_key();
@@ -449,20 +449,20 @@ impl<'a> RawtestHarness<'a> {
         self.wrench.api.update_resources(txn.resource_updates);
     }
 
     fn test_retained_blob_images_test(&mut self) {
         println!("\tretained blob images test...");
         let blob_img;
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(400, 400);
+        let test_size = DeviceIntSize::new(400, 400);
 
-        let window_rect = DeviceUintRect::new(
-            DeviceUintPoint::new(0, window_size.height - test_size.height),
+        let window_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(0, window_size.height - test_size.height),
             test_size,
         );
         let layout_size = LayoutSize::new(400., 400.);
         let mut txn = Transaction::new();
         {
             let api = &self.wrench.api;
 
             blob_img = api.generate_image_key();
@@ -537,19 +537,19 @@ impl<'a> RawtestHarness<'a> {
         *self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new();
     }
 
     fn test_blob_update_epoch_test(&mut self) {
         println!("\tblob update epoch test...");
         let (blob_img, blob_img2);
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(400, 400);
+        let test_size = DeviceIntSize::new(400, 400);
 
-        let window_rect = DeviceUintRect::new(
+        let window_rect = DeviceIntRect::new(
             point(0, window_size.height - test_size.height),
             test_size,
         );
         let layout_size = LayoutSize::new(400., 400.);
         let mut txn = Transaction::new();
         let (blob_img, blob_img2) = {
             let api = &self.wrench.api;
 
@@ -664,19 +664,19 @@ impl<'a> RawtestHarness<'a> {
         // cleanup
         *self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new();
     }
 
     fn test_blob_update_test(&mut self) {
         println!("\tblob update test...");
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(400, 400);
+        let test_size = DeviceIntSize::new(400, 400);
 
-        let window_rect = DeviceUintRect::new(
+        let window_rect = DeviceIntRect::new(
             point(0, window_size.height - test_size.height),
             test_size,
         );
         let layout_size = LayoutSize::new(400., 400.);
         let mut txn = Transaction::new();
 
         let blob_img = {
             let img = self.wrench.api.generate_image_key();
@@ -762,20 +762,20 @@ impl<'a> RawtestHarness<'a> {
         assert!(pixels_first != pixels_third);
     }
 
     // Ensures that content doing a save-restore produces the same results as not
     fn test_save_restore(&mut self) {
         println!("\tsave/restore...");
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(400, 400);
+        let test_size = DeviceIntSize::new(400, 400);
 
-        let window_rect = DeviceUintRect::new(
-            DeviceUintPoint::new(0, window_size.height - test_size.height),
+        let window_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(0, window_size.height - test_size.height),
             test_size,
         );
         let layout_size = LayoutSize::new(400., 400.);
 
         let mut do_test = |should_try_and_fail| {
             let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
 
             let clip = builder.define_clip(
@@ -840,20 +840,20 @@ impl<'a> RawtestHarness<'a> {
     }
 
     // regression test for #2769
     // "async scene building: cache collisions from reused picture ids"
     fn test_blur_cache(&mut self) {
         println!("\tblur cache...");
         let window_size = self.window.get_inner_size();
 
-        let test_size = DeviceUintSize::new(400, 400);
+        let test_size = DeviceIntSize::new(400, 400);
 
-        let window_rect = DeviceUintRect::new(
-            DeviceUintPoint::new(0, window_size.height - test_size.height),
+        let window_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(0, window_size.height - test_size.height),
             test_size,
         );
         let layout_size = LayoutSize::new(400., 400.);
 
         let mut do_test = |shadow_is_red| {
             let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
             let shadow_color = if shadow_is_red {
                 ColorF::new(1.0, 0.0, 0.0, 1.0)
@@ -884,19 +884,19 @@ impl<'a> RawtestHarness<'a> {
         assert_ne!(first, second);
     }
 
     fn test_capture(&mut self) {
         println!("\tcapture...");
         let path = "../captures/test";
         let layout_size = LayoutSize::new(400., 400.);
         let dim = self.window.get_inner_size();
-        let window_rect = DeviceUintRect::new(
-            point(0, dim.height - layout_size.height as u32),
-            size(layout_size.width as u32, layout_size.height as u32),
+        let window_rect = DeviceIntRect::new(
+            point(0, dim.height - layout_size.height as i32),
+            size(layout_size.width as i32, layout_size.height as i32),
         );
 
         // 1. render some scene
 
         let mut txn = Transaction::new();
         let image = self.wrench.api.generate_image_key();
         txn.add_image(
             image,
@@ -966,17 +966,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 = DeviceUintSize::new(layout_size.width as u32, layout_size.height as u32);
+        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 = LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(),
                                                             LayoutSize::new(100.0, 100.0)));
         builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
 
         let mut txn = Transaction::new();
--- a/gfx/wrench/src/reftest.rs
+++ b/gfx/wrench/src/reftest.rs
@@ -91,17 +91,17 @@ impl Display for Reftest {
             self.op,
             self.reference.display()
         )
     }
 }
 
 struct ReftestImage {
     data: Vec<u8>,
-    size: DeviceUintSize,
+    size: DeviceIntSize,
 }
 enum ReftestImageComparison {
     Equal,
     NotEqual {
         max_difference: usize,
         count_different: usize,
     },
 }
@@ -152,17 +152,17 @@ impl ReftestImage {
             (&mut self.data[dst_start .. dst_start + stride])
                 .clone_from_slice(&src_slice[.. stride]);
         }
 
         let mut png: Vec<u8> = vec![];
         {
             let encoder = PNGEncoder::new(&mut png);
             encoder
-                .encode(&self.data[..], width, height, ColorType::RGBA(8))
+                .encode(&self.data[..], width as u32, height as u32, ColorType::RGBA(8))
                 .expect("Unable to encode PNG!");
         }
         let png_base64 = base64::encode(&png);
         format!("data:image/png;base64,{}", png_base64)
     }
 }
 
 struct ReftestManifest {
@@ -465,24 +465,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: DeviceUintSize::new(size.0, size.1),
+            size: DeviceIntSize::new(size.0 as i32, size.1 as i32),
         }
     }
 
     fn render_yaml(
         &mut self,
         filename: &Path,
-        size: DeviceUintSize,
+        size: DeviceIntSize,
         font_render_mode: Option<FontRenderMode>,
         allow_mipmaps: bool,
     ) -> (ReftestImage, RendererStats) {
         let mut reader = YamlFrameReader::new(filename);
         reader.set_font_render_mode(font_render_mode);
         reader.allow_mipmaps(allow_mipmaps);
         reader.do_frame(self.wrench);
 
@@ -495,17 +495,17 @@ impl<'a> ReftestHarness<'a> {
         let window_size = self.window.get_inner_size();
         assert!(
             size.width <= window_size.width &&
             size.height <= window_size.height,
             format!("size={:?} ws={:?}", size, window_size)
         );
 
         // taking the bottom left sub-rectangle
-        let rect = DeviceUintRect::new(DeviceUintPoint::new(0, window_size.height - size.height), size);
+        let rect = DeviceIntRect::new(DeviceIntPoint::new(0, window_size.height - size.height), size);
         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/wrench/src/ron_frame_writer.rs
+++ b/gfx/wrench/src/ron_frame_writer.rs
@@ -13,18 +13,18 @@ use webrender::api::*;
 use webrender::api::channel::Payload;
 
 enum CachedFont {
     Native(NativeFontHandle),
     Raw(Option<Vec<u8>>, u32, Option<PathBuf>),
 }
 
 struct CachedImage {
-    width: u32,
-    height: u32,
+    width: i32,
+    height: i32,
     format: ImageFormat,
     bytes: Option<Vec<u8>>,
     path: Option<PathBuf>,
 }
 
 pub struct RonFrameWriter {
     frame_base: PathBuf,
     images: HashMap<ImageKey, CachedImage>,
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -141,17 +141,17 @@ impl WrenchThing for CapturedDocument {
                 wrench.refresh();
             }
         }
         0
     }
 }
 
 pub struct Wrench {
-    window_size: DeviceUintSize,
+    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,
 
@@ -169,17 +169,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: DeviceUintSize,
+        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,
@@ -486,17 +486,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: DeviceUintSize) {
+    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());
     }
--- a/gfx/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wrench/src/yaml_frame_reader.rs
@@ -116,17 +116,17 @@ fn generate_checkerboard_image(
                         pixels.push(value);
                     }
                 }
             }
         }
     }
 
     (
-        ImageDescriptor::new(width, height, ImageFormat::BGRA8, true, false),
+        ImageDescriptor::new(width as i32, height as i32, ImageFormat::BGRA8, true, false),
         ImageData::new(pixels),
     )
 }
 
 fn generate_xy_gradient_image(w: u32, h: u32) -> (ImageDescriptor, ImageData) {
     let mut pixels = Vec::with_capacity((w * h * 4) as usize);
     for y in 0 .. h {
         for x in 0 .. w {
@@ -134,17 +134,17 @@ fn generate_xy_gradient_image(w: u32, h:
             pixels.push((y as f32 / h as f32 * 255.0 * grid) as u8);
             pixels.push(0);
             pixels.push((x as f32 / w as f32 * 255.0 * grid) as u8);
             pixels.push(255);
         }
     }
 
     (
-        ImageDescriptor::new(w, h, ImageFormat::BGRA8, true, false),
+        ImageDescriptor::new(w as i32, h as i32, ImageFormat::BGRA8, true, false),
         ImageData::new(pixels),
     )
 }
 
 fn generate_solid_color_image(
     r: u8,
     g: u8,
     b: u8,
@@ -164,17 +164,17 @@ fn generate_solid_color_image(
         let end = ptr.offset((w * h) as isize);
         while ptr < end {
             *ptr = color;
             ptr = ptr.offset(1);
         }
     }
 
     (
-        ImageDescriptor::new(w, h, ImageFormat::BGRA8, a == 255, false),
+        ImageDescriptor::new(w as i32, h as i32, ImageFormat::BGRA8, a == 255, false),
         ImageData::new(pixels),
     )
 }
 
 
 
 fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool {
     match format {
@@ -456,18 +456,18 @@ impl YamlFrameReader {
                                 0xff
                             ]);
                         }
                         (ImageFormat::BGRA8, pixels)
                     }
                     _ => panic!("We don't support whatever your crazy image type is, come on"),
                 };
                 let descriptor = ImageDescriptor::new(
-                    image_width,
-                    image_height,
+                    image_width as i32,
+                    image_height as i32,
                     format,
                     is_image_opaque(format, &bytes[..]),
                     self.allow_mipmaps,
                 );
                 let data = ImageData::new(bytes);
                 (descriptor, data)
             }
             _ => {
@@ -962,19 +962,19 @@ impl YamlFrameReader {
                             NinePatchBorderSource::RadialGradient(gradient)
 
                         }
                         _ => unreachable!("Unexpected border type"),
                     };
 
                     Some(BorderDetails::NinePatch(NinePatchBorder {
                         source,
-                        width: image_width as u32,
-                        height: image_height as u32,
-                        slice: SideOffsets2D::new(slice[0], slice[1], slice[2], slice[3]),
+                        width: image_width as i32,
+                        height: image_height as i32,
+                        slice: SideOffsets2D::new(slice[0] as i32, slice[1] as i32, slice[2] as i32, slice[3] as i32),
                         fill,
                         repeat_horizontal,
                         repeat_vertical,
                         outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
                     }))
                 }
                 _ => {
                     println!("Unable to parse border {:?}", item);
--- a/gfx/wrench/src/yaml_frame_writer.rs
+++ b/gfx/wrench/src/yaml_frame_writer.rs
@@ -108,16 +108,20 @@ fn rect_node<U>(parent: &mut Table, key:
 fn matrix4d_node<U1, U2>(parent: &mut Table, key: &str, value: &TypedTransform3D<f32, U1, U2>) {
     f32_vec_node(parent, key, &value.to_row_major_array());
 }
 
 fn u32_node(parent: &mut Table, key: &str, value: u32) {
     yaml_node(parent, key, Yaml::Integer(value as i64));
 }
 
+fn i32_node(parent: &mut Table, key: &str, value: i32) {
+    yaml_node(parent, key, Yaml::Integer(value as i64));
+}
+
 fn usize_node(parent: &mut Table, key: &str, value: usize) {
     yaml_node(parent, key, Yaml::Integer(value as i64));
 }
 
 fn f32_node(parent: &mut Table, key: &str, value: f32) {
     yaml_node(parent, key, Yaml::Real(value.to_string()));
 }
 
@@ -140,16 +144,24 @@ fn string_vec_yaml(value: &[String], che
 fn u32_vec_yaml(value: &[u32], check_unique: bool) -> Yaml {
     if !value.is_empty() && check_unique && array_elements_are_same(value) {
         Yaml::Integer(value[0] as i64)
     } else {
         Yaml::Array(value.iter().map(|v| Yaml::Integer(*v as i64)).collect())
     }
 }
 
+fn i32_vec_yaml(value: &[i32], check_unique: bool) -> Yaml {
+    if !value.is_empty() && check_unique && array_elements_are_same(value) {
+        Yaml::Integer(value[0] as i64)
+    } else {
+        Yaml::Array(value.iter().map(|v| Yaml::Integer(*v as i64)).collect())
+    }
+}
+
 fn u32_vec_node(parent: &mut Table, key: &str, value: &[u32]) {
     yaml_node(parent, key, u32_vec_yaml(value, false));
 }
 
 fn f32_vec_yaml(value: &[f32], check_unique: bool) -> Yaml {
     if !value.is_empty() && check_unique && array_elements_are_same(value) {
         Yaml::Real(value[0].to_string())
     } else {
@@ -341,19 +353,19 @@ enum CachedFont {
 }
 
 struct CachedFontInstance {
     font_key: FontKey,
     glyph_size: Au,
 }
 
 struct CachedImage {
-    width: u32,
-    height: u32,
-    stride: u32,
+    width: i32,
+    height: i32,
+    stride: i32,
     format: ImageFormat,
     bytes: Option<Vec<u8>>,
     path: Option<PathBuf>,
     tiling: Option<u16>,
 }
 
 struct ResourceGenerator {
     base: PathBuf,
@@ -634,31 +646,43 @@ impl YamlFrameWriter {
                 return None;
             }
         };
 
         if data.stride == data.width * bpp {
             if data.format == ImageFormat::BGRA8 {
                 unpremultiply(bytes.as_mut_slice());
             }
-            save_buffer(&path_file, &bytes, data.width, data.height, color_type).unwrap();
+            save_buffer(
+                &path_file,
+                &bytes,
+                data.width as u32,
+                data.height as u32,
+                color_type,
+            ).unwrap();
         } else {
             // takes a buffer with a stride and copies it into a new buffer that has stride == width
             assert!(data.stride > data.width * bpp);
             let mut tmp: Vec<_> = bytes[..]
                 .chunks(data.stride as usize)
                 .flat_map(|chunk| {
                     chunk[.. (data.width * bpp) as usize].iter().cloned()
                 })
                 .collect();
             if data.format == ImageFormat::BGRA8 {
                 unpremultiply(tmp.as_mut_slice());
             }
 
-            save_buffer(&path_file, &tmp, data.width, data.height, color_type).unwrap();
+            save_buffer(
+                &path_file,
+                &tmp,
+                data.width as u32,
+                data.height as u32,
+                color_type
+            ).unwrap();
         }
 
         data.path = Some(path.clone());
         Some(path)
     }
 
     fn make_complex_clip_node(&mut self, complex_clip: &ComplexClipRegion) -> Yaml {
         let mut t = new_table();
@@ -920,25 +944,25 @@ impl YamlFrameWriter {
                                         &mut v,
                                         &gradient,
                                         base.gradient_stops(),
                                         display_list
                                     );
                                 }
                             }
 
-                            u32_node(&mut v, "image-width", details.width);
-                            u32_node(&mut v, "image-height", details.height);
-                            let slice: Vec<u32> = vec![
+                            i32_node(&mut v, "image-width", details.width);
+                            i32_node(&mut v, "image-height", details.height);
+                            let slice = [
                                 details.slice.top,
                                 details.slice.right,
                                 details.slice.bottom,
                                 details.slice.left,
                             ];
-                            yaml_node(&mut v, "slice", u32_vec_yaml(&slice, true));
+                            yaml_node(&mut v, "slice", i32_vec_yaml(&slice, true));
                             yaml_node(&mut v, "outset", f32_vec_yaml(&outset, true));
                             match details.repeat_horizontal {
                                 RepeatMode::Stretch => {
                                     str_node(&mut v, "repeat-horizontal", "stretch")
                                 }
                                 RepeatMode::Repeat => {
                                     str_node(&mut v, "repeat-horizontal", "repeat")
                                 }