diff --git a/ports/servoshell/app.rs b/ports/servoshell/app.rs index 2419ab5b4c8..c5965751e6d 100644 --- a/ports/servoshell/app.rs +++ b/ports/servoshell/app.rs @@ -39,18 +39,20 @@ pub struct App { minibrowser: Option>, } +enum Present { + Immediate, + Deferred, + None, +} + /// Action to be taken by the caller of [`App::handle_events`]. enum PumpResult { /// The caller should shut down Servo and its related context. Shutdown, - /// A new frame is ready to present. The caller can paint other things themselves during this - /// period, but has to call [`Servo::present`] to perform page flip and tell Servo compositor - /// to continue rendering. - ReadyToPresent, - /// The size has changed. The caller can paint other things themselves during this - /// period, but has to call [`Servo::present`] to perform page flip and tell Servo compositor - /// to continue rendering. - Resize, + Continue { + history_changed: bool, + present: Present, + }, } impl App { @@ -108,8 +110,15 @@ impl App { webrender_surfman.make_gl_context_current().unwrap(); debug_assert_eq!(webrender_gl.get_error(), gleam::gl::NO_ERROR); - app.minibrowser = - Some(Minibrowser::new(&webrender_surfman, &events_loop, window.as_ref()).into()); + app.minibrowser = Some( + Minibrowser::new( + &webrender_surfman, + &events_loop, + window.as_ref(), + initial_url.clone(), + ) + .into(), + ); } if let Some(mut minibrowser) = app.minibrowser() { @@ -271,57 +280,74 @@ impl App { } // Consume and handle any events from the Minibrowser. - if let Some(mut minibrowser) = app.minibrowser() { + if let Some(minibrowser) = app.minibrowser() { let browser = &mut app.browser.borrow_mut(); let app_event_queue = &mut app.event_queue.borrow_mut(); minibrowser.queue_embedder_events_for_minibrowser_events(browser, app_event_queue); - if minibrowser.update_location_in_toolbar(browser) { - // Update the minibrowser immediately. While we could update by requesting a - // redraw, doing so would delay the location update by two frames. - minibrowser - .update(window.winit_window().unwrap(), "update_location_in_toolbar"); - } } match app.handle_events() { - Some(PumpResult::Shutdown) => { + PumpResult::Shutdown => { *control_flow = winit::event_loop::ControlFlow::Exit; app.servo.take().unwrap().deinit(); if let Some(mut minibrowser) = app.minibrowser() { minibrowser.context.destroy(); } }, - Some(PumpResult::ReadyToPresent) => { - // The compositor has painted to this frame. - trace!("PumpResult::ReadyToPresent"); - - // Request a winit redraw event, so we can paint the minibrowser and present. - // Otherwise, it's in headless mode and we present directly. - if let Some(window) = window.winit_window() { - window.request_redraw(); - } else { - app.servo.as_mut().unwrap().present(); + PumpResult::Continue { + history_changed, + present, + } => { + if history_changed { + if let Some(mut minibrowser) = app.minibrowser() { + let browser = &mut app.browser.borrow_mut(); + if minibrowser.update_location_in_toolbar(browser) { + // Update the minibrowser immediately. While we could update by requesting a + // redraw, doing so would delay the location update by two frames. + minibrowser.update( + window.winit_window().unwrap(), + "update_location_in_toolbar", + ); + } + } } + match present { + Present::Immediate => { + // The window was resized. + trace!("PumpResult::Present::Immediate"); - // We don’t need the compositor to paint to this frame during the redraw event. - // TODO(servo#30331) broken on macOS? - // need_recomposite = false; - }, - Some(PumpResult::Resize) => { - // The window was resized. - trace!("PumpResult::Resize"); + // Resizes are unusual in that we need to repaint synchronously. + // TODO(servo#30049) can we replace this with the simpler Servo::recomposite? + app.servo.as_mut().unwrap().repaint_synchronously(); - // Resizes are unusual in that we need to repaint synchronously. - // TODO(servo#30049) can we replace this with the simpler Servo::recomposite? - app.servo.as_mut().unwrap().repaint_synchronously(); + if let Some(mut minibrowser) = app.minibrowser() { + minibrowser.update( + window.winit_window().unwrap(), + "PumpResult::Present::Immediate", + ); + minibrowser.paint(window.winit_window().unwrap()); + } + app.servo.as_mut().unwrap().present(); + }, + Present::Deferred => { + // The compositor has painted to this frame. + trace!("PumpResult::Present::Deferred"); - if let Some(mut minibrowser) = app.minibrowser() { - minibrowser.update(window.winit_window().unwrap(), "PumpResult::Resize"); - minibrowser.paint(window.winit_window().unwrap()); + // Request a winit redraw event, so we can paint the minibrowser and present. + // Otherwise, it's in headless mode and we present directly. + if let Some(window) = window.winit_window() { + window.request_redraw(); + } else { + app.servo.as_mut().unwrap().present(); + } + + // We don’t need the compositor to paint to this frame during the redraw event. + // TODO(servo#30331) broken on macOS? + // need_recomposite = false; + }, + Present::None => {}, } - app.servo.as_mut().unwrap().present(); }, - None => {}, } }); } @@ -381,7 +407,7 @@ impl App { /// Window queues to the Browser queue, and from the Browser queue to Servo. We receive and /// collect embedder messages from the various Servo components, then take them out of the /// Servo interface so that the Browser can handle them. - fn handle_events(&mut self) -> Option { + fn handle_events(&mut self) -> PumpResult { let mut browser = self.browser.borrow_mut(); // FIXME: @@ -404,9 +430,12 @@ impl App { let mut embedder_messages = self.servo.as_mut().unwrap().get_events(); let mut need_resize = false; let mut need_present = false; + let mut history_changed = false; loop { // Consume and handle those embedder messages. - need_present |= browser.handle_servo_events(embedder_messages); + let servo_event_response = browser.handle_servo_events(embedder_messages); + need_present |= servo_event_response.need_present; + history_changed |= servo_event_response.history_changed; // Route embedder events from the Browser to the relevant Servo components, // receives and collects embedder messages from various Servo components, @@ -417,7 +446,7 @@ impl App { .unwrap() .handle_events(browser.get_events()); if browser.shutdown_requested() { - return Some(PumpResult::Shutdown); + return PumpResult::Shutdown; } // Take any new embedder messages from Servo itself. @@ -427,12 +456,17 @@ impl App { } } - if need_resize { - Some(PumpResult::Resize) + let present = if need_resize { + Present::Immediate } else if need_present { - Some(PumpResult::ReadyToPresent) + Present::Deferred } else { - None + Present::None + }; + + PumpResult::Continue { + history_changed, + present, } } diff --git a/ports/servoshell/browser.rs b/ports/servoshell/browser.rs index ee707795d13..3978497491c 100644 --- a/ports/servoshell/browser.rs +++ b/ports/servoshell/browser.rs @@ -50,6 +50,11 @@ pub struct Browser { shutdown_requested: bool, } +pub struct ServoEventResponse { + pub need_present: bool, + pub history_changed: bool, +} + impl Browser where Window: WindowPortsMethods + ?Sized, @@ -277,9 +282,13 @@ where self.event_queue.push(event); } - /// Returns true iff the caller needs to manually present a new frame. - pub fn handle_servo_events(&mut self, events: Vec<(Option, EmbedderMsg)>) -> bool { + /// Returns true if the caller needs to manually present a new frame. + pub fn handle_servo_events( + &mut self, + events: Vec<(Option, EmbedderMsg)>, + ) -> ServoEventResponse { let mut need_present = false; + let mut history_changed = false; for (browser_id, msg) in events { trace!( "embedder <- servo EmbedderMsg ({:?}, {:?})", @@ -456,6 +465,7 @@ where EmbedderMsg::HistoryChanged(urls, current) => { self.current_url = Some(urls[current].clone()); self.current_url_string = Some(urls[current].clone().into_string()); + history_changed = true; }, EmbedderMsg::SetFullscreenState(state) => { self.window.set_fullscreen(state); @@ -538,7 +548,10 @@ where } } - need_present + ServoEventResponse { + need_present, + history_changed, + } } } diff --git a/ports/servoshell/minibrowser.rs b/ports/servoshell/minibrowser.rs index 16bf72ec34e..5ed322aa7fa 100644 --- a/ports/servoshell/minibrowser.rs +++ b/ports/servoshell/minibrowser.rs @@ -11,6 +11,7 @@ use euclid::Length; use log::{trace, warn}; use servo::compositing::windowing::EmbedderEvent; use servo::servo_geometry::DeviceIndependentPixel; +use servo::servo_url::ServoUrl; use servo::webrender_surfman::WebrenderSurfman; use crate::browser::Browser; @@ -40,6 +41,7 @@ impl Minibrowser { webrender_surfman: &WebrenderSurfman, events_loop: &EventsLoop, window: &dyn WindowPortsMethods, + initial_url: ServoUrl, ) -> Self { let gl = unsafe { glow::Context::from_loader_function(|s| webrender_surfman.get_proc_address(s)) @@ -56,7 +58,7 @@ impl Minibrowser { event_queue: RefCell::new(vec![]), toolbar_height: Default::default(), last_update: Instant::now(), - location: RefCell::new(String::default()), + location: RefCell::new(initial_url.to_string()), location_dirty: false.into(), } }