Bug 1464473 - Update webrender to 3829687ffbe8d55885d71a3d5e5e79216251548f. r?Gankro draft
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 29 May 2018 08:45:25 -0400
changeset 800880 93b08e28671e973a63213c2c1e5012cd8389c543
parent 800874 f01bb6245db1ea2a87e5360104a4110571265137
child 800881 91ffae362fafa17d00af7f1719da7098752787de
push id111510
push userkgupta@mozilla.com
push dateTue, 29 May 2018 12:47:09 +0000
reviewersGankro
bugs1464473
milestone62.0a1
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;