Auto merge of #15794 - paulrouget:head_parsed_url, r=asajeffrey

Notify embedder when history changes

`WindowMethods::set_page_url` is only called when the embedder set the URL. It is not called when the page url is updated. I believe that instead we should just pass the URL to `head_parsed`.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #15439 #15643 and #15642 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [x] These changes do not require tests because I'm not sure how to test that

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15794)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-04-25 14:14:31 -05:00 committed by GitHub
commit dc594face8
6 changed files with 111 additions and 77 deletions

View file

@ -481,10 +481,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
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);
@ -519,11 +515,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
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.
@ -534,7 +530,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// 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) => {
@ -612,6 +608,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
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 {
@ -707,10 +707,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
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<()>) {
@ -906,7 +902,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
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)

View file

@ -13,7 +13,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};
@ -75,16 +75,16 @@ pub enum Msg {
ScrollFragmentPoint(webrender_traits::ClipId, Point2D<f32>, bool),
/// Alerts the compositor that the current page has changed its title.
ChangePageTitle(PipelineId, Option<String>),
/// 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<LoadData>, usize),
/// Wether or not to follow a link
AllowNavigation(ServoUrl, IpcSender<bool>),
/// We hit the delayed composition timeout. (See `delayed_composition.rs`.)
@ -142,11 +142,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"),

View file

@ -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<String>);
/// 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<String>);
/// 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 <head> tag has finished parsing
fn head_parsed(&self);
/// Called when the history state has changed.
fn history_changed(&self, Vec<LoadData>, usize);
/// Returns the scale factor of the system (device pixels / device independent pixels).
fn hidpi_factor(&self) -> ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>;

View file

@ -1350,7 +1350,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
load_data: load_data,
replace_instant: None,
});
self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url));
}
fn handle_frame_size_msg(&mut self,
@ -1663,11 +1662,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
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) {
@ -1682,11 +1678,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
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);
}
@ -2101,6 +2093,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// 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();
@ -2123,6 +2116,64 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
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<LoadData> = 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 {
@ -2196,6 +2247,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
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 {
@ -2205,6 +2257,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// 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 {