Skip to content


Browse files Browse the repository at this point in the history
Implement diff-based session history
This new implementation of the session history keeps track of
a single tree of browsing contexts and pipelines which represents
the active entry of the session history and it keeps track of
diffs between adjacent entries. This allows use to traverse across
the joint session history by applying diffs to the active tree.
  • Loading branch information
cbrewster committed Apr 5, 2018
1 parent 044f19d commit f3d068f
Show file tree
Hide file tree
Showing 9 changed files with 499 additions and 464 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion components/constellation/Cargo.toml
Expand Up @@ -23,7 +23,6 @@ gfx = {path = "../gfx"}
gfx_traits = {path = "../gfx_traits"}
hyper = "0.10"
ipc-channel = "0.10"
itertools = "0.7"
layout_traits = {path = "../layout_traits"}
log = "0.4"
metrics = {path = "../metrics"}
Expand Down
107 changes: 9 additions & 98 deletions components/constellation/
Expand Up @@ -3,13 +3,9 @@
* file, You can obtain one at */

use euclid::TypedSize2D;
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, PipelineId};
use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
use pipeline::Pipeline;
use script_traits::LoadData;
use std::collections::HashMap;
use std::iter::once;
use std::mem::replace;
use std::time::Instant;
use std::collections::{HashMap, HashSet};
use style_traits::CSSPixel;

/// The constellation's view of a browsing context.
Expand All @@ -29,72 +25,33 @@ pub struct BrowsingContext {
/// The size of the frame.
pub size: Option<TypedSize2D<f32, CSSPixel>>,

/// The timestamp for the current session history entry.
pub instant: Instant,

/// The pipeline for the current session history entry.
pub pipeline_id: PipelineId,

/// The load data for the current session history entry.
pub load_data: LoadData,

/// The past session history, ordered chronologically.
pub prev: Vec<SessionHistoryEntry>,

/// The future session history, ordered reverse chronologically.
pub next: Vec<SessionHistoryEntry>,
pub pipelines: HashSet<PipelineId>,

impl BrowsingContext {
/// Create a new browsing context.
/// Note this just creates the browsing context, it doesn't add it to the constellation's set of browsing contexts.
pub fn new(id: BrowsingContextId,
top_level_id: TopLevelBrowsingContextId,
pipeline_id: PipelineId,
load_data: LoadData)
pipeline_id: PipelineId)
-> BrowsingContext
let mut pipelines = HashSet::new();
BrowsingContext {
id: id,
top_level_id: top_level_id,
size: None,
pipeline_id: pipeline_id,
instant: Instant::now(),
load_data: load_data,
prev: vec!(),
next: vec!(),

/// Get the current session history entry.
pub fn current(&self) -> SessionHistoryEntry {
SessionHistoryEntry {
instant: self.instant,
pipeline_id: Some(self.pipeline_id),
load_data: self.load_data.clone(),

/// Set the current session history entry, and push the current frame entry into the past.
pub fn load(&mut self, pipeline_id: PipelineId, load_data: LoadData) {
let current = self.current();
self.instant = Instant::now();
pub fn update_current_entry(&mut self, pipeline_id: PipelineId) {
self.pipeline_id = pipeline_id;
self.load_data = load_data;

/// Set the future to be empty.
pub fn remove_forward_entries(&mut self) -> Vec<SessionHistoryEntry> {
replace(&mut, vec!())

/// Update the current entry of the BrowsingContext from an entry that has been traversed to.
pub fn update_current(&mut self, pipeline_id: PipelineId, entry: SessionHistoryEntry) {
self.pipeline_id = pipeline_id;
self.instant = entry.instant;
self.load_data = entry.load_data;

/// Is this a top-level browsing context?
Expand All @@ -103,50 +60,6 @@ impl BrowsingContext {

/// An entry in a browsing context's session history.
/// Each entry stores the pipeline id for a document in the session history.
/// When we operate on the joint session history, entries are sorted chronologically,
/// so we timestamp the entries by when the entry was added to the session history.
/// <>
pub struct SessionHistoryEntry {
/// The timestamp for when the session history entry was created
pub instant: Instant,

/// The pipeline for the document in the session history,
/// None if the entry has been discarded
pub pipeline_id: Option<PipelineId>,

/// The load data for this entry, used to reload the pipeline if it has been discarded
pub load_data: LoadData,

/// The frame that this session history entry is part of
pub browsing_context_id: BrowsingContextId,

/// Represents a pending change in a session history, that will be applied
/// once the new pipeline has loaded and completed initial layout / paint.
pub struct SessionHistoryChange {
/// The browsing context to change.
pub browsing_context_id: BrowsingContextId,

/// The top-level browsing context ancestor.
pub top_level_browsing_context_id: TopLevelBrowsingContextId,

/// The pipeline for the document being loaded.
pub new_pipeline_id: PipelineId,

/// The data for the document being loaded.
pub load_data: LoadData,

/// Is the new document replacing the current document (e.g. a reload)
/// or pushing it into the session history (e.g. a navigation)?
/// If it is replacing an existing entry, we store its timestamp.
pub replace_instant: Option<Instant>,

/// An iterator over browsing contexts, returning the descendant
/// contexts whose active documents are fully active, in depth-first
/// order.
Expand Down Expand Up @@ -217,9 +130,7 @@ impl<'a> Iterator for AllBrowsingContextsIterator<'a> {
let child_browsing_context_ids = browsing_context.prev.iter().chain(
.filter_map(|entry| entry.pipeline_id)
let child_browsing_context_ids = browsing_context.pipelines.iter()
.filter_map(|pipeline_id| pipelines.get(&pipeline_id))
.flat_map(|pipeline| pipeline.children.iter());
Expand Down

0 comments on commit f3d068f

Please sign in to comment.