aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_task.rs
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-05-13 18:37:54 -0500
committerbors-servo <metajack+bors@gmail.com>2015-05-13 18:37:54 -0500
commit5e61ebaa05e5babb7b2fdd1347b6cdd23df38e62 (patch)
treef1fdda012759ab0d112c0d937412720d471f8499 /components/script/script_task.rs
parent100e2b46916c3a35664e58f908042bcf9b87a83f (diff)
parenteec3fad93da44724a661520e569fb7471c1b4f35 (diff)
downloadservo-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.rs52
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);