Auto merge of #6077 - pcwalton:multiple-events-per-frame, r=glennw

Improves scrolling performance significantly on Mac.

r? @glennw

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6077)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-05-20 13:06:52 -05:00
commit 071f89aa5f
12 changed files with 67 additions and 59 deletions

View file

@ -1003,7 +1003,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
if pipeline_details.animations_running || if pipeline_details.animations_running ||
pipeline_details.animation_callbacks_running { pipeline_details.animation_callbacks_running {
self.constellation_chan.0.send(ConstellationMsg::TickAnimation(*pipeline_id)).unwrap(); self.constellation_chan.0.send(ConstellationMsg::TickAnimation(*pipeline_id))
.unwrap();
} }
} }
} }
@ -1064,7 +1065,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
if let Some(min_zoom) = self.min_viewport_zoom.as_ref() { if let Some(min_zoom) = self.min_viewport_zoom.as_ref() {
viewport_zoom = min_zoom.get().max(viewport_zoom) viewport_zoom = min_zoom.get().max(viewport_zoom)
} }
let viewport_zoom = self.max_viewport_zoom.as_ref().map_or(1., |z| z.get()).min(viewport_zoom); let viewport_zoom = self.max_viewport_zoom
.as_ref()
.map_or(1., |z| z.get())
.min(viewport_zoom);
let viewport_zoom = ScaleFactor::new(viewport_zoom); let viewport_zoom = ScaleFactor::new(viewport_zoom);
self.viewport_zoom = viewport_zoom; self.viewport_zoom = viewport_zoom;
@ -1355,7 +1359,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
rv rv
} }
fn draw_png(&self, framebuffer_ids: Vec<gl::GLuint>, texture_ids: Vec<gl::GLuint>, width: usize, height: usize) -> png::Image { fn draw_png(&self,
framebuffer_ids: Vec<gl::GLuint>,
texture_ids: Vec<gl::GLuint>,
width: usize,
height: usize)
-> png::Image {
let mut pixels = gl::read_pixels(0, 0, let mut pixels = gl::read_pixels(0, 0,
width as gl::GLsizei, width as gl::GLsizei,
height as gl::GLsizei, height as gl::GLsizei,
@ -1489,7 +1498,7 @@ fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc<Layer<CompositorDat
} }
impl<Window> CompositorEventListener for IOCompositor<Window> where Window: WindowMethods { impl<Window> CompositorEventListener for IOCompositor<Window> where Window: WindowMethods {
fn handle_event(&mut self, msg: WindowEvent) -> bool { fn handle_events(&mut self, messages: Vec<WindowEvent>) -> bool {
// Check for new messages coming from the other tasks in the system. // Check for new messages coming from the other tasks in the system.
loop { loop {
match self.port.try_recv_compositor_msg() { match self.port.try_recv_compositor_msg() {
@ -1509,8 +1518,10 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
return false; return false;
} }
// Handle the message coming from the windowing system. // Handle any messages coming from the windowing system.
self.handle_window_message(msg); for message in messages.into_iter() {
self.handle_window_message(message);
}
// If a pinch-zoom happened recently, ask for tiles at the new resolution // If a pinch-zoom happened recently, ask for tiles at the new resolution
if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 { if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 {

View file

@ -87,7 +87,8 @@ pub trait CompositorLayer {
/// Destroys tiles for this layer and all descendent layers, sending the buffers back to the /// Destroys tiles for this layer and all descendent layers, sending the buffers back to the
/// painter to be destroyed or reused. /// painter to be destroyed or reused.
fn clear_all_tiles<Window>(&self, compositor: &IOCompositor<Window>) where Window: WindowMethods; fn clear_all_tiles<Window>(&self, compositor: &IOCompositor<Window>)
where Window: WindowMethods;
/// Removes the root layer (and any children) for a given pipeline from the /// Removes the root layer (and any children) for a given pipeline from the
/// compositor. Buffers that the compositor is holding are returned to the /// compositor. Buffers that the compositor is holding are returned to the

View file

@ -254,7 +254,7 @@ impl CompositorTask {
} }
pub trait CompositorEventListener { pub trait CompositorEventListener {
fn handle_event(&mut self, event: WindowEvent) -> bool; fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
fn repaint_synchronously(&mut self); fn repaint_synchronously(&mut self);
fn shutdown(&mut self); fn shutdown(&mut self);
fn pinch_zoom_level(&self) -> f32; fn pinch_zoom_level(&self) -> f32;

View file

@ -66,7 +66,7 @@ impl NullCompositor {
} }
impl CompositorEventListener for NullCompositor { impl CompositorEventListener for NullCompositor {
fn handle_event(&mut self, _: WindowEvent) -> bool { fn handle_events(&mut self, _: Vec<WindowEvent>) -> bool {
match self.port.recv_compositor_msg() { match self.port.recv_compositor_msg() {
Msg::Exit(chan) => { Msg::Exit(chan) => {
debug!("shutting down the constellation"); debug!("shutting down the constellation");

View file

@ -45,12 +45,11 @@ pub use constellation::Constellation;
pub mod compositor_task; pub mod compositor_task;
mod compositor_layer; mod compositor_layer;
mod scrolling;
mod compositor; mod compositor;
mod headless; mod headless;
mod scrolling;
pub mod pipeline; pub mod pipeline;
pub mod constellation; pub mod constellation;
pub mod windowing; pub mod windowing;

View file

@ -75,9 +75,9 @@ pub struct Browser {
/// application Servo is embedded in. Clients then create an event /// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and /// loop to pump messages between the embedding application and
/// various browser components. /// various browser components.
impl Browser { impl Browser {
pub fn new<Window>(window: Option<Rc<Window>>) -> Browser pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
where Window: WindowMethods + 'static { where Window: WindowMethods + 'static {
// Global configuration options, parsed from the command line. // Global configuration options, parsed from the command line.
let opts = opts::get(); let opts = opts::get();
@ -124,8 +124,8 @@ impl Browser {
} }
} }
pub fn handle_event(&mut self, event: WindowEvent) -> bool { pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
self.compositor.handle_event(event) self.compositor.handle_events(events)
} }
pub fn repaint_synchronously(&mut self) { pub fn repaint_synchronously(&mut self) {

View file

@ -64,17 +64,14 @@ fn main() {
maybe_register_glutin_resize_handler(&window, &mut browser); maybe_register_glutin_resize_handler(&window, &mut browser);
browser.browser.handle_event(WindowEvent::InitializeCompositing); browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]);
// Feed events from the window to the browser until the browser // Feed events from the window to the browser until the browser
// says to stop. // says to stop.
loop { loop {
let should_continue = match window { let should_continue = match window {
None => browser.browser.handle_event(WindowEvent::Idle), None => browser.browser.handle_events(Vec::new()),
Some(ref window) => { Some(ref window) => browser.browser.handle_events(window.wait_events()),
let event = window.wait_events();
browser.browser.handle_event(event)
}
}; };
if !should_continue { if !should_continue {
break break
@ -123,7 +120,7 @@ impl app::NestedEventLoopListener for BrowserWrapper {
WindowEvent::Resize(..) => true, WindowEvent::Resize(..) => true,
_ => false, _ => false,
}; };
if !self.browser.handle_event(event) { if !self.browser.handle_events(vec![event]) {
return false return false
} }
if is_resize { if is_resize {

View file

@ -32,8 +32,8 @@ pub enum ServoBrowser {
impl ServoBrowser { impl ServoBrowser {
fn handle_event(&mut self, event: WindowEvent) { fn handle_event(&mut self, event: WindowEvent) {
match *self { match *self {
ServoBrowser::OnScreen(ref mut browser) => { browser.handle_event(event); } ServoBrowser::OnScreen(ref mut browser) => { browser.handle_events(vec![event]); }
ServoBrowser::OffScreen(ref mut browser) => { browser.handle_event(event); } ServoBrowser::OffScreen(ref mut browser) => { browser.handle_events(vec![event]); }
ServoBrowser::Invalid => {} ServoBrowser::Invalid => {}
} }
} }

View file

@ -100,8 +100,8 @@ impl Window {
} }
/// Currently unimplemented. /// Currently unimplemented.
pub fn wait_events(&self) -> WindowEvent { pub fn wait_events(&self) -> Vec<WindowEvent> {
WindowEvent::Idle vec![WindowEvent::Idle]
} }
fn cursor_type_for_cursor(&self, cursor: Cursor) -> cef_cursor_type_t { fn cursor_type_for_cursor(&self, cursor: Cursor) -> cef_cursor_type_t {

View file

@ -14,13 +14,15 @@ use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata; use layers::platform::surface::NativeGraphicsMetadata;
use msg::constellation_msg; use msg::constellation_msg;
use msg::constellation_msg::Key; use msg::constellation_msg::Key;
use NestedEventLoopListener; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::sync::mpsc::{channel, Sender}; use std::sync::mpsc::{channel, Sender};
use url::Url; use url::Url;
use util::cursor::Cursor; use util::cursor::Cursor;
use util::geometry::ScreenPx; use util::geometry::ScreenPx;
use NestedEventLoopListener;
#[cfg(feature = "window")] #[cfg(feature = "window")]
use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg}; use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg};
#[cfg(feature = "window")] #[cfg(feature = "window")]
@ -259,7 +261,16 @@ impl Window {
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
fn handle_next_event(&self) -> bool { fn handle_next_event(&self) -> bool {
let event = self.window.wait_events().next().unwrap(); let event = self.window.wait_events().next().unwrap();
self.handle_window_event(event) let mut close = self.handle_window_event(event);
if !close {
while let Some(event) = self.window.poll_events().next() {
if self.handle_window_event(event) {
close = true;
break
}
}
}
close
} }
#[cfg(any(target_os="linux", target_os="android"))] #[cfg(any(target_os="linux", target_os="android"))]
@ -283,7 +294,9 @@ impl Window {
// //
// See https://github.com/servo/servo/issues/5780 // See https://github.com/servo/servo/issues/5780
// //
match self.window.poll_events().next() { let first_event = self.window.poll_events().next();
match first_event {
Some(event) => { Some(event) => {
self.handle_window_event(event) self.handle_window_event(event)
} }
@ -294,40 +307,27 @@ impl Window {
} }
} }
pub fn wait_events(&self) -> WindowEvent { pub fn wait_events(&self) -> Vec<WindowEvent> {
{ let mut events = mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new());
let mut event_queue = self.event_queue.borrow_mut();
if !event_queue.is_empty() {
return event_queue.remove(0);
}
}
let mut close_event = false; let mut close_event = false;
// When writing to a file then exiting, use event // When writing to a file then exiting, use event
// polling so that we don't block on a GUI event // polling so that we don't block on a GUI event
// such as mouse click. // such as mouse click.
if opts::get().output_file.is_some() { if opts::get().output_file.is_some() {
for event in self.window.poll_events() { while let Some(event) = self.window.poll_events().next() {
close_event = self.handle_window_event(event); close_event = self.handle_window_event(event) || close_event;
if close_event {
break;
}
} }
} else { } else {
close_event = self.handle_next_event(); close_event = self.handle_next_event();
} }
if close_event || self.window.is_closed() { if close_event || self.window.is_closed() {
WindowEvent::Quit events.push(WindowEvent::Quit)
} else {
let mut event_queue = self.event_queue.borrow_mut();
if event_queue.is_empty() {
WindowEvent::Idle
} else {
event_queue.remove(0)
}
} }
events.extend(mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new()).into_iter());
events
} }
pub unsafe fn set_nested_event_loop_listener( pub unsafe fn set_nested_event_loop_listener(
@ -634,8 +634,8 @@ impl Window {
Rc::new(window) Rc::new(window)
} }
pub fn wait_events(&self) -> WindowEvent { pub fn wait_events(&self) -> Vec<WindowEvent> {
WindowEvent::Idle vec![WindowEvent::Idle]
} }
pub unsafe fn set_nested_event_loop_listener( pub unsafe fn set_nested_event_loop_listener(

View file

@ -76,16 +76,16 @@ fn main() {
Some(ref window) => input::run_input_loop(&window.event_send) Some(ref window) => input::run_input_loop(&window.event_send)
} }
browser.browser.handle_event(WindowEvent::InitializeCompositing); browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]);
// Feed events from the window to the browser until the browser // Feed events from the window to the browser until the browser
// says to stop. // says to stop.
loop { loop {
let should_continue = match window { let should_continue = match window {
None => browser.browser.handle_event(WindowEvent::Idle), None => browser.browser.handle_events(vec![WindowEvent::Idle]),
Some(ref window) => { Some(ref window) => {
let event = window.wait_events(); let events = window.wait_events();
browser.browser.handle_event(event) browser.browser.handle_events(events)
} }
}; };
if !should_continue { if !should_continue {

View file

@ -754,8 +754,8 @@ impl Window {
Rc::new(window) Rc::new(window)
} }
pub fn wait_events(&self) -> WindowEvent { pub fn wait_events(&self) -> Vec<WindowEvent> {
self.event_recv.recv().unwrap() vec![self.event_recv.recv().unwrap()]
} }
} }