Auto merge of #8612 - glennw:pending-frames, r=jdm

Add test to constellation to avoid writing reftest image if there are pending frames.

This changes several tests that contain <iframe></iframe> from FAIL to TIMEOUT. This is correct
since there is a bug that prevents these iframes from ever rendering.

~~~There are also a few previous FAILs that changed to OK. These may be intermittents or they
may genuinely be fixed by this change.~~~

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8612)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-12-17 16:19:16 +05:30
commit c6ae32abdd
8 changed files with 109 additions and 118 deletions

View file

@ -6,7 +6,7 @@ use app_units::Au;
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType, WorkerId};
use dom::bindings::callback::ExceptionHandling;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::codegen::Bindings::EventHandlerBinding::{EventHandlerNonNull, OnErrorEventHandlerNonNull};
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions};
@ -44,7 +44,8 @@ use layout_interface::{LayoutChan, LayoutRPC, Msg, Reflow, ReflowGoal, ReflowQue
use libc;
use msg::ParseErrorReporter;
use msg::compositor_msg::{LayerId, ScriptToCompositorMsg};
use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId, WindowSizeData};
use msg::constellation_msg::{ConstellationChan, DocumentState, LoadData};
use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData};
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use net_traits::ResourceTask;
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask};
@ -990,16 +991,43 @@ impl Window {
///
/// TODO(pcwalton): Only wait for style recalc, since we have off-main-thread layout.
pub fn reflow(&self, goal: ReflowGoal, query_type: ReflowQueryType, reason: ReflowReason) {
if query_type == ReflowQueryType::NoQuery && !self.Document().needs_reflow() {
let for_display = query_type == ReflowQueryType::NoQuery;
if !for_display || self.Document().needs_reflow() {
self.force_reflow(goal, query_type, reason);
// If window_size is `None`, we don't reflow, so the document stays dirty.
// Otherwise, we shouldn't need a reflow immediately after a reflow.
assert!(!self.Document().needs_reflow() || self.window_size.get().is_none());
} else {
debug!("Document doesn't need reflow - skipping it (reason {:?})", reason);
return
}
self.force_reflow(goal, query_type, reason);
// If writing a screenshot, check if the script has reached a state
// where it's safe to write the image. This means that:
// 1) The reflow is for display (otherwise it could be a query)
// 2) The html element doesn't contain the 'reftest-wait' class
// 3) The load event has fired.
// When all these conditions are met, notify the constellation
// that this pipeline is ready to write the image (from the script task
// perspective at least).
if opts::get().output_file.is_some() && for_display {
let document = self.Document();
// If window_size is `None`, we don't reflow, so the document stays dirty.
// Otherwise, we shouldn't need a reflow immediately after a reflow.
assert!(!self.Document().needs_reflow() || self.window_size.get().is_none());
// Checks if the html element has reftest-wait attribute present.
// See http://testthewebforward.org/docs/reftests.html
let html_element = document.GetDocumentElement();
let reftest_wait = html_element.map_or(false, |elem| {
elem.has_class(&Atom::from("reftest-wait"))
});
let ready_state = document.ReadyState();
if ready_state == DocumentReadyState::Complete && !reftest_wait {
let event = ConstellationMsg::SetDocumentState(self.id, DocumentState::Idle);
self.constellation_chan().0.send(event).unwrap();
}
}
}
pub fn layout(&self) -> &LayoutRPC {

View file

@ -80,7 +80,7 @@ use profile_traits::time::{self, ProfilerCategory, profile};
use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent};
use script_traits::CompositorEvent::{TouchEvent};
use script_traits::{CompositorEvent, ConstellationControlMsg, InitialScriptState, NewLayoutInfo};
use script_traits::{OpaqueScriptLayoutChannel, ScriptMsg as ConstellationMsg, ScriptState};
use script_traits::{OpaqueScriptLayoutChannel, ScriptMsg as ConstellationMsg};
use script_traits::{ScriptTaskFactory, TimerEvent, TimerEventRequest, TimerSource};
use script_traits::{TouchEventType, TouchId};
use std::any::Any;
@ -97,7 +97,6 @@ use std::result::Result;
use std::sync::atomic::{Ordering, AtomicBool};
use std::sync::mpsc::{Receiver, Select, Sender, channel};
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use time::{Tm, now};
use url::{Url, UrlParser};
use util::opts;
@ -1014,10 +1013,6 @@ impl ScriptTask {
ConstellationControlMsg::DispatchFrameLoadEvent {
target: pipeline_id, parent: containing_id } =>
self.handle_frame_load_event(containing_id, pipeline_id),
ConstellationControlMsg::GetCurrentState(sender, pipeline_id) => {
let state = self.handle_get_current_state(pipeline_id);
sender.send(state).unwrap();
},
ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) =>
self.handle_css_error_reporting(pipeline_id, filename, line, column, msg),
}
@ -1173,40 +1168,6 @@ impl ScriptTask {
panic!("Page rect message sent to nonexistent pipeline");
}
/// 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();
// 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.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.GetDocumentElement();
let reftest_wait = html_element.map_or(false, |elem| elem.has_class(&Atom::from("reftest-wait")));
if reftest_wait {
return ScriptState::DocumentLoading;
}
ScriptState::DocumentLoaded
}
fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
let NewLayoutInfo {
containing_pipeline_id,
@ -1715,6 +1676,9 @@ impl ScriptTask {
window: JS::from_rooted(&window),
}));
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::ActivateDocument(incomplete.pipeline_id)).unwrap();
let is_javascript = incomplete.url.scheme == "javascript";
let parse_input = if is_javascript {
use url::percent_encoding::percent_decode_to;