From e49354813597616db0473c88c94a715705e5aaff Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Fri, 7 Apr 2017 06:27:30 +0200 Subject: [PATCH] Notify embedder when history changes --- components/compositing/compositor.rs | 21 +++--- components/compositing/compositor_thread.rs | 20 +++--- components/compositing/windowing.rs | 10 +-- components/constellation/constellation.rs | 75 ++++++++++++++++++--- ports/cef/window.rs | 46 +++++-------- ports/glutin/window.rs | 16 ++--- 6 files changed, 111 insertions(+), 77 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 981fc49e09ff..b2e3f5ca0a3c 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -494,10 +494,6 @@ impl IOCompositor { self.change_page_title(pipeline_id, title); } - (Msg::ChangePageUrl(pipeline_id, url), ShutdownState::NotShuttingDown) => { - self.change_page_url(pipeline_id, url); - } - (Msg::SetFrameTree(frame_tree, response_chan), ShutdownState::NotShuttingDown) => { self.set_frame_tree(&frame_tree, response_chan); @@ -532,11 +528,11 @@ impl IOCompositor { self.window.status(message); } - (Msg::LoadStart(back, forward), ShutdownState::NotShuttingDown) => { - self.window.load_start(back, forward); + (Msg::LoadStart, ShutdownState::NotShuttingDown) => { + self.window.load_start(); } - (Msg::LoadComplete(back, forward, root), ShutdownState::NotShuttingDown) => { + (Msg::LoadComplete, ShutdownState::NotShuttingDown) => { self.got_load_complete_message = true; // If we're painting in headless mode, schedule a recomposite. @@ -547,7 +543,7 @@ impl IOCompositor { // Inform the embedder that the load has finished. // // TODO(pcwalton): Specify which frame's load completed. - self.window.load_end(back, forward, root); + self.window.load_end(); } (Msg::AllowNavigation(url, response_chan), ShutdownState::NotShuttingDown) => { @@ -625,6 +621,10 @@ impl IOCompositor { self.window.head_parsed(); } + (Msg::HistoryChanged(entries, current), ShutdownState::NotShuttingDown) => { + self.window.history_changed(entries, current); + } + (Msg::PipelineVisibilityChanged(pipeline_id, visible), ShutdownState::NotShuttingDown) => { self.pipeline_details(pipeline_id).visible = visible; if visible { @@ -720,10 +720,6 @@ impl IOCompositor { } } - fn change_page_url(&mut self, _: PipelineId, url: ServoUrl) { - self.window.set_page_url(url); - } - fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree, response_chan: IpcSender<()>) { @@ -923,7 +919,6 @@ impl IOCompositor { self.got_load_complete_message = false; match ServoUrl::parse(&url_string) { Ok(url) => { - self.window.set_page_url(url.clone()); let msg = match self.root_pipeline { Some(ref pipeline) => ConstellationMsg::LoadUrl(pipeline.id, LoadData::new(url, None, None)), None => ConstellationMsg::InitLoadUrl(url) diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index e475bba05149..74d5f6df0d77 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -14,7 +14,7 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId}; use net_traits::image::base::Image; use profile_traits::mem; use profile_traits::time; -use script_traits::{AnimationState, ConstellationMsg, EventResult}; +use script_traits::{AnimationState, ConstellationMsg, EventResult, LoadData}; use servo_url::ServoUrl; use std::fmt::{Debug, Error, Formatter}; use std::sync::mpsc::{Receiver, Sender}; @@ -76,16 +76,16 @@ pub enum Msg { ScrollFragmentPoint(PipelineId, ScrollRootId, Point2D, bool), /// Alerts the compositor that the current page has changed its title. ChangePageTitle(PipelineId, Option), - /// Alerts the compositor that the current page has changed its URL. - ChangePageUrl(PipelineId, ServoUrl), /// Alerts the compositor that the given pipeline has changed whether it is running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), /// Replaces the current frame tree, typically called during main frame navigation. SetFrameTree(SendableFrameTree, IpcSender<()>), - /// The load of a page has begun: (can go back, can go forward). - LoadStart(bool, bool), - /// The load of a page has completed: (can go back, can go forward, is root frame). - LoadComplete(bool, bool, bool), + /// The load of a page has begun + LoadStart, + /// The load of a page has completed + LoadComplete, + /// The history state has changed. + HistoryChanged(Vec, usize), /// Wether or not to follow a link AllowNavigation(ServoUrl, IpcSender), /// We hit the delayed composition timeout. (See `delayed_composition.rs`.) @@ -143,11 +143,11 @@ impl Debug for Msg { Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"), Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"), Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), - Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"), Msg::SetFrameTree(..) => write!(f, "SetFrameTree"), - Msg::LoadComplete(..) => write!(f, "LoadComplete"), + Msg::LoadComplete => write!(f, "LoadComplete"), Msg::AllowNavigation(..) => write!(f, "AllowNavigation"), - Msg::LoadStart(..) => write!(f, "LoadStart"), + Msg::LoadStart => write!(f, "LoadStart"), + Msg::HistoryChanged(..) => write!(f, "HistoryChanged"), Msg::DelayedCompositionTimeout(..) => write!(f, "DelayedCompositionTimeout"), Msg::Recomposite(..) => write!(f, "Recomposite"), Msg::KeyEvent(..) => write!(f, "KeyEvent"), diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 08d78e48453a..f3c7e8f17136 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -13,7 +13,7 @@ use euclid::size::TypedSize2D; use gleam::gl; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use net_traits::net_error_list::NetError; -use script_traits::{DevicePixel, MouseButton, TouchEventType, TouchId, TouchpadPressurePhase}; +use script_traits::{DevicePixel, LoadData, MouseButton, TouchEventType, TouchId, TouchpadPressurePhase}; use servo_geometry::DeviceIndependentPixel; use servo_url::ServoUrl; use std::fmt::{Debug, Error, Formatter}; @@ -129,20 +129,20 @@ pub trait WindowMethods { /// Sets the page title for the current page. fn set_page_title(&self, title: Option); - /// Sets the load data for the current page. - fn set_page_url(&self, url: ServoUrl); /// Called when the browser chrome should display a status message. fn status(&self, Option); /// Called when the browser has started loading a frame. - fn load_start(&self, back: bool, forward: bool); + fn load_start(&self); /// Called when the browser is done loading a frame. - fn load_end(&self, back: bool, forward: bool, root: bool); + fn load_end(&self); /// Called when the browser encounters an error while loading a URL fn load_error(&self, code: NetError, url: String); /// Wether or not to follow a link fn allow_navigation(&self, url: ServoUrl) -> bool; /// Called when the tag has finished parsing fn head_parsed(&self); + /// Called when the history state has changed. + fn history_changed(&self, Vec, usize); /// Returns the scale factor of the system (device pixels / device independent pixels). fn hidpi_factor(&self) -> ScaleFactor; diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 31942533990b..ac5a5dca15f8 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1351,7 +1351,6 @@ impl Constellation load_data: load_data, replace_instant: None, }); - self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url)); } fn handle_frame_size_msg(&mut self, @@ -1664,11 +1663,8 @@ impl Constellation } } - fn handle_load_start_msg(&mut self, pipeline_id: PipelineId) { - let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id); - let forward = !self.joint_session_future_is_empty(frame_id); - let back = !self.joint_session_past_is_empty(frame_id); - self.compositor_proxy.send(ToCompositorMsg::LoadStart(back, forward)); + fn handle_load_start_msg(&mut self, _pipeline_id: PipelineId) { + self.compositor_proxy.send(ToCompositorMsg::LoadStart); } fn handle_load_complete_msg(&mut self, pipeline_id: PipelineId) { @@ -1683,11 +1679,7 @@ impl Constellation if webdriver_reset { self.webdriver.load_channel = None; } - let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id); - let forward = !self.joint_session_future_is_empty(frame_id); - let back = !self.joint_session_past_is_empty(frame_id); - let root = self.root_frame_id == frame_id; - self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root)); + self.compositor_proxy.send(ToCompositorMsg::LoadComplete); self.handle_subframe_loaded(pipeline_id); } @@ -2102,6 +2094,7 @@ impl Constellation // Deactivate the old pipeline, and activate the new one. self.update_activity(old_pipeline_id); self.update_activity(pipeline_id); + self.notify_history_changed(pipeline_id); // Set paint permissions correctly for the compositor layers. self.send_frame_tree(); @@ -2124,6 +2117,64 @@ impl Constellation } } + fn notify_history_changed(&self, pipeline_id: PipelineId) { + // Send a flat projection of the history. + // The final vector is a concatenation of the LoadData of the past entries, + // the current entry and the future entries. + // LoadData of inner frames are ignored and replaced with the LoadData of the parent. + + let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id); + + // Ignore LoadData of non-top-level frames. + let keep_load_data_if_top_frame = |state: &FrameState| { + match state.pipeline_id { + None => Some(state.load_data.clone()), + Some(pipeline_id) => { + match self.pipelines.get(&pipeline_id) { + None => Some(state.load_data.clone()), + Some(pipeline) => match pipeline.parent_info { + None => Some(state.load_data.clone()), + Some(_) => None, + } + } + } + } + }; + + // If LoadData was ignored, use the LoadData of the previous FrameState, which + // is the LoadData of the parent frame. + let resolve_load_data = |previous_load_data: &mut LoadData, load_data| { + let load_data = match load_data { + None => previous_load_data.clone(), + Some(load_data) => load_data, + }; + *previous_load_data = load_data.clone(); + Some(load_data) + }; + + let current_load_data = match self.frames.get(&top_level_frame_id) { + Some(frame) => frame.load_data.clone(), + None => return warn!("notify_history_changed error after top-level frame closed."), + }; + + let mut entries: Vec = self.joint_session_past(top_level_frame_id) + .map(&keep_load_data_if_top_frame) + .scan(current_load_data.clone(), &resolve_load_data) + .collect(); + + entries.reverse(); + + let current_index = entries.len(); + + entries.push(current_load_data.clone()); + + entries.extend(self.joint_session_future(top_level_frame_id) + .map(&keep_load_data_if_top_frame) + .scan(current_load_data.clone(), &resolve_load_data)); + + self.compositor_proxy.send(ToCompositorMsg::HistoryChanged(entries, current_index)); + } + fn get_top_level_frame_for_pipeline(&self, mut pipeline_id: PipelineId) -> FrameId { if PREFS.is_mozbrowser_enabled() { loop { @@ -2197,6 +2248,7 @@ impl Constellation if new_frame { self.new_frame(frame_change.frame_id, frame_change.new_pipeline_id, frame_change.load_data); self.update_activity(frame_change.new_pipeline_id); + self.notify_history_changed(frame_change.new_pipeline_id); }; if let Some(old_pipeline_id) = navigated { @@ -2206,6 +2258,7 @@ impl Constellation // Clear the joint session future let top_level_frame_id = self.get_top_level_frame_for_pipeline(frame_change.new_pipeline_id); self.clear_joint_session_future(top_level_frame_id); + self.notify_history_changed(frame_change.new_pipeline_id); } if location_changed { diff --git a/ports/cef/window.rs b/ports/cef/window.rs index 1e31df25a8e5..c1eea816e140 100644 --- a/ports/cef/window.rs +++ b/ports/cef/window.rs @@ -26,7 +26,7 @@ use euclid::size::{Size2D, TypedSize2D}; use gleam::gl; use msg::constellation_msg::{Key, KeyModifiers}; use net_traits::net_error_list::NetError; -use script_traits::DevicePixel; +use script_traits::{DevicePixel, LoadData}; use servo_geometry::DeviceIndependentPixel; use std::cell::RefCell; use std::ffi::CString; @@ -350,15 +350,15 @@ impl WindowMethods for Window { } } - fn load_start(&self, back: bool, forward: bool) { + fn load_start(&self) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, Some(ref browser) => browser, }; + let back = browser.downcast().back.get(); + let forward = browser.downcast().forward.get(); browser.downcast().loading.set(true); - browser.downcast().back.set(back); - browser.downcast().forward.set(forward); browser.downcast().favicons.borrow_mut().clear(); if check_ptr_exist!(browser.get_host().get_client(), get_load_handler) && check_ptr_exist!(browser.get_host().get_client().get_load_handler(), on_loading_state_change) { @@ -369,16 +369,16 @@ impl WindowMethods for Window { } } - fn load_end(&self, back: bool, forward: bool, _: bool) { + fn load_end(&self) { // FIXME(pcwalton): The status code 200 is a lie. let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, Some(ref browser) => browser, }; + let back = browser.downcast().back.get(); + let forward = browser.downcast().forward.get(); browser.downcast().loading.set(false); - browser.downcast().back.set(back); - browser.downcast().forward.set(forward); if check_ptr_exist!(browser.get_host().get_client(), get_load_handler) && check_ptr_exist!(browser.get_host().get_client().get_load_handler(), on_loading_state_change) { browser.get_host() @@ -448,20 +448,21 @@ impl WindowMethods for Window { } } - fn set_page_url(&self, url: ServoUrl) { - // it seems to be the case that load start is always called - // IMMEDIATELY before address change, so just stick it here - on_load_start(self); + fn history_changed(&self, history: Vec, current: usize) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, Some(ref browser) => browser, }; + + let can_go_back = current > 0; + let can_go_forward = current < history.len() - 1; + + browser.downcast().back.set(can_go_back); + browser.downcast().forward.set(can_go_forward); let frame = browser.get_main_frame(); - let servoframe = frame.downcast(); - // FIXME(https://github.com/rust-lang/rust/issues/23338) - let mut frame_url = servoframe.url.borrow_mut(); - *frame_url = url.into_string(); + let mut frame_url = frame.downcast().url.borrow_mut(); + *frame_url = history[current].url.to_string(); let utf16_chars: Vec = frame_url.encode_utf16().collect(); if check_ptr_exist!(browser.get_host().get_client(), get_display_handler) && check_ptr_exist!(browser.get_host().get_client().get_display_handler(), on_address_change) { @@ -516,21 +517,6 @@ impl CompositorProxy for CefCompositorProxy { } } -fn on_load_start(window: &Window) { - let browser = window.cef_browser.borrow(); - let browser = match *browser { - None => return, - Some(ref browser) => browser, - }; - if check_ptr_exist!(browser.get_host().get_client(), get_load_handler) && - check_ptr_exist!(browser.get_host().get_client().get_load_handler(), on_load_start) { - browser.get_host() - .get_client() - .get_load_handler() - .on_load_start((*browser).clone(), browser.get_main_frame()); - } -} - #[cfg(target_os="macos")] pub fn app_wakeup() { use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined}; diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index e044594ab0cd..1e54ba266a21 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -27,7 +27,7 @@ use msg::constellation_msg::{ALT, CONTROL, KeyState, NONE, SHIFT, SUPER}; use net_traits::net_error_list::NetError; #[cfg(any(target_os = "linux", target_os = "macos"))] use osmesa_sys; -use script_traits::{DevicePixel, TouchEventType, TouchpadPressurePhase}; +use script_traits::{DevicePixel, LoadData, TouchEventType, TouchpadPressurePhase}; use servo_config::opts; use servo_config::prefs::PREFS; use servo_config::resource_files; @@ -1001,18 +1001,14 @@ impl WindowMethods for Window { } } - fn set_page_url(&self, url: ServoUrl) { - *self.current_url.borrow_mut() = Some(url); - } - fn status(&self, _: Option) { } - fn load_start(&self, _: bool, _: bool) { + fn load_start(&self) { } - fn load_end(&self, _: bool, _: bool, root: bool) { - if root && opts::get().no_native_titlebar { + fn load_end(&self) { + if opts::get().no_native_titlebar { match self.kind { WindowKind::Window(ref window) => { window.show(); @@ -1022,6 +1018,10 @@ impl WindowMethods for Window { } } + fn history_changed(&self, history: Vec, current: usize) { + *self.current_url.borrow_mut() = Some(history[current].url.clone()); + } + fn load_error(&self, _: NetError, _: String) { }