mirror of
https://github.com/servo/servo.git
synced 2025-06-16 20:34:30 +00:00
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:
parent
d17a1f2ad7
commit
a6eaffcd93
16 changed files with 216 additions and 100 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ impl LayoutTask {
|
|||
}
|
||||
}
|
||||
RouteScriptMsg(script_msg) => {
|
||||
debug!("layout: routing %? to script task", script_msg);
|
||||
self.route_script_msg(script_msg);
|
||||
}
|
||||
ExitMsg => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -27,8 +27,13 @@ impl ConstellationChan {
|
|||
|
||||
pub enum Msg {
|
||||
LoadUrlMsg(Url),
|
||||
NavigateMsg(NavigationDirection),
|
||||
ExitMsg(Chan<()>),
|
||||
RendererReadyMsg(uint),
|
||||
TokenSurrenderMsg(~CompositorToken),
|
||||
}
|
||||
|
||||
pub enum NavigationDirection {
|
||||
Forward,
|
||||
Back,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue