Store Compositor ReadyState per-pipeline

Instead of storing a single ReadyState, store one per pipeline and
track the earliest one.
This commit is contained in:
Bryan Bell 2014-08-28 13:56:01 -07:00 committed by Martin Robinson
parent a2ab6f9799
commit c182308350
5 changed files with 31 additions and 15 deletions

View file

@ -21,6 +21,7 @@ use windowing::PinchZoomWindowEvent;
use azure::azure_hl::SourceSurfaceMethods; use azure::azure_hl::SourceSurfaceMethods;
use azure::azure_hl; use azure::azure_hl;
use std::cmp;
use geom::matrix::identity; use geom::matrix::identity;
use geom::point::{Point2D, TypedPoint2D}; use geom::point::{Point2D, TypedPoint2D};
use geom::rect::Rect; use geom::rect::Rect;
@ -100,8 +101,8 @@ pub struct IOCompositor {
/// The time of the last zoom action has started. /// The time of the last zoom action has started.
zoom_time: f64, zoom_time: f64,
/// Current display/reflow status of the page /// Current display/reflow status of each pipeline.
ready_state: ReadyState, ready_states: HashMap<PipelineId, ReadyState>,
/// Whether the page being rendered has loaded completely. /// Whether the page being rendered has loaded completely.
/// Differs from ReadyState because we can finish loading (ready) /// Differs from ReadyState because we can finish loading (ready)
@ -165,7 +166,7 @@ impl IOCompositor {
viewport_zoom: ScaleFactor(1.0), viewport_zoom: ScaleFactor(1.0),
zoom_action: false, zoom_action: false,
zoom_time: 0f64, zoom_time: 0f64,
ready_state: Blank, ready_states: HashMap::new(),
load_complete: false, load_complete: false,
constellation_chan: constellation_chan, constellation_chan: constellation_chan,
time_profiler_chan: time_profiler_chan, time_profiler_chan: time_profiler_chan,
@ -275,9 +276,8 @@ impl IOCompositor {
break; break;
} }
(Ok(ChangeReadyState(ready_state)), NotShuttingDown) => { (Ok(ChangeReadyState(pipeline_id, ready_state)), NotShuttingDown) => {
self.window.set_ready_state(ready_state); self.change_ready_state(pipeline_id, ready_state);
self.ready_state = ready_state;
} }
(Ok(ChangeRenderState(render_state)), NotShuttingDown) => { (Ok(ChangeRenderState(render_state)), NotShuttingDown) => {
@ -333,6 +333,21 @@ impl IOCompositor {
} }
} }
fn change_ready_state(&mut self, pipeline_id: PipelineId, ready_state: ReadyState) {
self.ready_states.insert_or_update_with(pipeline_id,
ready_state,
|_key, value| *value = ready_state);
self.window.set_ready_state(self.get_earliest_pipeline_ready_state());
}
fn get_earliest_pipeline_ready_state(&self) -> ReadyState {
if self.ready_states.len() == 0 {
return Blank;
}
return self.ready_states.values().fold(FinishedLoading, |a, &b| cmp::min(a, b));
}
fn change_render_state(&mut self, render_state: RenderState) { fn change_render_state(&mut self, render_state: RenderState) {
self.window.set_render_state(render_state); self.window.set_render_state(render_state);
if render_state == IdleRenderState { if render_state == IdleRenderState {
@ -873,7 +888,7 @@ impl IOCompositor {
// Render to PNG. We must read from the back buffer (ie, before // Render to PNG. We must read from the back buffer (ie, before
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer(). // self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
if self.load_complete && self.ready_state == FinishedLoading if self.load_complete && self.get_earliest_pipeline_ready_state() == FinishedLoading
&& self.opts.output_file.is_some() && !self.has_outstanding_render_msgs() { && self.opts.output_file.is_some() && !self.has_outstanding_render_msgs() {
let (width, height) = (self.window_size.width.get(), self.window_size.height.get()); let (width, height) = (self.window_size.width.get(), self.window_size.height.get());
let path = from_str::<Path>(self.opts.output_file.get_ref().as_slice()).unwrap(); let path = from_str::<Path>(self.opts.output_file.get_ref().as_slice()).unwrap();

View file

@ -38,8 +38,8 @@ pub struct CompositorChan {
/// Implementation of the abstract `ScriptListener` interface. /// Implementation of the abstract `ScriptListener` interface.
impl ScriptListener for CompositorChan { impl ScriptListener for CompositorChan {
fn set_ready_state(&self, ready_state: ReadyState) { fn set_ready_state(&self, pipeline_id: PipelineId, ready_state: ReadyState) {
let msg = ChangeReadyState(ready_state); let msg = ChangeReadyState(pipeline_id, ready_state);
self.chan.send(msg); self.chan.send(msg);
} }
@ -174,7 +174,7 @@ pub enum Msg {
/// Requests that the compositor paint the given layer buffer set for the given page size. /// Requests that the compositor paint the given layer buffer set for the given page size.
Paint(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>), Paint(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>),
/// Alerts the compositor to the current status of page loading. /// Alerts the compositor to the current status of page loading.
ChangeReadyState(ReadyState), ChangeReadyState(PipelineId, ReadyState),
/// Alerts the compositor to the current status of rendering. /// Alerts the compositor to the current status of rendering.
ChangeRenderState(RenderState), ChangeRenderState(RenderState),
/// Alerts the compositor that the RenderMsg has been discarded. /// Alerts the compositor that the RenderMsg has been discarded.

View file

@ -20,7 +20,7 @@ pub enum RenderState {
RenderingRenderState, RenderingRenderState,
} }
#[deriving(PartialEq, Clone)] #[deriving(Eq, Ord, PartialEq, PartialOrd, Clone)]
pub enum ReadyState { pub enum ReadyState {
/// Informs the compositor that nothing has been done yet. Used for setting status /// Informs the compositor that nothing has been done yet. Used for setting status
Blank, Blank,
@ -107,7 +107,7 @@ pub trait RenderListener {
/// The interface used by the script task to tell the compositor to update its ready state, /// The interface used by the script task to tell the compositor to update its ready state,
/// which is used in displaying the appropriate message in the window's title. /// which is used in displaying the appropriate message in the window's title.
pub trait ScriptListener : Clone { pub trait ScriptListener : Clone {
fn set_ready_state(&self, ReadyState); fn set_ready_state(&self, PipelineId, ReadyState);
fn scroll_fragment_point(&self, fn scroll_fragment_point(&self,
pipeline_id: PipelineId, pipeline_id: PipelineId,
layer_id: LayerId, layer_id: LayerId,

View file

@ -328,7 +328,7 @@ impl Page {
self.join_layout(); self.join_layout();
// Tell the user that we're performing layout. // Tell the user that we're performing layout.
compositor.set_ready_state(PerformingLayout); compositor.set_ready_state(self.id, PerformingLayout);
// Layout will let us know when it's done. // Layout will let us know when it's done.
let (join_chan, join_port) = channel(); let (join_chan, join_port) = channel();

View file

@ -512,7 +512,8 @@ impl ScriptTask {
let mut layout_join_port = page.layout_join_port.deref().borrow_mut(); let mut layout_join_port = page.layout_join_port.deref().borrow_mut();
*layout_join_port = None; *layout_join_port = None;
} }
self.compositor.set_ready_state(FinishedLoading);
self.compositor.set_ready_state(pipeline_id, FinishedLoading);
if page.pending_reflows.get() > 0 { if page.pending_reflows.get() > 0 {
page.pending_reflows.set(0); page.pending_reflows.set(0);
@ -616,7 +617,7 @@ impl ScriptTask {
let document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root(); let document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root();
window.deref().init_browser_context(&*document); window.deref().init_browser_context(&*document);
self.compositor.set_ready_state(Loading); self.compositor.set_ready_state(pipeline_id, Loading);
// Parse HTML. // Parse HTML.
// //
// Note: We can parse the next document in parallel with any previous documents. // Note: We can parse the next document in parallel with any previous documents.