mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Auto merge of #12685 - ConnorGBrewster:history_length, r=asajeffrey
Implement history.length <!-- Please describe your changes on the following line: --> --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- 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/12685) <!-- Reviewable:end -->
This commit is contained in:
commit
7aafc0d0ec
8 changed files with 95 additions and 64 deletions
|
@ -221,14 +221,16 @@ pub struct InitialConstellationState {
|
|||
|
||||
/// Stores the navigation context for a single frame in the frame tree.
|
||||
struct Frame {
|
||||
id: FrameId,
|
||||
prev: Vec<(PipelineId, Instant)>,
|
||||
current: (PipelineId, Instant),
|
||||
next: Vec<(PipelineId, Instant)>,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn new(pipeline_id: PipelineId) -> Frame {
|
||||
fn new(id: FrameId, pipeline_id: PipelineId) -> Frame {
|
||||
Frame {
|
||||
id: id,
|
||||
prev: vec!(),
|
||||
current: (pipeline_id, Instant::now()),
|
||||
next: vec!(),
|
||||
|
@ -290,6 +292,37 @@ impl<'a> Iterator for FrameTreeIterator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct FullFrameTreeIterator<'a> {
|
||||
stack: Vec<FrameId>,
|
||||
frames: &'a HashMap<FrameId, Frame>,
|
||||
pipelines: &'a HashMap<PipelineId, Pipeline>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FullFrameTreeIterator<'a> {
|
||||
type Item = &'a Frame;
|
||||
fn next(&mut self) -> Option<&'a Frame> {
|
||||
loop {
|
||||
let frame_id = match self.stack.pop() {
|
||||
Some(frame_id) => frame_id,
|
||||
None => return None,
|
||||
};
|
||||
let frame = match self.frames.get(&frame_id) {
|
||||
Some(frame) => frame,
|
||||
None => {
|
||||
warn!("Frame {:?} iterated after closure.", frame_id);
|
||||
continue;
|
||||
},
|
||||
};
|
||||
for &(pipeline_id, _) in frame.prev.iter().chain(frame.next.iter()).chain(once(&frame.current)) {
|
||||
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
||||
self.stack.extend(pipeline.children.iter().map(|&c| c));
|
||||
}
|
||||
}
|
||||
return Some(frame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WebDriverData {
|
||||
load_channel: Option<(PipelineId, IpcSender<webdriver_msg::LoadStatus>)>,
|
||||
resize_channel: Option<IpcSender<WindowSizeData>>,
|
||||
|
@ -578,77 +611,46 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
fn full_frame_tree_iter(&self, frame_id_root: FrameId) -> FullFrameTreeIterator {
|
||||
FullFrameTreeIterator {
|
||||
stack: vec!(frame_id_root),
|
||||
pipelines: &self.pipelines,
|
||||
frames: &self.frames,
|
||||
}
|
||||
}
|
||||
|
||||
fn joint_session_future(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> {
|
||||
let mut future = vec!();
|
||||
self.get_future_entries(frame_id_root, &mut future);
|
||||
for frame in self.full_frame_tree_iter(frame_id_root) {
|
||||
future.extend(frame.next.iter().map(|&(pipeline_id, instant)| (instant, frame.id, pipeline_id)));
|
||||
}
|
||||
|
||||
// reverse sorting
|
||||
future.sort_by(|a, b| b.cmp(a));
|
||||
future
|
||||
}
|
||||
|
||||
fn get_future_entries(&self, frame_id_root: FrameId, mut future: &mut Vec<(Instant, FrameId, PipelineId)>) {
|
||||
let frame = match self.frames.get(&frame_id_root) {
|
||||
Some(frame) => frame,
|
||||
None => return warn!("Tried to get frame future after frame {:?} closed.", frame_id_root),
|
||||
};
|
||||
|
||||
future.extend(frame.next.iter().map(|&(pipeline_id, instant)| (instant, frame_id_root, pipeline_id)));
|
||||
|
||||
for &(pipeline_id, _) in frame.next.iter().chain(once(&frame.current)) {
|
||||
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline,
|
||||
None => {
|
||||
warn!("Tried to get pipeline {:?} for child lookup after closure.", pipeline_id);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
for &frame_id in &pipeline.children {
|
||||
self.get_future_entries(frame_id, &mut future);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn joint_session_past(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> {
|
||||
let mut past = vec!();
|
||||
self.get_past_entries(frame_id_root, &mut past);
|
||||
for frame in self.full_frame_tree_iter(frame_id_root) {
|
||||
let mut prev_instant = frame.current.1;
|
||||
for &(pipeline_id, instant) in frame.prev.iter().rev() {
|
||||
past.push((prev_instant, frame.id, pipeline_id));
|
||||
prev_instant = instant;
|
||||
}
|
||||
}
|
||||
|
||||
past.sort();
|
||||
past
|
||||
}
|
||||
|
||||
fn get_past_entries(&self, frame_id_root: FrameId, mut past: &mut Vec<(Instant, FrameId, PipelineId)>) {
|
||||
let frame = match self.frames.get(&frame_id_root) {
|
||||
Some(frame) => frame,
|
||||
None => return warn!("Tried to get frame past after frame {:?} closed.", frame_id_root),
|
||||
};
|
||||
|
||||
let mut prev_instant = frame.current.1;
|
||||
for &(pipeline_id, instant) in frame.prev.iter().rev() {
|
||||
past.push((prev_instant, frame_id_root, pipeline_id));
|
||||
prev_instant = instant;
|
||||
}
|
||||
for &(pipeline_id, _) in frame.prev.iter().chain(once(&frame.current)) {
|
||||
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline,
|
||||
None => {
|
||||
warn!("Tried to get pipeline {:?} for child lookup after closure.", pipeline_id);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
for frame_id in &pipeline.children {
|
||||
self.get_past_entries(*frame_id, &mut past);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new frame and update the internal bookkeeping.
|
||||
fn new_frame(&mut self, pipeline_id: PipelineId) -> FrameId {
|
||||
let id = self.next_frame_id;
|
||||
let FrameId(ref mut i) = self.next_frame_id;
|
||||
*i += 1;
|
||||
|
||||
let frame = Frame::new(pipeline_id);
|
||||
let frame = Frame::new(id, pipeline_id);
|
||||
|
||||
assert!(self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame).is_none());
|
||||
assert!(!self.frames.contains_key(&id));
|
||||
|
@ -831,6 +833,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
debug!("constellation got traverse history message from script");
|
||||
self.handle_traverse_history_msg(pipeline_id, direction);
|
||||
}
|
||||
// Handle a joint session history length request.
|
||||
FromScriptMsg::JointSessionHistoryLength(pipeline_id, sender) => {
|
||||
debug!("constellation got joint session history length message from script");
|
||||
self.handle_joint_session_history_length(pipeline_id, sender);
|
||||
}
|
||||
// Notification that the new document is ready to become active
|
||||
FromScriptMsg::ActivateDocument(pipeline_id) => {
|
||||
debug!("constellation got activate document message");
|
||||
|
@ -1485,6 +1492,25 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) {
|
||||
let frame_id = match self.get_top_level_frame_for_pipeline(Some(pipeline_id)) {
|
||||
Some(frame_id) => frame_id,
|
||||
None => {
|
||||
warn!("Jsh length message received after root's closure.");
|
||||
let _ = sender.send(0);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize length at 1 to count for the current active entry
|
||||
let mut length = 1;
|
||||
for frame in self.full_frame_tree_iter(frame_id) {
|
||||
length += frame.next.len();
|
||||
length += frame.prev.len();
|
||||
}
|
||||
let _ = sender.send(length as u32);
|
||||
}
|
||||
|
||||
fn handle_key_msg(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
|
||||
// Send to the explicitly focused pipeline (if it exists), or the root
|
||||
// frame's current pipeline. If neither exist, fall back to sending to
|
||||
|
|
|
@ -10,6 +10,7 @@ use dom::bindings::global::GlobalRef;
|
|||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::window::Window;
|
||||
use ipc_channel::ipc;
|
||||
use msg::constellation_msg::TraversalDirection;
|
||||
use script_traits::ScriptMsg as ConstellationMsg;
|
||||
|
||||
|
@ -44,6 +45,15 @@ impl History {
|
|||
}
|
||||
|
||||
impl HistoryMethods for History {
|
||||
// https://html.spec.whatwg.org/multipage/#dom-history-length
|
||||
fn Length(&self) -> u32 {
|
||||
let pipeline = self.window.pipeline();
|
||||
let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length.");
|
||||
let msg = ConstellationMsg::JointSessionHistoryLength(pipeline, sender);
|
||||
let _ = self.window.constellation_chan().send(msg);
|
||||
recv.recv().unwrap()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-history-go
|
||||
fn Go(&self, delta: i32) {
|
||||
let direction = if delta > 0 {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// https://html.spec.whatwg.org/multipage/#the-history-interface
|
||||
[Exposed=(Window,Worker)]
|
||||
interface History {
|
||||
// readonly attribute unsigned long length;
|
||||
readonly attribute unsigned long length;
|
||||
// attribute ScrollRestoration scrollRestoration;
|
||||
// readonly attribute any state;
|
||||
void go(optional long delta = 0);
|
||||
|
|
|
@ -91,6 +91,8 @@ pub enum ScriptMsg {
|
|||
MozBrowserEvent(PipelineId, Option<SubpageId>, MozBrowserEvent),
|
||||
/// HTMLIFrameElement Forward or Back traversal.
|
||||
TraverseHistory(Option<PipelineId>, TraversalDirection),
|
||||
/// Gets the length of the joint session history from the constellation.
|
||||
JointSessionHistoryLength(PipelineId, IpcSender<u32>),
|
||||
/// Favicon detected
|
||||
NewFavicon(Url),
|
||||
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
[001.html]
|
||||
type: testharness
|
||||
[history.length should update when loading pages in an iframe]
|
||||
expected: FAIL
|
||||
|
||||
[history.length should update when setting location.hash]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
[002.html]
|
||||
type: testharness
|
||||
[history.length should update when loading pages in an iframe]
|
||||
expected: FAIL
|
||||
|
||||
[history.length should update when setting location.hash]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[location_assign_about_blank.html]
|
||||
type: testharness
|
||||
[location.assign with initial about:blank browsing context]
|
||||
expected: FAIL
|
||||
|
|
@ -5598,9 +5598,6 @@
|
|||
[BarProp interface: attribute visible]
|
||||
expected: FAIL
|
||||
|
||||
[History interface: attribute length]
|
||||
expected: FAIL
|
||||
|
||||
[History interface: attribute state]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5610,9 +5607,6 @@
|
|||
[History interface: operation replaceState(any,DOMString,DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[History interface: window.history must inherit property "length" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
[History interface: window.history must inherit property "state" with the proper type (1)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue