aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/devtools.rs1
-rw-r--r--components/script/document_loader.rs8
-rw-r--r--components/script/dom/bindings/cell.rs2
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py2
-rw-r--r--components/script/dom/bindings/global.rs2
-rw-r--r--components/script/dom/bindings/js.rs11
-rw-r--r--components/script/dom/bindings/utils.rs13
-rw-r--r--components/script/dom/browsercontext.rs4
-rw-r--r--components/script/dom/characterdata.rs3
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs66
-rw-r--r--components/script/dom/document.rs2
-rw-r--r--components/script/dom/element.rs2
-rw-r--r--components/script/dom/eventtarget.rs14
-rw-r--r--components/script/dom/htmlelement.rs61
-rw-r--r--components/script/dom/htmlmediaelement.rs2
-rw-r--r--components/script/dom/htmltablecellelement.rs2
-rw-r--r--components/script/dom/node.rs9
-rw-r--r--components/script/dom/webidls/CSSStyleDeclaration.webidl1
-rw-r--r--components/script/dom/webidls/HTMLElement.webidl11
-rw-r--r--components/script/dom/window.rs59
-rw-r--r--components/script/dom/worker.rs14
-rw-r--r--components/script/dom/workerglobalscope.rs36
-rw-r--r--components/script/dom/xmlhttprequesteventtarget.rs2
-rw-r--r--components/script/layout_interface.rs17
-rw-r--r--components/script/lib.rs1
-rw-r--r--components/script/mem.rs36
-rw-r--r--components/script/page.rs4
-rw-r--r--components/script/script_task.rs22
-rw-r--r--components/script/timers.rs19
29 files changed, 330 insertions, 96 deletions
diff --git a/components/script/devtools.rs b/components/script/devtools.rs
index 60d410bbda8..8b4dfb12e6f 100644
--- a/components/script/devtools.rs
+++ b/components/script/devtools.rs
@@ -43,7 +43,6 @@ pub fn handle_evaluate_js(global: &GlobalRef, eval: String, reply: IpcSender<Eva
} else if rval.ptr.is_null() {
EvaluateJSReply::NullValue
} else {
- //FIXME: jsvals don't have an is_int32/is_number yet
assert!(rval.ptr.is_object());
panic!("object values unimplemented")
}).unwrap();
diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs
index 56ee98bdbbf..9046f5cbbcf 100644
--- a/components/script/document_loader.rs
+++ b/components/script/document_loader.rs
@@ -12,7 +12,7 @@ use net_traits::AsyncResponseTarget;
use std::sync::Arc;
use url::Url;
-#[derive(JSTraceable, PartialEq, Clone, Debug)]
+#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
pub enum LoadType {
Image(Url),
Script(Url),
@@ -33,17 +33,19 @@ impl LoadType {
}
}
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
pub struct DocumentLoader {
/// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
/// are lots of iframes.
+ #[ignore_heap_size_of = "channels are hard"]
pub resource_task: Arc<ResourceTask>,
notifier_data: Option<NotifierData>,
blocking_loads: Vec<LoadType>,
}
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
pub struct NotifierData {
+ #[ignore_heap_size_of = "trait objects are hard"]
pub script_chan: Box<ScriptChan + Send>,
pub pipeline: PipelineId,
}
diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs
index 35b20d0a417..80bab8839bc 100644
--- a/components/script/dom/bindings/cell.rs
+++ b/components/script/dom/bindings/cell.rs
@@ -16,7 +16,7 @@ use std::cell::{BorrowState, RefCell, Ref, RefMut};
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
-#[derive(Clone)]
+#[derive(Clone, HeapSizeOf)]
pub struct DOMRefCell<T> {
value: RefCell<T>,
}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index a46c58ff7c7..9bfaa0c9cfd 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -3314,7 +3314,7 @@ class CGEnum(CGThing):
decl = """\
#[repr(usize)]
-#[derive(JSTraceable, PartialEq, Copy, Clone)]
+#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum %s {
%s
}
diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs
index 4a2879e9f41..053059cec9f 100644
--- a/components/script/dom/bindings/global.rs
+++ b/components/script/dom/bindings/global.rs
@@ -125,7 +125,7 @@ impl<'a> GlobalRef<'a> {
pub fn get_worker_id(&self) -> Option<WorkerId> {
match *self {
GlobalRef::Window(_) => None,
- GlobalRef::Worker(ref worker) => worker.get_worker_id(),
+ GlobalRef::Worker(ref worker) => Some(worker.get_worker_id()),
}
}
diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs
index fc929db1cac..0fde5678ab2 100644
--- a/components/script/dom/bindings/js.rs
+++ b/components/script/dom/bindings/js.rs
@@ -31,6 +31,7 @@ use js::jsapi::{JSObject, Heap, JSTracer};
use js::jsval::JSVal;
use layout_interface::TrustedNodeAddress;
use script_task::STACK_ROOTS;
+use util::mem::HeapSizeOf;
use core::nonzero::NonZero;
use std::cell::{Cell, UnsafeCell};
@@ -44,6 +45,14 @@ pub struct JS<T> {
ptr: NonZero<*const T>
}
+// JS<T> is similar to Rc<T>, in that it's not always clear how to avoid double-counting.
+// For now, we choose not to follow any such pointers.
+impl<T> HeapSizeOf for JS<T> {
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
+
impl<T> JS<T> {
/// Returns `LayoutJS<T>` containing the same pointer.
pub unsafe fn to_layout(self) -> LayoutJS<T> {
@@ -226,7 +235,7 @@ impl<T: HeapGCValue+Copy> MutHeap<T> {
/// place of traditional internal mutability to ensure that the proper GC
/// barriers are enforced.
#[must_root]
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
pub struct MutNullableHeap<T: HeapGCValue+Copy> {
ptr: Cell<Option<T>>
}
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index bacb6bc05ae..80db27bd894 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -16,6 +16,7 @@ use dom::bindings::js::Root;
use dom::bindings::trace::trace_object;
use dom::browsercontext;
use dom::window;
+use util::mem::HeapSizeOf;
use util::str::DOMString;
use libc;
@@ -61,10 +62,18 @@ use js;
use string_cache::{Atom, Namespace};
/// Proxy handler for a WindowProxy.
+#[allow(raw_pointer_derive)]
pub struct WindowProxyHandler(pub *const libc::c_void);
+impl HeapSizeOf for WindowProxyHandler {
+ fn heap_size_of_children(&self) -> usize {
+ //FIXME(#6907) this is a pointer to memory allocated by `new` in NewProxyHandler in rust-mozjs.
+ 0
+ }
+}
+
#[allow(raw_pointer_derive)]
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
/// Static data associated with a global object.
pub struct GlobalStaticData {
/// The WindowProxy proxy handler for this global.
@@ -416,8 +425,10 @@ pub fn reflect_dom_object<T: Reflectable>
#[allow(raw_pointer_derive, unrooted_must_root)]
#[must_root]
#[servo_lang = "reflector"]
+#[derive(HeapSizeOf)]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
+ #[ignore_heap_size_of = "defined and measured in rust-mozjs"]
object: UnsafeCell<*mut JSObject>,
}
diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs
index cc4dc346c3f..8fe518844ba 100644
--- a/components/script/dom/browsercontext.rs
+++ b/components/script/dom/browsercontext.rs
@@ -27,7 +27,7 @@ use js::{JSTrue, JSFalse};
use std::ptr;
use std::default::Default;
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
#[allow(raw_pointer_derive)]
#[must_root]
@@ -88,7 +88,7 @@ impl BrowsingContext {
// without a reflector, so we don't mark this as #[dom_struct]
#[must_root]
#[privatize]
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
document: JS<Document>,
children: Vec<BrowsingContext>
diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs
index 377a69b3d2d..f15b66c68f8 100644
--- a/components/script/dom/characterdata.rs
+++ b/components/script/dom/characterdata.rs
@@ -24,6 +24,7 @@ use std::cell::Ref;
// https://dom.spec.whatwg.org/#characterdata
#[dom_struct]
+#[derive(HeapSizeOf)]
pub struct CharacterData {
node: Node,
data: DOMRefCell<DOMString>,
@@ -150,7 +151,7 @@ impl<'a> CharacterDataMethods for &'a CharacterData {
}
/// The different types of CharacterData.
-#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)]
+#[derive(JSTraceable, Copy, Clone, PartialEq, Debug, HeapSizeOf)]
pub enum CharacterDataTypeId {
Comment,
Text,
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 90fb0283507..cef9c5f9789 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -21,21 +21,19 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use dom::messageevent::MessageEvent;
use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler, WorkerEventHandler, WorkerErrorHandler};
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
-use dom::workerglobalscope::WorkerGlobalScopeTypeId;
+use dom::workerglobalscope::{WorkerGlobalScopeTypeId, WorkerGlobalScopeInit};
use script_task::{ScriptTask, ScriptChan, ScriptMsg, TimerSource, ScriptPort};
use script_task::StackRootTLS;
-use msg::constellation_msg::{ConstellationChan, PipelineId, WorkerId};
-
-use devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolScriptControlMsg};
-
-use net_traits::{load_whole_resource, ResourceTask};
+use devtools_traits::DevtoolScriptControlMsg;
+use msg::constellation_msg::PipelineId;
+use net_traits::load_whole_resource;
use profile_traits::mem::{self, Reporter, ReporterRequest};
use util::task::spawn_named;
use util::task_state;
use util::task_state::{SCRIPT, IN_WORKER};
-use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
+use ipc_channel::ipc::{self, IpcReceiver};
use ipc_channel::router::ROUTER;
use js::jsapi::{JSContext, RootedValue, HandleValue};
use js::jsapi::{JSAutoRequest, JSAutoCompartment};
@@ -107,25 +105,19 @@ pub struct DedicatedWorkerGlobalScope {
}
impl DedicatedWorkerGlobalScope {
- fn new_inherited(worker_url: Url,
+ fn new_inherited(init: WorkerGlobalScopeInit,
+ worker_url: Url,
id: PipelineId,
- mem_profiler_chan: mem::ProfilerChan,
- devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
- devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
devtools_port: Receiver<DevtoolScriptControlMsg>,
runtime: Rc<Runtime>,
- resource_task: ResourceTask,
- constellation_chan: ConstellationChan,
parent_sender: Box<ScriptChan+Send>,
own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>,
- worker_id: Option<WorkerId>)
+ receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>)
-> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope::new_inherited(
- WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, runtime, resource_task,
- mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, constellation_chan,
- worker_id),
+ WorkerGlobalScopeTypeId::DedicatedGlobalScope, init, worker_url,
+ runtime, devtools_port),
id: id,
receiver: receiver,
own_sender: own_sender,
@@ -134,43 +126,32 @@ impl DedicatedWorkerGlobalScope {
}
}
- pub fn new(worker_url: Url,
+ pub fn new(init: WorkerGlobalScopeInit,
+ worker_url: Url,
id: PipelineId,
- mem_profiler_chan: mem::ProfilerChan,
- devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
- devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
devtools_port: Receiver<DevtoolScriptControlMsg>,
runtime: Rc<Runtime>,
- resource_task: ResourceTask,
- constellation_chan: ConstellationChan,
parent_sender: Box<ScriptChan+Send>,
own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>,
- worker_id: Option<WorkerId>)
+ receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>)
-> Root<DedicatedWorkerGlobalScope> {
let scope = box DedicatedWorkerGlobalScope::new_inherited(
- worker_url, id, mem_profiler_chan, devtools_chan, devtools_sender, devtools_port,
- runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver,
- worker_id);
+ init, worker_url, id, devtools_port, runtime.clone(), parent_sender,
+ own_sender, receiver);
DedicatedWorkerGlobalScopeBinding::Wrap(runtime.cx(), scope)
}
}
impl DedicatedWorkerGlobalScope {
#[allow(unsafe_code)]
- pub fn run_worker_scope(worker_url: Url,
+ pub fn run_worker_scope(init: WorkerGlobalScopeInit,
+ worker_url: Url,
id: PipelineId,
- mem_profiler_chan: mem::ProfilerChan,
- devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
- devtools_ipc_chan: Option<IpcSender<DevtoolScriptControlMsg>>,
devtools_ipc_port: IpcReceiver<DevtoolScriptControlMsg>,
worker: TrustedWorkerAddress,
- resource_task: ResourceTask,
- constellation_chan: ConstellationChan,
parent_sender: Box<ScriptChan+Send>,
own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>,
- worker_id: Option<WorkerId>) {
+ receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) {
let serialized_worker_url = worker_url.serialize();
spawn_named(format!("WebWorker for {}", serialized_worker_url), move || {
task_state::initialize(SCRIPT | IN_WORKER);
@@ -178,7 +159,7 @@ impl DedicatedWorkerGlobalScope {
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
- let (url, source) = match load_whole_resource(&resource_task, worker_url) {
+ let (url, source) = match load_whole_resource(&init.resource_task, worker_url) {
Err(_) => {
println!("error loading script {}", serialized_worker_url);
parent_sender.send(ScriptMsg::RunnableMsg(
@@ -198,9 +179,8 @@ impl DedicatedWorkerGlobalScope {
ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_ipc_port, devtools_mpsc_chan);
let global = DedicatedWorkerGlobalScope::new(
- url, id, mem_profiler_chan.clone(), devtools_chan, devtools_ipc_chan, devtools_mpsc_port,
- runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver,
- worker_id);
+ init, url, id, devtools_mpsc_port, runtime.clone(),
+ parent_sender, own_sender, receiver);
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
// registration (#6631), so we instead use a random number and cross our fingers.
let scope = WorkerGlobalScopeCast::from_ref(global.r());
@@ -230,7 +210,7 @@ impl DedicatedWorkerGlobalScope {
parent_sender_for_reporter.send(ScriptMsg::CollectReports(
reporter_request.reports_channel)).unwrap()
});
- mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(
+ scope.mem_profiler_chan().send(mem::ProfilerMsg::RegisterReporter(
reporter_name.clone(),
Reporter(reporter_sender)));
}
@@ -292,7 +272,7 @@ impl DedicatedWorkerGlobalScope {
// Unregister this task as a memory reporter.
let msg = mem::ProfilerMsg::UnregisterReporter(reporter_name);
- mem_profiler_chan.send(msg);
+ scope.mem_profiler_chan().send(msg);
});
}
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index dd7dc90e0fe..5383ea6df33 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -110,6 +110,7 @@ pub enum IsHTMLDocument {
// https://dom.spec.whatwg.org/#document
#[dom_struct]
+#[derive(HeapSizeOf)]
pub struct Document {
node: Node,
window: JS<Window>,
@@ -144,6 +145,7 @@ pub struct Document {
animation_frame_ident: Cell<i32>,
/// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks
/// List of animation frame callbacks
+ #[ignore_heap_size_of = "closures are hard"]
animation_frame_list: RefCell<HashMap<i32, Box<Fn(f64)>>>,
/// Tracks all outstanding loads related to this document.
loader: DOMRefCell<DocumentLoader>,
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 046b9a57c5f..1b200ed4e61 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -120,7 +120,7 @@ impl PartialEq for Element {
}
}
-#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)]
+#[derive(JSTraceable, Copy, Clone, PartialEq, Debug, HeapSizeOf)]
pub enum ElementTypeId {
HTMLElement(HTMLElementTypeId),
Element,
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index dfeae4ff08f..79679ff14d2 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -20,6 +20,7 @@ use js::jsapi::{CompileFunction, JS_GetFunctionObject};
use js::jsapi::{JSContext, RootedFunction, HandleObject};
use js::jsapi::{JSAutoCompartment, JSAutoRequest};
use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper};
+use util::mem::HeapSizeOf;
use util::str::DOMString;
use fnv::FnvHasher;
@@ -36,13 +37,14 @@ use url::Url;
use std::collections::HashMap;
-#[derive(JSTraceable, Copy, Clone, PartialEq)]
+#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum ListenerPhase {
Capturing,
Bubbling,
}
#[derive(JSTraceable, Copy, Clone)]
+#[derive(HeapSizeOf)]
pub enum EventTargetTypeId {
Node(NodeTypeId),
WebSocket,
@@ -95,6 +97,13 @@ pub enum EventListenerType {
Inline(Rc<EventListener>),
}
+impl HeapSizeOf for EventListenerType {
+ fn heap_size_of_children(&self) -> usize {
+ // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
+ 0
+ }
+}
+
impl EventListenerType {
fn get_listener(&self) -> Rc<EventListener> {
match *self {
@@ -104,7 +113,7 @@ impl EventListenerType {
}
}
-#[derive(JSTraceable, Clone, PartialEq)]
+#[derive(JSTraceable, Clone, PartialEq, HeapSizeOf)]
#[privatize]
pub struct EventListenerEntry {
phase: ListenerPhase,
@@ -112,6 +121,7 @@ pub struct EventListenerEntry {
}
#[dom_struct]
+#[derive(HeapSizeOf)]
pub struct EventTarget {
reflector_: Reflector,
type_id: EventTargetTypeId,
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index 513a9d39775..2a196073513 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived};
use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast, NodeCast};
-use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
+use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived, HTMLHtmlElementDerived};
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::error::ErrorResult;
use dom::bindings::error::Error::Syntax;
@@ -216,6 +216,63 @@ impl<'a> HTMLElementMethods for &'a HTMLElement {
// If `request_focus` is not called, focus will be set to None.
document.r().commit_focus_transaction(FocusType::Element);
}
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn GetOffsetParent(self) -> Option<Root<Element>> {
+ if self.is_htmlbodyelement() || self.is_htmlhtmlelement() {
+ return None;
+ }
+
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (element, _) = window.offset_parent_query(node.to_trusted_node_address());
+
+ element
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetTop(self) -> i32 {
+ if self.is_htmlbodyelement() {
+ return 0;
+ }
+
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.origin.y.to_nearest_px()
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetLeft(self) -> i32 {
+ if self.is_htmlbodyelement() {
+ return 0;
+ }
+
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.origin.x.to_nearest_px()
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetWidth(self) -> i32 {
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.size.width.to_nearest_px()
+ }
+
+ // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
+ fn OffsetHeight(self) -> i32 {
+ let node = NodeCast::from_ref(self);
+ let window = window_from_node(self);
+ let (_, rect) = window.offset_parent_query(node.to_trusted_node_address());
+
+ rect.size.height.to_nearest_px()
+ }
}
// https://html.spec.whatwg.org/#attr-data-*
@@ -309,7 +366,7 @@ impl<'a> VirtualMethods for &'a HTMLElement {
}
}
-#[derive(JSTraceable, Copy, Clone, Debug)]
+#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)]
pub enum HTMLElementTypeId {
HTMLElement,
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index b0b3ae9c6e9..847132c6452 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -41,7 +41,7 @@ impl HTMLMediaElement {
}
}
-#[derive(JSTraceable, Copy, Clone, Debug)]
+#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)]
pub enum HTMLMediaElementTypeId {
HTMLAudioElement = 0,
HTMLVideoElement = 1,
diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs
index 66359deb22f..873cbb184e8 100644
--- a/components/script/dom/htmltablecellelement.rs
+++ b/components/script/dom/htmltablecellelement.rs
@@ -22,7 +22,7 @@ use std::cmp::max;
const DEFAULT_COLSPAN: u32 = 1;
-#[derive(JSTraceable, Copy, Clone, Debug)]
+#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)]
pub enum HTMLTableCellElementTypeId {
HTMLTableDataCellElement = 0,
HTMLTableHeaderCellElement = 1,
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 1f6a681e582..94a0a1e05c0 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -78,6 +78,7 @@ use string_cache::{Atom, Namespace, QualName};
/// An HTML node.
#[dom_struct]
+#[derive(HeapSizeOf)]
pub struct Node {
/// The JavaScript reflector for this node.
eventtarget: EventTarget,
@@ -135,7 +136,7 @@ impl NodeDerived for EventTarget {
bitflags! {
#[doc = "Flags for node items."]
- #[derive(JSTraceable)]
+ #[derive(JSTraceable, HeapSizeOf)]
flags NodeFlags: u16 {
#[doc = "Specifies whether this node is in a document."]
const IS_IN_DOC = 0x01,
@@ -206,20 +207,25 @@ enum SuppressObserver {
}
/// Layout data that is shared between the script and layout tasks.
+#[derive(HeapSizeOf)]
pub struct SharedLayoutData {
/// The results of CSS styling for this node.
pub style: Option<Arc<ComputedValues>>,
}
/// Encapsulates the abstract layout data.
+#[allow(raw_pointer_derive)]
+#[derive(HeapSizeOf)]
pub struct LayoutData {
_shared_data: SharedLayoutData,
+ #[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but the type lives in layout"]
_data: NonZero<*const ()>,
}
#[allow(unsafe_code)]
unsafe impl Send for LayoutData {}
+#[derive(HeapSizeOf)]
pub struct LayoutDataRef {
data_cell: RefCell<Option<LayoutData>>,
}
@@ -274,6 +280,7 @@ impl LayoutDataRef {
/// The different types of nodes.
#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)]
+#[derive(HeapSizeOf)]
pub enum NodeTypeId {
CharacterData(CharacterDataTypeId),
DocumentType,
diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl
index 16fc0c63a6a..85506b8173c 100644
--- a/components/script/dom/webidls/CSSStyleDeclaration.webidl
+++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl
@@ -99,6 +99,7 @@ partial interface CSSStyleDeclaration {
[TreatNullAs=EmptyString] attribute DOMString backfaceVisibility;
[TreatNullAs=EmptyString] attribute DOMString direction;
+ [TreatNullAs=EmptyString] attribute DOMString unicodeBidi;
[TreatNullAs=EmptyString] attribute DOMString filter;
diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl
index f4c0376b618..90b11d85bff 100644
--- a/components/script/dom/webidls/HTMLElement.webidl
+++ b/components/script/dom/webidls/HTMLElement.webidl
@@ -45,5 +45,16 @@ interface HTMLElement : Element {
//readonly attribute boolean? commandDisabled;
//readonly attribute boolean? commandChecked;
};
+
+// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface
+partial interface HTMLElement {
+ // CSSOM things are not [Pure] because they can flush
+ readonly attribute Element? offsetParent;
+ readonly attribute long offsetTop;
+ readonly attribute long offsetLeft;
+ readonly attribute long offsetWidth;
+ readonly attribute long offsetHeight;
+};
+
HTMLElement implements GlobalEventHandlers;
HTMLElement implements ElementCSSInlineStyle;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index d7a9e9f243a..ba86c85b3ac 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerN
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::WindowBinding::{self, WindowMethods, FrameRequestCallback};
-use dom::bindings::codegen::InheritTypes::{NodeCast, EventTargetCast};
+use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast, WindowDerived};
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::error::{report_pending_exception, Fallible};
use dom::bindings::error::Error::InvalidCharacter;
@@ -27,7 +27,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::location::Location;
use dom::navigator::Navigator;
-use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers};
+use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers, from_untrusted_node_address};
use dom::performance::Performance;
use dom::screen::Screen;
use dom::storage::Storage;
@@ -72,6 +72,7 @@ use std::cell::{Cell, Ref, RefMut, RefCell};
use std::collections::HashSet;
use std::default::Default;
use std::ffi::CString;
+use std::io::{stdout, Write};
use std::mem as std_mem;
use std::rc::Rc;
use std::sync::Arc;
@@ -80,7 +81,7 @@ use std::sync::mpsc::{channel, Receiver};
use time;
/// Current state of the window object
-#[derive(JSTraceable, Copy, Clone, Debug, PartialEq)]
+#[derive(JSTraceable, Copy, Clone, Debug, PartialEq, HeapSizeOf)]
enum WindowState {
Alive,
Zombie, // Pipeline is closed, but the window hasn't been GCed yet.
@@ -105,15 +106,21 @@ pub enum ReflowReason {
}
#[dom_struct]
+#[derive(HeapSizeOf)]
pub struct Window {
eventtarget: EventTarget,
+ #[ignore_heap_size_of = "trait objects are hard"]
script_chan: Box<ScriptChan+Send>,
+ #[ignore_heap_size_of = "channels are hard"]
control_chan: ScriptControlChan,
console: MutNullableHeap<JS<Console>>,
crypto: MutNullableHeap<JS<Crypto>>,
navigator: MutNullableHeap<JS<Navigator>>,
+ #[ignore_heap_size_of = "channels are hard"]
image_cache_task: ImageCacheTask,
+ #[ignore_heap_size_of = "channels are hard"]
image_cache_chan: ImageCacheChan,
+ #[ignore_heap_size_of = "TODO(#6911) newtypes containing unmeasurable types are hard"]
compositor: DOMRefCell<ScriptListener>,
browsing_context: DOMRefCell<Option<BrowsingContext>>,
page: Rc<Page>,
@@ -128,13 +135,17 @@ pub struct Window {
next_worker_id: Cell<WorkerId>,
/// For sending messages to the memory profiler.
+ #[ignore_heap_size_of = "channels are hard"]
mem_profiler_chan: mem::ProfilerChan,
/// For providing instructions to an optional devtools server.
+ #[ignore_heap_size_of = "channels are hard"]
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// For sending timeline markers. Will be ignored if
/// no devtools server
+ #[ignore_heap_size_of = "TODO(#6909) need to measure HashSet"]
devtools_markers: RefCell<HashSet<TimelineMarkerType>>,
+ #[ignore_heap_size_of = "channels are hard"]
devtools_marker_sender: RefCell<Option<IpcSender<TimelineMarker>>>,
/// A flag to indicate whether the developer tools have requested live updates of
@@ -159,27 +170,34 @@ pub struct Window {
dom_static: GlobalStaticData,
/// The JavaScript runtime.
+ #[ignore_heap_size_of = "Rc<T> is hard"]
js_runtime: DOMRefCell<Option<Rc<Runtime>>>,
/// A handle for communicating messages to the layout task.
+ #[ignore_heap_size_of = "channels are hard"]
layout_chan: LayoutChan,
/// A handle to perform RPC calls into the layout, quickly.
+ #[ignore_heap_size_of = "trait objects are hard"]
layout_rpc: Box<LayoutRPC+'static>,
/// The port that we will use to join layout. If this is `None`, then layout is not running.
+ #[ignore_heap_size_of = "channels are hard"]
layout_join_port: DOMRefCell<Option<Receiver<()>>>,
/// The current size of the window, in pixels.
window_size: Cell<Option<WindowSizeData>>,
/// Associated resource task for use by DOM objects like XMLHttpRequest
+ #[ignore_heap_size_of = "channels are hard"]
resource_task: Arc<ResourceTask>,
/// A handle for communicating messages to the storage task.
+ #[ignore_heap_size_of = "channels are hard"]
storage_task: StorageTask,
/// A handle for communicating messages to the constellation task.
+ #[ignore_heap_size_of = "channels are hard"]
constellation_chan: ConstellationChan,
/// Pending scroll to fragment event, if any
@@ -193,6 +211,7 @@ pub struct Window {
pending_reflow_count: Cell<u32>,
/// A channel for communicating results of async scripts back to the webdriver server
+ #[ignore_heap_size_of = "channels are hard"]
webdriver_script_chan: RefCell<Option<IpcSender<WebDriverJSResult>>>,
/// The current state of the window object
@@ -342,7 +361,10 @@ impl<'a> WindowMethods for &'a Window {
// https://html.spec.whatwg.org/#dom-alert
fn Alert(self, s: DOMString) {
// Right now, just print to the console
- println!("ALERT: {}", s);
+ let stdout = stdout();
+ let mut stdout = stdout.lock();
+ writeln!(&mut stdout, "ALERT: {}", s).unwrap();
+ stdout.flush().unwrap();
}
// https://html.spec.whatwg.org/multipage/#dom-window-close
@@ -578,6 +600,7 @@ pub trait WindowHelpers {
fn client_rect_query(self, node_geometry_request: TrustedNodeAddress) -> Rect<i32>;
fn resolved_style_query(self, element: TrustedNodeAddress,
pseudo: Option<PseudoElement>, property: &Atom) -> Option<String>;
+ fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>);
fn handle_reflow_complete_msg(self, reflow_id: u32);
fn set_fragment_name(self, fragment: Option<String>);
fn steal_fragment_name(self) -> Option<String>;
@@ -827,6 +850,27 @@ impl<'a> WindowHelpers for &'a Window {
resolved
}
+ fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) {
+ self.reflow(ReflowGoal::ForScriptQuery,
+ ReflowQueryType::OffsetParentQuery(node),
+ ReflowReason::Query);
+ let response = self.layout_rpc.offset_parent();
+ let js_runtime = self.js_runtime.borrow();
+ let js_runtime = js_runtime.as_ref().unwrap();
+ let element = match response.node_address {
+ Some(parent_node_address) => {
+ let node = from_untrusted_node_address(js_runtime.rt(),
+ parent_node_address);
+ let element = ElementCast::to_ref(node.r());
+ element.map(Root::from_ref)
+ }
+ None => {
+ None
+ }
+ };
+ (element, response.rect)
+ }
+
fn handle_reflow_complete_msg(self, reflow_id: u32) {
let last_reflow_id = self.last_reflow_id.get();
if last_reflow_id == reflow_id {
@@ -1135,6 +1179,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
+ ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery",
});
debug_msg.push_str(match *reason {
@@ -1155,3 +1200,9 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
println!("{}", debug_msg);
}
+
+impl WindowDerived for EventTarget {
+ fn is_window(&self) -> bool {
+ self.type_id() == &EventTargetTypeId::Window
+ }
+}
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index daa752052b7..628b1178c32 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -20,6 +20,7 @@ use dom::errorevent::ErrorEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use dom::messageevent::MessageEvent;
+use dom::workerglobalscope::WorkerGlobalScopeInit;
use script_task::{ScriptChan, ScriptMsg, Runnable};
use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
@@ -95,10 +96,17 @@ impl Worker {
None => None,
};
+ let init = WorkerGlobalScopeInit {
+ resource_task: resource_task,
+ mem_profiler_chan: global.mem_profiler_chan(),
+ devtools_chan: global.devtools_chan(),
+ devtools_sender: optional_sender,
+ constellation_chan: constellation_chan,
+ worker_id: worker_id,
+ };
DedicatedWorkerGlobalScope::run_worker_scope(
- worker_url, global.pipeline(), global.mem_profiler_chan(), global.devtools_chan(),
- optional_sender, devtools_receiver, worker_ref, resource_task,
- constellation_chan, global.script_chan(), sender, receiver, Some(worker_id));
+ init, worker_url, global.pipeline(), devtools_receiver, worker_ref,
+ global.script_chan(), sender, receiver);
Ok(worker)
}
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 0887b6addcf..550834f7d09 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -37,16 +37,25 @@ use std::cell::Cell;
use std::rc::Rc;
use std::sync::mpsc::Receiver;
-#[derive(JSTraceable, Copy, Clone, PartialEq)]
+#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum WorkerGlobalScopeTypeId {
DedicatedGlobalScope,
}
+pub struct WorkerGlobalScopeInit {
+ pub resource_task: ResourceTask,
+ pub mem_profiler_chan: mem::ProfilerChan,
+ pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
+ pub devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
+ pub constellation_chan: ConstellationChan,
+ pub worker_id: WorkerId,
+}
+
// https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface
#[dom_struct]
pub struct WorkerGlobalScope {
eventtarget: EventTarget,
- worker_id: Option<WorkerId>,
+ worker_id: WorkerId,
worker_url: Url,
runtime: Rc<Runtime>,
next_worker_id: Cell<WorkerId>,
@@ -76,34 +85,29 @@ pub struct WorkerGlobalScope {
impl WorkerGlobalScope {
pub fn new_inherited(type_id: WorkerGlobalScopeTypeId,
+ init: WorkerGlobalScopeInit,
worker_url: Url,
runtime: Rc<Runtime>,
- resource_task: ResourceTask,
- mem_profiler_chan: mem::ProfilerChan,
- devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
- devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
- devtools_receiver: Receiver<DevtoolScriptControlMsg>,
- constellation_chan: ConstellationChan,
- worker_id: Option<WorkerId>)
+ devtools_receiver: Receiver<DevtoolScriptControlMsg>)
-> WorkerGlobalScope {
WorkerGlobalScope {
eventtarget: EventTarget::new_inherited(EventTargetTypeId::WorkerGlobalScope(type_id)),
next_worker_id: Cell::new(WorkerId(0)),
- worker_id: worker_id,
+ worker_id: init.worker_id,
worker_url: worker_url,
runtime: runtime,
- resource_task: resource_task,
+ resource_task: init.resource_task,
location: Default::default(),
navigator: Default::default(),
console: Default::default(),
crypto: Default::default(),
timers: TimerManager::new(),
- mem_profiler_chan: mem_profiler_chan,
- devtools_chan: devtools_chan,
- devtools_sender: devtools_sender,
+ mem_profiler_chan: init.mem_profiler_chan,
+ devtools_chan: init.devtools_chan,
+ devtools_sender: init.devtools_sender,
devtools_receiver: devtools_receiver,
devtools_wants_updates: Cell::new(false),
- constellation_chan: constellation_chan,
+ constellation_chan: init.constellation_chan,
}
}
@@ -144,7 +148,7 @@ impl WorkerGlobalScope {
&self.worker_url
}
- pub fn get_worker_id(&self) -> Option<WorkerId> {
+ pub fn get_worker_id(&self) -> WorkerId {
self.worker_id.clone()
}
diff --git a/components/script/dom/xmlhttprequesteventtarget.rs b/components/script/dom/xmlhttprequesteventtarget.rs
index 8c17d3c8b1a..6b50898ab27 100644
--- a/components/script/dom/xmlhttprequesteventtarget.rs
+++ b/components/script/dom/xmlhttprequesteventtarget.rs
@@ -8,7 +8,7 @@ use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::XMLHttpRequestEventTargetDerived;
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
-#[derive(JSTraceable, Copy, Clone, PartialEq)]
+#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)]
pub enum XMLHttpRequestEventTargetTypeId {
XMLHttpRequest,
XMLHttpRequestUpload,
diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs
index 8fcb298880c..a6fb9ad8491 100644
--- a/components/script/layout_interface.rs
+++ b/components/script/layout_interface.rs
@@ -104,6 +104,7 @@ pub trait LayoutRPC {
fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>;
/// Query layout for the resolved value of a given CSS property
fn resolved_style(&self) -> ResolvedStyleResponse;
+ fn offset_parent(&self) -> OffsetParentResponse;
}
@@ -116,6 +117,21 @@ pub struct HitTestResponse(pub UntrustedNodeAddress);
pub struct MouseOverResponse(pub Vec<UntrustedNodeAddress>);
pub struct ResolvedStyleResponse(pub Option<String>);
+#[derive(Clone)]
+pub struct OffsetParentResponse {
+ pub node_address: Option<UntrustedNodeAddress>,
+ pub rect: Rect<Au>,
+}
+
+impl OffsetParentResponse {
+ pub fn empty() -> OffsetParentResponse {
+ OffsetParentResponse {
+ node_address: None,
+ rect: Rect::zero(),
+ }
+ }
+}
+
/// Why we're doing reflow.
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum ReflowGoal {
@@ -133,6 +149,7 @@ pub enum ReflowQueryType {
ContentBoxesQuery(TrustedNodeAddress),
NodeGeometryQuery(TrustedNodeAddress),
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom),
+ OffsetParentQuery(TrustedNodeAddress),
}
/// Information needed for a reflow.
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 47dadf0d956..8fc23dc78b4 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -84,6 +84,7 @@ pub mod dom;
pub mod parse;
pub mod layout_interface;
+mod mem;
mod network_listener;
pub mod page;
pub mod script_task;
diff --git a/components/script/mem.rs b/components/script/mem.rs
new file mode 100644
index 00000000000..6dbd45e5b8a
--- /dev/null
+++ b/components/script/mem.rs
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+//! Routines for handling measuring the memory usage of arbitrary DOM nodes.
+
+use dom::bindings::codegen::InheritTypes::{DocumentCast, WindowCast, CharacterDataCast, NodeCast};
+use dom::eventtarget::{EventTarget, EventTargetTypeId};
+use dom::node::NodeTypeId;
+use libc;
+use util::mem::{HeapSizeOf, heap_size_of};
+
+// This is equivalent to measuring a Box<T>, except that DOM objects lose their
+// associated box in order to stash their pointers in a reserved slot of their
+// JS reflector. It is assumed that the caller passes a pointer to the most-derived
+// type that this pointer represents, or the actual heap usage of the pointee will
+// be under-reported.
+fn heap_size_of_self_and_children<T: HeapSizeOf>(obj: &T) -> usize {
+ heap_size_of(obj as *const T as *const libc::c_void) + obj.heap_size_of_children()
+}
+
+pub fn heap_size_of_eventtarget(target: &EventTarget) -> usize {
+ //TODO: add more specific matches for concrete element types as derive(HeapSizeOf) is
+ // added to each one.
+ match target.type_id() {
+ &EventTargetTypeId::Window =>
+ heap_size_of_self_and_children(WindowCast::to_ref(target).unwrap()),
+ &EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) =>
+ heap_size_of_self_and_children(CharacterDataCast::to_ref(target).unwrap()),
+ &EventTargetTypeId::Node(NodeTypeId::Document) =>
+ heap_size_of_self_and_children(DocumentCast::to_ref(target).unwrap()),
+ &EventTargetTypeId::Node(_) =>
+ heap_size_of_self_and_children(NodeCast::to_ref(target).unwrap()),
+ _ => 0,
+ }
+}
diff --git a/components/script/page.rs b/components/script/page.rs
index 1286a1427f1..f4b3fd6cd18 100644
--- a/components/script/page.rs
+++ b/components/script/page.rs
@@ -13,7 +13,7 @@ use std::cell::Cell;
use std::rc::Rc;
/// Encapsulates a handle to a frame in a frame tree.
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
#[allow(unrooted_must_root)] // FIXME(#6687) this is wrong
pub struct Page {
/// Pipeline id associated with this page.
@@ -127,7 +127,7 @@ impl Page {
}
/// Information for one frame in the browsing context.
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct Frame {
/// The document for this frame.
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index 279ff364bda..b3ea5b16818 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -46,6 +46,7 @@ use dom::worker::TrustedWorkerAddress;
use parse::html::{ParseContext, parse_html};
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;
@@ -1104,11 +1105,28 @@ impl ScriptTask {
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() {
- urls.push(it_page.document().url().serialize());
+ 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(", "));
- let reports = ScriptTask::get_reports(self.get_cx(), path_seg);
+ reports.extend(ScriptTask::get_reports(self.get_cx(), path_seg));
reports_chan.send(reports);
}
diff --git a/components/script/timers.rs b/components/script/timers.rs
index 0a0a37e0a7a..ac7142914ad 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -13,6 +13,7 @@ use dom::window::ScriptHelpers;
use script_task::{ScriptChan, ScriptMsg, TimerSource};
use horribly_inefficient_timers;
+use util::mem::HeapSizeOf;
use util::task::spawn_named;
use util::str::DOMString;
@@ -29,14 +30,15 @@ use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::default::Default;
-#[derive(JSTraceable, PartialEq, Eq, Copy, Clone)]
+#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf)]
pub struct TimerId(i32);
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
struct TimerHandle {
handle: TimerId,
data: TimerData,
+ #[ignore_heap_size_of = "channels are hard"]
control_chan: Option<Sender<TimerControlMsg>>,
}
@@ -46,6 +48,13 @@ pub enum TimerCallback {
FunctionTimerCallback(Rc<Function>)
}
+impl HeapSizeOf for TimerCallback {
+ fn heap_size_of_children(&self) -> usize {
+ // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
+ 0
+ }
+}
+
impl Hash for TimerId {
fn hash<H: Hasher>(&self, state: &mut H) {
let TimerId(id) = *self;
@@ -65,7 +74,7 @@ impl TimerHandle {
}
}
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
pub struct TimerManager {
active_timers: DOMRefCell<HashMap<TimerId, TimerHandle>>,
@@ -82,7 +91,7 @@ impl Drop for TimerManager {
}
// Enum allowing more descriptive values for the is_interval field
-#[derive(JSTraceable, PartialEq, Copy, Clone)]
+#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum IsInterval {
Interval,
NonInterval,
@@ -100,7 +109,7 @@ pub enum TimerControlMsg {
// (ie. function value to invoke and all arguments to pass
// to the function when calling it)
// TODO: Handle rooting during fire_timer when movable GC is turned on
-#[derive(JSTraceable)]
+#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
struct TimerData {
is_interval: IsInterval,