diff options
Diffstat (limited to 'components/script/dom')
23 files changed, 259 insertions, 172 deletions
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/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 2e100a92960..834e9606c49 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -9,7 +9,7 @@ use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods; use dom::bindings::codegen::InheritTypes::NodeCast; use dom::bindings::codegen::UnionTypes::HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D; use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; -use dom::bindings::error::Error::{IndexSize, NotSupported, Type, InvalidState, Syntax}; +use dom::bindings::error::Error::{IndexSize, InvalidState, Syntax}; use dom::bindings::error::Fallible; use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::js::{JS, LayoutJS, Root}; @@ -820,13 +820,11 @@ impl<'a> CanvasRenderingContext2DMethods for &'a CanvasRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-arc - fn Arc(self, x: Finite<f64>, y: Finite<f64>, r: Finite<f64>, - start: Finite<f64>, end: Finite<f64>, ccw: bool) -> Fallible<()> { - let x = *x; - let y = *y; - let r = *r; - let start = *start; - let end = *end; + fn Arc(self, x: f64, y: f64, r: f64, + start: f64, end: f64, ccw: bool) -> Fallible<()> { + if !([x, y, r, start, end].iter().all(|x| x.is_finite())) { + return Ok(()); + } if r < 0.0 { return Err(IndexSize); @@ -928,15 +926,12 @@ impl<'a> CanvasRenderingContext2DMethods for &'a CanvasRenderingContext2D { fn SetFillStyle(self, value: StringOrCanvasGradientOrCanvasPattern) { match value { StringOrCanvasGradientOrCanvasPattern::eString(string) => { - match parse_color(&string) { - Ok(rgba) => { - self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba); - self.ipc_renderer - .send(CanvasMsg::Canvas2d(Canvas2dMsg::SetFillStyle( - FillOrStrokeStyle::Color(rgba)))) - .unwrap() - } - _ => {} + if let Ok(rgba) = parse_color(&string) { + self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba); + self.ipc_renderer + .send(CanvasMsg::Canvas2d(Canvas2dMsg::SetFillStyle( + FillOrStrokeStyle::Color(rgba)))) + .unwrap() } } StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient) => { @@ -954,12 +949,8 @@ impl<'a> CanvasRenderingContext2DMethods for &'a CanvasRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata - fn CreateImageData(self, sw: f64, sh: f64) -> Fallible<Root<ImageData>> { - if !(sw.is_finite() && sh.is_finite()) { - return Err(NotSupported); - } - - if sw == 0.0 || sh == 0.0 { + fn CreateImageData(self, sw: Finite<f64>, sh: Finite<f64>) -> Fallible<Root<ImageData>> { + if *sw == 0.0 || *sh == 0.0 { return Err(IndexSize) } @@ -1000,49 +991,19 @@ impl<'a> CanvasRenderingContext2DMethods for &'a CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata fn PutImageData(self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) { - let dx = *dx; - let dy = *dy; - - // XXX: - // By the spec: http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#dom-context-2d-putimagedata - // "If any of the arguments to the method are infinite or NaN, the method must throw a NotSupportedError - // exception" - // But this arguments are stricted value, so if they are not finite values, - // they will be TypeError by WebIDL spec before call this methods. - - let data = imagedata.get_data_array(&self.global.root().r()); - let image_data_size = imagedata.get_size(); - let image_data_size = Size2D::new(image_data_size.width as f64, image_data_size.height as f64); - let image_data_rect = Rect::new(Point2D::new(dx, dy), image_data_size); - let dirty_rect = None; - let msg = CanvasMsg::Canvas2d(Canvas2dMsg::PutImageData(data, image_data_rect, dirty_rect)); - self.ipc_renderer.send(msg).unwrap(); - self.mark_as_dirty(); + self.PutImageData_(imagedata, dx, dy, Finite::wrap(0f64), Finite::wrap(0f64), + Finite::wrap(imagedata.Width() as f64), Finite::wrap(imagedata.Height() as f64)) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata fn PutImageData_(self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>, dirtyX: Finite<f64>, dirtyY: Finite<f64>, dirtyWidth: Finite<f64>, dirtyHeight: Finite<f64>) { - let dx = *dx; - let dy = *dy; - let dirtyX = *dirtyX; - let dirtyY = *dirtyY; - let dirtyWidth = *dirtyWidth; - let dirtyHeight = *dirtyHeight; - - // XXX: - // By the spec: http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#dom-context-2d-putimagedata - // "If any of the arguments to the method are infinite or NaN, the method must throw a NotSupportedError - // exception" - // But this arguments are stricted value, so if they are not finite values, - // they will be TypeError by WebIDL spec before call this methods. - let data = imagedata.get_data_array(&self.global.root().r()); - let image_data_rect = Rect::new(Point2D::new(dx, dy), + let image_data_rect = Rect::new(Point2D::new(*dx, *dy), Size2D::new(imagedata.Width() as f64, imagedata.Height() as f64)); - let dirty_rect = Some(Rect::new(Point2D::new(dirtyX, dirtyY), - Size2D::new(dirtyWidth, dirtyHeight))); + let dirty_rect = Some(Rect::new(Point2D::new(*dirtyX, *dirtyY), + Size2D::new(*dirtyWidth, *dirtyHeight))); let msg = CanvasMsg::Canvas2d(Canvas2dMsg::PutImageData(data, image_data_rect, dirty_rect)); self.ipc_renderer.send(msg).unwrap(); self.mark_as_dirty(); @@ -1050,38 +1011,18 @@ impl<'a> CanvasRenderingContext2DMethods for &'a CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient fn CreateLinearGradient(self, x0: Finite<f64>, y0: Finite<f64>, - x1: Finite<f64>, y1: Finite<f64>) -> Fallible<Root<CanvasGradient>> { - let x0 = *x0; - let y0 = *y0; - let x1 = *x1; - let y1 = *y1; - - if [x0, y0, x1, y1].iter().any(|x| x.is_nan() || x.is_infinite()) { - return Err(Type("One of the arguments of createLinearGradient() is not a finite \ - floating-point value.".to_owned())); - } - Ok(CanvasGradient::new(self.global.root().r(), - CanvasGradientStyle::Linear(LinearGradientStyle::new(x0, y0, x1, y1, Vec::new())))) + x1: Finite<f64>, y1: Finite<f64>) -> Root<CanvasGradient> { + CanvasGradient::new(self.global.root().r(), + CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, *y0, *x1, *y1, Vec::new()))) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient fn CreateRadialGradient(self, x0: Finite<f64>, y0: Finite<f64>, r0: Finite<f64>, x1: Finite<f64>, y1: Finite<f64>, r1: Finite<f64>) - -> Fallible<Root<CanvasGradient>> { - let x0 = *x0; - let y0 = *y0; - let r0 = *r0; - let x1 = *x1; - let y1 = *y1; - let r1 = *r1; - - if [x0, y0, r0, x1, y1, r1].iter().any(|x| x.is_nan() || x.is_infinite()) { - return Err(Type("One of the arguments of createRadialGradient() is not a \ - finite floating-point value.".to_owned())); - } - Ok(CanvasGradient::new(self.global.root().r(), - CanvasGradientStyle::Radial( - RadialGradientStyle::new(x0, y0, r0, x1, y1, r1, Vec::new())))) + -> Root<CanvasGradient> { + CanvasGradient::new(self.global.root().r(), + CanvasGradientStyle::Radial( + RadialGradientStyle::new(*x0, *y0, *r0, *x1, *y1, *r1, Vec::new()))) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern 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/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl index b2e1c51e9f5..251daaac846 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -58,9 +58,7 @@ interface CanvasRenderingContext2D { // colours and styles (see also the CanvasDrawingStyles interface) attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) - [Throws] CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1); - [Throws] CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1); [Throws] CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition); @@ -126,7 +124,7 @@ interface CanvasRenderingContext2D { // pixel manipulation [Throws] - ImageData createImageData(unrestricted double sw, unrestricted double sh); + ImageData createImageData(double sw, double sh); [Throws] ImageData createImageData(ImageData imagedata); [Throws] @@ -185,8 +183,8 @@ interface CanvasPathMethods { void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); [Throws] - void arc(double x, double y, double radius, double startAngle, double endAngle, - optional boolean anticlockwise = false); + void arc(unrestricted double x, unrestricted double y, unrestricted double radius, + unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); // [LenientFloat] void ellipse(double x, double y, double radiusX, double radiusY, // double rotation, double startAngle, double endAngle, // boolean anticlockwise); 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 4e90cc71012..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; @@ -81,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. @@ -106,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>, @@ -129,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 @@ -160,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 @@ -194,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 @@ -582,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>; @@ -831,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 { @@ -1139,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 { @@ -1159,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, |