diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-05-13 18:37:54 -0500 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-05-13 18:37:54 -0500 |
commit | 5e61ebaa05e5babb7b2fdd1347b6cdd23df38e62 (patch) | |
tree | f1fdda012759ab0d112c0d937412720d471f8499 /components/script/script_task.rs | |
parent | 100e2b46916c3a35664e58f908042bcf9b87a83f (diff) | |
parent | eec3fad93da44724a661520e569fb7471c1b4f35 (diff) | |
download | servo-5e61ebaa05e5babb7b2fdd1347b6cdd23df38e62.tar.gz servo-5e61ebaa05e5babb7b2fdd1347b6cdd23df38e62.zip |
Auto merge of #6031 - glennw:reftest-race-conditions, r=larsberg,jdm
The basic idea is it's safe to output an image for reftest by testing:
- That the compositor doesn't have any animations active.
- That the compositor is not waiting on any outstanding paint messages to arrive.
- That the script tasks are "idle" and therefore won't cause reflow.
- This currently means page loaded, onload fired, reftest-wait not active, first reflow triggered.
- It could easily be expanded to handle pending timers etc.
- That the "epoch" that the layout tasks have last laid out after script went idle, is reflected by the compositor in all visible layers for that pipeline.
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6031)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r-- | components/script/script_task.rs | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 504a4f169b3..c88dbb8537a 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -58,9 +58,8 @@ use script_traits::CompositorEvent::{MouseDownEvent, MouseUpEvent}; use script_traits::CompositorEvent::{MouseMoveEvent, KeyEvent}; use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel}; use script_traits::{ConstellationControlMsg, ScriptControlChan}; -use script_traits::ScriptTaskFactory; +use script_traits::{ScriptState, ScriptTaskFactory}; use webdriver_traits::WebDriverScriptCommand; -use msg::compositor_msg::ReadyState::{FinishedLoading, Loading, PerformingLayout}; use msg::compositor_msg::{LayerId, ScriptListener}; use msg::constellation_msg::{ConstellationChan, FocusType}; use msg::constellation_msg::{LoadData, PipelineId, SubpageId, MozBrowserEvent, WorkerId}; @@ -735,6 +734,10 @@ impl ScriptTask { responder.respond(); self.handle_resource_loaded(id, LoadType::Stylesheet(url)); } + ConstellationControlMsg::GetCurrentState(sender, pipeline_id) => { + let state = self.handle_get_current_state(pipeline_id); + sender.send(state).unwrap(); + } } } @@ -859,6 +862,40 @@ impl ScriptTask { doc.r().finish_load(load); } + /// Get the current state of a given pipeline. + fn handle_get_current_state(&self, pipeline_id: PipelineId) -> ScriptState { + // Check if the main page load is still pending + let loads = self.incomplete_loads.borrow(); + if let Some(_) = loads.iter().find(|load| load.pipeline_id == pipeline_id) { + return ScriptState::DocumentLoading; + } + + // If not in pending loads, the page should exist by now. + let page = self.root_page(); + let page = page.find(pipeline_id).expect("GetCurrentState sent to nonexistent pipeline"); + let doc = page.document().root(); + + // Check if document load event has fired. If the document load + // event has fired, this also guarantees that the first reflow + // has been kicked off. Since the script task does a join with + // layout, this ensures there are no race conditions that can occur + // between load completing and the first layout completing. + let load_pending = doc.r().ReadyState() != DocumentReadyState::Complete; + if load_pending { + return ScriptState::DocumentLoading; + } + + // Checks if the html element has reftest-wait attribute present. + // See http://testthewebforward.org/docs/reftests.html + let html_element = doc.r().GetDocumentElement().root(); + let reftest_wait = html_element.r().map_or(false, |elem| elem.has_class(&Atom::from_slice("reftest-wait"))); + if reftest_wait { + return ScriptState::DocumentLoading; + } + + return ScriptState::DocumentLoaded; + } + fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) { let NewLayoutInfo { containing_pipeline_id, @@ -993,14 +1030,6 @@ impl ScriptTask { with this script task. This is a bug."); let window = page.window().root(); window.r().handle_reflow_complete_msg(reflow_id); - - let doc = page.document().root(); - let html_element = doc.r().GetDocumentElement().root(); - let reftest_wait = html_element.r().map_or(false, |elem| elem.has_class(&Atom::from_slice("reftest-wait"))); - - if !reftest_wait { - self.compositor.borrow_mut().set_ready_state(pipeline_id, FinishedLoading); - } } /// Window was resized, but this script was not active, so don't reflow yet @@ -1102,8 +1131,6 @@ impl ScriptTask { }) }).root(); - self.compositor.borrow_mut().set_ready_state(incomplete.pipeline_id, Loading); - // Create a new frame tree entry. let page = Rc::new(Page::new(incomplete.pipeline_id, final_url.clone())); if !root_page_exists { @@ -1462,7 +1489,6 @@ impl ScriptTask { let final_url = document.r().url(); document.r().set_ready_state(DocumentReadyState::Interactive); - self.compositor.borrow_mut().set_ready_state(id, PerformingLayout); // Kick off the initial reflow of the page. debug!("kicking off initial reflow of {:?}", final_url); |