Bug 1464473 - Update webrender to 3829687ffbe8d55885d71a3d5e5e79216251548f. r=Gankro
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 29 May 2018 08:45:25 -0400
changeset 420514 84bcc6fa5f9c60bfea8c57ebd58b93f6f74c53c6
parent 420513 324e22546444ba80d38d5899706fdc993efd1f18
child 420515 23da3fec993bf78437791a545f4d14979de1066b
push id103828
push useraiakab@mozilla.com
push dateWed, 30 May 2018 22:08:58 +0000
treeherdermozilla-inbound@8d0ee6e73fb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGankro
bugs1464473
milestone62.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 1464473 - Update webrender to 3829687ffbe8d55885d71a3d5e5e79216251548f. r=Gankro MozReview-Commit-ID: 100EQ2cTdj4
gfx/webrender/Cargo.toml
gfx/webrender/examples/alpha_perf.rs
gfx/webrender/examples/animation.rs
gfx/webrender/examples/basic.rs
gfx/webrender/examples/blob.rs
gfx/webrender/examples/common/boilerplate.rs
gfx/webrender/examples/document.rs
gfx/webrender/examples/frame_output.rs
gfx/webrender/examples/iframe.rs
gfx/webrender/examples/image_resize.rs
gfx/webrender/examples/multiwindow.rs
gfx/webrender/examples/scrolling.rs
gfx/webrender/examples/texture_cache_stress.rs
gfx/webrender/examples/yuv.rs
gfx/webrender/src/clip_scroll_node.rs
gfx/webrender/src/device.rs
gfx/webrender/src/lib.rs
gfx/webrender/src/renderer.rs
gfx/webrender/src/scene_builder.rs
gfx/webrender_bindings/revision.txt
gfx/wrench/Cargo.toml
gfx/wrench/src/angle.rs
gfx/wrench/src/egl.rs
gfx/wrench/src/main.rs
gfx/wrench/src/wrench.rs
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -10,16 +10,17 @@ build = "build.rs"
 default = ["freetype-lib"]
 freetype-lib = ["freetype/servo-freetype-sys"]
 profiler = ["thread_profiler/thread_profiler", "debug_renderer"]
 debugger = ["ws", "serde_json", "serde", "image", "base64", "debug_renderer"]
 capture = ["webrender_api/serialize", "ron", "serde", "debug_renderer"]
 replay = ["webrender_api/deserialize", "ron", "serde"]
 debug_renderer = []
 pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_partitioner", "pathfinder_path_utils"]
+serialize_program = ["serde"]
 
 [dependencies]
 app_units = "0.6"
 base64 = { optional = true, version = "0.6" }
 bincode = "1.0"
 bitflags = "1.0"
 byteorder = "1.0"
 cfg-if = "0.1.2"
@@ -59,17 +60,18 @@ optional = true
 [dependencies.pathfinder_path_utils]
 git = "https://github.com/pcwalton/pathfinder"
 optional = true
 
 [dev-dependencies]
 mozangle = "0.1"
 env_logger = "0.5"
 rand = "0.3"                # for the benchmarks
-glutin = "0.13"             # for the example apps
+glutin = "0.15"             # for the example apps
+winit = "0.13"              # for the example apps
 
 [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
 freetype = { version = "0.4", default-features = false }
 
 [target.'cfg(target_os = "windows")'.dependencies]
 dwrote = "0.4.1"
 
 [target.'cfg(target_os = "macos")'.dependencies]
--- a/gfx/webrender/examples/alpha_perf.rs
+++ b/gfx/webrender/examples/alpha_perf.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use std::cmp;
 use webrender::api::*;
 
@@ -46,35 +47,35 @@ impl Example for App {
             builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 0.05));
         }
 
         builder.pop_stacking_context();
     }
 
     fn on_event(
         &mut self,
-        event: glutin::WindowEvent,
+        event: winit::WindowEvent,
         _api: &RenderApi,
         _document_id: DocumentId
     ) -> bool {
         match event {
-            glutin::WindowEvent::KeyboardInput {
-                input: glutin::KeyboardInput {
-                    state: glutin::ElementState::Pressed,
+            winit::WindowEvent::KeyboardInput {
+                input: winit::KeyboardInput {
+                    state: winit::ElementState::Pressed,
                     virtual_keycode: Some(key),
                     ..
                 },
                 ..
             } => {
                 match key {
-                    glutin::VirtualKeyCode::Right => {
+                    winit::VirtualKeyCode::Right => {
                         self.rect_count += 1;
                         println!("rects = {}", self.rect_count);
                     }
-                    glutin::VirtualKeyCode::Left => {
+                    winit::VirtualKeyCode::Left => {
                         self.rect_count = cmp::max(self.rect_count, 1) - 1;
                         println!("rects = {}", self.rect_count);
                     }
                     _ => {}
                 };
             }
             _ => (),
         }
--- a/gfx/webrender/examples/animation.rs
+++ b/gfx/webrender/examples/animation.rs
@@ -9,16 +9,17 @@
 //! The example also features seamless opaque/transparent split of a
 //! rounded cornered rectangle, which is done automatically during the
 //! scene building for render optimization.
 
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use euclid::Angle;
 use webrender::api::*;
 
@@ -69,35 +70,35 @@ impl Example for App {
         // Fill it with a white rect
         builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
 
         builder.pop_clip_id();
 
         builder.pop_stacking_context();
     }
 
-    fn on_event(&mut self, win_event: glutin::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
+    fn on_event(&mut self, win_event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
         match win_event {
-            glutin::WindowEvent::KeyboardInput {
-                input: glutin::KeyboardInput {
-                    state: glutin::ElementState::Pressed,
+            winit::WindowEvent::KeyboardInput {
+                input: winit::KeyboardInput {
+                    state: winit::ElementState::Pressed,
                     virtual_keycode: Some(key),
                     ..
                 },
                 ..
             } => {
                 let (offset_x, offset_y, angle, delta_opacity) = match key {
-                    glutin::VirtualKeyCode::Down => (0.0, 10.0, 0.0, 0.0),
-                    glutin::VirtualKeyCode::Up => (0.0, -10.0, 0.0, 0.0),
-                    glutin::VirtualKeyCode::Right => (10.0, 0.0, 0.0, 0.0),
-                    glutin::VirtualKeyCode::Left => (-10.0, 0.0, 0.0, 0.0),
-                    glutin::VirtualKeyCode::Comma => (0.0, 0.0, 0.1, 0.0),
-                    glutin::VirtualKeyCode::Period => (0.0, 0.0, -0.1, 0.0),
-                    glutin::VirtualKeyCode::Z => (0.0, 0.0, 0.0, -0.1),
-                    glutin::VirtualKeyCode::X => (0.0, 0.0, 0.0, 0.1),
+                    winit::VirtualKeyCode::Down => (0.0, 10.0, 0.0, 0.0),
+                    winit::VirtualKeyCode::Up => (0.0, -10.0, 0.0, 0.0),
+                    winit::VirtualKeyCode::Right => (10.0, 0.0, 0.0, 0.0),
+                    winit::VirtualKeyCode::Left => (-10.0, 0.0, 0.0, 0.0),
+                    winit::VirtualKeyCode::Comma => (0.0, 0.0, 0.1, 0.0),
+                    winit::VirtualKeyCode::Period => (0.0, 0.0, -0.1, 0.0),
+                    winit::VirtualKeyCode::Z => (0.0, 0.0, 0.0, -0.1),
+                    winit::VirtualKeyCode::X => (0.0, 0.0, 0.0, 0.1),
                     _ => return false,
                 };
                 // Update the transform based on the keyboard input and push it to
                 // webrender using the generate_frame API. This will recomposite with
                 // the updated transform.
                 self.opacity += delta_opacity;
                 let new_transform = self.transform
                     .pre_rotate(0.0, 0.0, 1.0, Angle::radians(angle))
--- a/gfx/webrender/examples/basic.rs
+++ b/gfx/webrender/examples/basic.rs
@@ -2,23 +2,24 @@
  * 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/. */
 
 extern crate app_units;
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use euclid::vec2;
-use glutin::TouchPhase;
+use winit::TouchPhase;
 use std::collections::HashMap;
 use webrender::api::*;
 
 #[derive(Debug)]
 enum Gesture {
     None,
     Pan,
     Zoom,
@@ -80,17 +81,17 @@ impl TouchState {
             current_gesture: Gesture::None,
             start_zoom: 1.0,
             current_zoom: 1.0,
             start_pan: DeviceIntPoint::zero(),
             current_pan: DeviceIntPoint::zero(),
         }
     }
 
-    fn handle_event(&mut self, touch: glutin::Touch) -> TouchResult {
+    fn handle_event(&mut self, touch: winit::Touch) -> TouchResult {
         match touch.phase {
             TouchPhase::Started => {
                 debug_assert!(!self.active_touches.contains_key(&touch.id));
                 self.active_touches.insert(
                     touch.id,
                     Touch {
                         id: touch.id,
                         start_x: touch.location.0 as f32,
@@ -269,20 +270,20 @@ impl Example for App {
                 BorderRadius::uniform(simple_border_radius),
                 box_shadow_type,
             );
         }
 
         builder.pop_stacking_context();
     }
 
-    fn on_event(&mut self, event: glutin::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
+    fn on_event(&mut self, event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
         let mut txn = Transaction::new();
         match event {
-            glutin::WindowEvent::Touch(touch) => match self.touch_state.handle_event(touch) {
+            winit::WindowEvent::Touch(touch) => match self.touch_state.handle_event(touch) {
                 TouchResult::Pan(pan) => {
                     txn.set_pan(pan);
                 }
                 TouchResult::Zoom(zoom) => {
                     txn.set_pinch_zoom(ZoomFactor::new(zoom));
                 }
                 TouchResult::None => {}
             },
--- a/gfx/webrender/examples/blob.rs
+++ b/gfx/webrender/examples/blob.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate gleam;
 extern crate glutin;
 extern crate rayon;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use rayon::{ThreadPool, ThreadPoolBuilder};
 use std::collections::HashMap;
 use std::collections::hash_map::Entry;
--- a/gfx/webrender/examples/common/boilerplate.rs
+++ b/gfx/webrender/examples/common/boilerplate.rs
@@ -5,24 +5,25 @@
 extern crate env_logger;
 extern crate euclid;
 
 use gleam::gl;
 use glutin::{self, GlContext};
 use std::env;
 use std::path::PathBuf;
 use webrender;
+use winit;
 use webrender::api::*;
 
 struct Notifier {
-    events_proxy: glutin::EventsLoopProxy,
+    events_proxy: winit::EventsLoopProxy,
 }
 
 impl Notifier {
-    fn new(events_proxy: glutin::EventsLoopProxy) -> Notifier {
+    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
         Notifier { events_proxy }
     }
 }
 
 impl RenderNotifier for Notifier {
     fn clone(&self) -> Box<RenderNotifier> {
         Box::new(Notifier {
             events_proxy: self.events_proxy.clone(),
@@ -71,17 +72,17 @@ pub trait Example {
         &mut self,
         api: &RenderApi,
         builder: &mut DisplayListBuilder,
         txn: &mut Transaction,
         framebuffer_size: DeviceUintSize,
         pipeline_id: PipelineId,
         document_id: DocumentId,
     );
-    fn on_event(&mut self, glutin::WindowEvent, &RenderApi, DocumentId) -> bool {
+    fn on_event(&mut self, winit::WindowEvent, &RenderApi, DocumentId) -> bool {
         false
     }
     fn get_image_handlers(
         &mut self,
         _gl: &gl::Gl,
     ) -> (Option<Box<webrender::ExternalImageHandler>>,
           Option<Box<webrender::OutputImageHandler>>) {
         (None, None)
@@ -98,23 +99,23 @@ pub fn main_wrapper<E: Example>(
 
     let args: Vec<String> = env::args().collect();
     let res_path = if args.len() > 1 {
         Some(PathBuf::from(&args[1]))
     } else {
         None
     };
 
-    let mut events_loop = glutin::EventsLoop::new();
+    let mut events_loop = winit::EventsLoop::new();
     let context_builder = glutin::ContextBuilder::new()
         .with_gl(glutin::GlRequest::GlThenGles {
             opengl_version: (3, 2),
             opengles_version: (3, 0),
         });
-    let window_builder = glutin::WindowBuilder::new()
+    let window_builder = winit::WindowBuilder::new()
         .with_title(E::TITLE)
         .with_multitouch()
         .with_dimensions(E::WIDTH, E::HEIGHT);
     let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
         .unwrap();
 
     unsafe {
         window.make_current().ok();
@@ -191,65 +192,68 @@ pub fn main_wrapper<E: Example>(
     api.send_transaction(document_id, txn);
 
     println!("Entering event loop");
     events_loop.run_forever(|global_event| {
         let mut txn = Transaction::new();
         let mut custom_event = true;
 
         match global_event {
-            glutin::Event::WindowEvent { event: glutin::WindowEvent::Closed, .. } => return glutin::ControlFlow::Break,
-            glutin::Event::WindowEvent {
-                event: glutin::WindowEvent::KeyboardInput {
-                    input: glutin::KeyboardInput {
-                        state: glutin::ElementState::Pressed,
+            winit::Event::WindowEvent {
+                event: winit::WindowEvent::CloseRequested,
+                ..
+            } => return winit::ControlFlow::Break,
+            winit::Event::WindowEvent {
+                event: winit::WindowEvent::KeyboardInput {
+                    input: winit::KeyboardInput {
+                        state: winit::ElementState::Pressed,
                         virtual_keycode: Some(key),
                         ..
                     },
                     ..
                 },
                 ..
             } => match key {
-                glutin::VirtualKeyCode::Escape => return glutin::ControlFlow::Break,
-                glutin::VirtualKeyCode::P => renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG),
-                glutin::VirtualKeyCode::O => renderer.toggle_debug_flags(webrender::DebugFlags::RENDER_TARGET_DBG),
-                glutin::VirtualKeyCode::I => renderer.toggle_debug_flags(webrender::DebugFlags::TEXTURE_CACHE_DBG),
-                glutin::VirtualKeyCode::S => renderer.toggle_debug_flags(webrender::DebugFlags::COMPACT_PROFILER),
-                glutin::VirtualKeyCode::Q => renderer.toggle_debug_flags(
+                winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break,
+                winit::VirtualKeyCode::P => renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG),
+                winit::VirtualKeyCode::O => renderer.toggle_debug_flags(webrender::DebugFlags::RENDER_TARGET_DBG),
+                winit::VirtualKeyCode::I => renderer.toggle_debug_flags(webrender::DebugFlags::TEXTURE_CACHE_DBG),
+                winit::VirtualKeyCode::S => renderer.toggle_debug_flags(webrender::DebugFlags::COMPACT_PROFILER),
+                winit::VirtualKeyCode::Q => renderer.toggle_debug_flags(
                     webrender::DebugFlags::GPU_TIME_QUERIES | webrender::DebugFlags::GPU_SAMPLE_QUERIES
                 ),
-                glutin::VirtualKeyCode::Key1 => txn.set_window_parameters(
+                winit::VirtualKeyCode::Key1 => txn.set_window_parameters(
                     framebuffer_size,
                     DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size),
                     1.0
                 ),
-                glutin::VirtualKeyCode::Key2 => txn.set_window_parameters(
+                winit::VirtualKeyCode::Key2 => txn.set_window_parameters(
                     framebuffer_size,
                     DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size),
                     2.0
                 ),
-                glutin::VirtualKeyCode::M => api.notify_memory_pressure(),
+                winit::VirtualKeyCode::M => api.notify_memory_pressure(),
                 #[cfg(feature = "capture")]
-                glutin::VirtualKeyCode::C => {
+                winit::VirtualKeyCode::C => {
                     let path: PathBuf = "../captures/example".into();
                     //TODO: switch between SCENE/FRAME capture types
                     // based on "shift" modifier, when `glutin` is updated.
                     let bits = CaptureBits::all();
                     api.save_capture(path, bits);
                 },
                 _ => {
                     let win_event = match global_event {
-                        glutin::Event::WindowEvent { event, .. } => event,
+                        winit::Event::WindowEvent { event, .. } => event,
                         _ => unreachable!()
                     };
                     custom_event = example.on_event(win_event, &api, document_id)
                 },
             },
-            glutin::Event::WindowEvent { event, .. } => custom_event = example.on_event(event, &api, document_id),
-            _ => return glutin::ControlFlow::Continue,
+            winit::Event::WindowEvent { event, .. } => custom_event = example.on_event(event, &api, document_id),
+            _ => return winit::ControlFlow::Continue,
         };
 
         if custom_event {
             let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
 
             example.render(
                 &api,
                 &mut builder,
@@ -270,13 +274,13 @@ pub fn main_wrapper<E: Example>(
         api.send_transaction(document_id, txn);
 
         renderer.update();
         renderer.render(framebuffer_size).unwrap();
         let _ = renderer.flush_pipeline_info();
         example.draw_custom(&*gl);
         window.swap_buffers().ok();
 
-        glutin::ControlFlow::Continue
+        winit::ControlFlow::Continue
     });
 
     renderer.deinit();
 }
--- a/gfx/webrender/examples/document.rs
+++ b/gfx/webrender/examples/document.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::Example;
 use euclid::TypedScale;
 use webrender::api::*;
 
--- a/gfx/webrender/examples/frame_output.rs
+++ b/gfx/webrender/examples/frame_output.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use euclid::TypedScale;
 use gleam::gl;
 use webrender::api::*;
--- a/gfx/webrender/examples/iframe.rs
+++ b/gfx/webrender/examples/iframe.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use webrender::api::*;
 
 // This example uses the push_iframe API to nest a second pipeline's displaylist
--- a/gfx/webrender/examples/image_resize.rs
+++ b/gfx/webrender/examples/image_resize.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 #[path = "common/image_helper.rs"]
 mod image_helper;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use webrender::api::*;
@@ -75,22 +76,22 @@ impl Example for App {
             ImageRendering::Pixelated,
             AlphaType::PremultipliedAlpha,
             self.image_key,
         );
 
         builder.pop_stacking_context();
     }
 
-    fn on_event(&mut self, event: glutin::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
+    fn on_event(&mut self, event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
         match event {
-            glutin::WindowEvent::KeyboardInput {
-                input: glutin::KeyboardInput {
-                    state: glutin::ElementState::Pressed,
-                    virtual_keycode: Some(glutin::VirtualKeyCode::Space),
+            winit::WindowEvent::KeyboardInput {
+                input: winit::KeyboardInput {
+                    state: winit::ElementState::Pressed,
+                    virtual_keycode: Some(winit::VirtualKeyCode::Space),
                     ..
                 },
                 ..
             } => {
                 let mut image_data = Vec::new();
                 for y in 0 .. 64 {
                     for x in 0 .. 64 {
                         let r = 255 * ((y & 32) == 0) as u8;
--- a/gfx/webrender/examples/multiwindow.rs
+++ b/gfx/webrender/examples/multiwindow.rs
@@ -2,30 +2,31 @@
  * 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/. */
 
 extern crate app_units;
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 use app_units::Au;
 use gleam::gl;
 use glutin::GlContext;
 use std::fs::File;
 use std::io::Read;
 use webrender::api::*;
 
 struct Notifier {
-    events_proxy: glutin::EventsLoopProxy,
+    events_proxy: winit::EventsLoopProxy,
 }
 
 impl Notifier {
-    fn new(events_proxy: glutin::EventsLoopProxy) -> Notifier {
+    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
         Notifier { events_proxy }
     }
 }
 
 impl RenderNotifier for Notifier {
     fn clone(&self) -> Box<RenderNotifier> {
         Box::new(Notifier {
             events_proxy: self.events_proxy.clone(),
@@ -38,36 +39,36 @@ impl RenderNotifier for Notifier {
     }
 
     fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool) {
         self.wake_up();
     }
 }
 
 struct Window {
-    events_loop: glutin::EventsLoop, //TODO: share events loop?
+    events_loop: winit::EventsLoop, //TODO: share events loop?
     window: glutin::GlWindow,
     renderer: webrender::Renderer,
     name: &'static str,
     pipeline_id: PipelineId,
     document_id: DocumentId,
     epoch: Epoch,
     api: RenderApi,
     font_instance_key: FontInstanceKey,
 }
 
 impl Window {
     fn new(name: &'static str, clear_color: ColorF) -> Self {
-        let events_loop = glutin::EventsLoop::new();
+        let events_loop = winit::EventsLoop::new();
         let context_builder = glutin::ContextBuilder::new()
             .with_gl(glutin::GlRequest::GlThenGles {
                 opengl_version: (3, 2),
                 opengles_version: (3, 0),
             });
-        let window_builder = glutin::WindowBuilder::new()
+        let window_builder = winit::WindowBuilder::new()
             .with_title(name)
             .with_multitouch()
             .with_dimensions(800, 600);
         let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
             .unwrap();
 
         unsafe {
             window.make_current().ok();
@@ -130,31 +131,31 @@ impl Window {
         unsafe {
             self.window.make_current().ok();
         }
         let mut do_exit = false;
         let my_name = &self.name;
         let renderer = &mut self.renderer;
 
         self.events_loop.poll_events(|global_event| match global_event {
-            glutin::Event::WindowEvent { event, .. } => match event {
-                glutin::WindowEvent::Closed |
-                glutin::WindowEvent::KeyboardInput {
-                    input: glutin::KeyboardInput {
-                        virtual_keycode: Some(glutin::VirtualKeyCode::Escape),
+            winit::Event::WindowEvent { event, .. } => match event {
+                winit::WindowEvent::CloseRequested |
+                winit::WindowEvent::KeyboardInput {
+                    input: winit::KeyboardInput {
+                        virtual_keycode: Some(winit::VirtualKeyCode::Escape),
                         ..
                     },
                     ..
                 } => {
                     do_exit = true
                 }
-                glutin::WindowEvent::KeyboardInput {
-                    input: glutin::KeyboardInput {
-                        state: glutin::ElementState::Pressed,
-                        virtual_keycode: Some(glutin::VirtualKeyCode::P),
+                winit::WindowEvent::KeyboardInput {
+                    input: winit::KeyboardInput {
+                        state: winit::ElementState::Pressed,
+                        virtual_keycode: Some(winit::VirtualKeyCode::P),
                         ..
                     },
                     ..
                 } => {
                     println!("toggle flags {}", my_name);
                     renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG);
                 }
                 _ => {}
--- a/gfx/webrender/examples/scrolling.rs
+++ b/gfx/webrender/examples/scrolling.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use euclid::SideOffsets2D;
 use webrender::api::*;
 
@@ -138,56 +139,56 @@ impl Example for App {
 
             builder.pop_clip_id(); // clip_id
             builder.pop_stacking_context();
         }
 
         builder.pop_stacking_context();
     }
 
-    fn on_event(&mut self, event: glutin::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
+    fn on_event(&mut self, event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
         let mut txn = Transaction::new();
         match event {
-            glutin::WindowEvent::KeyboardInput {
-                input: glutin::KeyboardInput {
-                    state: glutin::ElementState::Pressed,
+            winit::WindowEvent::KeyboardInput {
+                input: winit::KeyboardInput {
+                    state: winit::ElementState::Pressed,
                     virtual_keycode: Some(key),
                     ..
                 },
                 ..
             } => {
                 let offset = match key {
-                    glutin::VirtualKeyCode::Down => (0.0, -10.0),
-                    glutin::VirtualKeyCode::Up => (0.0, 10.0),
-                    glutin::VirtualKeyCode::Right => (-10.0, 0.0),
-                    glutin::VirtualKeyCode::Left => (10.0, 0.0),
+                    winit::VirtualKeyCode::Down => (0.0, -10.0),
+                    winit::VirtualKeyCode::Up => (0.0, 10.0),
+                    winit::VirtualKeyCode::Right => (-10.0, 0.0),
+                    winit::VirtualKeyCode::Left => (10.0, 0.0),
                     _ => return false,
                 };
 
                 txn.scroll(
                     ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
                     self.cursor_position,
                 );
             }
-            glutin::WindowEvent::CursorMoved { position: (x, y), .. } => {
+            winit::WindowEvent::CursorMoved { position: (x, y), .. } => {
                 self.cursor_position = WorldPoint::new(x as f32, y as f32);
             }
-            glutin::WindowEvent::MouseWheel { delta, .. } => {
+            winit::WindowEvent::MouseWheel { delta, .. } => {
                 const LINE_HEIGHT: f32 = 38.0;
                 let (dx, dy) = match delta {
-                    glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
-                    glutin::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
+                    winit::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
+                    winit::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
                 };
 
                 txn.scroll(
                     ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
                     self.cursor_position,
                 );
             }
-            glutin::WindowEvent::MouseInput { .. } => {
+            winit::WindowEvent::MouseInput { .. } => {
                 let results = api.hit_test(
                     document_id,
                     None,
                     self.cursor_position,
                     HitTestFlags::FIND_ALL
                 );
 
                 println!("Hit test results:");
--- a/gfx/webrender/examples/texture_cache_stress.rs
+++ b/gfx/webrender/examples/texture_cache_stress.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::{Example, HandyDandyRectBuilder};
 use gleam::gl;
 use std::mem;
 use webrender::api::*;
@@ -182,33 +183,33 @@ impl Example for App {
         );
         self.swap_index = 1 - self.swap_index;
 
         builder.pop_stacking_context();
     }
 
     fn on_event(
         &mut self,
-        event: glutin::WindowEvent,
+        event: winit::WindowEvent,
         api: &RenderApi,
         _document_id: DocumentId,
     ) -> bool {
         match event {
-            glutin::WindowEvent::KeyboardInput {
-                input: glutin::KeyboardInput {
-                    state: glutin::ElementState::Pressed,
+            winit::WindowEvent::KeyboardInput {
+                input: winit::KeyboardInput {
+                    state: winit::ElementState::Pressed,
                     virtual_keycode: Some(key),
                     ..
                 },
                 ..
             } => {
                 let mut txn = Transaction::new();
 
                 match key {
-                    glutin::VirtualKeyCode::S => {
+                    winit::VirtualKeyCode::S => {
                         self.stress_keys.clear();
 
                         for _ in 0 .. 16 {
                             for _ in 0 .. 16 {
                                 let size = 4;
 
                                 let image_key = api.generate_image_key();
 
@@ -220,31 +221,31 @@ impl Example for App {
                                     ImageData::new(self.image_generator.take()),
                                     None,
                                 );
 
                                 self.stress_keys.push(image_key);
                             }
                         }
                     }
-                    glutin::VirtualKeyCode::D => if let Some(image_key) = self.image_key.take() {
+                    winit::VirtualKeyCode::D => if let Some(image_key) = self.image_key.take() {
                         txn.delete_image(image_key);
                     },
-                    glutin::VirtualKeyCode::U => if let Some(image_key) = self.image_key {
+                    winit::VirtualKeyCode::U => if let Some(image_key) = self.image_key {
                         let size = 128;
                         self.image_generator.generate_image(size);
 
                         txn.update_image(
                             image_key,
                             ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
                             ImageData::new(self.image_generator.take()),
                             None,
                         );
                     },
-                    glutin::VirtualKeyCode::E => {
+                    winit::VirtualKeyCode::E => {
                         if let Some(image_key) = self.image_key.take() {
                             txn.delete_image(image_key);
                         }
 
                         let size = 32;
                         let image_key = api.generate_image_key();
 
                         let image_data = ExternalImageData {
@@ -257,17 +258,17 @@ impl Example for App {
                             image_key,
                             ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
                             ImageData::External(image_data),
                             None,
                         );
 
                         self.image_key = Some(image_key);
                     }
-                    glutin::VirtualKeyCode::R => {
+                    winit::VirtualKeyCode::R => {
                         if let Some(image_key) = self.image_key.take() {
                             txn.delete_image(image_key);
                         }
 
                         let image_key = api.generate_image_key();
                         let size = 32;
                         self.image_generator.generate_image(size);
 
--- a/gfx/webrender/examples/yuv.rs
+++ b/gfx/webrender/examples/yuv.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
+extern crate winit;
 
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use boilerplate::Example;
 use gleam::gl;
 use webrender::api::*;
 
@@ -171,17 +172,17 @@ impl Example for App {
             ImageRendering::Auto,
         );
 
         builder.pop_stacking_context();
     }
 
     fn on_event(
         &mut self,
-        _event: glutin::WindowEvent,
+        _event: winit::WindowEvent,
         _api: &RenderApi,
         _document_id: DocumentId,
     ) -> bool {
         false
     }
 
     fn get_image_handlers(
         &mut self,
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -206,28 +206,22 @@ impl ClipScrollNode {
         Self::new(pipeline_id, Some(parent_index), node_type)
     }
 
 
     pub fn add_child(&mut self, child: ClipScrollNodeIndex) {
         self.children.push(child);
     }
 
-    pub fn apply_old_scrolling_state(&mut self, old_scrolling_state: &ScrollFrameInfo) {
+    pub fn apply_old_scrolling_state(&mut self, old_scroll_info: &ScrollFrameInfo) {
         match self.node_type {
             NodeType::ScrollFrame(ref mut scrolling) => {
-                let scroll_sensitivity = scrolling.scroll_sensitivity;
-                let scrollable_size = scrolling.scrollable_size;
-                let viewport_rect = scrolling.viewport_rect;
-                *scrolling = *old_scrolling_state;
-                scrolling.scroll_sensitivity = scroll_sensitivity;
-                scrolling.scrollable_size = scrollable_size;
-                scrolling.viewport_rect = viewport_rect;
+                *scrolling = scrolling.combine_with_old_scroll_info(old_scroll_info);
             }
-            _ if old_scrolling_state.offset != LayoutVector2D::zero() => {
+            _ if old_scroll_info.offset != LayoutVector2D::zero() => {
                 warn!("Tried to scroll a non-scroll node.")
             }
             _ => {}
         }
     }
 
     pub fn set_scroll_origin(&mut self, origin: &LayoutPoint, clamp: ScrollClamping) -> bool {
         let scrollable_size = self.scrollable_size();
@@ -763,16 +757,29 @@ impl ScrollFrameInfo {
     }
 
     pub fn sensitive_to_input_events(&self) -> bool {
         match self.scroll_sensitivity {
             ScrollSensitivity::ScriptAndInputEvents => true,
             ScrollSensitivity::Script => false,
         }
     }
+
+    pub fn combine_with_old_scroll_info(
+        self,
+        old_scroll_info: &ScrollFrameInfo
+    ) -> ScrollFrameInfo {
+        ScrollFrameInfo {
+            viewport_rect: self.viewport_rect,
+            offset: old_scroll_info.offset,
+            scroll_sensitivity: self.scroll_sensitivity,
+            scrollable_size: self.scrollable_size,
+            external_id: self.external_id,
+        }
+    }
 }
 
 /// Contains information about reference frames.
 #[derive(Copy, Clone, Debug)]
 pub struct ReferenceFrameInfo {
     /// The transformation that establishes this reference frame, relative to the parent
     /// reference frame. The origin of the reference frame is included in the transformation.
     pub resolved_transform: LayoutFastTransform,
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -18,16 +18,17 @@ use std::fs::File;
 use std::io::Read;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::Add;
 use std::path::PathBuf;
 use std::ptr;
 use std::rc::Rc;
 use std::slice;
+use std::sync::Arc;
 use std::thread;
 
 #[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FrameId(usize);
 
 impl FrameId {
@@ -570,59 +571,86 @@ pub struct FBOId(gl::GLuint);
 pub struct RBOId(gl::GLuint);
 
 #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
 pub struct VBOId(gl::GLuint);
 
 #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
 struct IBOId(gl::GLuint);
 
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))]
 pub struct ProgramSources {
     renderer_name: String,
     vs_source: String,
     fs_source: String,
 }
 
 impl ProgramSources {
     fn new(renderer_name: String, vs_source: String, fs_source: String) -> Self {
         ProgramSources {
             renderer_name,
             vs_source,
             fs_source,
         }
     }
 }
 
+#[cfg_attr(feature = "serialize_program", derive(Deserialize, Serialize))]
 pub struct ProgramBinary {
     binary: Vec<u8>,
     format: gl::GLenum,
+    #[cfg(feature = "serialize_program")]
+    sources: ProgramSources,
 }
 
 impl ProgramBinary {
-    fn new(binary: Vec<u8>, format: gl::GLenum) -> Self {
+    #[allow(unused_variables)]
+    fn new(binary: Vec<u8>,
+           format: gl::GLenum,
+           sources: &ProgramSources) -> Self {
         ProgramBinary {
             binary,
-            format
+            format,
+            #[cfg(feature = "serialize_program")]
+            sources: sources.clone(),
         }
     }
 }
 
+/// The interfaces that an application can implement to handle ProgramCache update
+pub trait ProgramCacheObserver {
+    fn notify_binary_added(&self, program_binary: &Arc<ProgramBinary>);
+    fn notify_program_binary_failed(&self, program_binary: &Arc<ProgramBinary>);
+}
+
 pub struct ProgramCache {
-    pub binaries: RefCell<FastHashMap<ProgramSources, ProgramBinary>>,
+    binaries: RefCell<FastHashMap<ProgramSources, Arc<ProgramBinary>>>,
+
+    /// Optional trait object that allows the client
+    /// application to handle ProgramCache updating
+    program_cache_handler: Option<Box<ProgramCacheObserver>>,
 }
 
 impl ProgramCache {
-    pub fn new() -> Rc<Self> {
+    pub fn new(program_cache_observer: Option<Box<ProgramCacheObserver>>) -> Rc<Self> {
         Rc::new(
             ProgramCache {
                 binaries: RefCell::new(FastHashMap::default()),
+                program_cache_handler: program_cache_observer,
             }
         )
     }
+    /// Load ProgramBinary to ProgramCache.
+    /// The function is typically used to load ProgramBinary from disk.
+    #[cfg(feature = "serialize_program")]
+    pub fn load_program_binary(&self, program_binary: Arc<ProgramBinary>) {
+        let sources = program_binary.sources.clone();
+        self.binaries.borrow_mut().insert(sources, program_binary);
+    }
 }
 
 #[derive(Debug, Copy, Clone)]
 pub enum VertexUsageHint {
     Static,
     Dynamic,
     Stream,
 }
@@ -1417,16 +1445,19 @@ impl Device {
                 if link_status[0] == 0 {
                     let error_log = self.gl.get_program_info_log(pid);
                     error!(
                       "Failed to load a program object with a program binary: {} renderer {}\n{}",
                       base_filename,
                       self.renderer_name,
                       error_log
                     );
+                    if let Some(ref program_cache_handler) = cached_programs.program_cache_handler {
+                        program_cache_handler.notify_program_binary_failed(&binary);
+                    }
                 } else {
                     loaded = true;
                 }
             }
         }
 
         if loaded == false {
             // Compile the vertex shader
@@ -1491,17 +1522,21 @@ impl Device {
                 return Err(ShaderError::Link(base_filename.to_string(), error_log));
             }
         }
 
         if let Some(ref cached_programs) = self.cached_programs {
             if !cached_programs.binaries.borrow().contains_key(&sources) {
                 let (buffer, format) = self.gl.get_program_binary(pid);
                 if buffer.len() > 0 {
-                  cached_programs.binaries.borrow_mut().insert(sources, ProgramBinary::new(buffer, format));
+                    let program_binary = Arc::new(ProgramBinary::new(buffer, format, &sources));
+                    if let Some(ref program_cache_handler) = cached_programs.program_cache_handler {
+                        program_cache_handler.notify_binary_added(&program_binary);
+                    }
+                    cached_programs.binaries.borrow_mut().insert(sources, program_binary);
                 }
             }
         }
 
         let u_transform = self.gl.get_uniform_location(pid, "uTransform");
         let u_device_pixel_ratio = self.gl.get_uniform_location(pid, "uDevicePixelRatio");
         let u_mode = self.gl.get_uniform_location(pid, "uMode");
 
--- a/gfx/webrender/src/lib.rs
+++ b/gfx/webrender/src/lib.rs
@@ -43,17 +43,17 @@ they're nestable.
 #[macro_use]
 extern crate bitflags;
 #[macro_use]
 extern crate cfg_if;
 #[macro_use]
 extern crate lazy_static;
 #[macro_use]
 extern crate log;
-#[cfg(any(feature = "debugger", feature = "capture", feature = "replay"))]
+#[cfg(any(feature = "serde"))]
 #[macro_use]
 extern crate serde;
 #[macro_use]
 extern crate thread_profiler;
 
 mod batch;
 mod border;
 mod box_shadow;
@@ -175,16 +175,17 @@ extern crate image as image_loader;
 #[cfg(feature = "debugger")]
 extern crate base64;
 #[cfg(all(feature = "capture", feature = "png"))]
 extern crate png;
 
 pub extern crate webrender_api;
 
 #[doc(hidden)]
-pub use device::{build_shader_strings, ProgramCache, ReadPixelsFormat, UploadMethod, VertexUsageHint};
+pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint};
+pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSources};
 pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind};
 pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile};
 pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions};
 pub use renderer::{RendererStats, SceneBuilderHooks, ThreadListener};
 pub use renderer::MAX_VERTEX_TEXTURE_WIDTH;
 pub use webrender_api as api;
 pub use resource_cache::intersect_for_tile;
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -4015,16 +4015,20 @@ pub trait SceneBuilderHooks {
     /// and before it processes anything.
     fn register(&self);
     /// This is called before each scene swap occurs.
     fn pre_scene_swap(&self);
     /// This is called after each scene swap occurs. The PipelineInfo contains
     /// the updated epochs and pipelines removed in the new scene compared to
     /// the old scene.
     fn post_scene_swap(&self, info: PipelineInfo);
+    /// This is called after a resource update operation on the scene builder
+    /// thread, in the case where resource updates were applied without a scene
+    /// build.
+    fn post_resource_update(&self);
     /// This is a generic callback which provides an opportunity to run code
     /// on the scene builder thread. This is called as part of the main message
     /// loop of the scene builder thread, but outside of any specific message
     /// handler.
     fn poke(&self);
     /// This is called exactly once, when the scene builder thread is about to
     /// terminate.
     fn deregister(&self);
--- a/gfx/webrender/src/scene_builder.rs
+++ b/gfx/webrender/src/scene_builder.rs
@@ -157,16 +157,17 @@ impl SceneBuilder {
 
                         hooks.pre_scene_swap();
 
                         (Some(info), Some(tx), Some(rx))
                     }
                     _ => (None, None, None),
                 };
 
+                let has_resources_updates = !resource_updates.is_empty();
                 self.tx.send(SceneBuilderResult::Transaction {
                     document_id,
                     built_scene,
                     resource_updates,
                     frame_ops,
                     render,
                     result_tx,
                 }).unwrap();
@@ -179,16 +180,20 @@ impl SceneBuilder {
                     self.hooks.as_ref().unwrap().post_scene_swap(pipeline_info);
                     // Once the hook is done, allow the RB thread to resume
                     match swap_result {
                         Ok(SceneSwapResult::Complete(resume_tx)) => {
                             resume_tx.send(()).ok();
                         },
                         _ => (),
                     };
+                } else if has_resources_updates {
+                    if let &Some(ref hooks) = &self.hooks {
+                        hooks.post_resource_update();
+                    }
                 }
             }
             SceneBuilderRequest::Stop => {
                 self.tx.send(SceneBuilderResult::Stopped).unwrap();
                 // We don't need to send a WakeUp to api_tx because we only
                 // get the Stop when the RenderBackend loop is exiting.
                 return false;
             }
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-63c71ca9bbe4dec0ebc9c9bc8ab65b06a6b40641
+3829687ffbe8d55885d71a3d5e5e79216251548f
--- a/gfx/wrench/Cargo.toml
+++ b/gfx/wrench/Cargo.toml
@@ -7,31 +7,32 @@ license = "MPL-2.0"
 
 [dependencies]
 base64 = "0.6"
 bincode = "1.0"
 byteorder = "1.0"
 env_logger = { version = "0.5", optional = true }
 euclid = "0.17"
 gleam = "0.5"
-glutin = "0.13"
+glutin = "0.15"
 app_units = "0.6"
 image = "0.18"
 clap = { version = "2", features = ["yaml"] }
 lazy_static = "1"
 log = "0.4"
 yaml-rust = { git = "https://github.com/vvuk/yaml-rust", features = ["preserve_order"] }
 serde_json = "1.0"
 ron = "0.1.5"
 time = "0.1"
 crossbeam = "0.2"
 osmesa-sys = { version = "0.1.2", optional = true }
 osmesa-src = { git = "https://github.com/jrmuizel/osmesa-src", optional = true, branch = "serialize" }
 webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler"]}
 webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
+winit = "0.13"
 serde = {version = "1.0", features = ["derive"] }
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-graphics = "0.13"
 core-foundation = "0.5"
 
 [features]
 headless = [ "osmesa-sys", "osmesa-src" ]
--- a/gfx/wrench/src/angle.rs
+++ b/gfx/wrench/src/angle.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 glutin;
-use glutin::{WindowBuilder, ContextBuilder, EventsLoop, Window, CreationError};
+use glutin::{self, ContextBuilder, CreationError};
+use winit::{EventsLoop, Window, WindowBuilder};
 
 #[cfg(not(windows))]
 pub enum Context {}
 
 #[cfg(windows)]
 pub use ::egl::Context;
 
 impl Context {
@@ -22,17 +22,17 @@ impl Context {
     }
 
     #[cfg(windows)]
     pub fn with_window(
         window_builder: WindowBuilder,
         context_builder: ContextBuilder,
         events_loop: &EventsLoop,
     ) -> Result<(Window, Self), CreationError> {
-        use glutin::os::windows::WindowExt;
+        use winit::os::windows::WindowExt;
 
         // FIXME: &context_builder.pf_reqs  https://github.com/tomaka/glutin/pull/1002
         let pf_reqs = &glutin::PixelFormatRequirements::default();
         let gl_attr = &context_builder.gl_attr.map_sharing(|_| unimplemented!());
         let window = window_builder.build(events_loop)?;
         Self::new(pf_reqs, gl_attr)
             .and_then(|p| p.finish(window.get_hwnd() as _))
             .map(|context| (window, context))
--- a/gfx/wrench/src/egl.rs
+++ b/gfx/wrench/src/egl.rs
@@ -49,17 +49,17 @@ impl Context {
         if opengl.sharing.is_some() {
             unimplemented!()
         }
 
         // calling `eglGetDisplay` or equivalent
         let display = unsafe { egl::GetDisplay(ptr::null_mut()) };
 
         if display.is_null() {
-            return Err(CreationError::OsError("Could not create EGL display object".to_string()));
+            return Err(CreationError::PlatformSpecific("Could not create EGL display object".to_string()));
         }
 
         let egl_version = unsafe {
             let mut major: ffi::egl::types::EGLint = mem::uninitialized();
             let mut minor: ffi::egl::types::EGLint = mem::uninitialized();
 
             if egl::Initialize(display, &mut major, &mut minor) == 0 {
                 return Err(CreationError::OsError(format!("eglInitialize failed")))
--- a/gfx/wrench/src/main.rs
+++ b/gfx/wrench/src/main.rs
@@ -32,16 +32,17 @@ extern crate mozangle;
 #[cfg(feature = "headless")]
 extern crate osmesa_sys;
 extern crate ron;
 #[macro_use]
 extern crate serde;
 extern crate serde_json;
 extern crate time;
 extern crate webrender;
+extern crate winit;
 extern crate yaml_rust;
 
 mod angle;
 mod binary_frame_reader;
 mod blob;
 mod egl;
 mod json_frame_writer;
 mod parse_function;
@@ -56,33 +57,34 @@ mod wrench;
 mod yaml_frame_reader;
 mod yaml_frame_writer;
 mod yaml_helper;
 #[cfg(target_os = "macos")]
 mod cgfont_to_data;
 
 use binary_frame_reader::BinaryFrameReader;
 use gleam::gl;
-use glutin::{GlContext, VirtualKeyCode};
+use glutin::GlContext;
 use perf::PerfHarness;
 use png::save_flipped;
 use rawtest::RawtestHarness;
 use reftest::{ReftestHarness, ReftestOptions};
 #[cfg(feature = "headless")]
 use std::ffi::CString;
 #[cfg(feature = "headless")]
 use std::mem;
 use std::os::raw::c_void;
 use std::path::{Path, PathBuf};
 use std::process;
 use std::ptr;
 use std::rc::Rc;
 use std::sync::mpsc::{channel, Sender, Receiver};
 use webrender::DebugFlags;
 use webrender::api::*;
+use winit::VirtualKeyCode;
 use wrench::{Wrench, WrenchThing};
 use yaml_frame_reader::YamlFrameReader;
 
 lazy_static! {
     static ref PLATFORM_DEFAULT_FACE_NAME: String = String::from("Arial");
     static ref WHITE_COLOR: ColorF = ColorF::new(1.0, 1.0, 1.0, 1.0);
     static ref BLACK_COLOR: ColorF = ColorF::new(0.0, 0.0, 0.0, 1.0);
 }
@@ -158,17 +160,17 @@ impl HeadlessContext {
     #[cfg(not(feature = "headless"))]
     fn get_proc_address(_: &str) -> *const c_void {
         ptr::null() as *const _
     }
 }
 
 pub enum WindowWrapper {
     Window(glutin::GlWindow, Rc<gl::Gl>),
-    Angle(glutin::Window, angle::Context, Rc<gl::Gl>),
+    Angle(winit::Window, angle::Context, Rc<gl::Gl>),
     Headless(HeadlessContext, Rc<gl::Gl>),
 }
 
 pub struct HeadlessEventIterater;
 
 impl WindowWrapper {
     fn swap_buffers(&self) {
         match *self {
@@ -176,23 +178,23 @@ impl WindowWrapper {
             WindowWrapper::Angle(_, ref context, _) => context.swap_buffers().unwrap(),
             WindowWrapper::Headless(_, _) => {}
         }
     }
 
     fn get_inner_size(&self) -> DeviceUintSize {
         //HACK: `winit` needs to figure out its hidpi story...
         #[cfg(target_os = "macos")]
-        fn inner_size(window: &glutin::Window) -> (u32, u32) {
+        fn inner_size(window: &winit::Window) -> (u32, u32) {
             let (w, h) = window.get_inner_size().unwrap();
             let factor = window.hidpi_factor();
             ((w as f32 * factor) as _, (h as f32 * factor) as _)
         }
         #[cfg(not(target_os = "macos"))]
-        fn inner_size(window: &glutin::Window) -> (u32, u32) {
+        fn inner_size(window: &winit::Window) -> (u32, u32) {
             window.get_inner_size().unwrap()
         }
         let (w, h) = match *self {
             WindowWrapper::Window(ref window, _) => inner_size(window.window()),
             WindowWrapper::Angle(ref window, ..) => inner_size(window),
             WindowWrapper::Headless(ref context, _) => (context.width, context.height),
         };
         DeviceUintSize::new(w, h)
@@ -238,28 +240,28 @@ impl WindowWrapper {
         }
     }
 }
 
 fn make_window(
     size: DeviceUintSize,
     dp_ratio: Option<f32>,
     vsync: bool,
-    events_loop: &Option<glutin::EventsLoop>,
+    events_loop: &Option<winit::EventsLoop>,
     angle: bool,
 ) -> WindowWrapper {
     let wrapper = match *events_loop {
         Some(ref events_loop) => {
             let context_builder = glutin::ContextBuilder::new()
                 .with_gl(glutin::GlRequest::GlThenGles {
                     opengl_version: (3, 2),
                     opengles_version: (3, 0),
                 })
                 .with_vsync(vsync);
-            let window_builder = glutin::WindowBuilder::new()
+            let window_builder = winit::WindowBuilder::new()
                 .with_title("WRech")
                 .with_multitouch()
                 .with_dimensions(size.width, size.height);
 
             let init = |context: &glutin::GlContext| {
                 unsafe {
                     context
                         .make_current()
@@ -396,17 +398,17 @@ fn main() {
             DeviceUintSize::new(w, h)
         })
         .unwrap_or(DeviceUintSize::new(1920, 1080));
     let zoom_factor = args.value_of("zoom").map(|z| z.parse::<f32>().unwrap());
 
     let mut events_loop = if args.is_present("headless") {
         None
     } else {
-        Some(glutin::EventsLoop::new())
+        Some(winit::EventsLoop::new())
     };
 
     let mut window = make_window(
         size, dp_ratio, args.is_present("vsync"), &events_loop, args.is_present("angle"),
     );
     let dp_ratio = dp_ratio.unwrap_or(window.hidpi_factor());
     let dim = window.get_inner_size();
 
@@ -505,52 +507,52 @@ fn main() {
     let mut do_loop = false;
     let mut cpu_profile_index = 0;
     let mut cursor_position = WorldPoint::zero();
 
     let dim = window.get_inner_size();
     wrench.update(dim);
     thing.do_frame(&mut wrench);
 
-    let mut body = |wrench: &mut Wrench, global_event: glutin::Event| {
+    let mut body = |wrench: &mut Wrench, global_event: winit::Event| {
         if let Some(window_title) = wrench.take_title() {
             if !cfg!(windows) { //TODO: calling `set_title` from inside the `run_forever` loop is illegal...
                 window.set_title(&window_title);
             }
         }
 
         let mut do_frame = false;
         let mut do_render = false;
 
         match global_event {
-            glutin::Event::Awakened => {
+            winit::Event::Awakened => {
                 do_render = true;
             }
-            glutin::Event::WindowEvent { event, .. } => match event {
-                glutin::WindowEvent::Closed => {
-                    return glutin::ControlFlow::Break;
+            winit::Event::WindowEvent { event, .. } => match event {
+                winit::WindowEvent::CloseRequested => {
+                    return winit::ControlFlow::Break;
                 }
-                glutin::WindowEvent::Refresh |
-                glutin::WindowEvent::Focused(..) => {
+                winit::WindowEvent::Refresh |
+                winit::WindowEvent::Focused(..) => {
                     do_render = true;
                 }
-                glutin::WindowEvent::CursorMoved { position: (x, y), .. } => {
+                winit::WindowEvent::CursorMoved { position: (x, y), .. } => {
                     cursor_position = WorldPoint::new(x as f32, y as f32);
                     do_render = true;
                 }
-                glutin::WindowEvent::KeyboardInput {
-                    input: glutin::KeyboardInput {
-                        state: glutin::ElementState::Pressed,
+                winit::WindowEvent::KeyboardInput {
+                    input: winit::KeyboardInput {
+                        state: winit::ElementState::Pressed,
                         virtual_keycode: Some(vk),
                         ..
                     },
                     ..
                 } => match vk {
                     VirtualKeyCode::Escape => {
-                        return glutin::ControlFlow::Break;
+                        return winit::ControlFlow::Break;
                     }
                     VirtualKeyCode::P => {
                         wrench.renderer.toggle_debug_flags(DebugFlags::PROFILER_DBG);
                         do_render = true;
                     }
                     VirtualKeyCode::O => {
                         wrench.renderer.toggle_debug_flags(DebugFlags::RENDER_TARGET_DBG);
                         do_render = true;
@@ -629,17 +631,17 @@ fn main() {
                             println!("  • {:?}", item);
                         }
                         println!("");
                     }
                     _ => {}
                 }
                 _ => {}
             },
-            _ => return glutin::ControlFlow::Continue,
+            _ => return winit::ControlFlow::Continue,
         };
 
         let dim = window.get_inner_size();
         wrench.update(dim);
 
         if do_frame {
             let frame_num = thing.do_frame(wrench);
             unsafe {
@@ -655,22 +657,22 @@ fn main() {
             wrench.render();
             window.swap_buffers();
 
             if do_loop {
                 thing.next_frame();
             }
         }
 
-        glutin::ControlFlow::Continue
+        winit::ControlFlow::Continue
     };
 
     match events_loop {
         None => {
-            while body(&mut wrench, glutin::Event::Awakened) == glutin::ControlFlow::Continue {}
+            while body(&mut wrench, winit::Event::Awakened) == winit::ControlFlow::Continue {}
             let rect = DeviceUintRect::new(DeviceUintPoint::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(&mut wrench, event));
         }
     }
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -5,17 +5,17 @@
 
 use app_units::Au;
 use blob;
 use crossbeam::sync::chase_lev;
 #[cfg(windows)]
 use dwrote;
 #[cfg(any(target_os = "linux", target_os = "macos"))]
 use font_loader::system_fonts;
-use glutin::EventsLoopProxy;
+use winit::EventsLoopProxy;
 use json_frame_writer::JsonFrameWriter;
 use ron_frame_writer::RonFrameWriter;
 use std::collections::HashMap;
 use std::path::PathBuf;
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::Receiver;
 use time;
 use webrender;