servo: Merge #1597 - Ensure ref tests wait to write their PNG until the page has fully loaded and reflowed (from larsbergstrom:add_page_loaded); r=pcwalton

Add a LoadComplete message so that script informs the constellation, which can then inform the compositor (and anyone else, later) about the completion of loading a page. This is important for ref tests, which should not emit a PNG until load has completed, even if we perform a composite before then.

Note that we must *also* wait for the `ready_state` to indicate that additionally layout has completed any associated reflow with the page, otherwise we could get the `LoadComplete` while the final reflow is still in progress and thus would write out the `n-1`'th reflow result.

r? @pcwalton

Source-Repo: https://github.com/servo/servo
Source-Revision: e9a0c8184f1af460583fe5ab2615e01d08ffc22f
This commit is contained in:
Lars Bergstrom 2014-01-30 12:49:28 -08:00
Родитель acce5f3c6f
Коммит 77a80051d5
6 изменённых файлов: 43 добавлений и 12 удалений

Просмотреть файл

@ -31,7 +31,7 @@ use layers::rendergl::RenderContext;
use layers::scene::Scene; use layers::scene::Scene;
use opengles::gl2; use opengles::gl2;
use png; use png;
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBufferSet, RenderState}; use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdleRenderState, LayerBufferSet, ReadyState, RenderState};
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId}; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_util::time::{profile, ProfilerChan, Timer}; use servo_util::time::{profile, ProfilerChan, Timer};
@ -84,6 +84,14 @@ 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
ready_state: ReadyState,
/// Whether the page being rendered has loaded completely.
/// Differs from ReadyState because we can finish loading (ready)
/// many times for a single page.
load_complete: bool,
/// The command line option flags. /// The command line option flags.
opts: Opts, opts: Opts,
@ -132,6 +140,8 @@ impl IOCompositor {
world_zoom: 1f32, world_zoom: 1f32,
zoom_action: false, zoom_action: false,
zoom_time: 0f64, zoom_time: 0f64,
ready_state: Blank,
load_complete: false,
compositor_layer: None, compositor_layer: None,
constellation_chan: constellation_chan, constellation_chan: constellation_chan,
profiler_chan: profiler_chan, profiler_chan: profiler_chan,
@ -222,6 +232,7 @@ impl IOCompositor {
(Some(ChangeReadyState(ready_state)), false) => { (Some(ChangeReadyState(ready_state)), false) => {
self.window.set_ready_state(ready_state); self.window.set_ready_state(ready_state);
self.ready_state = ready_state;
} }
(Some(ChangeRenderState(render_state)), false) => { (Some(ChangeRenderState(render_state)), false) => {
@ -269,6 +280,10 @@ impl IOCompositor {
self.scroll_fragment_to_point(id, point); self.scroll_fragment_to_point(id, point);
} }
(Some(LoadComplete(..)), false) => {
self.load_complete = true;
}
// When we are shutting_down, we need to avoid performing operations // When we are shutting_down, we need to avoid performing operations
// such as Paint that may crash because we have begun tearing down // such as Paint that may crash because we have begun tearing down
// the rest of our resources. // the rest of our resources.
@ -540,8 +555,9 @@ impl IOCompositor {
} }
} }
fn on_load_url_window_event(&self, url_string: ~str) { fn on_load_url_window_event(&mut self, url_string: ~str) {
debug!("osmain: loading URL `{:s}`", url_string); debug!("osmain: loading URL `{:s}`", url_string);
self.load_complete = false;
let root_pipeline_id = match self.compositor_layer { let root_pipeline_id = match self.compositor_layer {
Some(ref layer) => layer.pipeline.id.clone(), Some(ref layer) => layer.pipeline.id.clone(),
None => fail!("Compositor: Received LoadUrlWindowEvent without initialized compositor layers"), None => fail!("Compositor: Received LoadUrlWindowEvent without initialized compositor layers"),
@ -650,8 +666,8 @@ 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().
let write_png = self.opts.output_file.is_some(); if self.load_complete && self.ready_state == FinishedLoading
if write_png { && self.opts.output_file.is_some() {
let (width, height) = (self.window_size.width as uint, self.window_size.height as uint); let (width, height) = (self.window_size.width as uint, self.window_size.height as uint);
let path = from_str::<Path>(*self.opts.output_file.get_ref()).unwrap(); let path = from_str::<Path>(*self.opts.output_file.get_ref()).unwrap();
let mut pixels = gl2::read_pixels(0, 0, let mut pixels = gl2::read_pixels(0, 0,

Просмотреть файл

@ -21,6 +21,8 @@ use servo_util::time::ProfilerChan;
use std::comm::{Chan, SharedChan, Port}; use std::comm::{Chan, SharedChan, Port};
use std::num::Orderable; use std::num::Orderable;
use extra::url::Url;
#[cfg(target_os="linux")] #[cfg(target_os="linux")]
use azure::azure_hl; use azure::azure_hl;
@ -151,6 +153,9 @@ pub enum Msg {
SetIds(SendableFrameTree, Chan<()>, ConstellationChan), SetIds(SendableFrameTree, Chan<()>, ConstellationChan),
SetUnRenderedColor(PipelineId, Color), SetUnRenderedColor(PipelineId, Color),
/// The load of a page for a given URL has completed.
LoadComplete(PipelineId, Url),
} }
pub enum CompositorMode { pub enum CompositorMode {

Просмотреть файл

@ -63,7 +63,7 @@ impl NullCompositor {
NewLayer(..) | SetLayerPageSize(..) | SetLayerClipRect(..) | DeleteLayer(..) | NewLayer(..) | SetLayerPageSize(..) | SetLayerClipRect(..) | DeleteLayer(..) |
Paint(..) | InvalidateRect(..) | ChangeReadyState(..) | ChangeRenderState(..)| Paint(..) | InvalidateRect(..) | ChangeReadyState(..) | ChangeRenderState(..)|
ScrollFragmentPoint(..) | SetUnRenderedColor(..) ScrollFragmentPoint(..) | SetUnRenderedColor(..) | LoadComplete(..)
=> () => ()
} }
} }

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositing::{CompositorChan, SetIds, SetLayerClipRect, ShutdownComplete}; use compositing::{CompositorChan, LoadComplete, SetIds, SetLayerClipRect, ShutdownComplete};
use extra::url::Url; use extra::url::Url;
use geom::rect::Rect; use geom::rect::Rect;
@ -12,8 +12,9 @@ use pipeline::{Pipeline, CompositionPipeline};
use script::script_task::{ResizeMsg, ResizeInactiveMsg}; use script::script_task::{ResizeMsg, ResizeInactiveMsg};
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg}; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg};
use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg};
use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadUrlMsg, Msg, NavigateMsg, NavigationType}; use servo_msg::constellation_msg::{LoadCompleteMsg, LoadIframeUrlMsg, LoadUrlMsg, Msg, NavigateMsg};
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId}; use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg, ResizedWindowMsg};
use servo_msg::constellation_msg::SubpageId;
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
@ -345,6 +346,12 @@ impl Constellation {
debug!("constellation got URL load message"); debug!("constellation got URL load message");
self.handle_load_url_msg(source_id, url); self.handle_load_url_msg(source_id, url);
} }
// A page loaded through one of several methods above has completed all parsing,
// script, and reflow messages have been sent.
LoadCompleteMsg(pipeline_id, url) => {
debug!("constellation got load complete message");
self.compositor_chan.send(LoadComplete(pipeline_id, url));
}
// Handle a forward or back request // Handle a forward or back request
NavigateMsg(direction) => { NavigateMsg(direction) => {
debug!("constellation got navigation message"); debug!("constellation got navigation message");

Просмотреть файл

@ -26,11 +26,12 @@ pub enum IFrameSandboxState {
IFrameUnsandboxed IFrameUnsandboxed
} }
/// Messages from the compositor to the constellation. /// Messages from the compositor and script to the constellation.
pub enum Msg { pub enum Msg {
ExitMsg, ExitMsg,
FailureMsg(PipelineId, Option<SubpageId>), FailureMsg(PipelineId, Option<SubpageId>),
InitLoadUrlMsg(Url), InitLoadUrlMsg(Url),
LoadCompleteMsg(PipelineId, Url),
FrameRectMsg(PipelineId, SubpageId, Rect<f32>), FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
LoadUrlMsg(PipelineId, Url), LoadUrlMsg(PipelineId, Url),
LoadIframeUrlMsg(Url, PipelineId, SubpageId, IFrameSandboxState), LoadIframeUrlMsg(Url, PipelineId, SubpageId, IFrameSandboxState),

Просмотреть файл

@ -38,8 +38,8 @@ use js::rust::{Compartment, Cx};
use js; use js;
use servo_msg::compositor_msg::{FinishedLoading, Loading, PerformingLayout, ScriptListener}; use servo_msg::compositor_msg::{FinishedLoading, Loading, PerformingLayout, ScriptListener};
use servo_msg::constellation_msg::{ConstellationChan, IFrameSandboxed, IFrameUnsandboxed}; use servo_msg::constellation_msg::{ConstellationChan, IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadUrlMsg, NavigationDirection, PipelineId}; use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
use servo_msg::constellation_msg::{SubpageId}; use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
@ -745,7 +745,7 @@ impl ScriptTask {
let fragment = url.fragment.as_ref().map(|ref fragment| fragment.to_owned()); let fragment = url.fragment.as_ref().map(|ref fragment| fragment.to_owned());
// No more reflow required // No more reflow required
page.url = Some((url, false)); page.url = Some((url.clone(), false));
// Receive the JavaScript scripts. // Receive the JavaScript scripts.
assert!(js_scripts.is_some()); assert!(js_scripts.is_some());
@ -775,6 +775,8 @@ impl ScriptTask {
window.eventtarget.dispatch_event_with_target(wintarget, Some(doctarget), event); window.eventtarget.dispatch_event_with_target(wintarget, Some(doctarget), event);
page.fragment_node = fragment.map_default(None, |fragid| self.find_fragment_node(page, fragid)); page.fragment_node = fragment.map_default(None, |fragid| self.find_fragment_node(page, fragid));
self.constellation_chan.send(LoadCompleteMsg(page.id, url));
} }
fn find_fragment_node(&self, page: &mut Page, fragid: ~str) -> Option<AbstractNode> { fn find_fragment_node(&self, page: &mut Page, fragid: ~str) -> Option<AbstractNode> {