aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r--components/script/script_task.rs380
1 files changed, 293 insertions, 87 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index 9a5f01084cf..832024a1c03 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -21,10 +21,12 @@
use document_loader::{LoadType, DocumentLoader, NotifierData};
use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
-use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLIFrameElementCast, NodeCast, EventCast};
+use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, NodeCast, EventCast};
use dom::bindings::conversions::FromJSValConvertible;
use dom::bindings::conversions::StringificationBehavior;
+use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, RootCollection, trace_roots};
use dom::bindings::js::{RootCollectionPtr, Root, RootedReference};
use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference, trace_refcounted_objects};
@@ -35,30 +37,31 @@ use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentProgressH
DocumentProgressTask, DocumentSource, MouseEventType};
use dom::element::{Element, AttributeHandlers};
use dom::event::{EventHelpers, EventBubbles, EventCancelable};
-use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementHelpers};
+use dom::htmliframeelement::HTMLIFrameElementHelpers;
use dom::uievent::UIEvent;
use dom::node::{Node, NodeHelpers, NodeDamage, window_from_node};
use dom::servohtmlparser::{ServoHTMLParser, ParserContext};
use dom::window::{Window, WindowHelpers, ScriptHelpers, ReflowReason};
use dom::worker::TrustedWorkerAddress;
use parse::html::{ParseContext, parse_html};
-use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowGoal, ReflowQueryType};
-use layout_interface;
+use layout_interface::{self, NewLayoutTaskInfo, ScriptLayoutChan, LayoutChan, ReflowGoal};
+use layout_interface::{ReflowQueryType};
+use mem::heap_size_of_eventtarget;
use network_listener::NetworkListener;
use page::{Page, IterablePage, Frame};
use timers::TimerId;
use devtools;
use webdriver_handlers;
-use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, DevtoolsPageInfo};
-use devtools_traits::{DevtoolsControlMsg, DevtoolScriptControlMsg};
-use devtools_traits::{TimelineMarker, TimelineMarkerType, TracingMetadata};
-use script_traits::{CompositorEvent, MouseButton};
-use script_traits::CompositorEvent::{ResizeEvent, ClickEvent};
+use devtools_traits::{DevtoolsControlPort, DevtoolsPageInfo, DevtoolScriptControlMsg};
+use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
+use devtools_traits::{TracingMetadata};
use script_traits::CompositorEvent::{MouseDownEvent, MouseUpEvent};
use script_traits::CompositorEvent::{MouseMoveEvent, KeyEvent};
-use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel};
+use script_traits::CompositorEvent::{ResizeEvent, ClickEvent};
+use script_traits::{CompositorEvent, MouseButton};
use script_traits::{ConstellationControlMsg, ScriptControlChan};
+use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel};
use script_traits::{ScriptState, ScriptTaskFactory};
use msg::compositor_msg::{LayerId, ScriptListener};
use msg::constellation_msg::{ConstellationChan, FocusType};
@@ -66,10 +69,11 @@ use msg::constellation_msg::{LoadData, PipelineId, SubpageId, MozBrowserEvent, W
use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType};
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::webdriver_msg::WebDriverScriptCommand;
-use net_traits::{ResourceTask, LoadConsumer, ControlMsg, Metadata};
use net_traits::LoadData as NetLoadData;
+use net_traits::{AsyncResponseTarget, ResourceTask, LoadConsumer, ControlMsg, Metadata};
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult};
use net_traits::storage_task::StorageTask;
+use profile_traits::mem::{self, Report, Reporter, ReporterRequest, ReportKind, ReportsChan};
use string_cache::Atom;
use util::str::DOMString;
use util::task::spawn_named_with_send_on_failure;
@@ -78,20 +82,23 @@ use util::task_state;
use euclid::Rect;
use euclid::point::Point2D;
use hyper::header::{LastModified, Headers};
+use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::router::ROUTER;
+use js::glue::CollectServoSizes;
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_AddExtraGCRootsTracer, DisableIncrementalGC};
use js::jsapi::{JSContext, JSRuntime, JSTracer};
-use js::jsapi::{JS_SetGCCallback, JSGCStatus, JSAutoRequest, SetDOMCallbacks};
+use js::jsapi::{JS_GetRuntime, JS_SetGCCallback, JSGCStatus, JSAutoRequest, SetDOMCallbacks};
use js::jsapi::{SetDOMProxyInformation, DOMProxyShadowsResult, HandleObject, HandleId, RootedValue};
use js::jsval::UndefinedValue;
use js::rust::Runtime;
-use url::Url;
+use url::{Url, UrlParser};
use libc;
use std::any::Any;
use std::borrow::ToOwned;
use std::cell::{Cell, RefCell};
use std::collections::HashSet;
-use std::mem;
+use std::mem as std_mem;
use std::option::Option;
use std::ptr;
use std::rc::Rc;
@@ -121,7 +128,7 @@ unsafe extern fn trace_rust_roots(tr: *mut JSTracer, _data: *mut libc::c_void) {
/// data that will need to be present when the document and frame tree entry are created,
/// but is only easily available at initiation of the load and on a push basis (so some
/// data will be updated according to future resize events, viewport changes, etc.)
-#[jstraceable]
+#[derive(JSTraceable)]
struct InProgressLoad {
/// The pipeline which requested this load.
pipeline_id: PipelineId,
@@ -131,7 +138,7 @@ struct InProgressLoad {
window_size: Option<WindowSizeData>,
/// Channel to the layout task associated with this pipeline.
layout_chan: LayoutChan,
- /// The current viewport clipping rectangle applying to this pipelie, if any.
+ /// The current viewport clipping rectangle applying to this pipeline, if any.
clip_rect: Option<Rect<f32>>,
/// The requested URL of the load.
url: Url,
@@ -196,6 +203,9 @@ pub enum ScriptMsg {
RefcountCleanup(TrustedReference),
/// Notify a document that all pending loads are complete.
DocumentLoadsComplete(PipelineId),
+ /// Requests that the script task measure its memory usage. The results are sent back via the
+ /// supplied channel.
+ CollectReports(ReportsChan),
}
/// A cloneable interface for communicating with an event loop.
@@ -226,7 +236,7 @@ impl ScriptPort for Receiver<(TrustedWorkerAddress, ScriptMsg)> {
}
/// Encapsulates internal communication within the script task.
-#[jstraceable]
+#[derive(JSTraceable)]
pub struct NonWorkerScriptChan(pub Sender<ScriptMsg>);
impl ScriptChan for NonWorkerScriptChan {
@@ -269,7 +279,9 @@ impl Drop for StackRootTLS {
/// Information for an entire page. Pages are top-level browsing contexts and can contain multiple
/// frames.
-#[jstraceable]
+#[derive(JSTraceable)]
+// ScriptTask instances are rooted on creation, so this is okay
+#[allow(unrooted_must_root)]
pub struct ScriptTask {
/// A handle to the information pertaining to page layout
page: DOMRefCell<Option<Rc<Page>>>,
@@ -277,8 +289,9 @@ pub struct ScriptTask {
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
/// A handle to the image cache task.
image_cache_task: ImageCacheTask,
- /// A handle to the resource task.
- resource_task: ResourceTask,
+ /// A handle to the resource task. This is an `Arc` to avoid running out of file descriptors if
+ /// there are many iframes.
+ resource_task: Arc<ResourceTask>,
/// A handle to the storage task.
storage_task: StorageTask,
@@ -297,8 +310,9 @@ pub struct ScriptTask {
/// For communicating load url messages to the constellation
constellation_chan: ConstellationChan,
+
/// A handle to the compositor for communicating ready state messages.
- compositor: DOMRefCell<Box<ScriptListener+'static>>,
+ compositor: DOMRefCell<ScriptListener>,
/// The port on which we receive messages from the image cache
image_cache_port: Receiver<ImageCacheResult>,
@@ -306,16 +320,19 @@ pub struct ScriptTask {
/// The channel on which the image cache can send messages to ourself.
image_cache_channel: ImageCacheChan,
+ /// For providing contact with the memory profiler.
+ mem_profiler_chan: mem::ProfilerChan,
+
/// For providing instructions to an optional devtools server.
- devtools_chan: Option<DevtoolsControlChan>,
+ devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// For receiving commands from an optional devtools server. Will be ignored if
/// no such server exists.
devtools_port: DevtoolsControlPort,
- devtools_sender: Sender<DevtoolScriptControlMsg>,
+ devtools_sender: IpcSender<DevtoolScriptControlMsg>,
/// For sending timeline markers. Will be ignored if
/// no devtools server
devtools_markers: RefCell<HashSet<TimelineMarkerType>>,
- devtools_marker_sender: RefCell<Option<Sender<TimelineMarker>>>,
+ devtools_marker_sender: RefCell<Option<IpcSender<TimelineMarker>>>,
/// The JavaScript runtime.
js_runtime: Rc<Runtime>,
@@ -374,37 +391,40 @@ impl ScriptTaskFactory for ScriptTask {
box pair.sender() as Box<Any+Send>
}
- fn create<C>(_phantom: Option<&mut ScriptTask>,
- id: PipelineId,
- parent_info: Option<(PipelineId, SubpageId)>,
- compositor: C,
- layout_chan: &OpaqueScriptLayoutChannel,
- control_chan: ScriptControlChan,
- control_port: Receiver<ConstellationControlMsg>,
- constellation_chan: ConstellationChan,
- failure_msg: Failure,
- resource_task: ResourceTask,
- storage_task: StorageTask,
- image_cache_task: ImageCacheTask,
- devtools_chan: Option<DevtoolsControlChan>,
- window_size: Option<WindowSizeData>,
- load_data: LoadData)
- where C: ScriptListener + Send + 'static {
+ fn create(_phantom: Option<&mut ScriptTask>,
+ id: PipelineId,
+ parent_info: Option<(PipelineId, SubpageId)>,
+ compositor: ScriptListener,
+ layout_chan: &OpaqueScriptLayoutChannel,
+ control_chan: ScriptControlChan,
+ control_port: Receiver<ConstellationControlMsg>,
+ constellation_chan: ConstellationChan,
+ failure_msg: Failure,
+ resource_task: ResourceTask,
+ storage_task: StorageTask,
+ image_cache_task: ImageCacheTask,
+ mem_profiler_chan: mem::ProfilerChan,
+ devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
+ window_size: Option<WindowSizeData>,
+ load_data: LoadData) {
let ConstellationChan(const_chan) = constellation_chan.clone();
let (script_chan, script_port) = channel();
let layout_chan = LayoutChan(layout_chan.sender());
spawn_named_with_send_on_failure(format!("ScriptTask {:?}", id), task_state::SCRIPT, move || {
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
- let script_task = ScriptTask::new(box compositor as Box<ScriptListener>,
+ let chan = NonWorkerScriptChan(script_chan);
+ let channel_for_reporter = chan.clone();
+ let script_task = ScriptTask::new(compositor,
script_port,
- NonWorkerScriptChan(script_chan),
+ chan,
control_chan,
control_port,
constellation_chan,
- resource_task,
+ Arc::new(resource_task),
storage_task,
image_cache_task,
+ mem_profiler_chan.clone(),
devtools_chan);
SCRIPT_TASK_ROOT.with(|root| {
@@ -417,8 +437,25 @@ impl ScriptTaskFactory for ScriptTask {
load_data.url.clone());
script_task.start_page_load(new_load, load_data);
+ // Register this task as a memory reporter.
+ let reporter_name = format!("script-reporter-{}", id.0);
+ let (reporter_sender, reporter_receiver) = ipc::channel().unwrap();
+ ROUTER.add_route(reporter_receiver.to_opaque(), box move |reporter_request| {
+ // Just injects an appropriate event into the worker task's queue.
+ let reporter_request: ReporterRequest = reporter_request.to().unwrap();
+ channel_for_reporter.send(ScriptMsg::CollectReports(
+ reporter_request.reports_channel)).unwrap()
+ });
+ let reporter = Reporter(reporter_sender);
+ let msg = mem::ProfilerMsg::RegisterReporter(reporter_name.clone(), reporter);
+ mem_profiler_chan.send(msg);
+
script_task.start();
+ // Unregister this task as a memory reporter.
+ let msg = mem::ProfilerMsg::UnregisterReporter(reporter_name);
+ mem_profiler_chan.send(msg);
+
// This must always be the very last operation performed before the task completes
failsafe.neuter();
}, ConstellationMsg::Failure(failure_msg), const_chan);
@@ -464,16 +501,17 @@ impl ScriptTask {
}
/// Creates a new script task.
- pub fn new(compositor: Box<ScriptListener+'static>,
+ pub fn new(compositor: ScriptListener,
port: Receiver<ScriptMsg>,
chan: NonWorkerScriptChan,
control_chan: ScriptControlChan,
control_port: Receiver<ConstellationControlMsg>,
constellation_chan: ConstellationChan,
- resource_task: ResourceTask,
+ resource_task: Arc<ResourceTask>,
storage_task: StorageTask,
image_cache_task: ImageCacheTask,
- devtools_chan: Option<DevtoolsControlChan>)
+ mem_profiler_chan: mem::ProfilerChan,
+ devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>)
-> ScriptTask {
let runtime = ScriptTask::new_rt_and_cx();
@@ -482,15 +520,21 @@ impl ScriptTask {
&WRAP_CALLBACKS);
}
- let (devtools_sender, devtools_receiver) = channel();
- let (image_cache_channel, image_cache_port) = channel();
+ // Ask the router to proxy IPC messages from the devtools to us.
+ let (ipc_devtools_sender, ipc_devtools_receiver) = ipc::channel().unwrap();
+ let devtools_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_devtools_receiver);
+
+ // Ask the router to proxy IPC messages from the image cache task to us.
+ let (ipc_image_cache_channel, ipc_image_cache_port) = ipc::channel().unwrap();
+ let image_cache_port =
+ ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_image_cache_port);
ScriptTask {
page: DOMRefCell::new(None),
incomplete_loads: DOMRefCell::new(vec!()),
image_cache_task: image_cache_task,
- image_cache_channel: ImageCacheChan(image_cache_channel),
+ image_cache_channel: ImageCacheChan(ipc_image_cache_channel),
image_cache_port: image_cache_port,
resource_task: resource_task,
@@ -502,9 +546,11 @@ impl ScriptTask {
control_port: control_port,
constellation_chan: constellation_chan,
compositor: DOMRefCell::new(compositor),
+ mem_profiler_chan: mem_profiler_chan,
+
devtools_chan: devtools_chan,
- devtools_port: devtools_receiver,
- devtools_sender: devtools_sender,
+ devtools_port: devtools_port,
+ devtools_sender: ipc_devtools_sender,
devtools_markers: RefCell::new(HashSet::new()),
devtools_marker_sender: RefCell::new(None),
@@ -623,8 +669,9 @@ impl ScriptTask {
}
};
- // Squash any pending resize, reflow, and mouse-move events in the queue.
+ // Squash any pending resize, reflow, animation tick, and mouse-move events in the queue.
let mut mouse_move_event_index = None;
+ let mut animation_ticks = HashSet::new();
loop {
match event {
// This has to be handled before the ResizeMsg below,
@@ -640,6 +687,13 @@ impl ScriptTask {
MixedMessage::FromConstellation(ConstellationControlMsg::Viewport(id, rect)) => {
self.handle_viewport(id, rect);
}
+ MixedMessage::FromConstellation(ConstellationControlMsg::TickAllAnimations(
+ pipeline_id)) => {
+ if !animation_ticks.contains(&pipeline_id) {
+ animation_ticks.insert(pipeline_id);
+ sequential.push(event);
+ }
+ }
MixedMessage::FromConstellation(ConstellationControlMsg::SendEvent(
_,
MouseMoveEvent(_))) => {
@@ -783,14 +837,19 @@ impl ScriptTask {
LiveDOMReferences::cleanup(addr),
ScriptMsg::DocumentLoadsComplete(id) =>
self.handle_loads_complete(id),
+ ScriptMsg::CollectReports(reports_chan) =>
+ self.collect_reports(reports_chan),
}
}
fn handle_msg_from_devtools(&self, msg: DevtoolScriptControlMsg) {
let page = self.root_page();
match msg {
- DevtoolScriptControlMsg::EvaluateJS(id, s, reply) =>
- devtools::handle_evaluate_js(&page, id, s, reply),
+ DevtoolScriptControlMsg::EvaluateJS(id, s, reply) => {
+ let window = get_page(&page, id).window();
+ let global_ref = GlobalRef::Window(window.r());
+ devtools::handle_evaluate_js(&global_ref, s, reply)
+ },
DevtoolScriptControlMsg::GetRootNode(id, reply) =>
devtools::handle_get_root_node(&page, id, reply),
DevtoolScriptControlMsg::GetDocumentElement(id, reply) =>
@@ -803,8 +862,11 @@ impl ScriptTask {
devtools::handle_get_cached_messages(pipeline_id, message_types, reply),
DevtoolScriptControlMsg::ModifyAttribute(id, node_id, modifications) =>
devtools::handle_modify_attribute(&page, id, node_id, modifications),
- DevtoolScriptControlMsg::WantsLiveNotifications(pipeline_id, to_send) =>
- devtools::handle_wants_live_notifications(&page, pipeline_id, to_send),
+ DevtoolScriptControlMsg::WantsLiveNotifications(id, to_send) => {
+ let window = get_page(&page, id).window();
+ let global_ref = GlobalRef::Window(window.r());
+ devtools::handle_wants_live_notifications(&global_ref, to_send)
+ },
DevtoolScriptControlMsg::SetTimelineMarkers(_pipeline_id, marker_types, reply) =>
devtools::handle_set_timeline_markers(&page, self, marker_types, reply),
DevtoolScriptControlMsg::DropTimelineMarkers(_pipeline_id, marker_types) =>
@@ -835,6 +897,8 @@ impl ScriptTask {
webdriver_handlers::handle_get_text(&page, pipeline_id, node_id, reply),
WebDriverScriptCommand::GetFrameId(frame_id, reply) =>
webdriver_handlers::handle_get_frame_id(&page, pipeline_id, frame_id, reply),
+ WebDriverScriptCommand::GetUrl(reply) =>
+ webdriver_handlers::handle_get_url(&page, pipeline_id, reply),
WebDriverScriptCommand::GetTitle(reply) =>
webdriver_handlers::handle_get_title(&page, pipeline_id, reply),
WebDriverScriptCommand::ExecuteAsyncScript(script, reply) =>
@@ -925,18 +989,44 @@ impl ScriptTask {
containing_pipeline_id,
new_pipeline_id,
subpage_id,
- layout_chan,
load_data,
+ paint_chan,
+ failure,
+ pipeline_port,
+ layout_shutdown_chan,
} = new_layout_info;
+ let layout_pair = ScriptTask::create_layout_channel(None::<&mut ScriptTask>);
+ let layout_chan = LayoutChan(*ScriptTask::clone_layout_channel(
+ None::<&mut ScriptTask>,
+ &layout_pair).downcast::<Sender<layout_interface::Msg>>().unwrap());
+
+ let layout_creation_info = NewLayoutTaskInfo {
+ id: new_pipeline_id,
+ url: load_data.url.clone(),
+ is_parent: false,
+ layout_pair: layout_pair,
+ pipeline_port: pipeline_port,
+ constellation_chan: self.constellation_chan.clone(),
+ failure: failure,
+ paint_chan: paint_chan,
+ script_chan: self.control_chan.0.clone(),
+ image_cache_task: self.image_cache_task.clone(),
+ layout_shutdown_chan: layout_shutdown_chan,
+ };
+
let page = self.root_page();
let parent_page = page.find(containing_pipeline_id).expect("ScriptTask: received a layout
whose parent has a PipelineId which does not correspond to a pipeline in the script
task's page tree. This is a bug.");
-
let parent_window = parent_page.window();
- let chan = layout_chan.downcast_ref::<Sender<layout_interface::Msg>>().unwrap();
- let layout_chan = LayoutChan(chan.clone());
+
+ // Tell layout to actually spawn the task.
+ parent_window.layout_chan()
+ .0
+ .send(layout_interface::Msg::CreateLayoutTask(layout_creation_info))
+ .unwrap();
+
// Kick off the fetch for the new resource.
let new_load = InProgressLoad::new(new_pipeline_id, Some((containing_pipeline_id, subpage_id)),
layout_chan, parent_window.r().window_size(),
@@ -963,6 +1053,83 @@ impl ScriptTask {
chan.send(ConstellationMsg::LoadComplete(pipeline)).unwrap();
}
+ pub fn get_reports(cx: *mut JSContext, path_seg: String) -> Vec<Report> {
+ let mut reports = vec![];
+
+ unsafe {
+ let rt = JS_GetRuntime(cx);
+ let mut stats = ::std::mem::zeroed();
+ if CollectServoSizes(rt, &mut stats) {
+ let mut report = |mut path_suffix, kind, size| {
+ let mut path = path![path_seg, "js"];
+ path.append(&mut path_suffix);
+ reports.push(Report {
+ path: path,
+ kind: kind,
+ size: size as usize,
+ })
+ };
+
+ // A note about possibly confusing terminology: the JS GC "heap" is allocated via
+ // mmap/VirtualAlloc, which means it's not on the malloc "heap", so we use
+ // `ExplicitNonHeapSize` as its kind.
+
+ report(path!["gc-heap", "used"],
+ ReportKind::ExplicitNonHeapSize,
+ stats.gcHeapUsed);
+
+ report(path!["gc-heap", "unused"],
+ ReportKind::ExplicitNonHeapSize,
+ stats.gcHeapUnused);
+
+ report(path!["gc-heap", "admin"],
+ ReportKind::ExplicitNonHeapSize,
+ stats.gcHeapAdmin);
+
+ report(path!["gc-heap", "decommitted"],
+ ReportKind::ExplicitNonHeapSize,
+ stats.gcHeapDecommitted);
+
+ // SpiderMonkey uses the system heap, not jemalloc.
+ report(path!["malloc-heap"],
+ ReportKind::ExplicitSystemHeapSize,
+ stats.mallocHeap);
+
+ report(path!["non-heap"],
+ ReportKind::ExplicitNonHeapSize,
+ stats.nonHeap);
+ }
+ }
+ reports
+ }
+
+ fn collect_reports(&self, reports_chan: ReportsChan) {
+ let mut urls = vec![];
+ let mut dom_tree_size = 0;
+ let mut reports = vec![];
+ for it_page in self.root_page().iter() {
+ let current_url = it_page.document().url().serialize();
+ urls.push(current_url.clone());
+
+ for child in NodeCast::from_ref(&*it_page.document()).traverse_preorder() {
+ let target = EventTargetCast::from_ref(&*child);
+ dom_tree_size += heap_size_of_eventtarget(target);
+ }
+ let window = it_page.window();
+ let target = EventTargetCast::from_ref(&*window);
+ dom_tree_size += heap_size_of_eventtarget(target);
+
+ reports.push(Report {
+ path: path![format!("url({})", current_url), "dom-tree"],
+ kind: ReportKind::ExplicitJemallocHeapSize,
+ size: dom_tree_size,
+ })
+ }
+ let path_seg = format!("url({})", urls.join(", "));
+ reports.extend(ScriptTask::get_reports(self.get_cx(), path_seg));
+ reports_chan.send(reports);
+ }
+
/// Handles a timer that fired.
fn handle_fire_timer_msg(&self, id: PipelineId, timer_id: TimerId) {
let page = self.root_page();
@@ -1003,7 +1170,7 @@ impl ScriptTask {
let page = borrowed_page.find(parent_pipeline_id).unwrap();
let doc = page.document();
- let frame_element = self.find_iframe(doc.r(), subpage_id);
+ let frame_element = doc.find_iframe(subpage_id);
if let Some(ref frame_element) = frame_element {
let element = ElementCast::from_ref(frame_element.r());
@@ -1023,7 +1190,7 @@ impl ScriptTask {
let frame_element = borrowed_page.find(parent_pipeline_id).and_then(|page| {
let doc = page.document();
- self.find_iframe(doc.r(), subpage_id)
+ doc.find_iframe(subpage_id)
});
if let Some(ref frame_element) = frame_element {
@@ -1039,7 +1206,7 @@ impl ScriptTask {
let frame_element = borrowed_page.find(containing_pipeline_id).and_then(|page| {
let doc = page.document();
- self.find_iframe(doc.r(), old_subpage_id)
+ doc.find_iframe(old_subpage_id)
});
frame_element.r().unwrap().update_subpage_id(new_subpage_id);
@@ -1162,7 +1329,7 @@ impl ScriptTask {
fn handle_tick_all_animations(&self, id: PipelineId) {
let page = get_page(&self.root_page(), id);
let document = page.document();
- document.r().invoke_animation_callbacks();
+ document.r().run_the_animation_frame_callbacks();
}
/// The entry point to document loading. Defines bindings, sets up the window and document
@@ -1190,13 +1357,13 @@ impl ScriptTask {
borrowed_page.as_ref().and_then(|borrowed_page| {
borrowed_page.find(parent_id).and_then(|page| {
let doc = page.document();
- self.find_iframe(doc.r(), subpage_id)
+ doc.find_iframe(subpage_id)
})
})
});
// Create a new frame tree entry.
- let page = Rc::new(Page::new(incomplete.pipeline_id, final_url.clone()));
+ let page = Rc::new(Page::new(incomplete.pipeline_id));
if !root_page_exists {
// We have a new root frame tree.
*self.page.borrow_mut() = Some(page.clone());
@@ -1261,6 +1428,7 @@ impl ScriptTask {
self.image_cache_task.clone(),
self.resource_task.clone(),
self.storage_task.clone(),
+ self.mem_profiler_chan.clone(),
self.devtools_chan.clone(),
self.constellation_chan.clone(),
incomplete.layout_chan,
@@ -1273,7 +1441,9 @@ impl ScriptTask {
});
let content_type = match metadata.content_type {
- Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => Some("text/plain".to_owned()),
+ Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => {
+ Some("text/plain".to_owned())
+ }
_ => None
};
@@ -1293,7 +1463,7 @@ impl ScriptTask {
loader);
let frame_element = frame_element.r().map(|elem| ElementCast::from_ref(elem));
- window.r().init_browser_context(document.r(), frame_element);
+ window.r().init_browsing_context(document.r(), frame_element);
// Create the root frame
page.set_frame(Some(Frame {
@@ -1330,9 +1500,10 @@ impl ScriptTask {
title: title,
url: url,
};
- chan.send(DevtoolsControlMsg::NewGlobal(ids,
- self.devtools_sender.clone(),
- page_info)).unwrap();
+ chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
+ ids,
+ self.devtools_sender.clone(),
+ page_info)).unwrap();
}
}
}
@@ -1356,16 +1527,6 @@ impl ScriptTask {
window.r().reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, reason);
}
- /// Find an iframe element in a provided document.
- fn find_iframe(&self, doc: &Document, subpage_id: SubpageId)
- -> Option<Root<HTMLIFrameElement>> {
- let doc = NodeCast::from_ref(doc);
-
- doc.traverse_preorder()
- .filter_map(HTMLIFrameElementCast::to_root)
- .find(|node| node.r().subpage_id() == Some(subpage_id))
- }
-
/// This is the main entry point for receiving and dispatching DOM events.
///
/// TODO: Actually perform DOM event dispatch.
@@ -1400,12 +1561,49 @@ impl ScriptTask {
}
let page = get_page(&self.root_page(), pipeline_id);
let document = page.document();
+
+ let mut prev_mouse_over_targets: RootedVec<JS<Node>> = RootedVec::new();
+ for target in self.mouse_over_targets.borrow_mut().iter() {
+ prev_mouse_over_targets.push(target.clone());
+ }
+
// We temporarily steal the list of targets over which the mouse is to pass it to
// handle_mouse_move_event() in a safe RootedVec container.
let mut mouse_over_targets = RootedVec::new();
- mem::swap(&mut *self.mouse_over_targets.borrow_mut(), &mut *mouse_over_targets);
+ std_mem::swap(&mut *self.mouse_over_targets.borrow_mut(), &mut *mouse_over_targets);
document.r().handle_mouse_move_event(self.js_runtime.rt(), point, &mut mouse_over_targets);
- mem::swap(&mut *self.mouse_over_targets.borrow_mut(), &mut *mouse_over_targets);
+
+ // Notify Constellation about anchors that are no longer mouse over targets.
+ for target in prev_mouse_over_targets.iter() {
+ if !mouse_over_targets.contains(target) {
+ if target.root().r().is_anchor_element() {
+ let event = ConstellationMsg::NodeStatus(None);
+ let ConstellationChan(ref chan) = self.constellation_chan;
+ chan.send(event).unwrap();
+ break;
+ }
+ }
+ }
+
+ // Notify Constellation about the topmost anchor mouse over target.
+ for target in mouse_over_targets.iter() {
+ let target = target.root();
+ if target.r().is_anchor_element() {
+ let element = ElementCast::to_ref(target.r()).unwrap();
+ let status = element.get_attribute(&ns!(""), &atom!("href"))
+ .and_then(|href| {
+ let value = href.r().Value();
+ let url = document.r().url();
+ UrlParser::new().base_url(&url).parse(&value).map(|url| url.serialize()).ok()
+ });
+ let event = ConstellationMsg::NodeStatus(status);
+ let ConstellationChan(ref chan) = self.constellation_chan;
+ chan.send(event).unwrap();
+ break;
+ }
+ }
+
+ std_mem::swap(&mut *self.mouse_over_targets.borrow_mut(), &mut *mouse_over_targets);
}
KeyEvent(key, state, modifiers) => {
@@ -1444,7 +1642,7 @@ impl ScriptTask {
let borrowed_page = self.root_page();
let iframe = borrowed_page.find(pipeline_id).and_then(|page| {
let doc = page.document();
- self.find_iframe(doc.r(), subpage_id)
+ doc.find_iframe(subpage_id)
});
if let Some(iframe) = iframe.r() {
iframe.navigate_child_browsing_context(load_data.url);
@@ -1510,10 +1708,17 @@ impl ScriptTask {
let context = Arc::new(Mutex::new(ParserContext::new(id, subpage, script_chan.clone(),
load_data.url.clone())));
+ let (action_sender, action_receiver) = ipc::channel().unwrap();
let listener = box NetworkListener {
context: context,
script_chan: script_chan.clone(),
};
+ ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
+ listener.notify(message.to().unwrap());
+ });
+ let response_target = AsyncResponseTarget {
+ sender: action_sender,
+ };
if load_data.url.scheme == "javascript" {
load_data.url = Url::parse("about:blank").unwrap();
@@ -1527,7 +1732,7 @@ impl ScriptTask {
data: load_data.data,
cors: None,
pipeline_id: Some(id),
- }, LoadConsumer::Listener(listener))).unwrap();
+ }, LoadConsumer::Listener(response_target))).unwrap();
self.incomplete_loads.borrow_mut().push(incomplete);
}
@@ -1542,7 +1747,9 @@ impl ScriptTask {
sender.send(marker).unwrap();
}
- pub fn set_devtools_timeline_marker(&self, marker: TimelineMarkerType, reply: Sender<TimelineMarker>) {
+ pub fn set_devtools_timeline_marker(&self,
+ marker: TimelineMarkerType,
+ reply: IpcSender<TimelineMarker>) {
*self.devtools_marker_sender.borrow_mut() = Some(reply);
self.devtools_markers.borrow_mut().insert(marker);
}
@@ -1646,7 +1853,6 @@ fn shut_down_layout(page_tree: &Rc<Page>, exit_type: PipelineExitType) {
}
}
-
pub fn get_page(page: &Rc<Page>, pipeline_id: PipelineId) -> Rc<Page> {
page.find(pipeline_id).expect("ScriptTask: received an event \
message for a layout channel that is not associated with this script task.\