forward/back navigation with shift+backspace and backspace

script caches last loaded url -- currently no caching policy
naive caching of render layers for near-instant forward/back
handling evicted pipelines is currently broken
This commit is contained in:
Tim Kuehn 2013-06-28 16:45:56 -07:00
parent d17a1f2ad7
commit a6eaffcd93
16 changed files with 216 additions and 100 deletions

View file

@ -21,7 +21,6 @@ use render_context::RenderContext;
use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan};
use std::uint;
use std::util::replace;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
@ -73,7 +72,7 @@ priv struct RenderTask<C> {
/// A token that grants permission to send paint messages to compositor
compositor_token: Option<~CompositorToken>,
/// Cached copy of last layers rendered
next_paint_msg: Option<(LayerBufferSet, Size2D<uint>)>,
last_paint_msg: Option<(LayerBufferSet, Size2D<uint>)>,
}
impl<C: RenderListener + Owned> RenderTask<C> {
@ -108,7 +107,7 @@ impl<C: RenderListener + Owned> RenderTask<C> {
constellation_chan: constellation_chan.take(),
compositor_token: None,
next_paint_msg: None,
last_paint_msg: None,
};
render_task.start();
@ -129,11 +128,9 @@ impl<C: RenderListener + Owned> RenderTask<C> {
}
TokenBestowMsg(token) => {
self.compositor_token = Some(token);
let next_paint_msg = replace(&mut self.next_paint_msg, None);
match next_paint_msg {
Some((layer_buffer_set, layer_size)) => {
println("retrieving cached paint msg");
self.compositor.paint(layer_buffer_set, layer_size);
match self.last_paint_msg {
Some((ref layer_buffer_set, ref layer_size)) => {
self.compositor.paint(layer_buffer_set.clone(), *layer_size);
self.compositor.set_render_state(IdleRenderState);
}
None => {}
@ -162,7 +159,7 @@ impl<C: RenderListener + Owned> RenderTask<C> {
}
self.compositor.set_render_state(RenderingRenderState);
do profile(time::RenderingCategory, self.profiler_chan.clone()) {
do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {
let tile_size = self.opts.tile_size;
// FIXME: Try not to create a new array here.
@ -235,12 +232,10 @@ impl<C: RenderListener + Owned> RenderTask<C> {
debug!("render_task: returning surface");
if self.compositor_token.is_some() {
self.compositor.paint(layer_buffer_set, render_layer.size);
}
else {
println("caching paint msg");
self.next_paint_msg = Some((layer_buffer_set, render_layer.size));
self.compositor.paint(layer_buffer_set.clone(), render_layer.size);
}
debug!("caching paint msg");
self.last_paint_msg = Some((layer_buffer_set, render_layer.size));
self.compositor.set_render_state(IdleRenderState);
}
}

View file

@ -4,12 +4,14 @@
use platform::{Application, Window};
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
use script::script_task::{LoadMsg, SendEventMsg};
use script::script_task::{LoadMsg, NavigateMsg, SendEventMsg};
use script::layout_interface::{LayoutChan, RouteScriptMsg};
use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClickEvent};
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
use servo_msg::compositor::{RenderListener, LayerBufferSet, RenderState};
use servo_msg::compositor::{ReadyState, ScriptListener};
use servo_msg::constellation;
use gfx::render_task::{RenderChan, ReRenderMsg};
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
@ -32,6 +34,7 @@ use servo_util::{time, url};
use servo_util::time::profile;
use servo_util::time::ProfilerChan;
pub use windowing;
/// The implementation of the layers-based compositor.
#[deriving(Clone)]
@ -179,6 +182,15 @@ impl CompositorTask {
let render_chan: @mut Option<RenderChan> = @mut None;
let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
let layout_chan_clone = layout_chan.clone();
do window.set_navigation_callback |direction| {
let direction = match direction {
windowing::Forward => constellation::Forward,
windowing::Back => constellation::Back,
};
layout_chan_clone.send(RouteScriptMsg(NavigateMsg(direction)));
}
let layout_chan_clone = layout_chan.clone();
// Hook the windowing system's resize callback up to the resize rate limiter.
do window.set_resize_callback |width, height| {
@ -186,7 +198,7 @@ impl CompositorTask {
if *window_size != new_size {
debug!("osmain: window resized to %ux%u", width, height);
*window_size = new_size;
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(ResizeEvent(width, height))));
layout_chan_clone.send(RouteScriptMsg(SendEventMsg(ResizeEvent(width, height))));
} else {
debug!("osmain: dropping window resize since size is still %ux%u", width, height);
}
@ -197,7 +209,7 @@ impl CompositorTask {
// When the user enters a new URL, load it.
do window.set_load_url_callback |url_string| {
debug!("osmain: loading URL `%s`", url_string);
layout_chan_clone.chan.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None))));
layout_chan_clone.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None))));
}
let layout_chan_clone = layout_chan.clone();
@ -229,7 +241,7 @@ impl CompositorTask {
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
}
}
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(event)));
layout_chan_clone.send(RouteScriptMsg(SendEventMsg(event)));
}
};
@ -410,6 +422,7 @@ impl CompositorTask {
window.set_needs_display()
}
// Enter the main event loop.
while !*done {
// Check for new messages coming from the rendering task.

View file

@ -12,14 +12,15 @@ use gfx::opts::Opts;
use gfx::render_task::{TokenBestowMsg, TokenProcureMsg};
use pipeline::Pipeline;
use servo_msg::compositor::{CompositorToken};
use servo_msg::constellation::{ConstellationChan, ExitMsg, LoadUrlMsg, Msg, RendererReadyMsg};
use servo_msg::constellation::TokenSurrenderMsg;
use script::script_task::{ExecuteMsg, LoadMsg};
use servo_msg::constellation::{ConstellationChan, ExitMsg, LoadUrlMsg, Msg, NavigateMsg};
use servo_msg::constellation::{Forward, Back, RendererReadyMsg, TokenSurrenderMsg};
use script::script_task::ExecuteMsg;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask;
use servo_net::resource_task;
use servo_util::time::ProfilerChan;
use std::hashmap::HashMap;
use std::util::replace;
pub struct Constellation {
chan: ConstellationChan,
@ -30,12 +31,20 @@ pub struct Constellation {
pipelines: HashMap<uint, Pipeline>,
navigation_context: NavigationContext,
next_id: uint,
current_token_holder: Option<uint>,
loading: Option<uint>,
current_token_bearer: Option<uint>,
next_token_bearer: Option<(uint, NavigationType)>,
compositor_token: Option<~CompositorToken>,
profiler_chan: ProfilerChan,
opts: Opts,
}
/// Represents the two different ways to which a page can be navigated
enum NavigationType {
Load, // entered or clicked on a url
Navigate, // browser forward/back buttons
}
/// Stores the ID's of the pipelines previous and next in the browser's history
pub struct NavigationContext {
previous: ~[uint],
next: ~[uint],
@ -52,18 +61,16 @@ impl NavigationContext {
}
pub fn back(&mut self) -> uint {
do self.current.mutate |id| {
self.next.push(id);
self.previous.pop()
}
self.next.push(self.current.get());
self.current = Some(self.previous.pop());
debug!("previous: %? next: %? current: %?", self.previous, self.next, self.current);
self.current.get()
}
pub fn forward(&mut self) -> uint {
do self.current.mutate |id| {
self.previous.push(id);
self.next.pop()
}
self.previous.push(self.current.get());
self.current = Some(self.next.pop());
debug!("previous: %? next: %? current: %?", self.previous, self.next, self.current);
self.current.get()
}
@ -102,8 +109,9 @@ impl Constellation {
pipelines: HashMap::new(),
navigation_context: NavigationContext::new(),
next_id: 0,
current_token_holder: None,
loading: None,
current_token_bearer: None,
next_token_bearer: None,
compositor_token: Some(~CompositorToken::new()),
profiler_chan: profiler_chan.clone(),
opts: opts.take(),
};
@ -122,17 +130,19 @@ impl Constellation {
}
}
/// Helper function for getting a unique pipeline ID
fn get_next_id(&mut self) -> uint {
let id = self.next_id;
self.next_id = id + 1;
id
}
/// Handles loading pages, navigation, and granting access to the compositor
fn handle_request(&mut self, request: Msg) -> bool {
match request {
LoadUrlMsg(url) => {
let pipeline_id = self.get_next_id();
let pipeline = Pipeline::create(pipeline_id,
let mut pipeline = Pipeline::create(pipeline_id,
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
@ -142,23 +152,41 @@ impl Constellation {
if url.path.ends_with(".js") {
pipeline.script_chan.send(ExecuteMsg(url));
} else {
pipeline.script_chan.send(LoadMsg(url));
self.loading = Some(pipeline_id);
pipeline.load(url);
self.next_token_bearer = Some((pipeline_id, Load));
}
self.pipelines.insert(pipeline_id, pipeline);
}
RendererReadyMsg(pipeline_id) => {
let loading = self.loading.clone();
do loading.map() |&id| {
if pipeline_id == id {
match self.current_token_holder {
Some(ref id) => {
let current_holder = self.pipelines.get(id);
current_holder.render_chan.send(TokenProcureMsg);
}
None => self.bestow_compositor_token(id, ~CompositorToken::new())
NavigateMsg(direction) => {
debug!("received message to navigate %?", direction);
let destination_id = match direction {
Forward => {
if self.navigation_context.next.is_empty() {
debug!("no next page to navigate to");
return true
}
self.navigation_context.forward()
}
Back => {
if self.navigation_context.previous.is_empty() {
debug!("no previous page to navigate to");
return true
}
self.navigation_context.back()
}
};
debug!("navigating to pipeline %u", destination_id);
self.pipelines.get(&destination_id).reload();
self.next_token_bearer = Some((destination_id, Navigate));
self.procure_or_bestow();
}
RendererReadyMsg(pipeline_id) => {
let next_token_bearer = self.next_token_bearer;
for next_token_bearer.iter().advance |&(id, _)| {
if pipeline_id == id {
self.procure_or_bestow();
}
};
}
@ -166,9 +194,9 @@ impl Constellation {
TokenSurrenderMsg(token) => {
self.remove_active_pipeline();
let token = Cell::new(token);
let loading = self.loading;
do loading.map |&id| {
self.bestow_compositor_token(id, token.take());
let next_token_bearer = self.next_token_bearer;
for next_token_bearer.iter().advance |&(id, nav_type)| {
self.bestow_compositor_token(id, token.take(), nav_type);
};
}
@ -186,23 +214,45 @@ impl Constellation {
true
}
/// Either procures the token, sends the token to next bearer, or does nothing if waiting for token surrender.
fn procure_or_bestow(&mut self) {
let current_token_bearer = replace(&mut self.current_token_bearer, None);
match current_token_bearer {
Some(ref id) => {
let pipeline = self.pipelines.get(id);
pipeline.render_chan.send(TokenProcureMsg);
}
None => {
let compositor_token = replace(&mut self.compositor_token, None);
for compositor_token.iter().advance |&token| {
let (id, nav_type) = self.next_token_bearer.get();
self.bestow_compositor_token(id, token, nav_type);
}
}
};
}
fn remove_active_pipeline(&mut self) {
// FIXME(tkuehn): currently, pipelines are not removed at all
// do self.current_token_holder.map |id| {
// do self.current_token_bearer.map |id| {
// self.pipelines.pop(id).unwrap().exit();
// };
self.current_token_holder = None;
self.current_token_bearer = None;
}
fn bestow_compositor_token(&mut self, id: uint, compositor_token: ~CompositorToken) {
fn bestow_compositor_token(&mut self, id: uint, compositor_token: ~CompositorToken, navigation_type: NavigationType) {
let pipeline = self.pipelines.get(&id);
pipeline.render_chan.send(TokenBestowMsg(compositor_token));
self.compositor_chan.send(SetLayoutChan(pipeline.layout_chan.clone()));
self.compositor_chan.send(SetRenderChan(pipeline.render_chan.clone()));
self.current_token_holder = Some(id);
self.loading = None;
self.navigation_context.navigate(id);
self.current_token_bearer = Some(id);
self.next_token_bearer = None;
// Don't navigate on Navigate type, because that is handled by forward/back
match navigation_type {
Load => self.navigation_context.navigate(id),
_ => {}
}
}
}

View file

@ -141,6 +141,7 @@ impl LayoutTask {
}
}
RouteScriptMsg(script_msg) => {
debug!("layout: routing %? to script task", script_msg);
self.route_script_msg(script_msg);
}
ExitMsg => {

View file

@ -234,7 +234,7 @@ impl TextRunScanner {
for clump.eachi |i| {
let range = new_ranges[i - self.clump.begin()];
if range.length() == 0 {
error!("Elided an `UnscannedTextbox` because it was zero-length after \
debug!("Elided an `UnscannedTextbox` because it was zero-length after \
compression; %s",
in_boxes[i].debug_str());
loop

View file

@ -2,13 +2,14 @@
* 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/. */
use extra::net::url::Url;
use compositing::CompositorChan;
use gfx::render_task::{RenderChan, RenderTask};
use gfx::render_task;
use gfx::opts::Opts;
use layout::layout_task::LayoutTask;
use script::layout_interface::LayoutChan;
use script::layout_interface;
use script::script_task::LoadMsg;
use servo_msg::constellation::{ConstellationChan};
use script::script_task::{ScriptTask, ScriptChan, ScriptMsg};
use script::script_task;
@ -23,6 +24,8 @@ pub struct Pipeline {
script_chan: ScriptChan,
layout_chan: LayoutChan,
render_chan: RenderChan,
/// The most recently loaded url
url: Option<Url>,
}
impl Pipeline {
@ -90,12 +93,24 @@ impl Pipeline {
script_chan: script_chan,
layout_chan: layout_chan,
render_chan: render_chan,
url: None,
}
}
pub fn load(&mut self, url: Url) {
self.url = Some(url.clone());
self.script_chan.send(LoadMsg(url));
}
pub fn reload(&self) {
for self.url.iter().advance |&url| {
self.script_chan.send(LoadMsg(url));
}
}
pub fn exit(&self) {
// Script task handles shutting down layout, as well
self.script_chan.send(script_task::ExitMsg);
self.layout_chan.send(layout_interface::ExitMsg);
let (response_port, response_chan) = comm::stream();
self.render_chan.send(render_task::ExitMsg(response_chan));

View file

@ -9,7 +9,7 @@
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, MouseCallback};
use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent, WindowClickEvent};
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent, ZoomCallback};
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent, ZoomCallback, Forward, Back, NavigationCallback};
use alert::{Alert, AlertMethods};
use std::libc::c_int;
@ -17,7 +17,8 @@ use geom::point::Point2D;
use geom::size::Size2D;
use servo_msg::compositor::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor::{FinishedLoading, Loading, PerformingLayout, ReadyState};
use glut::glut::{ACTIVE_CTRL, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight, WindowWidth};
use glut::glut::{ACTIVE_CTRL, ACTIVE_SHIFT, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight};
use glut::glut::WindowWidth;
use glut::glut;
use glut::machack;
@ -44,6 +45,7 @@ pub struct Window {
mouse_callback: Option<MouseCallback>,
scroll_callback: Option<ScrollCallback>,
zoom_callback: Option<ZoomCallback>,
navigation_callback: Option<NavigationCallback>,
drag_origin: Point2D<c_int>,
@ -72,6 +74,7 @@ impl WindowMethods<Application> for Window {
mouse_callback: None,
scroll_callback: None,
zoom_callback: None,
navigation_callback: None,
drag_origin: Point2D(0 as c_int, 0),
@ -177,6 +180,11 @@ impl WindowMethods<Application> for Window {
self.zoom_callback = Some(new_zoom_callback)
}
/// Registers a callback to be run when backspace or shift-backspace is pressed.
pub fn set_navigation_callback(&mut self, new_navigation_callback: NavigationCallback) {
self.navigation_callback = Some(new_navigation_callback)
}
/// Spins the event loop.
pub fn check_loop(@mut self) {
glut::check_loop()
@ -226,20 +234,33 @@ impl Window {
/// Helper function to handle keyboard events.
fn handle_key(&self, key: u8) {
debug!("got key: %d", key as int);
debug!("got key: %?", key);
let modifiers = glut::get_modifiers();
match key {
12 => self.load_url(), // Ctrl+L
k if k == ('=' as u8) && (glut::get_modifiers() & ACTIVE_CTRL) != 0 => { // Ctrl++
for self.zoom_callback.iter().advance |&callback| {
callback(0.1);
}
}
k if k == 31 && (glut::get_modifiers() & ACTIVE_CTRL) != 0 => { // Ctrl+-
12 => self.load_url(), // Ctrl+L
31 if (modifiers & ACTIVE_CTRL) != 0 => { // Ctrl+-
for self.zoom_callback.iter().advance |&callback| {
callback(-0.1);
}
}
_ => {}
127 => {
for self.navigation_callback.iter().advance |&callback| {
if (modifiers & ACTIVE_SHIFT) != 0 { // Shift+Backspace
callback(Forward);
}
else {
callback(Back);
}
}
}
c => match c as char {
'=' if (modifiers & ACTIVE_CTRL) != 0 => { // Ctrl++
for self.zoom_callback.iter().advance |&callback| {
callback(0.1);
}
}
_ => {}
}
}
}

View file

@ -14,6 +14,11 @@ pub enum WindowMouseEvent {
WindowMouseUpEvent(uint, Point2D<f32>),
}
pub enum WindowNavigateMsg {
Forward,
Back,
}
/// Type of the function that is called when the screen is to be redisplayed.
pub type CompositeCallback = @fn();
@ -29,9 +34,12 @@ pub type MouseCallback = @fn(WindowMouseEvent);
/// Type of the function that is called when the user scrolls.
pub type ScrollCallback = @fn(Point2D<f32>);
///Type of the function that is called when the user zooms.
/// Type of the function that is called when the user zooms.
pub type ZoomCallback = @fn(f32);
/// Type of the function that is called when the user clicks backspace or shift-backspace
pub type NavigationCallback = @fn(WindowNavigateMsg);
/// Methods for an abstract Application.
pub trait ApplicationMethods {
fn new() -> Self;
@ -57,6 +65,8 @@ pub trait WindowMethods<A> {
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);
/// Registers a callback to run when the user zooms.
pub fn set_zoom_callback(&mut self, new_zoom_callback: ZoomCallback);
/// Registers a callback to run when the user presses backspace or shift-backspace.
pub fn set_navigation_callback(&mut self, new_navigation_callback: NavigationCallback);
/// Spins the event loop.
pub fn check_loop(@mut self);

View file

@ -8,6 +8,7 @@ use geom::rect::Rect;
use geom::size::Size2D;
use std::util::NonCopyable;
#[deriving(Clone)]
pub struct LayerBuffer {
draw_target: DrawTarget,
@ -23,6 +24,7 @@ pub struct LayerBuffer {
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
/// buffers.
#[deriving(Clone)]
pub struct LayerBufferSet {
buffers: ~[LayerBuffer]
}

View file

@ -27,8 +27,13 @@ impl ConstellationChan {
pub enum Msg {
LoadUrlMsg(Url),
NavigateMsg(NavigationDirection),
ExitMsg(Chan<()>),
RendererReadyMsg(uint),
TokenSurrenderMsg(~CompositorToken),
}
pub enum NavigationDirection {
Forward,
Back,
}

View file

@ -7,8 +7,6 @@
use dom::bindings::utils::{DOMString, null_string, str};
use dom::node::{Node, NodeTypeId, ScriptView};
use std::str;
pub struct CharacterData {
parent: Node<ScriptView>,
data: DOMString

View file

@ -367,7 +367,7 @@ impl<View> AbstractNode<View> {
pub fn dump_indent(&self, indent: uint) {
let mut s = ~"";
for uint::range(0u, indent) |_i| {
s += ~" ";
s += " ";
}
s += self.debug_str();

View file

@ -8,7 +8,6 @@ use std::cell::Cell;
use std::comm;
use std::comm::Port;
use std::task;
use std::str;
use newcss::stylesheet::Stylesheet;
use newcss::util::DataStream;
use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done};

View file

@ -19,7 +19,9 @@ use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, Reflo
use layout_interface::{ReflowDocumentDamage, ReflowForDisplay, ReflowForScriptQuery, ReflowGoal};
use layout_interface::ReflowMsg;
use layout_interface;
use servo_msg::constellation::{ConstellationChan, LoadUrlMsg, RendererReadyMsg};
use servo_msg::constellation::{ConstellationChan, LoadUrlMsg, NavigationDirection};
use servo_msg::constellation::RendererReadyMsg;
use servo_msg::constellation;
use std::cast::transmute;
use std::cell::Cell;
@ -53,6 +55,8 @@ pub enum ScriptMsg {
LoadMsg(Url),
/// Executes a standalone script.
ExecuteMsg(Url),
/// Instructs the script task to send a navigate message to the constellation.
NavigateMsg(NavigationDirection),
/// Sends a DOM event.
SendEventMsg(Event),
/// Fires a JavaScript timeout.
@ -136,6 +140,11 @@ pub struct ScriptTask {
window_size: Size2D<uint>,
/// What parts of the document are dirty, if any.
damage: Option<DocumentDamage>,
/// Cached copy of the most recent url loaded by the script
/// TODO(tkuehn): this currently does not follow any particular caching policy
/// and simply caches pages forever (!).
last_loaded_url: Option<Url>,
}
fn global_script_context_key(_: @ScriptTask) {}
@ -212,6 +221,8 @@ impl ScriptTask {
window_size: Size2D(800u, 600),
damage: None,
last_loaded_url: None,
};
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
let script_task_ptr = {
@ -264,31 +275,18 @@ impl ScriptTask {
/// Handles an incoming control message.
fn handle_msg(&mut self) -> bool {
match self.script_port.recv() {
LoadMsg(url) => {
self.load(url);
true
}
ExecuteMsg(url) => {
self.handle_execute_msg(url);
true
}
SendEventMsg(event) => {
self.handle_event(event);
true
}
FireTimerMsg(timer_data) => {
self.handle_fire_timer_msg(timer_data);
true
}
ReflowCompleteMsg => {
self.handle_reflow_complete_msg();
true
}
LoadMsg(url) => self.load(url),
ExecuteMsg(url) => self.handle_execute_msg(url),
SendEventMsg(event) => self.handle_event(event),
FireTimerMsg(timer_data) => self.handle_fire_timer_msg(timer_data),
NavigateMsg(direction) => self.handle_navigate_msg(direction),
ReflowCompleteMsg => self.handle_reflow_complete_msg(),
ExitMsg => {
self.handle_exit_msg();
false
return false
}
}
true
}
/// Handles a request to execute a script.
@ -337,6 +335,11 @@ impl ScriptTask {
self.compositor.set_ready_state(FinishedLoading);
}
/// Handles a navigate forward or backward message.
fn handle_navigate_msg(&self, direction: NavigationDirection) {
self.constellation_chan.send(constellation::NavigateMsg(direction));
}
/// Handles a request to exit the script task and shut down layout.
fn handle_exit_msg(&mut self) {
self.join_layout();
@ -350,6 +353,9 @@ impl ScriptTask {
/// The entry point to document loading. Defines bindings, sets up the window and document
/// objects, parses HTML and CSS, and kicks off initial layout.
fn load(&mut self, url: Url) {
for self.last_loaded_url.iter().advance |&last_loaded_url| {
if url == last_loaded_url { return; }
}
// Define the script DOM bindings.
//
// FIXME: Can this be done earlier, to save the flag?
@ -362,7 +368,7 @@ impl ScriptTask {
// Parse HTML.
//
// Note: We can parse the next document in parallel with any previous documents.
let html_parsing_result = hubbub_html_parser::parse_html(copy url,
let html_parsing_result = hubbub_html_parser::parse_html(url.clone(),
self.resource_task.clone(),
self.image_cache_task.clone());
@ -396,7 +402,7 @@ impl ScriptTask {
self.root_frame = Some(Frame {
document: document,
window: window,
url: url
url: url.clone(),
});
// Perform the initial reflow.
@ -416,6 +422,7 @@ impl ScriptTask {
~"???",
1);
}
self.last_loaded_url = Some(url);
}
/// Sends a ping to layout and waits for the response. The response will arrive when the

View file

@ -152,7 +152,7 @@ impl Profiler {
priv fn print_buckets(&mut self) {
println(fmt!("%31s %15s %15s %15s %15s %15s",
"_category (ms)_", "_mean (ms)_", "_median (ms)_",
"_category_", "_mean (ms)_", "_median (ms)_",
"_min (ms)_", "_max (ms)_", "_bucket size_"));
for self.buckets.mut_iter().advance |bucket| {
match *bucket {

@ -1 +1 @@
Subproject commit 502ec156da38860a4dff911cf8f33f388a0a1883
Subproject commit 68875af396cb583e670dd5caad99431dac62f8db