mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Add link following and refactor the profiler.
This commit is contained in:
parent
e5c0021299
commit
a53a7f689d
18 changed files with 325 additions and 107 deletions
|
@ -18,6 +18,8 @@ use azure::scaled_font::ScaledFont;
|
||||||
use azure::azure_hl::{BackendType, ColorPattern};
|
use azure::azure_hl::{BackendType, ColorPattern};
|
||||||
use geom::{Point2D, Rect, Size2D};
|
use geom::{Point2D, Rect, Size2D};
|
||||||
|
|
||||||
|
use servo_util::time::ProfilerChan;
|
||||||
|
|
||||||
// FontHandle encapsulates access to the platform's font API,
|
// FontHandle encapsulates access to the platform's font API,
|
||||||
// e.g. quartz, FreeType. It provides access to metrics and tables
|
// e.g. quartz, FreeType. It provides access to metrics and tables
|
||||||
// needed by the text shaper as well as access to the underlying font
|
// needed by the text shaper as well as access to the underlying font
|
||||||
|
@ -210,13 +212,15 @@ pub struct Font {
|
||||||
style: UsedFontStyle,
|
style: UsedFontStyle,
|
||||||
metrics: FontMetrics,
|
metrics: FontMetrics,
|
||||||
backend: BackendType,
|
backend: BackendType,
|
||||||
|
profiler_chan: ProfilerChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Font {
|
pub impl Font {
|
||||||
fn new_from_buffer(ctx: &FontContext,
|
fn new_from_buffer(ctx: &FontContext,
|
||||||
buffer: ~[u8],
|
buffer: ~[u8],
|
||||||
style: &SpecifiedFontStyle,
|
style: &SpecifiedFontStyle,
|
||||||
backend: BackendType)
|
backend: BackendType,
|
||||||
|
profiler_chan: ProfilerChan)
|
||||||
-> Result<@mut Font, ()> {
|
-> Result<@mut Font, ()> {
|
||||||
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
||||||
let handle: FontHandle = if handle.is_ok() {
|
let handle: FontHandle = if handle.is_ok() {
|
||||||
|
@ -235,11 +239,13 @@ pub impl Font {
|
||||||
style: copy *style,
|
style: copy *style,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
|
profiler_chan: profiler_chan,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
|
fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
|
||||||
style: &SpecifiedFontStyle, backend: BackendType) -> @mut Font {
|
style: &SpecifiedFontStyle, backend: BackendType,
|
||||||
|
profiler_chan: ProfilerChan) -> @mut Font {
|
||||||
let metrics = handle.get_metrics();
|
let metrics = handle.get_metrics();
|
||||||
|
|
||||||
@mut Font {
|
@mut Font {
|
||||||
|
@ -249,11 +255,13 @@ pub impl Font {
|
||||||
style: copy *style,
|
style: copy *style,
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
|
profiler_chan: profiler_chan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
|
fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
|
||||||
style: &SpecifiedFontStyle, backend: BackendType) -> Result<@mut Font,()> {
|
style: &SpecifiedFontStyle, backend: BackendType,
|
||||||
|
profiler_chan: ProfilerChan) -> Result<@mut Font,()> {
|
||||||
|
|
||||||
// TODO(Issue #179): convert between specified and used font style here?
|
// TODO(Issue #179): convert between specified and used font style here?
|
||||||
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
|
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
|
||||||
|
@ -261,7 +269,7 @@ pub impl Font {
|
||||||
Err(()) => return Err(())
|
Err(()) => return Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Font::new_from_adopted_handle(fctx, styled_handle, style, backend));
|
return Ok(Font::new_from_adopted_handle(fctx, styled_handle, style, backend, profiler_chan));
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn get_shaper(@mut self) -> @Shaper {
|
priv fn get_shaper(@mut self) -> @Shaper {
|
||||||
|
|
|
@ -40,17 +40,18 @@ pub struct FontContext {
|
||||||
handle: FontContextHandle,
|
handle: FontContextHandle,
|
||||||
backend: BackendType,
|
backend: BackendType,
|
||||||
generic_fonts: HashMap<~str,~str>,
|
generic_fonts: HashMap<~str,~str>,
|
||||||
|
profiler_chan: ProfilerChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
pub impl<'self> FontContext {
|
pub impl<'self> FontContext {
|
||||||
fn new(backend: BackendType,
|
fn new(backend: BackendType,
|
||||||
needs_font_list: bool,
|
needs_font_list: bool,
|
||||||
prof_chan: ProfilerChan)
|
profiler_chan: ProfilerChan)
|
||||||
-> FontContext {
|
-> FontContext {
|
||||||
let handle = FontContextHandle::new();
|
let handle = FontContextHandle::new();
|
||||||
let font_list = if needs_font_list {
|
let font_list = if needs_font_list {
|
||||||
Some(FontList::new(&handle, prof_chan.clone())) }
|
Some(FontList::new(&handle, profiler_chan.clone())) }
|
||||||
else { None };
|
else { None };
|
||||||
|
|
||||||
// TODO: Allow users to specify these.
|
// TODO: Allow users to specify these.
|
||||||
|
@ -69,6 +70,7 @@ pub impl<'self> FontContext {
|
||||||
handle: handle,
|
handle: handle,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
generic_fonts: generic_fonts,
|
generic_fonts: generic_fonts,
|
||||||
|
profiler_chan: profiler_chan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +127,8 @@ pub impl<'self> FontContext {
|
||||||
for result.each |font_entry| {
|
for result.each |font_entry| {
|
||||||
found = true;
|
found = true;
|
||||||
// TODO(Issue #203): route this instantion through FontContext's Font instance cache.
|
// TODO(Issue #203): route this instantion through FontContext's Font instance cache.
|
||||||
let instance = Font::new_from_existing_handle(self, &font_entry.handle, style, self.backend);
|
let instance = Font::new_from_existing_handle(self, &font_entry.handle, style, self.backend,
|
||||||
|
self.profiler_chan.clone());
|
||||||
do result::iter(&instance) |font: &@mut Font| { fonts.push(*font); }
|
do result::iter(&instance) |font: &@mut Font| { fonts.push(*font); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,7 +166,8 @@ pub impl<'self> FontContext {
|
||||||
Ok(Font::new_from_adopted_handle(self,
|
Ok(Font::new_from_adopted_handle(self,
|
||||||
handle,
|
handle,
|
||||||
&desc.style,
|
&desc.style,
|
||||||
self.backend))
|
self.backend,
|
||||||
|
self.profiler_chan.clone()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub struct Opts {
|
||||||
render_backend: BackendType,
|
render_backend: BackendType,
|
||||||
n_render_threads: uint,
|
n_render_threads: uint,
|
||||||
tile_size: uint,
|
tile_size: uint,
|
||||||
|
profiler_period: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
|
@ -26,13 +27,13 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||||
getopts::optopt(~"r"), // rendering backend
|
getopts::optopt(~"r"), // rendering backend
|
||||||
getopts::optopt(~"s"), // size of tiles
|
getopts::optopt(~"s"), // size of tiles
|
||||||
getopts::optopt(~"t"), // threads to render with
|
getopts::optopt(~"t"), // threads to render with
|
||||||
|
getopts::optflagopt(~"p"), // profiler flag and output interval
|
||||||
];
|
];
|
||||||
|
|
||||||
let opt_match = match getopts::getopts(args, opts) {
|
let opt_match = match getopts::getopts(args, opts) {
|
||||||
result::Ok(m) => { copy m }
|
result::Ok(m) => { copy m }
|
||||||
result::Err(f) => { fail!(getopts::fail_str(copy f)) }
|
result::Err(f) => { fail!(getopts::fail_str(copy f)) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let urls = if opt_match.free.is_empty() {
|
let urls = if opt_match.free.is_empty() {
|
||||||
fail!(~"servo asks that you provide 1 or more URLs")
|
fail!(~"servo asks that you provide 1 or more URLs")
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,10 +69,18 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||||
None => 1, // FIXME: Number of cores.
|
None => 1, // FIXME: Number of cores.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let profiler_period: Option<f64> =
|
||||||
|
// if only flag is present, default to 5 second period
|
||||||
|
match getopts::opt_default(&opt_match, ~"p", ~"5") {
|
||||||
|
Some(period) => Some(f64::from_str(period).get()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
Opts {
|
Opts {
|
||||||
urls: urls,
|
urls: urls,
|
||||||
render_backend: render_backend,
|
render_backend: render_backend,
|
||||||
n_render_threads: n_render_threads,
|
n_render_threads: n_render_threads,
|
||||||
tile_size: tile_size,
|
tile_size: tile_size,
|
||||||
|
profiler_period: profiler_period,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@ use core::task::SingleThreaded;
|
||||||
use std::task_pool::TaskPool;
|
use std::task_pool::TaskPool;
|
||||||
use servo_net::util::spawn_listener;
|
use servo_net::util::spawn_listener;
|
||||||
|
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time::profile;
|
|
||||||
use servo_util::time::time;
|
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
|
@ -124,7 +122,7 @@ impl<C: Compositor + Owned> Renderer<C> {
|
||||||
|
|
||||||
fn render(&mut self, render_layer: RenderLayer) {
|
fn render(&mut self, render_layer: RenderLayer) {
|
||||||
debug!("renderer: rendering");
|
debug!("renderer: rendering");
|
||||||
do time("rendering") {
|
do profile(time::RenderingCategory, self.profiler_chan.clone()) {
|
||||||
let layer_buffer_set = do render_layers(&render_layer,
|
let layer_buffer_set = do render_layers(&render_layer,
|
||||||
&self.opts,
|
&self.opts,
|
||||||
self.profiler_chan.clone()) |render_layer_ref,
|
self.profiler_chan.clone()) |render_layer_ref,
|
||||||
|
|
|
@ -6,6 +6,8 @@ use font_context::FontContext;
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
use text::glyph::{BreakTypeNormal, GlyphStore};
|
use text::glyph::{BreakTypeNormal, GlyphStore};
|
||||||
use font::{Font, FontDescriptor, RunMetrics};
|
use font::{Font, FontDescriptor, RunMetrics};
|
||||||
|
use servo_util::time;
|
||||||
|
use servo_util::time::profile;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
|
|
||||||
/// A text run.
|
/// A text run.
|
||||||
|
@ -44,7 +46,9 @@ pub impl<'self> TextRun {
|
||||||
fn new(font: @mut Font, text: ~str, underline: bool) -> TextRun {
|
fn new(font: @mut Font, text: ~str, underline: bool) -> TextRun {
|
||||||
let mut glyph_store = GlyphStore::new(str::char_len(text));
|
let mut glyph_store = GlyphStore::new(str::char_len(text));
|
||||||
TextRun::compute_potential_breaks(text, &mut glyph_store);
|
TextRun::compute_potential_breaks(text, &mut glyph_store);
|
||||||
font.shape_text(text, &mut glyph_store);
|
do profile(time::LayoutShapingCategory, font.profiler_chan.clone()) {
|
||||||
|
font.shape_text(text, &mut glyph_store);
|
||||||
|
}
|
||||||
|
|
||||||
let run = TextRun {
|
let run = TextRun {
|
||||||
text: text,
|
text: text,
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
use compositing::resize_rate_limiter::ResizeRateLimiter;
|
use compositing::resize_rate_limiter::ResizeRateLimiter;
|
||||||
use platform::{Application, Window};
|
use platform::{Application, Window};
|
||||||
use script::script_task::{LoadMsg, ScriptMsg, SendEventMsg};
|
use script::script_task::{LoadMsg, ScriptMsg, SendEventMsg};
|
||||||
use windowing::{ApplicationMethods, WindowMethods};
|
use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
||||||
use script::dom::event::ClickEvent;
|
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
|
||||||
|
|
||||||
|
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||||
|
|
||||||
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods};
|
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods};
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
@ -233,12 +235,24 @@ fn run_main_loop(port: Port<Msg>,
|
||||||
|
|
||||||
let script_chan_clone = script_chan.clone();
|
let script_chan_clone = script_chan.clone();
|
||||||
|
|
||||||
// When the user clicks, perform hit testing
|
// When the user triggers a mouse event, perform appropriate hit testing
|
||||||
do window.set_click_callback |layer_click_point| {
|
do window.set_mouse_callback |window_mouse_event: WindowMouseEvent| {
|
||||||
let world_click_point = layer_click_point + *world_offset;
|
let event: Event;
|
||||||
debug!("osmain: clicked at %?", world_click_point);
|
let world_mouse_point = |layer_mouse_point: Point2D<f32>| {
|
||||||
|
layer_mouse_point + *world_offset
|
||||||
script_chan_clone.send(SendEventMsg(ClickEvent(world_click_point)));
|
};
|
||||||
|
match window_mouse_event {
|
||||||
|
WindowClickEvent(button, layer_mouse_point) => {
|
||||||
|
event = ClickEvent(button, world_mouse_point(layer_mouse_point));
|
||||||
|
}
|
||||||
|
WindowMouseDownEvent(button, layer_mouse_point) => {
|
||||||
|
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
|
||||||
|
}
|
||||||
|
WindowMouseUpEvent(button, layer_mouse_point) => {
|
||||||
|
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
script_chan_clone.send(SendEventMsg(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the user scrolls, move the layer around.
|
// When the user scrolls, move the layer around.
|
||||||
|
|
|
@ -24,6 +24,16 @@ fn with_node_name<R>(node: AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectHandler<AbstractNode<LayoutView>> for NodeSelectHandler {
|
impl SelectHandler<AbstractNode<LayoutView>> for NodeSelectHandler {
|
||||||
|
// FIXME(tkuehn): placeholder to get servo to compile
|
||||||
|
fn node_has_class(&self, node: &AbstractNode<LayoutView>, s: &str) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(tkuehn): placeholder to get servo to compile
|
||||||
|
fn with_node_classes<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(Option<&str>) -> R) -> R {
|
||||||
|
f(None)
|
||||||
|
}
|
||||||
|
|
||||||
fn with_node_name<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
|
fn with_node_name<R>(&self, node: &AbstractNode<LayoutView>, f: &fn(&str) -> R) -> R {
|
||||||
with_node_name(*node, f)
|
with_node_name(*node, f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use script::script_task;
|
||||||
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;
|
||||||
use servo_net::resource_task;
|
use servo_net::resource_task;
|
||||||
use servo_util::time::{ProfilerChan, ProfilerPort, ProfilerTask};
|
use servo_util::time::{profiler_force_print, ProfilerChan, ProfilerPort, ProfilerTask};
|
||||||
use std::net::url::Url;
|
use std::net::url::Url;
|
||||||
|
|
||||||
pub type EngineTask = Chan<Msg>;
|
pub type EngineTask = Chan<Msg>;
|
||||||
|
@ -39,6 +39,12 @@ pub struct Engine {
|
||||||
profiler_task: ProfilerTask,
|
profiler_task: ProfilerTask,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Engine {
|
||||||
|
fn finalize(&self) {
|
||||||
|
profiler_force_print(self.profiler_task.chan.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
pub fn start(compositor: CompositorTask,
|
pub fn start(compositor: CompositorTask,
|
||||||
opts: &Opts,
|
opts: &Opts,
|
||||||
|
@ -58,9 +64,12 @@ impl Engine {
|
||||||
opts.with_ref(|o| copy *o),
|
opts.with_ref(|o| copy *o),
|
||||||
profiler_chan.clone());
|
profiler_chan.clone());
|
||||||
|
|
||||||
let profiler_task = ProfilerTask::new(profiler_port.take(), profiler_chan.clone());
|
|
||||||
|
|
||||||
let opts = opts.take();
|
let opts = opts.take();
|
||||||
|
|
||||||
|
let profiler_task = ProfilerTask::new(profiler_port.take(),
|
||||||
|
profiler_chan.clone(),
|
||||||
|
opts.profiler_period);
|
||||||
|
|
||||||
let layout_task = layout_task::create_layout_task(render_task.clone(),
|
let layout_task = layout_task::create_layout_task(render_task.clone(),
|
||||||
image_cache_task.clone(),
|
image_cache_task.clone(),
|
||||||
opts,
|
opts,
|
||||||
|
|
|
@ -342,13 +342,14 @@ impl Layout {
|
||||||
flow.build_display_list(&builder,
|
flow.build_display_list(&builder,
|
||||||
&flow.position(),
|
&flow.position(),
|
||||||
display_list);
|
display_list);
|
||||||
// iterate in reverse to ensure we have the most recently painted render box
|
|
||||||
let (x, y) = (Au::from_frac_px(point.x as float),
|
let (x, y) = (Au::from_frac_px(point.x as float),
|
||||||
Au::from_frac_px(point.y as float));
|
Au::from_frac_px(point.y as float));
|
||||||
let mut resp = Err(());
|
let mut resp = Err(());
|
||||||
let display_list = &display_list.take().list;
|
let display_list = &display_list.take().list;
|
||||||
|
// iterate in reverse to ensure we have the most recently painted render box
|
||||||
for display_list.each_reverse |display_item| {
|
for display_list.each_reverse |display_item| {
|
||||||
let bounds = display_item.bounds();
|
let bounds = display_item.bounds();
|
||||||
|
// TODO this check should really be performed by a method of DisplayItem
|
||||||
if x <= bounds.origin.x + bounds.size.width &&
|
if x <= bounds.origin.x + bounds.size.width &&
|
||||||
bounds.origin.x <= x &&
|
bounds.origin.x <= x &&
|
||||||
y < bounds.origin.y + bounds.size.height &&
|
y < bounds.origin.y + bounds.size.height &&
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
/// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at
|
/// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at
|
||||||
/// least on desktops. It is designed for testing Servo without the need of a UI.
|
/// least on desktops. It is designed for testing Servo without the need of a UI.
|
||||||
|
|
||||||
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, ClickCallback};
|
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, MouseCallback};
|
||||||
use windowing::{ResizeCallback, ScrollCallback, WindowMethods};
|
use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
||||||
|
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
|
||||||
|
|
||||||
use alert::{Alert, AlertMethods};
|
use alert::{Alert, AlertMethods};
|
||||||
use core::libc::c_int;
|
use core::libc::c_int;
|
||||||
|
@ -36,10 +37,12 @@ pub struct Window {
|
||||||
composite_callback: Option<CompositeCallback>,
|
composite_callback: Option<CompositeCallback>,
|
||||||
resize_callback: Option<ResizeCallback>,
|
resize_callback: Option<ResizeCallback>,
|
||||||
load_url_callback: Option<LoadUrlCallback>,
|
load_url_callback: Option<LoadUrlCallback>,
|
||||||
click_callback: Option<ClickCallback>,
|
mouse_callback: Option<MouseCallback>,
|
||||||
scroll_callback: Option<ScrollCallback>,
|
scroll_callback: Option<ScrollCallback>,
|
||||||
|
|
||||||
drag_origin: Point2D<c_int>,
|
drag_origin: Point2D<c_int>,
|
||||||
|
mouse_down_button: @mut c_int,
|
||||||
|
mouse_down_point: @mut Point2D<c_int>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowMethods<Application> for Window {
|
impl WindowMethods<Application> for Window {
|
||||||
|
@ -56,10 +59,12 @@ impl WindowMethods<Application> for Window {
|
||||||
composite_callback: None,
|
composite_callback: None,
|
||||||
resize_callback: None,
|
resize_callback: None,
|
||||||
load_url_callback: None,
|
load_url_callback: None,
|
||||||
click_callback: None,
|
mouse_callback: None,
|
||||||
scroll_callback: None,
|
scroll_callback: None,
|
||||||
|
|
||||||
drag_origin: Point2D(0, 0),
|
drag_origin: Point2D(0, 0),
|
||||||
|
mouse_down_button: @mut 0,
|
||||||
|
mouse_down_point: @mut Point2D(0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register event handlers.
|
// Register event handlers.
|
||||||
|
@ -79,9 +84,9 @@ impl WindowMethods<Application> for Window {
|
||||||
do glut::keyboard_func |key, _, _| {
|
do glut::keyboard_func |key, _, _| {
|
||||||
window.handle_key(key)
|
window.handle_key(key)
|
||||||
}
|
}
|
||||||
do glut::mouse_func |button, _, x, y| {
|
do glut::mouse_func |button, state, x, y| {
|
||||||
if button < 3 {
|
if button < 3 {
|
||||||
window.handle_click(x, y);
|
window.handle_mouse(button, state, x, y);
|
||||||
} else {
|
} else {
|
||||||
window.handle_scroll(if button == 4 { -30.0 } else { 30.0 });
|
window.handle_scroll(if button == 4 { -30.0 } else { 30.0 });
|
||||||
}
|
}
|
||||||
|
@ -117,9 +122,9 @@ impl WindowMethods<Application> for Window {
|
||||||
self.load_url_callback = Some(new_load_url_callback)
|
self.load_url_callback = Some(new_load_url_callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback to be run when a click event occurs.
|
/// Registers a callback to be run when a mouse event occurs.
|
||||||
pub fn set_click_callback(&mut self, new_click_callback: ClickCallback) {
|
pub fn set_mouse_callback(&mut self, new_mouse_callback: MouseCallback) {
|
||||||
self.click_callback = Some(new_click_callback)
|
self.mouse_callback = Some(new_mouse_callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback to be run when the user scrolls.
|
/// Registers a callback to be run when the user scrolls.
|
||||||
|
@ -148,10 +153,36 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to handle a click
|
/// Helper function to handle a click
|
||||||
fn handle_click(&self, x: c_int, y: c_int) {
|
fn handle_mouse(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
|
||||||
match self.click_callback {
|
// FIXME(tkuehn): max pixel dist should be based on pixel density
|
||||||
|
let max_pixel_dist = 10f;
|
||||||
|
match self.mouse_callback {
|
||||||
None => {}
|
None => {}
|
||||||
Some(callback) => callback(Point2D(x as f32, y as f32)),
|
Some(callback) => {
|
||||||
|
let event: WindowMouseEvent;
|
||||||
|
match state {
|
||||||
|
glut::MOUSE_DOWN => {
|
||||||
|
event = WindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32));
|
||||||
|
*self.mouse_down_point = Point2D(x, y);
|
||||||
|
*self.mouse_down_button = button;
|
||||||
|
}
|
||||||
|
glut::MOUSE_UP => {
|
||||||
|
event = WindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32));
|
||||||
|
if *self.mouse_down_button == button {
|
||||||
|
let pixel_dist = *self.mouse_down_point - Point2D(x, y);
|
||||||
|
let pixel_dist = ((pixel_dist.x * pixel_dist.x +
|
||||||
|
pixel_dist.y * pixel_dist.y) as float).sqrt();
|
||||||
|
if pixel_dist < max_pixel_dist {
|
||||||
|
let click_event = WindowClickEvent(button as uint,
|
||||||
|
Point2D(x as f32, y as f32));
|
||||||
|
callback(click_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => fail!("I cannot recognize the type of mouse action that occured. :-(")
|
||||||
|
};
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,12 @@
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
|
||||||
|
pub enum WindowMouseEvent {
|
||||||
|
WindowClickEvent(uint, Point2D<f32>),
|
||||||
|
WindowMouseDownEvent(uint, Point2D<f32>),
|
||||||
|
WindowMouseUpEvent(uint, Point2D<f32>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Type of the function that is called when the screen is to be redisplayed.
|
/// Type of the function that is called when the screen is to be redisplayed.
|
||||||
pub type CompositeCallback = @fn();
|
pub type CompositeCallback = @fn();
|
||||||
|
|
||||||
|
@ -16,9 +22,8 @@ pub type ResizeCallback = @fn(uint, uint);
|
||||||
/// Type of the function that is called when a new URL is to be loaded.
|
/// Type of the function that is called when a new URL is to be loaded.
|
||||||
pub type LoadUrlCallback = @fn(&str);
|
pub type LoadUrlCallback = @fn(&str);
|
||||||
|
|
||||||
/// Type of the function that is called when hit testing is to be performed.
|
/// Type of the function that is called when a mouse hit test is to be performed.
|
||||||
/// FIXME this currently does not discriminate between left and right clicks or any modifiers
|
pub type MouseCallback = @fn(WindowMouseEvent);
|
||||||
pub type ClickCallback = @fn(Point2D<f32>);
|
|
||||||
|
|
||||||
/// Type of the function that is called when the user scrolls.
|
/// Type of the function that is called when the user scrolls.
|
||||||
pub type ScrollCallback = @fn(Point2D<f32>);
|
pub type ScrollCallback = @fn(Point2D<f32>);
|
||||||
|
@ -43,7 +48,7 @@ pub trait WindowMethods<A> {
|
||||||
/// Registers a callback to run when a new URL is to be loaded.
|
/// Registers a callback to run when a new URL is to be loaded.
|
||||||
pub fn set_load_url_callback(&mut self, new_load_url_callback: LoadUrlCallback);
|
pub fn set_load_url_callback(&mut self, new_load_url_callback: LoadUrlCallback);
|
||||||
/// Registers a callback to run when the user clicks.
|
/// Registers a callback to run when the user clicks.
|
||||||
pub fn set_click_callback(&mut self, new_click_callback: ClickCallback);
|
pub fn set_mouse_callback(&mut self, new_mouse_callback: MouseCallback);
|
||||||
/// Registers a callback to run when the user scrolls.
|
/// Registers a callback to run when the user scrolls.
|
||||||
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);
|
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ use geom::point::Point2D;
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
ResizeEvent(uint, uint, comm::Chan<()>),
|
ResizeEvent(uint, uint, comm::Chan<()>),
|
||||||
ReflowEvent,
|
ReflowEvent,
|
||||||
ClickEvent(Point2D<f32>),
|
ClickEvent(uint, Point2D<f32>),
|
||||||
|
MouseDownEvent(uint, Point2D<f32>),
|
||||||
|
MouseUpEvent(uint, Point2D<f32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Event_ {
|
pub struct Event_ {
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
use dom::bindings::utils::GlobalStaticData;
|
use dom::bindings::utils::GlobalStaticData;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent};
|
use dom::element::Element;
|
||||||
|
use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||||
use dom::node::{AbstractNode, ScriptView, define_bindings};
|
use dom::node::{AbstractNode, ScriptView, define_bindings};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery};
|
use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery};
|
||||||
|
@ -37,7 +38,7 @@ use js;
|
||||||
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;
|
||||||
use servo_util::tree::TreeNodeRef;
|
use servo_util::tree::TreeNodeRef;
|
||||||
use std::net::url::Url;
|
use std::net::url::{Url, from_str};
|
||||||
use std::net::url;
|
use std::net::url;
|
||||||
|
|
||||||
/// Messages used to control the script task.
|
/// Messages used to control the script task.
|
||||||
|
@ -503,7 +504,7 @@ impl ScriptContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClickEvent(point) => {
|
ClickEvent(button, point) => {
|
||||||
debug!("ClickEvent: clicked at %?", point);
|
debug!("ClickEvent: clicked at %?", point);
|
||||||
let root = match self.root_frame {
|
let root = match self.root_frame {
|
||||||
Some(ref frame) => frame.document.root,
|
Some(ref frame) => frame.document.root,
|
||||||
|
@ -511,14 +512,51 @@ impl ScriptContext {
|
||||||
};
|
};
|
||||||
match self.query_layout(HitTestQuery(root, point)) {
|
match self.query_layout(HitTestQuery(root, point)) {
|
||||||
Ok(node) => match node {
|
Ok(node) => match node {
|
||||||
HitTestResponse(node) => debug!("clicked on %?", node.debug_str()),
|
HitTestResponse(node) => {
|
||||||
|
debug!("clicked on %?", node.debug_str());
|
||||||
|
let mut node = node;
|
||||||
|
// traverse node generations until a node that is an element is found
|
||||||
|
while !node.is_element() {
|
||||||
|
match node.parent_node() {
|
||||||
|
Some(parent) => {
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
None => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if node.is_element() {
|
||||||
|
do node.with_imm_element |element| {
|
||||||
|
match element.tag_name {
|
||||||
|
~"a" => self.load_url_from_element(element),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => fail!(~"unexpected layout reply")
|
_ => fail!(~"unexpected layout reply")
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
println(fmt!("layout query error"));
|
debug!(fmt!("layout query error"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
MouseDownEvent(*) => {}
|
||||||
|
MouseUpEvent(*) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
priv fn load_url_from_element(&self, element: &Element) {
|
||||||
|
// if the node's element is "a," load url from href attr
|
||||||
|
for element.attrs.each |attr| {
|
||||||
|
if attr.name == ~"href" {
|
||||||
|
debug!("clicked on link to %?", attr.value);
|
||||||
|
let url = from_str(attr.value);
|
||||||
|
match url {
|
||||||
|
Ok(url) => self.script_chan.send(LoadMsg(url)),
|
||||||
|
Err(msg) => debug!(msg)
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,62 +6,129 @@
|
||||||
use std::time::precise_time_ns;
|
use std::time::precise_time_ns;
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::comm::{Port, SharedChan};
|
use core::comm::{Port, SharedChan};
|
||||||
use core::os::getenv;
|
use std::sort::tim_sort;
|
||||||
|
|
||||||
|
#[deriving(Eq)]
|
||||||
pub enum ProfilerCategory {
|
pub enum ProfilerCategory {
|
||||||
CompositingCategory,
|
CompositingCategory,
|
||||||
LayoutPerformCategory,
|
|
||||||
LayoutQueryCategory,
|
LayoutQueryCategory,
|
||||||
|
LayoutPerformCategory,
|
||||||
LayoutAuxInitCategory,
|
LayoutAuxInitCategory,
|
||||||
LayoutSelectorMatchCategory,
|
LayoutSelectorMatchCategory,
|
||||||
LayoutTreeBuilderCategory,
|
LayoutTreeBuilderCategory,
|
||||||
LayoutMainCategory,
|
LayoutMainCategory,
|
||||||
|
LayoutShapingCategory,
|
||||||
LayoutDispListBuildCategory,
|
LayoutDispListBuildCategory,
|
||||||
GfxRegenAvailableFontsCategory,
|
GfxRegenAvailableFontsCategory,
|
||||||
RenderingPrepBuffCategory,
|
RenderingPrepBuffCategory,
|
||||||
RenderingWaitSubtasksCategory,
|
RenderingWaitSubtasksCategory,
|
||||||
RenderingCategory,
|
RenderingCategory,
|
||||||
|
// hackish but helps prevent errors when adding new categories
|
||||||
|
NUM_BUCKETS,
|
||||||
}
|
}
|
||||||
// change this whenever buckets are added/rm'd
|
|
||||||
static NUM_BUCKETS: uint = 12;
|
|
||||||
|
|
||||||
pub type ProfilerChan = SharedChan<(ProfilerCategory, uint)>;
|
impl ProfilerCategory {
|
||||||
pub type ProfilerPort = Port<(ProfilerCategory, uint)>;
|
|
||||||
|
// convenience function to not have to cast every time
|
||||||
|
pub fn num_buckets() -> uint {
|
||||||
|
NUM_BUCKETS as uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// enumeration of all ProfilerCategory types
|
||||||
|
// FIXME(tkuehn): this is ugly and error-prone,
|
||||||
|
// but currently we lack better alternatives without an enum enumeration
|
||||||
|
priv fn empty_buckets() -> ~[(ProfilerCategory, ~[f64])] {
|
||||||
|
let mut vec = ~[];
|
||||||
|
vec.push((CompositingCategory, ~[]));
|
||||||
|
vec.push((LayoutQueryCategory, ~[]));
|
||||||
|
vec.push((LayoutPerformCategory, ~[]));
|
||||||
|
vec.push((LayoutAuxInitCategory, ~[]));
|
||||||
|
vec.push((LayoutSelectorMatchCategory, ~[]));
|
||||||
|
vec.push((LayoutTreeBuilderCategory, ~[]));
|
||||||
|
vec.push((LayoutMainCategory, ~[]));
|
||||||
|
vec.push((LayoutShapingCategory, ~[]));
|
||||||
|
vec.push((LayoutDispListBuildCategory, ~[]));
|
||||||
|
vec.push((GfxRegenAvailableFontsCategory, ~[]));
|
||||||
|
vec.push((RenderingPrepBuffCategory, ~[]));
|
||||||
|
vec.push((RenderingWaitSubtasksCategory, ~[]));
|
||||||
|
vec.push((RenderingCategory, ~[]));
|
||||||
|
|
||||||
|
ProfilerCategory::check_order(vec);
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
|
||||||
|
priv fn check_order(vec: &[(ProfilerCategory, ~[f64])]) {
|
||||||
|
for vec.each |&(category, _)| {
|
||||||
|
if category != vec[category as uint].first() {
|
||||||
|
fail!("Enum category does not match bucket index. This is a bug.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// some categories are subcategories of LayoutPerformCategory
|
||||||
|
// and should be printed to indicate this
|
||||||
|
pub fn format(self) -> ~str {
|
||||||
|
let padding = match self {
|
||||||
|
LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
|
||||||
|
LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
|
fmt!("%s%?", padding, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME(#5873) this should be initialized by a NUM_BUCKETS cast,
|
||||||
|
static BUCKETS: uint = 13;
|
||||||
|
|
||||||
|
pub enum ProfilerMsg {
|
||||||
|
// Normal message used for reporting time
|
||||||
|
TimeMsg(ProfilerCategory, f64),
|
||||||
|
// Message used to force print the profiling metrics
|
||||||
|
ForcePrintMsg,
|
||||||
|
}
|
||||||
|
pub type ProfilerChan = SharedChan<ProfilerMsg>;
|
||||||
|
pub type ProfilerPort = Port<ProfilerMsg>;
|
||||||
pub struct ProfilerTask {
|
pub struct ProfilerTask {
|
||||||
chan: ProfilerChan,
|
chan: ProfilerChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProfilerTask {
|
impl ProfilerTask {
|
||||||
pub fn new(prof_port: ProfilerPort,
|
pub fn new(profiler_port: ProfilerPort,
|
||||||
prof_chan: ProfilerChan)
|
profiler_chan: ProfilerChan,
|
||||||
|
period: Option<f64>)
|
||||||
-> ProfilerTask {
|
-> ProfilerTask {
|
||||||
let prof_port = Cell(prof_port);
|
let profiler_port = Cell(profiler_port);
|
||||||
|
|
||||||
do spawn {
|
do spawn {
|
||||||
let mut profiler_context = ProfilerContext::new(prof_port.take());
|
let mut profiler_context = ProfilerContext::new(profiler_port.take(), period);
|
||||||
profiler_context.start();
|
profiler_context.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilerTask {
|
ProfilerTask {
|
||||||
chan: prof_chan
|
chan: profiler_chan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProfilerContext {
|
pub struct ProfilerContext {
|
||||||
port: ProfilerPort,
|
port: ProfilerPort,
|
||||||
buckets: [~[uint], ..NUM_BUCKETS],
|
buckets: ~[(ProfilerCategory, ~[f64])],
|
||||||
verbose: Option<~str>,
|
verbose: bool,
|
||||||
mut last_print: u64,
|
period: f64,
|
||||||
|
mut last_print: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProfilerContext {
|
impl ProfilerContext {
|
||||||
pub fn new(port: ProfilerPort) -> ProfilerContext {
|
pub fn new(port: ProfilerPort, period: Option<f64>) -> ProfilerContext {
|
||||||
|
let (verbose, period) = match period {
|
||||||
|
Some(period) => (true, period),
|
||||||
|
None => (false, 0f64)
|
||||||
|
};
|
||||||
ProfilerContext {
|
ProfilerContext {
|
||||||
port: port,
|
port: port,
|
||||||
buckets: [~[], ..NUM_BUCKETS],
|
buckets: ProfilerCategory::empty_buckets(),
|
||||||
verbose: getenv("SERVO_PROFILER"),
|
verbose: verbose,
|
||||||
last_print: 0,
|
period: period,
|
||||||
|
last_print: 0f64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,62 +139,76 @@ impl ProfilerContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn handle_msg(&mut self, msg: (ProfilerCategory, uint)) {
|
priv fn handle_msg(&mut self, msg: ProfilerMsg) {
|
||||||
let (prof_msg, t) = msg;
|
match msg {
|
||||||
self.buckets[prof_msg as uint].push(t);
|
TimeMsg(category, t) => {
|
||||||
if self.verbose.is_some() {
|
// FIXME(#3874): this should be a let (cat, ref mut bucket) = ...,
|
||||||
let cur_time = precise_time_ns() / 1000000000u64;
|
// not a match
|
||||||
if cur_time - self.last_print > 5 {
|
match self.buckets[category as uint] {
|
||||||
self.last_print = cur_time;
|
(_, ref mut data) => {
|
||||||
let mut i = 0;
|
data.push(t);
|
||||||
for self.buckets.each |bucket| {
|
tim_sort(*data);
|
||||||
let prof_msg = match i {
|
}
|
||||||
// must be in same order as ProfilerCategory
|
|
||||||
0 => CompositingCategory,
|
|
||||||
1 => LayoutPerformCategory,
|
|
||||||
2 => LayoutQueryCategory,
|
|
||||||
3 => LayoutAuxInitCategory,
|
|
||||||
4 => LayoutSelectorMatchCategory,
|
|
||||||
5 => LayoutTreeBuilderCategory,
|
|
||||||
6 => LayoutMainCategory,
|
|
||||||
7 => LayoutDispListBuildCategory,
|
|
||||||
8 => GfxRegenAvailableFontsCategory,
|
|
||||||
9 => RenderingPrepBuffCategory,
|
|
||||||
10 => RenderingWaitSubtasksCategory,
|
|
||||||
11 => RenderingCategory,
|
|
||||||
_ => fail!()
|
|
||||||
};
|
|
||||||
io::println(fmt!("%?: %f", prof_msg,
|
|
||||||
(bucket.foldl(0 as uint, |a, b| a + *b) as float) /
|
|
||||||
(bucket.len() as float)));
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
io::println("");
|
|
||||||
|
if self.verbose {
|
||||||
|
let cur_time = precise_time_ns() as f64 / 1000000000f64;
|
||||||
|
if cur_time - self.last_print > self.period {
|
||||||
|
self.last_print = cur_time;
|
||||||
|
self.print_buckets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ForcePrintMsg => self.print_buckets(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
priv fn print_buckets(&mut self) {
|
||||||
|
println(fmt!("%31s %15s %15s %15s %15s %15s",
|
||||||
|
"_category (ms)_", "_mean (ms)_", "_median (ms)_",
|
||||||
|
"_min (ms)_", "_max (ms)_", "_bucket size_"));
|
||||||
|
for self.buckets.each |bucket| {
|
||||||
|
let &(category, data) = bucket;
|
||||||
|
let data_len = data.len();
|
||||||
|
if data_len > 0 {
|
||||||
|
let (mean, median, min, max) =
|
||||||
|
(data.foldl(0f64, |a, b| a + *b) / (data_len as f64),
|
||||||
|
data[data_len / 2],
|
||||||
|
data.min(),
|
||||||
|
data.max());
|
||||||
|
println(fmt!("%-30s: %15.4? %15.4? %15.4? %15.4? %15u",
|
||||||
|
category.format(), mean, median, min, max, data_len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn profile<T>(cat: ProfilerCategory,
|
|
||||||
prof_chan: ProfilerChan,
|
pub fn profile<T>(category: ProfilerCategory,
|
||||||
|
profiler_chan: ProfilerChan,
|
||||||
callback: &fn() -> T)
|
callback: &fn() -> T)
|
||||||
-> T {
|
-> T {
|
||||||
let start_time = precise_time_ns();
|
let start_time = precise_time_ns();
|
||||||
let val = callback();
|
let val = callback();
|
||||||
let end_time = precise_time_ns();
|
let end_time = precise_time_ns();
|
||||||
let ms = ((end_time - start_time) / 1000000u64) as uint;
|
let ms = ((end_time - start_time) as f64 / 1000000f64);
|
||||||
prof_chan.send((cat, ms));
|
profiler_chan.send(TimeMsg(category, ms));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn profiler_force_print(profiler_chan: ProfilerChan) {
|
||||||
|
profiler_chan.send(ForcePrintMsg);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
|
pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
|
||||||
let start_time = precise_time_ns();
|
let start_time = precise_time_ns();
|
||||||
let val = callback();
|
let val = callback();
|
||||||
let end_time = precise_time_ns();
|
let end_time = precise_time_ns();
|
||||||
let ms = ((end_time - start_time) / 1000000u64) as uint;
|
let ms = ((end_time - start_time) as f64 / 1000000f64);
|
||||||
if ms >= 5 {
|
if ms >= 5f64 {
|
||||||
debug!("%s took %u ms", msg, ms);
|
debug!("%s took %? ms", msg, ms);
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 865f539114383a021822583801e8362faf916699
|
Subproject commit 09d2db847c11bcab7f1832d5daf5947a7c1384ee
|
|
@ -1 +1 @@
|
||||||
Subproject commit 453bf81e021008f5eba29b135f07f4529e6c8b2e
|
Subproject commit 7db24a19d25fbedca2898381ae0b13b723c14135
|
|
@ -1 +1 @@
|
||||||
Subproject commit 325cd5197ed953f5c7c9317111b20ec1599eaffe
|
Subproject commit 8fc7400ed332c3d9edf358c2a18dd047ebde09a6
|
|
@ -12,3 +12,7 @@ for (var i = 0; i < count; i++) {
|
||||||
}
|
}
|
||||||
var stop = new Date();
|
var stop = new Date();
|
||||||
window.alert((stop - start) / count * 1e6 + " ns/layout");
|
window.alert((stop - start) / count * 1e6 + " ns/layout");
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
window.close();
|
||||||
|
>>>>>>> 0560988... Add link following and refactor the profiler.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue