diff options
Diffstat (limited to 'components/script/dom')
105 files changed, 1361 insertions, 532 deletions
diff --git a/components/script/dom/abstractworker.rs b/components/script/dom/abstractworker.rs index 4f2f029800b..28c755d4f03 100644 --- a/components/script/dom/abstractworker.rs +++ b/components/script/dom/abstractworker.rs @@ -15,7 +15,7 @@ pub enum WorkerScriptMsg { /// Common variants associated with the script messages Common(CommonScriptMsg), /// Message sent through Worker.postMessage - DOMMessage(StructuredCloneData), + DOMMessage(StructuredCloneData) } pub struct SimpleWorkerErrorHandler<T: Reflectable> { diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 36dc8a3c380..2e0dc2415dd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1872,56 +1872,31 @@ class CGDOMJSClass(CGThing): elif self.descriptor.weakReferenceable: args["slots"] = "2" return """\ +static CLASS_OPS: js::jsapi::ClassOps = js::jsapi::ClassOps { + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: %(enumerateHook)s, + resolve: %(resolveHook)s, + mayResolve: None, + finalize: Some(%(finalizeHook)s), + call: None, + hasInstance: None, + construct: None, + trace: Some(%(traceHook)s), +}; + static Class: DOMJSClass = DOMJSClass { base: js::jsapi::Class { name: %(name)s as *const u8 as *const libc::c_char, flags: JSCLASS_IS_DOMJSCLASS | %(flags)s | (((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) /* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: %(enumerateHook)s, - resolve: %(resolveHook)s, - mayResolve: None, - finalize: Some(%(finalizeHook)s), - call: None, - hasInstance: None, - construct: None, - trace: Some(%(traceHook)s), - - spec: js::jsapi::ClassSpec { - createConstructor_: None, - createPrototype_: None, - constructorFunctions_: 0 as *const js::jsapi::JSFunctionSpec, - constructorProperties_: 0 as *const js::jsapi::JSPropertySpec, - prototypeFunctions_: 0 as *const js::jsapi::JSFunctionSpec, - prototypeProperties_: 0 as *const js::jsapi::JSPropertySpec, - finishInit_: None, - flags: 0, - }, - - ext: js::jsapi::ClassExtension { - isWrappedNative: false, - weakmapKeyDelegateOp: None, - objectMovedOp: None, - }, - - ops: js::jsapi::ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - watch: None, - unwatch: None, - getElements: None, - enumerate: None, - funToString: None, - }, + cOps: &CLASS_OPS, + spec: ptr::null(), + ext: ptr::null(), + oOps: ptr::null(), }, dom_class: %(domClass)s };""" % args @@ -1947,19 +1922,8 @@ static PrototypeClass: JSClass = JSClass { flags: // JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s) (%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: None, - hasInstance: None, - construct: None, - trace: None, - reserved: [0 as *mut os::raw::c_void; 23] + cOps: 0 as *const _, + reserved: [0 as *mut os::raw::c_void; 3] }; """ % {'name': name, 'slotCount': slotCount} @@ -1983,9 +1947,12 @@ class CGInterfaceObjectJSClass(CGThing): "depth": self.descriptor.prototypeDepth } return """\ +static INTERFACE_OBJECT_OPS: js::jsapi::ClassOps = + NonCallbackInterfaceObjectClass::ops(%(constructorBehavior)s); + static InterfaceObjectClass: NonCallbackInterfaceObjectClass = NonCallbackInterfaceObjectClass::new( - %(constructorBehavior)s, + &INTERFACE_OBJECT_OPS, %(representation)s, PrototypeList::ID::%(id)s, %(depth)s); @@ -2077,7 +2044,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config): 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', 'dom::bindings::js::Root', - 'dom::bindings::str::{DOMString, USVString}', + 'dom::bindings::str::{ByteString, DOMString, USVString}', 'dom::types::*', 'js::jsapi::JSContext', 'js::jsapi::{HandleValue, MutableHandleValue}', @@ -2772,6 +2739,7 @@ let traps = ProxyTraps { ownPropertyKeys: Some(own_property_keys), delete_: Some(%(delete)s), enumerate: None, + getPrototypeIfOrdinary: Some(proxyhandler::get_prototype_if_ordinary), preventExtensions: Some(proxyhandler::prevent_extensions), isExtensible: Some(proxyhandler::is_extensible), has: None, @@ -3754,6 +3722,9 @@ def getUnionTypeTemplateVars(type, descriptorProvider): name = str(type) # XXXjdm dunno about typeName here typeName = "/*" + type.name + "*/" + elif type.isByteString(): + name = type.name + typeName = "ByteString" elif type.isDOMString(): name = type.name typeName = "DOMString" diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index d0074335c23..c4bda97e521 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -4,15 +4,26 @@ //! Utilities to throw exceptions from Rust bindings. +use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; -use dom::bindings::conversions::ToJSValConvertible; +use dom::bindings::conversions::root_from_object; +use dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}; use dom::bindings::global::GlobalRef; +use dom::bindings::str::USVString; use dom::domexception::{DOMErrorName, DOMException}; use js::error::{throw_range_error, throw_type_error}; +use js::jsapi::HandleObject; use js::jsapi::JSAutoCompartment; -use js::jsapi::{JSContext, JSObject}; -use js::jsapi::{JS_IsExceptionPending, JS_ReportPendingException, JS_SetPendingException}; +use js::jsapi::JSContext; +use js::jsapi::JSObject; +use js::jsapi::JS_ClearPendingException; +use js::jsapi::JS_ErrorFromException; +use js::jsapi::JS_GetPendingException; +use js::jsapi::JS_IsExceptionPending; +use js::jsapi::JS_SetPendingException; use js::jsval::UndefinedValue; +use libc::c_uint; +use std::slice::from_raw_parts; /// DOM exceptions that can be thrown by a native DOM method. #[derive(Debug, Clone, HeapSizeOf)] @@ -123,11 +134,101 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, result: JS_SetPendingException(cx, thrown.handle()); } +struct ErrorInfo { + filename: String, + message: String, + lineno: c_uint, + column: c_uint, +} + +impl ErrorInfo { + unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) + -> Option<ErrorInfo> { + let report = JS_ErrorFromException(cx, object); + if report.is_null() { + return None; + } + + let filename = { + let filename = (*report).filename as *const u8; + if !filename.is_null() { + let length = (0..).find(|idx| *filename.offset(*idx) == 0).unwrap(); + let filename = from_raw_parts(filename, length as usize); + String::from_utf8_lossy(filename).into_owned() + } else { + "none".to_string() + } + }; + + let lineno = (*report).lineno; + let column = (*report).column; + + let message = { + let message = (*report).ucmessage; + let length = (0..).find(|idx| *message.offset(*idx) == 0).unwrap(); + let message = from_raw_parts(message, length as usize); + String::from_utf16_lossy(message) + }; + + Some(ErrorInfo { + filename: filename, + message: message, + lineno: lineno, + column: column, + }) + } + + fn from_dom_exception(object: HandleObject) -> Option<ErrorInfo> { + let exception = match root_from_object::<DOMException>(object.get()) { + Ok(exception) => exception, + Err(_) => return None, + }; + + Some(ErrorInfo { + filename: "".to_string(), + message: exception.Stringifier().into(), + lineno: 0, + column: 0, + }) + } +} + /// Report a pending exception, thereby clearing it. pub unsafe fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { if JS_IsExceptionPending(cx) { let _ac = JSAutoCompartment::new(cx, obj); - JS_ReportPendingException(cx); + rooted!(in(cx) let mut value = UndefinedValue()); + if !JS_GetPendingException(cx, value.handle_mut()) { + JS_ClearPendingException(cx); + error!("Uncaught exception: JS_GetPendingException failed"); + return; + } + + JS_ClearPendingException(cx); + if !value.is_object() { + match USVString::from_jsval(cx, value.handle(), ()) { + Ok(USVString(string)) => error!("Uncaught exception: {}", string), + Err(_) => error!("Uncaught exception: failed to stringify primitive"), + } + return; + } + + rooted!(in(cx) let object = value.to_object()); + let error_info = ErrorInfo::from_native_error(cx, object.handle()) + .or_else(|| ErrorInfo::from_dom_exception(object.handle())); + let error_info = match error_info { + Some(error_info) => error_info, + None => { + error!("Uncaught exception: failed to extract information"); + return; + } + }; + + error!("Error at {}:{}:{} {}", + error_info.filename, + error_info.lineno, + error_info.column, + error_info.message); } } diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index fe81b8a14de..bfc3212a9c4 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -19,7 +19,6 @@ use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment}; use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue}; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; use msg::constellation_msg::PipelineId; -use net_traits::filemanager_thread::FileManagerThreadMsg; use net_traits::{ResourceThreads, CoreResourceThread, IpcSend}; use profile_traits::{mem, time}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; @@ -133,11 +132,6 @@ impl<'a> GlobalRef<'a> { self.resource_threads().sender() } - /// Get the port to file manager for this global scope - pub fn filemanager_thread(&self) -> IpcSender<FileManagerThreadMsg> { - self.resource_threads().sender() - } - /// Get the worker's id. pub fn get_worker_id(&self) -> Option<WorkerId> { match *self { diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 4e2c630a453..3b2b5dbde36 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -11,7 +11,7 @@ use dom::bindings::guard::Guard; use dom::bindings::utils::get_proto_or_iface_array; use js::error::throw_type_error; use js::glue::{RUST_SYMBOL_TO_JSID, UncheckedUnwrapObject}; -use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment}; +use js::jsapi::{Class, ClassOps, GetGlobalForObjectCrossCompartment}; use js::jsapi::{GetWellKnownSymbol, HandleObject, HandleValue, JSClass, JSContext}; use js::jsapi::{JSFunctionSpec, JSNative, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE}; use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING, JSPropertySpec}; @@ -101,6 +101,21 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext, ret } +const OBJECT_OPS: ObjectOps = ObjectOps { + lookupProperty: None, + defineProperty: None, + hasProperty: None, + getProperty: None, + setProperty: None, + getOwnPropertyDescriptor: None, + deleteProperty: None, + watch: None, + unwatch: None, + getElements: None, + enumerate: None, + funToString: Some(fun_to_string_hook), +}; + /// The class of a non-callback interface object. #[derive(Copy, Clone)] pub struct NonCallbackInterfaceObjectClass { @@ -117,58 +132,39 @@ pub struct NonCallbackInterfaceObjectClass { unsafe impl Sync for NonCallbackInterfaceObjectClass {} impl NonCallbackInterfaceObjectClass { + /// Create `ClassOps` for a `NonCallbackInterfaceObjectClass`. + pub const fn ops(constructor_behavior: InterfaceConstructorBehavior) + -> ClassOps { + ClassOps { + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: None, + resolve: None, + mayResolve: None, + finalize: None, + call: constructor_behavior.call, + construct: constructor_behavior.construct, + hasInstance: Some(has_instance_hook), + trace: None, + } + } + /// Create a new `NonCallbackInterfaceObjectClass` structure. - pub const fn new( - constructor_behavior: InterfaceConstructorBehavior, - string_rep: &'static [u8], - proto_id: PrototypeList::ID, - proto_depth: u16) - -> NonCallbackInterfaceObjectClass { + pub const fn new(ops: &'static ClassOps, + string_rep: &'static [u8], + proto_id: PrototypeList::ID, + proto_depth: u16) + -> NonCallbackInterfaceObjectClass { NonCallbackInterfaceObjectClass { class: Class { name: b"Function\0" as *const _ as *const libc::c_char, flags: 0, - addProperty: None, - delProperty: None, - getProperty: None, - setProperty: None, - enumerate: None, - resolve: None, - mayResolve: None, - finalize: None, - call: constructor_behavior.call, - construct: constructor_behavior.construct, - hasInstance: Some(has_instance_hook), - trace: None, - spec: ClassSpec { - createConstructor_: None, - createPrototype_: None, - constructorFunctions_: ptr::null(), - constructorProperties_: ptr::null(), - prototypeFunctions_: ptr::null(), - prototypeProperties_: ptr::null(), - finishInit_: None, - flags: 0, - }, - ext: ClassExtension { - isWrappedNative: false, - weakmapKeyDelegateOp: None, - objectMovedOp: None, - }, - ops: ObjectOps { - lookupProperty: None, - defineProperty: None, - hasProperty: None, - getProperty: None, - setProperty: None, - getOwnPropertyDescriptor: None, - deleteProperty: None, - watch: None, - unwatch: None, - getElements: None, - enumerate: None, - funToString: Some(fun_to_string_hook), - } + cOps: ops, + spec: ptr::null(), + ext: ptr::null(), + oOps: &OBJECT_OPS, }, proto_id: proto_id, proto_depth: proto_depth, diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 9db30d8835c..c863cc31994 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -12,7 +12,9 @@ use js::glue::GetProxyExtra; use js::glue::InvokeGetOwnPropertyDescriptor; use js::glue::{GetProxyHandler, SetProxyExtra}; use js::jsapi::GetObjectProto; +use js::jsapi::GetStaticPrototype; use js::jsapi::JS_GetPropertyDescriptorById; +use js::jsapi::MutableHandleObject; use js::jsapi::{Handle, HandleId, HandleObject, MutableHandle, ObjectOpResult}; use js::jsapi::{JSContext, JSObject, JSPROP_GETTER, PropertyDescriptor}; use js::jsapi::{JSErrNum, JS_StrictPropertyStub}; @@ -103,6 +105,25 @@ pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext, true } +/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as +/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior +/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s +/// prototype in `proto`. Otherwise set `*isOrdinary` to false. In case of +/// error, both outparams have unspecified value. +/// +/// This implementation always handles the case of the ordinary +/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be +/// necessary for the Location object. +pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, + proxy: HandleObject, + is_ordinary: *mut bool, + proto: MutableHandleObject) + -> bool { + *is_ordinary = true; + proto.set(GetStaticPrototype(proxy.get())); + true +} + /// Get the expando object, or null if there is none. pub fn get_expando_object(obj: HandleObject) -> *mut JSObject { unsafe { diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 3c13572bf37..618061fe769 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -91,6 +91,7 @@ use style::element_state::*; use style::properties::PropertyDeclarationBlock; use style::selector_impl::{PseudoElement, ElementSnapshot}; use style::values::specified::Length; +use time::Duration; use url::Origin as UrlOrigin; use url::Url; use uuid::Uuid; @@ -109,6 +110,8 @@ no_jsmanaged_fields!(EncodingRef); no_jsmanaged_fields!(Reflector); +no_jsmanaged_fields!(Duration); + /// Trace a `JSVal`. pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) { unsafe { diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index f63e66e3b7b..4711da80010 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -14,18 +14,20 @@ use dom::bindings::str::DOMString; use encoding::all::UTF_8; use encoding::types::{EncoderTrap, Encoding}; use ipc_channel::ipc; -use net_traits::IpcSend; use net_traits::blob_url_store::{BlobBuf, get_blob_origin}; -use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos}; +use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos, ReadFileProgress}; +use net_traits::{CoreResourceMsg, IpcSend}; use std::cell::Cell; +use std::mem; use std::ops::Index; use std::path::PathBuf; +use uuid::Uuid; /// File-based blob #[derive(JSTraceable)] pub struct FileBlob { id: SelectedFileId, - name: PathBuf, + name: Option<PathBuf>, cache: DOMRefCell<Option<Vec<u8>>>, size: u64, } @@ -56,7 +58,7 @@ impl BlobImpl { pub fn new_from_file(file_id: SelectedFileId, name: PathBuf, size: u64) -> BlobImpl { BlobImpl::File(FileBlob { id: file_id, - name: name, + name: Some(name), cache: DOMRefCell::new(None), size: size, }) @@ -97,9 +99,7 @@ impl Blob { relativeContentType: DOMString) -> Root<Blob> { let global = parent.global(); let blob_impl = match *parent.blob_impl.borrow() { - BlobImpl::File(ref f) => { - inc_ref_id(global.r(), f.id.clone()); - + BlobImpl::File(_) => { // Create new parent node BlobImpl::Sliced(JS::from_ref(parent), rel_pos) } @@ -109,13 +109,7 @@ impl Blob { } BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => { // Adjust the slicing position, using same parent - let new_rel_pos = old_rel_pos.slice_inner(&rel_pos); - - if let BlobImpl::File(ref f) = *grandparent.blob_impl.borrow() { - inc_ref_id(global.r(), f.id.clone()); - } - - BlobImpl::Sliced(grandparent.clone(), new_rel_pos) + BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos)) } }; @@ -172,85 +166,116 @@ impl Blob { /// Get a FileID representing the Blob content, /// used by URL.createObjectURL pub fn get_blob_url_id(&self) -> SelectedFileId { - match *self.blob_impl.borrow() { - BlobImpl::File(ref f) => { - let global = self.global(); - let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); - let (tx, rx) = ipc::channel().unwrap(); - - let _ = filemanager.send(FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone())); - - match rx.recv().unwrap() { - Ok(_) => f.id.clone(), - Err(_) => SelectedFileId("".to_string()) // Return a dummy id on error - } - } - BlobImpl::Memory(ref slice) => { - self.promote(slice, true) - } + let opt_sliced_parent = match *self.blob_impl.borrow() { BlobImpl::Sliced(ref parent, ref rel_pos) => { - match *parent.blob_impl.borrow() { - BlobImpl::Sliced(_, _) => { - debug!("Sliced can't have a sliced parent"); - // Return dummy id - SelectedFileId("".to_string()) - } - BlobImpl::File(ref f) => - self.create_sliced_url_id(&f.id, rel_pos), - BlobImpl::Memory(ref bytes) => { - let parent_id = parent.promote(bytes, false); - *self.blob_impl.borrow_mut() = BlobImpl::Sliced(parent.clone(), rel_pos.clone()); - self.create_sliced_url_id(&parent_id, rel_pos) - } - } + Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size())) } + _ => None + }; + + match opt_sliced_parent { + Some((parent_id, rel_pos, size)) => self.create_sliced_url_id(&parent_id, &rel_pos, size), + None => self.promote(/* set_valid is */ true), } } - /// Promite memory-based Blob to file-based, - /// The bytes in data slice will be transferred to file manager thread. + /// Promote non-Slice blob: + /// 1. Memory-based: The bytes in data slice will be transferred to file manager thread. + /// 2. File-based: Activation /// Depending on set_valid, the returned FileID can be part of /// valid or invalid Blob URL. - fn promote(&self, bytes: &[u8], set_valid: bool) -> SelectedFileId { + fn promote(&self, set_valid: bool) -> SelectedFileId { + let mut bytes = vec![]; + + match *self.blob_impl.borrow_mut() { + BlobImpl::Sliced(_, _) => { + debug!("Sliced can't have a sliced parent"); + // Return dummy id + return SelectedFileId(Uuid::new_v4().simple().to_string()); + } + BlobImpl::File(ref f) => { + if set_valid { + let global = self.global(); + let origin = get_blob_origin(&global.r().get_url()); + let (tx, rx) = ipc::channel().unwrap(); + + let msg = FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone()); + self.send_to_file_manager(msg); + + match rx.recv().unwrap() { + Ok(_) => return f.id.clone(), + // Return a dummy id on error + Err(_) => return SelectedFileId(Uuid::new_v4().simple().to_string()) + } + } else { + // no need to activate + return f.id.clone(); + } + } + BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes), + }; + let global = self.global(); let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); let blob_buf = BlobBuf { filename: None, type_string: self.typeString.clone(), - size: self.Size(), + size: bytes.len() as u64, bytes: bytes.to_vec(), }; let (tx, rx) = ipc::channel().unwrap(); - let _ = filemanager.send(FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone())); + let msg = FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone()); + self.send_to_file_manager(msg); match rx.recv().unwrap() { - Ok(new_id) => SelectedFileId(new_id.0), + Ok(id) => { + let id = SelectedFileId(id.0); + *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob { + id: id.clone(), + name: None, + cache: DOMRefCell::new(Some(bytes.to_vec())), + size: bytes.len() as u64, + }); + id + } // Dummy id - Err(_) => SelectedFileId("".to_string()), + Err(_) => SelectedFileId(Uuid::new_v4().simple().to_string()), } } /// Get a FileID representing sliced parent-blob content fn create_sliced_url_id(&self, parent_id: &SelectedFileId, - rel_pos: &RelativePos) -> SelectedFileId { + rel_pos: &RelativePos, parent_len: u64) -> SelectedFileId { let global = self.global(); let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); let msg = FileManagerThreadMsg::AddSlicedURLEntry(parent_id.clone(), rel_pos.clone(), tx, origin.clone()); - let _ = filemanager.send(msg); - let new_id = rx.recv().unwrap().unwrap(); - - // Return the indirect id reference - SelectedFileId(new_id.0) + self.send_to_file_manager(msg); + match rx.recv().expect("File manager thread is down") { + Ok(new_id) => { + let new_id = SelectedFileId(new_id.0); + + *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob { + id: new_id.clone(), + name: None, + cache: DOMRefCell::new(None), + size: rel_pos.to_abs_range(parent_len as usize).len() as u64, + }); + + // Return the indirect id reference + new_id + } + Err(_) => { + // Return dummy id + SelectedFileId(Uuid::new_v4().simple().to_string()) + } + } } /// Cleanups at the time of destruction/closing @@ -259,14 +284,19 @@ impl Blob { let global = self.global(); let origin = get_blob_origin(&global.r().get_url()); - let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); let msg = FileManagerThreadMsg::DecRef(f.id.clone(), origin, tx); - let _ = filemanager.send(msg); + self.send_to_file_manager(msg); let _ = rx.recv().unwrap(); } } + + fn send_to_file_manager(&self, msg: FileManagerThreadMsg) { + let global = self.global(); + let resource_threads = global.r().resource_threads(); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)); + } } impl Drop for Blob { @@ -278,16 +308,28 @@ impl Drop for Blob { } fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<Vec<u8>, ()> { - let file_manager = global.filemanager_thread(); + let resource_threads = global.resource_threads(); let (chan, recv) = ipc::channel().map_err(|_|())?; let origin = get_blob_origin(&global.get_url()); let check_url_validity = false; let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin); - let _ = file_manager.send(msg); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)); + + let mut bytes = vec![]; - match recv.recv().unwrap() { - Ok(blob_buf) => Ok(blob_buf.bytes), - Err(_) => Err(()), + loop { + match recv.recv().unwrap() { + Ok(ReadFileProgress::Meta(mut blob_buf)) => { + bytes.append(&mut blob_buf.bytes); + } + Ok(ReadFileProgress::Partial(mut bytes_in)) => { + bytes.append(&mut bytes_in); + } + Ok(ReadFileProgress::EOF) => { + return Ok(bytes); + } + Err(_) => return Err(()), + } } } @@ -379,11 +421,3 @@ fn is_ascii_printable(string: &str) -> bool { // https://w3c.github.io/FileAPI/#constructorBlob string.chars().all(|c| c >= '\x20' && c <= '\x7E') } - -/// Bump the reference counter in file manager thread -fn inc_ref_id(global: GlobalRef, id: SelectedFileId) { - let file_manager = global.filemanager_thread(); - let origin = get_blob_origin(&global.get_url()); - let msg = FileManagerThreadMsg::IncRef(id, origin); - let _ = file_manager.send(msg); -} diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 7deca26c9d3..c86fa0150a3 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -7,7 +7,7 @@ use core::clone::Clone; use dom::bindings::codegen::Bindings::BluetoothBinding; use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions; use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothScanFilter, BluetoothMethods}; -use dom::bindings::error::Error::{Security, Type}; +use dom::bindings::error::Error::{self, Security, Type}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; @@ -19,7 +19,7 @@ use dom::bluetoothuuid::BluetoothUUID; use ipc_channel::ipc::{self, IpcSender}; use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence}; use net_traits::bluetooth_scanfilter::{RequestDeviceoptions, ServiceUUIDSequence}; -use net_traits::bluetooth_thread::BluetoothMethodMsg; +use net_traits::bluetooth_thread::{BluetoothError, BluetoothMethodMsg}; const FILTER_EMPTY_ERROR: &'static str = "'filters' member must be non - empty to find any devices."; const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way."; @@ -135,6 +135,18 @@ fn convert_request_device_options(options: &RequestDeviceOptions, ServiceUUIDSequence::new(optional_services))) } +impl From<BluetoothError> for Error { + fn from(error: BluetoothError) -> Self { + match error { + BluetoothError::Type(message) => Error::Type(message), + BluetoothError::Network => Error::Network, + BluetoothError::NotFound => Error::NotFound, + BluetoothError::NotSupported => Error::NotSupported, + BluetoothError::Security => Error::Security, + } + } +} + impl BluetoothMethods for Bluetooth { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> { @@ -154,7 +166,7 @@ impl BluetoothMethods for Bluetooth { &ad_data)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs index e3e17b4a0f9..0c27097625c 100644 --- a/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding:: BluetoothRemoteGATTCharacteristicMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; -use dom::bindings::error::Error::{InvalidModification, Network, NotSupported, Security, Type}; +use dom::bindings::error::Error::{self, InvalidModification, Network, NotSupported, Security}; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -115,7 +115,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris descriptor.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -147,7 +147,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris .collect()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -177,7 +177,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris ByteString::new(val) }, Err(error) => { - return Err(Type(error)) + return Err(Error::from(error)) }, }; *self.value.borrow_mut() = Some(value.clone()); @@ -195,6 +195,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris if !self.Service().Device().Gatt().Connected() { return Err(Network) } + + if !(self.Properties().Write() || + self.Properties().WriteWithoutResponse() || + self.Properties().AuthenticatedSignedWrites()) { + return Err(NotSupported) + } let (sender, receiver) = ipc::channel().unwrap(); self.get_bluetooth_thread().send( BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap(); @@ -202,7 +208,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris match result { Ok(_) => Ok(()), Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetoothremotegattdescriptor.rs index f821d4aca2d..0ba52181b48 100644 --- a/components/script/dom/bluetoothremotegattdescriptor.rs +++ b/components/script/dom/bluetoothremotegattdescriptor.rs @@ -11,7 +11,7 @@ use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; -use dom::bindings::error::Error::{InvalidModification, Network, Security, Type}; +use dom::bindings::error::Error::{self, InvalidModification, Network, Security}; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -101,7 +101,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { ByteString::new(val) }, Err(error) => { - return Err(Type(error)) + return Err(Error::from(error)) }, }; *self.value.borrow_mut() = Some(value.clone()); @@ -126,7 +126,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { match result { Ok(_) => Ok(()), Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs index 56aad1b8bf6..f4b1e532f10 100644 --- a/components/script/dom/bluetoothremotegattserver.rs +++ b/components/script/dom/bluetoothremotegattserver.rs @@ -6,7 +6,7 @@ use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted}; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; -use dom::bindings::error::Error::{Security, Type}; +use dom::bindings::error::Error::{self, Security}; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -72,7 +72,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { Ok(Root::from_ref(self)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -89,7 +89,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { Ok(()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -113,7 +113,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { service.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -146,7 +146,7 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { .collect()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs index f0954a1c76f..5b80bc6afc0 100644 --- a/components/script/dom/bluetoothremotegattservice.rs +++ b/components/script/dom/bluetoothremotegattservice.rs @@ -5,7 +5,7 @@ use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted}; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; -use dom::bindings::error::Error::{Security, Type}; +use dom::bindings::error::Error::{self, Security}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; @@ -115,7 +115,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { characteristic.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -160,7 +160,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { Ok(characteristics) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -188,7 +188,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { service.instance_id)) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } @@ -223,7 +223,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { .collect()) }, Err(error) => { - Err(Type(error)) + Err(Error::from(error)) }, } } diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs index 4c0914ddf3c..878d376ca66 100644 --- a/components/script/dom/browsingcontext.rs +++ b/components/script/dom/browsingcontext.rs @@ -22,7 +22,7 @@ use js::jsapi::{Handle, HandleId, HandleObject, HandleValue, JSAutoCompartment}; use js::jsapi::{JSContext, JSPROP_READONLY, JSErrNum, JSObject, PropertyDescriptor, JS_DefinePropertyById}; use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass, JSTracer, FreeOp}; use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle}; -use js::jsapi::{MutableHandleValue, ObjectOpResult}; +use js::jsapi::{MutableHandleObject, MutableHandleValue, ObjectOpResult}; use js::jsval::{UndefinedValue, PrivateValue}; use msg::constellation_msg::{PipelineId, SubpageId}; use std::cell::Cell; @@ -354,6 +354,28 @@ unsafe extern "C" fn set(cx: *mut JSContext, res) } +#[allow(unsafe_code)] +unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext, + _: HandleObject, + is_ordinary: *mut bool, + _: MutableHandleObject) + -> bool { + // Window's [[GetPrototypeOf]] trap isn't the ordinary definition: + // + // https://html.spec.whatwg.org/multipage/#windowproxy-getprototypeof + // + // We nonetheless can implement it with a static [[Prototype]], because + // wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply + // all non-ordinary behavior. + // + // But from a spec point of view, it's the exact same object in both cases -- + // only the observer's changed. So this getPrototypeIfOrdinary trap on the + // non-wrapper object *must* report non-ordinary, even if static [[Prototype]] + // usually means ordinary. + *is_ordinary = false; + return true; +} + static PROXY_HANDLER: ProxyTraps = ProxyTraps { enter: None, getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor), @@ -361,6 +383,7 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps { ownPropertyKeys: None, delete_: None, enumerate: None, + getPrototypeIfOrdinary: Some(get_prototype_if_ordinary), preventExtensions: None, isExtensible: None, has: Some(has), diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index b65fd72ab62..dfe385f0696 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -218,7 +218,7 @@ impl DedicatedWorkerGlobalScope { scope.execute_script(DOMString::from(source)); } - let reporter_name = format!("worker-reporter-{}", random::<u64>()); + let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>()); scope.mem_profiler_chan().run_with_memory_reporting(|| { while let Ok(event) = global.receive_event() { if scope.is_closing() { @@ -307,7 +307,7 @@ impl DedicatedWorkerGlobalScope { let path_seg = format!("url({})", scope.get_url()); let reports = get_reports(cx, path_seg); reports_chan.send(reports); - }, + } } } @@ -370,6 +370,12 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope { Ok(()) } + // https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-close + fn Close(&self) { + // Step 2 + self.upcast::<WorkerGlobalScope>().close(); + } + // https://html.spec.whatwg.org/multipage/#handler-dedicatedworkerglobalscope-onmessage event_handler!(message, GetOnmessage, SetOnmessage); } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 28edce553ad..9366f9e18bb 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -241,6 +241,8 @@ pub struct Document { referrer_policy: Cell<Option<ReferrerPolicy>>, /// https://html.spec.whatwg.org/multipage/#dom-document-referrer referrer: Option<String>, + /// https://html.spec.whatwg.org/multipage/#target-element + target_element: MutNullableHeap<JS<Element>>, } #[derive(JSTraceable, HeapSizeOf)] @@ -347,6 +349,10 @@ impl Document { true } + pub fn origin(&self) -> &Origin { + &self.origin + } + // https://dom.spec.whatwg.org/#concept-document-url pub fn url(&self) -> &Url { &self.url @@ -376,6 +382,7 @@ impl Document { // that workable. match self.GetDocumentElement() { Some(root) => { + root.upcast::<Node>().is_dirty() || root.upcast::<Node>().has_dirty_descendants() || !self.modified_elements.borrow().is_empty() } @@ -1371,6 +1378,7 @@ impl Document { } pub fn finish_load(&self, load: LoadType) { + debug!("Document got finish_load: {:?}", load); // The parser might need the loader, so restrict the lifetime of the borrow. { let mut loader = self.loader.borrow_mut(); @@ -1396,9 +1404,9 @@ impl Document { // If we don't have a parser, and the reflow timer has been reset, explicitly // trigger a reflow. if let LoadType::Stylesheet(_) = load { - self.window().reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::StylesheetLoaded); + self.window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::StylesheetLoaded); } } @@ -1487,24 +1495,25 @@ impl Document { return; } self.domcontentloaded_dispatched.set(true); + assert!(self.ReadyState() != DocumentReadyState::Complete, + "Complete before DOMContentLoaded?"); update_with_current_time_ms(&self.dom_content_loaded_event_start); let window = self.window(); window.dom_manipulation_task_source().queue_event(self.upcast(), atom!("DOMContentLoaded"), EventBubbles::Bubbles, EventCancelable::NotCancelable, window); + window.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DOMContentLoaded); - update_with_current_time_ms(&self.dom_content_loaded_event_end); } pub fn notify_constellation_load(&self) { let pipeline_id = self.window.pipeline(); - let event = ConstellationMsg::DOMLoad(pipeline_id); - self.window.constellation_chan().send(event).unwrap(); - + let load_event = ConstellationMsg::LoadComplete(pipeline_id); + self.window.constellation_chan().send(load_event).unwrap(); } pub fn set_current_parser(&self, script: Option<ParserRef>) { @@ -1732,6 +1741,7 @@ impl Document { origin: origin, referrer: referrer, referrer_policy: Cell::new(referrer_policy), + target_element: MutNullableHeap::new(None), } } @@ -1883,6 +1893,22 @@ impl Document { pub fn get_referrer_policy(&self) -> Option<ReferrerPolicy> { return self.referrer_policy.get(); } + + pub fn set_target_element(&self, node: Option<&Element>) { + if let Some(ref element) = self.target_element.get() { + element.set_target_state(false); + } + + self.target_element.set(node); + + if let Some(ref element) = self.target_element.get() { + element.set_target_state(true); + } + + self.window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::ElementStateChanged); + } } @@ -2908,16 +2934,18 @@ impl DocumentProgressHandler { // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart update_with_current_time_ms(&document.load_event_start); + debug!("About to dispatch load for {:?}", document.url()); let _ = wintarget.dispatch_event_with_target(document.upcast(), &event); // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd update_with_current_time_ms(&document.load_event_end); - document.notify_constellation_load(); window.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DocumentLoaded); + + document.notify_constellation_load(); } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index a4c1ed28583..b9b02183762 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -103,6 +103,7 @@ use style::values::specified::{self, CSSColor, CSSRGBA, LengthOrPercentage}; pub struct Element { node: Node, local_name: Atom, + tag_name: TagName, namespace: Namespace, prefix: Option<DOMString>, attrs: DOMRefCell<Vec<JS<Attr>>>, @@ -165,6 +166,7 @@ impl Element { Element { node: Node::new_inherited(document), local_name: local_name, + tag_name: TagName::new(), namespace: namespace, prefix: prefix, attrs: DOMRefCell::new(vec![]), @@ -347,7 +349,8 @@ impl LayoutElementHelpers for LayoutJS<Element> { if let Some(url) = background { hints.push(from_declaration( PropertyDeclaration::BackgroundImage(DeclaredValue::Value( - background_image::SpecifiedValue(Some(specified::Image::Url(url))))))); + background_image::SpecifiedValue(Some( + specified::Image::Url(url, specified::UrlExtraData { }))))))); } let color = if let Some(this) = self.downcast::<HTMLFontElement>() { @@ -1366,17 +1369,20 @@ impl ElementMethods for Element { // https://dom.spec.whatwg.org/#dom-element-tagname fn TagName(&self) -> DOMString { - let qualified_name = match self.prefix { - Some(ref prefix) => { - Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)) - }, - None => Cow::Borrowed(&*self.local_name) - }; - DOMString::from(if self.html_element_in_html_document() { - qualified_name.to_ascii_uppercase() - } else { - qualified_name.into_owned() - }) + let name = self.tag_name.or_init(|| { + let qualified_name = match self.prefix { + Some(ref prefix) => { + Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)) + }, + None => Cow::Borrowed(&*self.local_name) + }; + if self.html_element_in_html_document() { + Atom::from(qualified_name.to_ascii_uppercase()) + } else { + Atom::from(qualified_name) + } + }); + DOMString::from(&*name) } // https://dom.spec.whatwg.org/#dom-element-id @@ -2218,6 +2224,14 @@ impl VirtualMethods for Element { } } } + + fn adopting_steps(&self, old_doc: &Document) { + self.super_type().unwrap().adopting_steps(old_doc); + + if document_from_node(self).is_html_document() != old_doc.is_html_document() { + self.tag_name.clear(); + } + } } impl<'a> ::selectors::MatchAttrGeneric for Root<Element> { @@ -2323,7 +2337,8 @@ impl<'a> ::selectors::Element for Root<Element> { NonTSPseudoClass::Checked | NonTSPseudoClass::Indeterminate | NonTSPseudoClass::ReadWrite | - NonTSPseudoClass::PlaceholderShown => + NonTSPseudoClass::PlaceholderShown | + NonTSPseudoClass::Target => Element::state(self).contains(pseudo_class.state_flag()), } } @@ -2585,6 +2600,14 @@ impl Element { self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } } + + pub fn target_state(&self) -> bool { + self.state.get().contains(IN_TARGET_STATE) + } + + pub fn set_target_state(&self, value: bool) { + self.set_state(IN_TARGET_STATE, value) + } } impl Element { @@ -2681,3 +2704,38 @@ impl AtomicElementFlags { self.0.fetch_or(flags.bits() as usize, Ordering::Relaxed); } } + +/// A holder for an element's "tag name", which will be lazily +/// resolved and cached. Should be reset when the document +/// owner changes. +#[derive(JSTraceable, HeapSizeOf)] +struct TagName { + ptr: DOMRefCell<Option<Atom>>, +} + +impl TagName { + fn new() -> TagName { + TagName { ptr: DOMRefCell::new(None) } + } + + /// Retrieve a copy of the current inner value. If it is `None`, it is + /// initialized with the result of `cb` first. + fn or_init<F>(&self, cb: F) -> Atom + where F: FnOnce() -> Atom + { + match &mut *self.ptr.borrow_mut() { + &mut Some(ref name) => name.clone(), + ptr => { + let name = cb(); + *ptr = Some(name.clone()); + name + } + } + } + + /// Clear the cached tag name, so that it will be re-calculated the + /// next time that `or_init()` is called. + fn clear(&self) { + *self.ptr.borrow_mut() = None; + } +} diff --git a/components/script/dom/file.rs b/components/script/dom/file.rs index 4528a116e45..f9b181dbf1a 100644 --- a/components/script/dom/file.rs +++ b/components/script/dom/file.rs @@ -73,7 +73,10 @@ impl File { let ref typeString = blobPropertyBag.type_; let modified = filePropertyBag.lastModified; - Ok(File::new(global, BlobImpl::new_from_bytes(bytes), filename, modified, typeString)) + // NOTE: Following behaviour might be removed in future, + // see https://github.com/w3c/FileAPI/issues/41 + let replaced_filename = DOMString::from_string(filename.replace("/", ":")); + Ok(File::new(global, BlobImpl::new_from_bytes(bytes), replaced_filename, modified, typeString)) } pub fn name(&self) -> &DOMString { diff --git a/components/script/dom/filelist.rs b/components/script/dom/filelist.rs index 96bfc4ce0d3..4f8e976f5f7 100644 --- a/components/script/dom/filelist.rs +++ b/components/script/dom/filelist.rs @@ -9,6 +9,7 @@ use dom::bindings::js::{JS, Root}; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::file::File; use dom::window::Window; +use std::slice::Iter; // https://w3c.github.io/FileAPI/#dfn-filelist #[dom_struct] @@ -32,6 +33,10 @@ impl FileList { GlobalRef::Window(window), FileListBinding::Wrap) } + + pub fn iter_files(&self) -> Iter<JS<File>> { + self.list.iter() + } } impl FileListMethods for FileList { diff --git a/components/script/dom/filereadersync.rs b/components/script/dom/filereadersync.rs new file mode 100644 index 00000000000..b248848edad --- /dev/null +++ b/components/script/dom/filereadersync.rs @@ -0,0 +1,34 @@ +/* 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/. */ + +use dom::bindings::codegen::Bindings::FileReaderSyncBinding; +use dom::bindings::error::Fallible; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::Root; +use dom::bindings::reflector::reflect_dom_object; +use dom::eventtarget::EventTarget; + + + +#[dom_struct] +pub struct FileReaderSync { + eventtarget: EventTarget +} + +impl FileReaderSync { + pub fn new_inherited() -> FileReaderSync { + FileReaderSync { + eventtarget: EventTarget::new_inherited(), + } + } + + pub fn new(global: GlobalRef) -> Root<FileReaderSync> { + reflect_dom_object(box FileReaderSync::new_inherited(), + global, FileReaderSyncBinding::Wrap) + } + + pub fn Constructor(global: GlobalRef) -> Fallible<Root<FileReaderSync>> { + Ok(FileReaderSync::new(global)) + } +} diff --git a/components/script/dom/headers.rs b/components/script/dom/headers.rs index e97edc00572..4ae212aee78 100644 --- a/components/script/dom/headers.rs +++ b/components/script/dom/headers.rs @@ -5,12 +5,13 @@ use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HeadersBinding; use dom::bindings::codegen::Bindings::HeadersBinding::HeadersMethods; -use dom::bindings::error::Error; +use dom::bindings::codegen::UnionTypes::HeadersOrByteStringSequenceSequence; +use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, is_token}; -use hyper; +use hyper::header::Headers as HyperHeaders; use std::result::Result; #[dom_struct] @@ -18,7 +19,7 @@ pub struct Headers { reflector_: Reflector, guard: Guard, #[ignore_heap_size_of = "Defined in hyper"] - header_list: DOMRefCell<hyper::header::Headers> + header_list: DOMRefCell<HyperHeaders> } // https://fetch.spec.whatwg.org/#concept-headers-guard @@ -36,12 +37,50 @@ impl Headers { Headers { reflector_: Reflector::new(), guard: Guard::None, - header_list: DOMRefCell::new(hyper::header::Headers::new()), + header_list: DOMRefCell::new(HyperHeaders::new()), } } - pub fn new(global: GlobalRef) -> Root<Headers> { - reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap) + // https://fetch.spec.whatwg.org/#concept-headers-fill + pub fn new(global: GlobalRef, init: Option<HeadersBinding::HeadersInit>) + -> Fallible<Root<Headers>> { + let dom_headers_new = reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap); + match init { + // Step 1 + Some(HeadersOrByteStringSequenceSequence::Headers(h)) => { + // header_list_copy has type hyper::header::Headers + let header_list_copy = h.header_list.clone(); + for header in header_list_copy.borrow().iter() { + try!(dom_headers_new.Append( + ByteString::new(Vec::from(header.name())), + ByteString::new(Vec::from(header.value_string().into_bytes())) + )); + } + Ok(dom_headers_new) + }, + // Step 2 + Some(HeadersOrByteStringSequenceSequence::ByteStringSequenceSequence(v)) => { + for mut seq in v { + if seq.len() == 2 { + let val = seq.pop().unwrap(); + let name = seq.pop().unwrap(); + try!(dom_headers_new.Append(name, val)); + } else { + return Err(Error::Type( + format!("Each header object must be a sequence of length 2 - found one with length {}", + seq.len()))); + } + } + Ok(dom_headers_new) + }, + // Step 3 TODO constructor for when init is an open-ended dictionary + None => Ok(dom_headers_new), + } + } + + pub fn Constructor(global: GlobalRef, init: Option<HeadersBinding::HeadersInit>) + -> Fallible<Root<Headers>> { + Headers::new(global, init) } } @@ -50,32 +89,102 @@ impl HeadersMethods for Headers { fn Append(&self, name: ByteString, value: ByteString) -> Result<(), Error> { // Step 1 let value = normalize_value(value); - // Step 2 - let (valid_name, valid_value) = try!(validate_name_and_value(name, value)); + let (mut valid_name, valid_value) = try!(validate_name_and_value(name, value)); + valid_name = valid_name.to_lowercase(); // Step 3 if self.guard == Guard::Immutable { return Err(Error::Type("Guard is immutable".to_string())); } - // Step 4 if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { return Ok(()); } - // Step 5 if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { return Ok(()); } - // Step 6 if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { return Ok(()); } + // Step 7 + let mut combined_value = self.header_list.borrow_mut().get_raw(&valid_name).unwrap()[0].clone(); + combined_value.push(b","[0]); + combined_value.extend(valid_value.iter().cloned()); + self.header_list.borrow_mut().set_raw(valid_name, vec![combined_value]); + Ok(()) + } + + // https://fetch.spec.whatwg.org/#dom-headers-delete + fn Delete(&self, name: ByteString) -> ErrorResult { + // Step 1 + let valid_name = try!(validate_name(name)); + // Step 2 + if self.guard == Guard::Immutable { + return Err(Error::Type("Guard is immutable".to_string())); + } + // Step 3 + if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { + return Ok(()); + } + // Step 4 + if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { + return Ok(()); + } + // Step 5 + if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { + return Ok(()); + } + // Step 6 + self.header_list.borrow_mut().remove_raw(&valid_name); + Ok(()) + } + + // https://fetch.spec.whatwg.org/#dom-headers-get + fn Get(&self, name: ByteString) -> Fallible<Option<ByteString>> { + // Step 1 + let valid_name = &try!(validate_name(name)); + Ok(self.header_list.borrow().get_raw(&valid_name).map(|v| { + ByteString::new(v[0].clone()) + })) + } + // https://fetch.spec.whatwg.org/#dom-headers-has + fn Has(&self, name: ByteString) -> Fallible<bool> { + // Step 1 + let valid_name = try!(validate_name(name)); + // Step 2 + Ok(self.header_list.borrow_mut().get_raw(&valid_name).is_some()) + } + + // https://fetch.spec.whatwg.org/#dom-headers-set + fn Set(&self, name: ByteString, value: ByteString) -> Fallible<()> { + // Step 1 + let value = normalize_value(value); + // Step 2 + let (mut valid_name, valid_value) = try!(validate_name_and_value(name, value)); + valid_name = valid_name.to_lowercase(); + // Step 3 + if self.guard == Guard::Immutable { + return Err(Error::Type("Guard is immutable".to_string())); + } + // Step 4 + if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { + return Ok(()); + } + // Step 5 + if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { + return Ok(()); + } + // Step 6 + if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { + return Ok(()); + } // Step 7 + // https://fetch.spec.whatwg.org/#concept-header-list-set self.header_list.borrow_mut().set_raw(valid_name, vec![valid_value]); - return Ok(()); + Ok(()) } } @@ -130,7 +239,7 @@ pub fn is_forbidden_header_name(name: &str) -> bool { // ISSUE 1: // It defines a value as "a byte sequence that matches the field-content token production." // To note, there is a difference between field-content and -// field-value (which is made up of fied-content and obs-fold). The +// field-value (which is made up of field-content and obs-fold). The // current definition does not allow for obs-fold (which are white // space and newlines) in values. So perhaps a value should be defined // as "a byte sequence that matches the field-value token production." @@ -147,14 +256,19 @@ pub fn is_forbidden_header_name(name: &str) -> bool { // [4] https://www.rfc-editor.org/errata_search.php?rfc=7230 fn validate_name_and_value(name: ByteString, value: ByteString) -> Result<(String, Vec<u8>), Error> { - if !is_field_name(&name) { - return Err(Error::Type("Name is not valid".to_string())); - } + let valid_name = try!(validate_name(name)); if !is_field_content(&value) { return Err(Error::Type("Value is not valid".to_string())); } + Ok((valid_name, value.into())) +} + +fn validate_name(name: ByteString) -> Result<String, Error> { + if !is_field_name(&name) { + return Err(Error::Type("Name is not valid".to_string())); + } match String::from_utf8(name.into()) { - Ok(ns) => Ok((ns, value.into())), + Ok(ns) => Ok(ns), _ => Err(Error::Type("Non-UTF8 header name found".to_string())), } } diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs new file mode 100644 index 00000000000..559b39f9b2c --- /dev/null +++ b/components/script/dom/history.rs @@ -0,0 +1,80 @@ +/* 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/. */ + +use dom::bindings::codegen::Bindings::HistoryBinding; +use dom::bindings::codegen::Bindings::HistoryBinding::HistoryMethods; +use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{JS, Root}; +use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::window::Window; +use ipc_channel::ipc; +use msg::constellation_msg::TraversalDirection; +use script_traits::ScriptMsg as ConstellationMsg; + +// https://html.spec.whatwg.org/multipage/#the-history-interface +#[dom_struct] +pub struct History { + reflector_: Reflector, + window: JS<Window>, +} + +impl History { + pub fn new_inherited(window: &Window) -> History { + History { + reflector_: Reflector::new(), + window: JS::from_ref(&window), + } + } + + pub fn new(window: &Window) -> Root<History> { + reflect_dom_object(box History::new_inherited(window), + GlobalRef::Window(window), + HistoryBinding::Wrap) + } +} + +impl History { + fn traverse_history(&self, direction: TraversalDirection) { + let pipeline = self.window.pipeline(); + let msg = ConstellationMsg::TraverseHistory(Some(pipeline), direction); + let _ = self.window.constellation_chan().send(msg); + } +} + +impl HistoryMethods for History { + // https://html.spec.whatwg.org/multipage/#dom-history-length + fn Length(&self) -> u32 { + let pipeline = self.window.pipeline(); + let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length."); + let msg = ConstellationMsg::JointSessionHistoryLength(pipeline, sender); + let _ = self.window.constellation_chan().send(msg); + recv.recv().unwrap() + } + + // https://html.spec.whatwg.org/multipage/#dom-history-go + fn Go(&self, delta: i32) { + let direction = if delta > 0 { + TraversalDirection::Forward(delta as usize) + } else if delta < 0 { + TraversalDirection::Back(-delta as usize) + } else { + self.window.Location().Reload(); + return; + }; + + self.traverse_history(direction); + } + + // https://html.spec.whatwg.org/multipage/#dom-history-back + fn Back(&self) { + self.traverse_history(TraversalDirection::Back(1)); + } + + // https://html.spec.whatwg.org/multipage/#dom-history-forward + fn Forward(&self) { + self.traverse_history(TraversalDirection::Forward(1)); + } +} diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index 798d0731b2c..95134556bc0 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -248,7 +248,7 @@ impl<'a> Iterator for HTMLCollectionElementsIter<'a> { .filter_map(Root::downcast) .filter(|element| filter.filter(&element, root)) .next() - } + } } impl HTMLCollectionMethods for HTMLCollection { diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 9d7ce208ee2..72b8cc19c16 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -37,11 +37,9 @@ use dom::htmlselectelement::HTMLSelectElement; use dom::htmltextareaelement::HTMLTextAreaElement; use dom::node::{Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; -use dom::window::Window; use encoding::EncodingRef; use encoding::all::UTF_8; use encoding::label::encoding_from_whatwg_label; -use encoding::types::DecoderTrap; use hyper::header::{Charset, ContentDisposition, ContentType, DispositionParam, DispositionType}; use hyper::method::Method; use msg::constellation_msg::{LoadData, PipelineId}; @@ -54,7 +52,6 @@ use string_cache::Atom; use style::attr::AttrValue; use style::str::split_html_space_chars; use task_source::TaskSource; -use url::form_urlencoded; #[derive(JSTraceable, PartialEq, Clone, Copy, HeapSizeOf)] pub struct GenerationId(u32); @@ -280,39 +277,38 @@ impl HTMLFormElement { // https://html.spec.whatwg.org/multipage/#multipart/form-data-encoding-algorithm fn encode_multipart_form_data(&self, form_data: &mut Vec<FormDatum>, - encoding: Option<EncodingRef>, - boundary: String) -> String { + boundary: String, encoding: EncodingRef) -> Vec<u8> { // Step 1 - let mut result = "".to_owned(); + let mut result = vec![]; // Step 2 - // (maybe take encoding as input) - let encoding = encoding.unwrap_or(self.pick_encoding()); - - // Step 3 let charset = &*encoding.whatwg_name().unwrap_or("UTF-8"); - // Step 4 + // Step 3 for entry in form_data.iter_mut() { - // Substep 1 + // 3.1 if entry.name == "_charset_" && entry.ty == "hidden" { entry.value = FormDatumValue::String(DOMString::from(charset.clone())); } - // TODO: Substep 2 + // TODO: 3.2 - // Step 5 + // Step 4 // https://tools.ietf.org/html/rfc7578#section-4 - result.push_str(&*format!("\r\n--{}\r\n", boundary)); + // NOTE(izgzhen): The encoding here expected by most servers seems different from + // what spec says (that it should start with a '\r\n'). + let mut boundary_bytes = format!("--{}\r\n", boundary).into_bytes(); + result.append(&mut boundary_bytes); let mut content_disposition = ContentDisposition { disposition: DispositionType::Ext("form-data".to_owned()), parameters: vec![DispositionParam::Ext("name".to_owned(), String::from(entry.name.clone()))] }; match entry.value { - FormDatumValue::String(ref s) => - result.push_str(&*format!("Content-Disposition: {}\r\n\r\n{}", - content_disposition, - s)), + FormDatumValue::String(ref s) => { + let mut bytes = format!("Content-Disposition: {}\r\n\r\n{}", + content_disposition, s).into_bytes(); + result.append(&mut bytes); + } FormDatumValue::File(ref f) => { content_disposition.parameters.push( DispositionParam::Filename(Charset::Ext(String::from(charset.clone())), @@ -321,20 +317,20 @@ impl HTMLFormElement { // https://tools.ietf.org/html/rfc7578#section-4.4 let content_type = ContentType(f.upcast::<Blob>().Type() .parse().unwrap_or(mime!(Text / Plain))); - result.push_str(&*format!("Content-Disposition: {}\r\n{}\r\n\r\n", - content_disposition, - content_type)); + let mut type_bytes = format!("Content-Disposition: {}\r\n{}\r\n\r\n", + content_disposition, + content_type).into_bytes(); + result.append(&mut type_bytes); - let bytes = &f.upcast::<Blob>().get_bytes().unwrap_or(vec![])[..]; + let mut bytes = f.upcast::<Blob>().get_bytes().unwrap_or(vec![]); - let decoded = encoding.decode(bytes, DecoderTrap::Replace) - .expect("Invalid encoding in file"); - result.push_str(&decoded); + result.append(&mut bytes); } } } - result.push_str(&*format!("\r\n--{}--", boundary)); + let mut boundary_bytes = format!("\r\n--{}--", boundary).into_bytes(); + result.append(&mut boundary_bytes); result } @@ -351,18 +347,11 @@ impl HTMLFormElement { let charset = &*encoding.whatwg_name().unwrap(); for entry in form_data.iter_mut() { - // Step 4 - if entry.name == "_charset_" && entry.ty == "hidden" { - entry.value = FormDatumValue::String(DOMString::from(charset.clone())); - } - - // Step 5 - if entry.ty == "file" { - entry.value = FormDatumValue::String(DOMString::from(entry.value_str())); - } + // Step 4, 5 + let value = entry.replace_value(charset); // Step 6 - result.push_str(&*format!("{}={}\r\n", entry.name, entry.value_str())); + result.push_str(&*format!("{}={}\r\n", entry.name, value)); } // Step 7 @@ -374,7 +363,7 @@ impl HTMLFormElement { // Step 1 let doc = document_from_node(self); let base = doc.url(); - // TODO: Handle browsing contexts + // TODO: Handle browsing contexts (Step 2, 3) // Step 4 if submit_method_flag == SubmittedFrom::NotFromForm && !submitter.no_validate(self) @@ -397,13 +386,18 @@ impl HTMLFormElement { } // Step 6 let mut form_data = self.get_form_dataset(Some(submitter)); + // Step 7 - let mut action = submitter.action(); + let encoding = self.pick_encoding(); + // Step 8 + let mut action = submitter.action(); + + // Step 9 if action.is_empty() { action = DOMString::from(base.as_str()); } - // Step 9-11 + // Step 10-11 let action_components = match base.join(&action) { Ok(url) => url, Err(_) => return @@ -417,57 +411,87 @@ impl HTMLFormElement { let mut load_data = LoadData::new(action_components, doc.get_referrer_policy(), Some(doc.url().clone())); - let parsed_data = match enctype { + // Step 18 + match (&*scheme, method) { + (_, FormMethod::FormDialog) => { + // TODO: Submit dialog + // https://html.spec.whatwg.org/multipage/#submit-dialog + } + // https://html.spec.whatwg.org/multipage/#submit-mutate-action + ("http", FormMethod::FormGet) | ("https", FormMethod::FormGet) | ("data", FormMethod::FormGet) => { + load_data.headers.set(ContentType::form_url_encoded()); + self.mutate_action_url(&mut form_data, load_data, encoding); + } + // https://html.spec.whatwg.org/multipage/#submit-body + ("http", FormMethod::FormPost) | ("https", FormMethod::FormPost) => { + load_data.method = Method::Post; + self.submit_entity_body(&mut form_data, load_data, enctype, encoding); + } + // https://html.spec.whatwg.org/multipage/#submit-get-action + ("file", _) | ("about", _) | ("data", FormMethod::FormPost) | + ("ftp", _) | ("javascript", _) => { + self.plan_to_navigate(load_data); + } + ("mailto", FormMethod::FormPost) => { + // TODO: Mail as body + // https://html.spec.whatwg.org/multipage/#submit-mailto-body + } + ("mailto", FormMethod::FormGet) => { + // TODO: Mail with headers + // https://html.spec.whatwg.org/multipage/#submit-mailto-headers + } + _ => return, + } + } + + // https://html.spec.whatwg.org/multipage/#submit-mutate-action + fn mutate_action_url(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, encoding: EncodingRef) { + let charset = &*encoding.whatwg_name().unwrap(); + + load_data.url.query_pairs_mut().clear() + .encoding_override(Some(self.pick_encoding())) + .extend_pairs(form_data.into_iter() + .map(|field| (field.name.clone(), field.replace_value(charset)))); + + self.plan_to_navigate(load_data); + } + + // https://html.spec.whatwg.org/multipage/#submit-body + fn submit_entity_body(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, + enctype: FormEncType, encoding: EncodingRef) { + let boundary = self.generate_boundary(); + let bytes = match enctype { FormEncType::UrlEncoded => { + let mut url = load_data.url.clone(); + let charset = &*encoding.whatwg_name().unwrap(); load_data.headers.set(ContentType::form_url_encoded()); - form_urlencoded::Serializer::new(String::new()) - .encoding_override(Some(self.pick_encoding())) - .extend_pairs(form_data.into_iter().map(|field| (field.name.clone(), field.value_str()))) - .finish() + url.query_pairs_mut().clear() + .encoding_override(Some(self.pick_encoding())) + .extend_pairs(form_data.into_iter() + .map(|field| (field.name.clone(), field.replace_value(charset)))); + + url.query().unwrap_or("").to_string().into_bytes() } FormEncType::FormDataEncoded => { - let boundary = self.generate_boundary(); let mime = mime!(Multipart / FormData; Boundary =(&boundary)); load_data.headers.set(ContentType(mime)); - - self.encode_multipart_form_data(&mut form_data, None, boundary) + self.encode_multipart_form_data(form_data, boundary, encoding) } FormEncType::TextPlainEncoded => { load_data.headers.set(ContentType(mime!(Text / Plain))); - - self.encode_plaintext(&mut form_data) + self.encode_plaintext(form_data).into_bytes() } }; - // Step 18 - let win = window_from_node(self); - match (&*scheme, method) { - // https://html.spec.whatwg.org/multipage/#submit-dialog - (_, FormMethod::FormDialog) => return, // Unimplemented - // https://html.spec.whatwg.org/multipage/#submit-mutate-action - ("http", FormMethod::FormGet) | ("https", FormMethod::FormGet) => { - // FIXME(SimonSapin): use url.query_pairs_mut() here. - load_data.url.set_query(Some(&*parsed_data)); - self.plan_to_navigate(load_data, &win); - } - // https://html.spec.whatwg.org/multipage/#submit-body - ("http", FormMethod::FormPost) | ("https", FormMethod::FormPost) => { - load_data.method = Method::Post; - load_data.data = Some(parsed_data.into_bytes()); - self.plan_to_navigate(load_data, &win); - } - // https://html.spec.whatwg.org/multipage/#submit-get-action - ("file", _) | ("about", _) | ("data", FormMethod::FormGet) | - ("ftp", _) | ("javascript", _) => { - self.plan_to_navigate(load_data, &win); - } - _ => return // Unimplemented (data and mailto) - } + load_data.data = Some(bytes); + self.plan_to_navigate(load_data); } /// [Planned navigation](https://html.spec.whatwg.org/multipage/#planned-navigation) - fn plan_to_navigate(&self, load_data: LoadData, window: &Window) { + fn plan_to_navigate(&self, load_data: LoadData) { + let window = window_from_node(self); + // Step 1 // Each planned navigation runnable is tagged with a generation ID, and // before the runnable is handled, it first checks whether the HTMLFormElement's @@ -485,7 +509,7 @@ impl HTMLFormElement { }; // Step 3 - window.dom_manipulation_task_source().queue(nav, GlobalRef::Window(window)).unwrap(); + window.dom_manipulation_task_source().queue(nav, GlobalRef::Window(&window)).unwrap(); } /// Interactively validate the constraints of form elements @@ -558,10 +582,8 @@ impl HTMLFormElement { match element { HTMLElementTypeId::HTMLInputElement => { let input = child.downcast::<HTMLInputElement>().unwrap(); - // Step 3.2-3.7 - if let Some(datum) = input.form_datum(submitter) { - data_set.push(datum); - } + + data_set.append(&mut input.form_datums(submitter)); } HTMLElementTypeId::HTMLButtonElement => { let button = child.downcast::<HTMLButtonElement>().unwrap(); @@ -709,10 +731,14 @@ pub struct FormDatum { } impl FormDatum { - pub fn value_str(&self) -> String { + pub fn replace_value(&self, charset: &str) -> String { + if self.name == "_charset_" && self.ty == "hidden" { + return charset.to_string(); + } + match self.value { + FormDatumValue::File(ref f) => String::from(f.name().clone()), FormDatumValue::String(ref s) => String::from(s.clone()), - FormDatumValue::File(ref f) => String::from(f.name().clone()) } } } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index efd33eecf54..73d750cc8dd 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -38,7 +38,7 @@ use dom::window::{ReflowReason, Window}; use ipc_channel::ipc; use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue}; use js::jsval::{UndefinedValue, NullValue}; -use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId}; +use msg::constellation_msg::{FrameType, LoadData, TraversalDirection, PipelineId, SubpageId}; use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; @@ -419,15 +419,11 @@ unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent, } } - -pub fn Navigate(iframe: &HTMLIFrameElement, direction: NavigationDirection) -> ErrorResult { +pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult { if iframe.Mozbrowser() { if iframe.upcast::<Node>().is_in_doc() { let window = window_from_node(iframe); - - let pipeline_info = Some((window.pipeline(), - iframe.subpage_id().unwrap())); - let msg = ConstellationMsg::Navigate(pipeline_info, direction); + let msg = ConstellationMsg::TraverseHistory(iframe.pipeline(), direction); window.constellation_chan().send(msg).unwrap(); } @@ -500,12 +496,12 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack fn GoBack(&self) -> ErrorResult { - Navigate(self, NavigationDirection::Back(1)) + Navigate(self, TraversalDirection::Back(1)) } // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goForward fn GoForward(&self) -> ErrorResult { - Navigate(self, NavigationDirection::Forward(1)) + Navigate(self, TraversalDirection::Forward(1)) } // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/reload diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 7f524cac29d..a98fcbcfb4e 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -34,9 +34,9 @@ use dom::virtualmethods::VirtualMethods; use ipc_channel::ipc::{self, IpcSender}; use mime_guess; use msg::constellation_msg::Key; -use net_traits::IpcSend; use net_traits::blob_url_store::get_blob_origin; use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; +use net_traits::{IpcSend, CoreResourceMsg}; use script_traits::ScriptMsg as ConstellationMsg; use std::borrow::ToOwned; use std::cell::Cell; @@ -648,7 +648,7 @@ impl HTMLInputElement { /// https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set /// Steps range from 3.1 to 3.7 (specific to HTMLInputElement) - pub fn form_datum(&self, submitter: Option<FormSubmitter>) -> Option<FormDatum> { + pub fn form_datums(&self, submitter: Option<FormSubmitter>) -> Vec<FormDatum> { // 3.1: disabled state check is in get_unclean_dataset // Step 3.2 @@ -664,26 +664,55 @@ impl HTMLInputElement { match ty { // Step 3.1: it's a button but it is not submitter. - atom!("submit") | atom!("button") | atom!("reset") if !is_submitter => return None, + atom!("submit") | atom!("button") | atom!("reset") if !is_submitter => return vec![], // Step 3.1: it's the "Checkbox" or "Radio Button" and whose checkedness is false. atom!("radio") | atom!("checkbox") => if !self.Checked() || name.is_empty() { - return None; + return vec![]; }, + atom!("file") => { + let mut datums = vec![]; + + // Step 3.2-3.7 + let name = self.Name(); + let type_ = self.Type(); + + match self.GetFiles() { + Some(fl) => { + for f in fl.iter_files() { + datums.push(FormDatum { + ty: type_.clone(), + name: name.clone(), + value: FormDatumValue::File(Root::from_ref(&f)), + }); + } + } + None => { + datums.push(FormDatum { + // XXX(izgzhen): Spec says 'application/octet-stream' as the type, + // but this is _type_ of element rather than content right? + ty: type_.clone(), + name: name.clone(), + value: FormDatumValue::String(DOMString::from("")), + }) + } + } - atom!("image") | atom!("file") => return None, // Unimplemented + return datums; + } + atom!("image") => return vec![], // Unimplemented // Step 3.1: it's not the "Image Button" and doesn't have a name attribute. _ => if name.is_empty() { - return None; + return vec![]; } } // Step 3.9 - Some(FormDatum { + vec![FormDatum { ty: DOMString::from(&*ty), // FIXME(ajeffrey): Convert directly from Atoms to DOMStrings name: name, value: FormDatumValue::String(self.Value()) - }) + }] } // https://html.spec.whatwg.org/multipage/#radio-button-group @@ -751,7 +780,7 @@ impl HTMLInputElement { fn select_files(&self, opt_test_paths: Option<Vec<DOMString>>) { let window = window_from_node(self); let origin = get_blob_origin(&window.get_url()); - let filemanager = window.resource_threads().sender(); + let resource_threads = window.resource_threads(); let mut files: Vec<Root<File>> = vec![]; let mut error = None; @@ -764,7 +793,7 @@ impl HTMLInputElement { let (chan, recv) = ipc::channel().expect("Error initializing channel"); let msg = FileManagerThreadMsg::SelectFiles(filter, chan, origin, opt_test_paths); - let _ = filemanager.send(msg).unwrap(); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)).unwrap(); match recv.recv().expect("IpcSender side error") { Ok(selected_files) => { @@ -788,7 +817,7 @@ impl HTMLInputElement { let (chan, recv) = ipc::channel().expect("Error initializing channel"); let msg = FileManagerThreadMsg::SelectFile(filter, chan, origin, opt_test_path); - let _ = filemanager.send(msg).unwrap(); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)).unwrap(); match recv.recv().expect("IpcSender side error") { Ok(selected) => { diff --git a/components/script/dom/htmllielement.rs b/components/script/dom/htmllielement.rs index 444fc37827c..32915a5c351 100644 --- a/components/script/dom/htmllielement.rs +++ b/components/script/dom/htmllielement.rs @@ -3,12 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::HTMLLIElementBinding; +use dom::bindings::codegen::Bindings::HTMLLIElementBinding::HTMLLIElementMethods; +use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::str::DOMString; use dom::document::Document; use dom::htmlelement::HTMLElement; use dom::node::Node; +use dom::virtualmethods::VirtualMethods; use string_cache::Atom; +use style::attr::AttrValue; #[dom_struct] pub struct HTMLLIElement { @@ -31,3 +35,24 @@ impl HTMLLIElement { HTMLLIElementBinding::Wrap) } } + +impl HTMLLIElementMethods for HTMLLIElement { + // https://html.spec.whatwg.org/multipage/#dom-li-value + make_int_getter!(Value, "value"); + + // https://html.spec.whatwg.org/multipage/#dom-li-value + make_int_setter!(SetValue, "value"); +} + +impl VirtualMethods for HTMLLIElement { + fn super_type(&self) -> Option<&VirtualMethods> { + Some(self.upcast::<HTMLElement>() as &VirtualMethods) + } + + fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue { + match name { + &atom!("value") => AttrValue::from_i32(value.into(), 0), + _ => self.super_type().unwrap().parse_plain_attribute(name, value), + } + } +} diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index d089caed3f5..0d5ae4ee179 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -22,6 +22,7 @@ use dom::virtualmethods::VirtualMethods; use encoding::EncodingRef; use encoding::all::UTF_8; use hyper::header::ContentType; +use hyper::http::RawStatus; use hyper::mime::{Mime, TopLevel, SubLevel}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; @@ -296,15 +297,18 @@ impl AsyncResponseListener for StylesheetContext { fn response_complete(&mut self, status: Result<(), NetworkError>) { let elem = self.elem.root(); let document = document_from_node(&*elem); + let mut successful = false; - if status.is_err() { - self.elem.root().upcast::<EventTarget>().fire_simple_event("error"); - } else { - let data = mem::replace(&mut self.data, vec!()); + if status.is_ok() { let metadata = match self.metadata.take() { Some(meta) => meta, None => return, }; + let is_css = metadata.content_type.map_or(false, |ContentType(Mime(top, sub, _))| + top == TopLevel::Text && sub == SubLevel::Css); + + let data = if is_css { mem::replace(&mut self.data, vec!()) } else { vec!() }; + // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding let environment_encoding = UTF_8 as EncodingRef; let protocol_encoding_label = metadata.charset.as_ref().map(|s| &**s); @@ -328,6 +332,9 @@ impl AsyncResponseListener for StylesheetContext { *elem.stylesheet.borrow_mut() = Some(sheet); document.invalidate_stylesheets(); + + // FIXME: Revisit once consensus is reached at: https://github.com/whatwg/html/issues/1142 + successful = metadata.status.map_or(false, |RawStatus(code, _)| code == 200); } if elem.parser_inserted.get() { @@ -335,6 +342,10 @@ impl AsyncResponseListener for StylesheetContext { } document.finish_load(LoadType::Stylesheet(self.url.clone())); + + let event = if successful { "load" } else { "error" }; + + elem.upcast::<EventTarget>().fire_simple_event(event); } } diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 7a94768c13a..119139ae6d8 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -35,6 +35,8 @@ use string_cache::Atom; use task_source::TaskSource; use time::{self, Timespec, Duration}; use url::Url; +#[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))] +use video_metadata; struct HTMLMediaElementContext { /// The element that initiated the request. @@ -75,12 +77,11 @@ impl AsyncResponseListener for HTMLMediaElementContext { } } - fn data_available(&mut self, payload: Vec<u8>) { + fn data_available(&mut self, mut payload: Vec<u8>) { if self.ignore_response { return; } - let mut payload = payload; self.data.append(&mut payload); let elem = self.elem.root(); @@ -88,11 +89,7 @@ impl AsyncResponseListener for HTMLMediaElementContext { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "Once enough of the media data has been fetched to determine the duration..." if !self.have_metadata { - //TODO: actually check if the payload contains the full metadata - - // Step 6 - elem.change_ready_state(HAVE_METADATA); - self.have_metadata = true; + self.check_metadata(&elem); } else { elem.change_ready_state(HAVE_CURRENT_DATA); } @@ -162,6 +159,46 @@ impl HTMLMediaElementContext { ignore_response: false, } } + + #[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))] + fn check_metadata(&mut self, elem: &HTMLMediaElement) { + match video_metadata::get_format_from_slice(&self.data) { + Ok(meta) => { + let dur = meta.duration.unwrap_or(::std::time::Duration::new(0, 0)); + *elem.video.borrow_mut() = Some(VideoMedia { + format: format!("{:?}", meta.format), + duration: Duration::seconds(dur.as_secs() as i64) + + Duration::nanoseconds(dur.subsec_nanos() as i64), + width: meta.size.width, + height: meta.size.height, + video: meta.video, + audio: meta.audio, + }); + // Step 6 + elem.change_ready_state(HAVE_METADATA); + self.have_metadata = true; + } + _ => {} + } + } + + #[cfg(any(target_os = "android", target_arch = "arm", target_arch = "aarch64"))] + fn check_metadata(&mut self, elem: &HTMLMediaElement) { + // Step 6. + elem.change_ready_state(HAVE_METADATA); + self.have_metadata = true; + } +} + +#[derive(JSTraceable, HeapSizeOf)] +pub struct VideoMedia { + format: String, + #[ignore_heap_size_of = "defined in time"] + duration: Duration, + width: u32, + height: u32, + video: String, + audio: Option<String>, } #[dom_struct] @@ -175,6 +212,7 @@ pub struct HTMLMediaElement { error: MutNullableHeap<JS<MediaError>>, paused: Cell<bool>, autoplaying: Cell<bool>, + video: DOMRefCell<Option<VideoMedia>>, } impl HTMLMediaElement { @@ -192,6 +230,7 @@ impl HTMLMediaElement { error: Default::default(), paused: Cell::new(true), autoplaying: Cell::new(true), + video: DOMRefCell::new(None), } } diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index 4cff33b78a1..1d189f4a21f 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -34,6 +34,20 @@ pub struct HTMLTableElement { tbodies: MutNullableHeap<JS<HTMLCollection>>, } +#[allow(unrooted_must_root)] +#[derive(JSTraceable, HeapSizeOf)] +struct TableRowFilter { + sections: Vec<JS<Node>>, +} + +impl CollectionFilter for TableRowFilter { + fn filter(&self, elem: &Element, root: &Node) -> bool { + elem.is::<HTMLTableRowElement>() && + (root.is_parent_of(elem.upcast()) + || self.sections.iter().any(|ref section| section.is_parent_of(elem.upcast()))) + } +} + impl HTMLTableElement { fn new_inherited(localName: Atom, prefix: Option<DOMString>, document: &Document) -> HTMLTableElement { @@ -120,32 +134,22 @@ impl HTMLTableElement { thead.upcast::<Node>().remove_self(); } } -} - -impl HTMLTableElementMethods for HTMLTableElement { - // https://html.spec.whatwg.org/multipage/#dom-table-rows - fn Rows(&self) -> Root<HTMLCollection> { - #[allow(unrooted_must_root)] - #[derive(JSTraceable, HeapSizeOf)] - struct TableRowFilter { - sections: Vec<JS<Node>> - } - - impl CollectionFilter for TableRowFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - elem.is::<HTMLTableRowElement>() && - (root.is_parent_of(elem.upcast()) - || self.sections.iter().any(|ref section| section.is_parent_of(elem.upcast()))) - } - } - let filter = TableRowFilter { + fn get_rows(&self) -> TableRowFilter { + TableRowFilter { sections: self.upcast::<Node>() .children() .filter_map(|ref node| node.downcast::<HTMLTableSectionElement>().map(|_| JS::from_ref(&**node))) .collect() - }; + } + } +} + +impl HTMLTableElementMethods for HTMLTableElement { + // https://html.spec.whatwg.org/multipage/#dom-table-rows + fn Rows(&self) -> Root<HTMLCollection> { + let filter = self.get_rows(); HTMLCollection::new(window_from_node(self).r(), self.upcast(), box filter) } @@ -338,6 +342,22 @@ impl HTMLTableElementMethods for HTMLTableElement { Ok(new_row) } + // https://html.spec.whatwg.org/multipage/#dom-table-deleterow + fn DeleteRow(&self, mut index: i32) -> Fallible<()> { + let rows = self.Rows(); + // Step 1. + if index == -1 { + index = rows.Length() as i32 - 1; + } + // Step 2. + if index < 0 || index as u32 >= rows.Length() { + return Err(Error::IndexSize); + } + // Step 3. + Root::upcast::<Node>(rows.Item(index as u32).unwrap()).remove_self(); + Ok(()) + } + // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor make_getter!(BgColor, "bgcolor"); diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 58af2b28ac6..2b29ec8014c 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -47,6 +47,22 @@ macro_rules! make_limited_int_setter( ); #[macro_export] +macro_rules! make_int_setter( + ($attr:ident, $htmlname:tt, $default:expr) => ( + fn $attr(&self, value: i32) { + use dom::bindings::inheritance::Castable; + use dom::element::Element; + + let element = self.upcast::<Element>(); + element.set_int_attribute(&atom!($htmlname), value) + } + ); + ($attr:ident, $htmlname:tt) => { + make_int_setter!($attr, $htmlname, 0); + }; +); + +#[macro_export] macro_rules! make_int_getter( ($attr:ident, $htmlname:tt, $default:expr) => ( fn $attr(&self) -> i32 { diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 172026c4d8e..a2112526228 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -265,11 +265,13 @@ pub mod eventtarget; pub mod file; pub mod filelist; pub mod filereader; +pub mod filereadersync; pub mod focusevent; pub mod forcetouchevent; pub mod formdata; pub mod hashchangeevent; pub mod headers; +pub mod history; pub mod htmlanchorelement; pub mod htmlappletelement; pub mod htmlareaelement; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 37495be3ba3..2769b7503bc 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -479,19 +479,7 @@ impl Node { return } - // 2. Dirty descendants. - fn dirty_subtree(node: &Node) { - // Stop if this subtree is already dirty. - if node.is_dirty() { return } - - node.set_flag(IS_DIRTY | HAS_DIRTY_DESCENDANTS, true); - - for kid in node.children() { - dirty_subtree(kid.r()); - } - } - - dirty_subtree(self); + self.set_flag(IS_DIRTY, true); // 4. Dirty ancestors. for ancestor in self.ancestors() { @@ -1299,22 +1287,17 @@ impl TreeIterator { depth: 0, } } -} -impl Iterator for TreeIterator { - type Item = Root<Node>; - - // https://dom.spec.whatwg.org/#concept-tree-order - fn next(&mut self) -> Option<Root<Node>> { + pub fn next_skipping_children(&mut self) -> Option<Root<Node>> { let current = match self.current.take() { None => return None, Some(current) => current, }; - if let Some(first_child) = current.GetFirstChild() { - self.current = Some(first_child); - self.depth += 1; - return Some(current); - }; + + self.next_skipping_children_impl(current) + } + + fn next_skipping_children_impl(&mut self, current: Root<Node>) -> Option<Root<Node>> { for ancestor in current.inclusive_ancestors() { if self.depth == 0 { break; @@ -1331,6 +1314,25 @@ impl Iterator for TreeIterator { } } +impl Iterator for TreeIterator { + type Item = Root<Node>; + + // https://dom.spec.whatwg.org/#concept-tree-order + fn next(&mut self) -> Option<Root<Node>> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }; + if let Some(first_child) = current.GetFirstChild() { + self.current = Some(first_child); + self.depth += 1; + return Some(current); + }; + + self.next_skipping_children_impl(current) + } +} + /// Specifies whether children must be recursively cloned or not. #[derive(Copy, Clone, PartialEq, HeapSizeOf)] pub enum CloneChildrenFlag { diff --git a/components/script/dom/serviceworkercontainer.rs b/components/script/dom/serviceworkercontainer.rs index 17fea7100be..4487c064fe1 100644 --- a/components/script/dom/serviceworkercontainer.rs +++ b/components/script/dom/serviceworkercontainer.rs @@ -6,6 +6,7 @@ use dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::Registratio use dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::{ServiceWorkerContainerMethods, Wrap}; use dom::bindings::error::{Error, Fallible}; use dom::bindings::global::GlobalRef; +use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::USVString; @@ -41,7 +42,8 @@ pub trait Controllable { impl Controllable for ServiceWorkerContainer { fn set_controller(&self, active_worker: &ServiceWorker) { - self.controller.set(Some(active_worker)) + self.controller.set(Some(active_worker)); + self.upcast::<EventTarget>().fire_simple_event("controllerchange"); } } diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 4841e0ff08a..dc8a8788a61 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -15,6 +15,7 @@ use dom::bindings::js::{Root, RootCollection}; use dom::bindings::refcounted::LiveDOMReferences; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; +use dom::eventtarget::EventTarget; use dom::messageevent::MessageEvent; use dom::serviceworker::TrustedServiceWorkerAddress; use dom::workerglobalscope::WorkerGlobalScope; @@ -24,7 +25,8 @@ use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext}; use js::jsval::UndefinedValue; use js::rust::Runtime; use msg::constellation_msg::PipelineId; -use net_traits::{LoadContext, load_whole_resource, IpcSend}; +use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator}; +use rand::random; use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx}; use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg}; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; @@ -36,8 +38,16 @@ use util::thread::spawn_named; use util::thread_state; use util::thread_state::{IN_WORKER, SCRIPT}; +/// Messages used to control service worker event loop +pub enum ServiceWorkerScriptMsg { + /// Message common to all workers + CommonWorker(WorkerScriptMsg), + // Message to request a custom response by the service worker + Response(CustomResponseMediator) +} + pub enum MixedMessage { - FromServiceWorker((TrustedServiceWorkerAddress, WorkerScriptMsg)), + FromServiceWorker(ServiceWorkerScriptMsg), FromDevtools(DevtoolScriptControlMsg), FromTimeoutThread(()), } @@ -47,9 +57,9 @@ pub struct ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, id: PipelineId, #[ignore_heap_size_of = "Defined in std"] - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + receiver: Receiver<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] timer_event_port: Receiver<()>, #[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"] @@ -66,8 +76,8 @@ impl ServiceWorkerGlobalScope { id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, timer_event_chan: IpcSender<TimerEvent>, timer_event_port: Receiver<()>, swmanager_sender: IpcSender<ServiceWorkerMsg>, @@ -95,8 +105,8 @@ impl ServiceWorkerGlobalScope { id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, timer_event_chan: IpcSender<TimerEvent>, timer_event_port: Receiver<()>, swmanager_sender: IpcSender<ServiceWorkerMsg>, @@ -119,8 +129,8 @@ impl ServiceWorkerGlobalScope { #[allow(unsafe_code)] pub fn run_serviceworker_scope(scope_things: ScopeThings, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, swmanager_sender: IpcSender<ServiceWorkerMsg>, scope_url: Url) { @@ -152,11 +162,9 @@ impl ServiceWorkerGlobalScope { let (devtools_mpsc_chan, devtools_mpsc_port) = channel(); ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_receiver, devtools_mpsc_chan); - // TODO XXXcreativcoder use this timer_ipc_port, when we have a service worker instance here let (timer_ipc_chan, _timer_ipc_port) = ipc::channel().unwrap(); let (timer_chan, timer_port) = channel(); - let global = ServiceWorkerGlobalScope::new( init, url, pipeline_id, devtools_mpsc_port, runtime, own_sender, receiver, @@ -169,7 +177,6 @@ impl ServiceWorkerGlobalScope { } scope.execute_script(DOMString::from(source)); - // Service workers are time limited spawn_named("SWTimeoutThread".to_owned(), move || { let sw_lifetime_timeout = PREFS.get("dom.serviceworker.timeout_seconds").as_u64().unwrap(); @@ -177,12 +184,15 @@ impl ServiceWorkerGlobalScope { let _ = timer_chan.send(()); }); - // TODO XXXcreativcoder bring back run_with_memory_reporting when things are more concrete here. - while let Ok(event) = global.receive_event() { - if !global.handle_event(event) { - break; + scope.upcast::<EventTarget>().fire_simple_event("activate"); + let reporter_name = format!("service-worker-reporter-{}", random::<u64>()); + scope.mem_profiler_chan().run_with_memory_reporting(|| { + while let Ok(event) = global.receive_event() { + if !global.handle_event(event) { + break; + } } - } + }, reporter_name, scope.script_chan(), CommonScriptMsg::CollectReports); }); } @@ -201,7 +211,7 @@ impl ServiceWorkerGlobalScope { } true } - MixedMessage::FromServiceWorker((_, msg)) => { + MixedMessage::FromServiceWorker(msg) => { self.handle_script_event(msg); true } @@ -212,9 +222,11 @@ impl ServiceWorkerGlobalScope { } } - fn handle_script_event(&self, msg: WorkerScriptMsg) { + fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) { + use self::ServiceWorkerScriptMsg::*; + match msg { - WorkerScriptMsg::DOMMessage(data) => { + CommonWorker(WorkerScriptMsg::DOMMessage(data)) => { let scope = self.upcast::<WorkerGlobalScope>(); let target = self.upcast(); let _ac = JSAutoCompartment::new(scope.get_cx(), @@ -223,19 +235,26 @@ impl ServiceWorkerGlobalScope { data.read(GlobalRef::Worker(scope), message.handle_mut()); MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle()); }, - WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable))) => { runnable.handler() }, - WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr))) => { LiveDOMReferences::cleanup(addr); }, - WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan))) => { let scope = self.upcast::<WorkerGlobalScope>(); let cx = scope.get_cx(); let path_seg = format!("url({})", scope.get_url()); let reports = get_reports(cx, path_seg); reports_chan.send(reports); }, + Response(mediator) => { + // TODO XXXcreativcoder This will eventually use a FetchEvent interface to fire event + // when we have the Request and Response dom api's implemented + // https://slightlyoff.github.io/ServiceWorker/spec/service_worker_1/index.html#fetch-event-section + self.upcast::<EventTarget>().fire_simple_event("fetch"); + let _ = mediator.response_chan.send(None); + } } } @@ -275,7 +294,7 @@ impl ServiceWorkerGlobalScope { } pub fn process_event(&self, msg: CommonScriptMsg) { - self.handle_script_event(WorkerScriptMsg::Common(msg)); + self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg))); } } diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index a28612416fc..09ee38a1232 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -7,13 +7,18 @@ use document_loader::LoadType; use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; +use dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods; +use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::ServoHTMLParserBinding; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, Root}; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::str::DOMString; use dom::bindings::trace::JSTraceable; use dom::document::Document; +use dom::htmlimageelement::HTMLImageElement; use dom::node::Node; use dom::window::Window; use encoding::all::UTF_8; @@ -112,13 +117,20 @@ impl AsyncResponseListener for ParserContext { match content_type { Some(ContentType(Mime(TopLevel::Image, _, _))) => { self.is_synthesized_document = true; - let page = format!("<html><body><img src='{}' /></body></html>", self.url); + let page = "<html><body></body></html>".into(); parser.pending_input().borrow_mut().push(page); parser.parse_sync(); + + let doc = parser.document(); + let doc_body = Root::upcast::<Node>(doc.GetBody().unwrap()); + let img = HTMLImageElement::new(atom!("img"), None, doc); + img.SetSrc(DOMString::from(self.url.to_string())); + doc_body.AppendChild(&Root::upcast::<Node>(img)).expect("Appending failed"); + }, Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => { // https://html.spec.whatwg.org/multipage/#read-text - let page = format!("<pre>\n"); + let page = "<pre>\n".into(); parser.pending_input().borrow_mut().push(page); parser.parse_sync(); parser.set_plaintext_state(); diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index c117c6a31aa..13579d71330 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -11,6 +11,7 @@ use dom::bindings::codegen::Bindings::TestBindingBinding::{TestBindingMethods, T use dom::bindings::codegen::Bindings::TestBindingBinding::{TestDictionaryDefaults, TestEnum}; use dom::bindings::codegen::UnionTypes::{BlobOrBoolean, BlobOrBlobSequence, LongOrLongSequenceSequence}; use dom::bindings::codegen::UnionTypes::{BlobOrString, BlobOrUnsignedLong, EventOrString}; +use dom::bindings::codegen::UnionTypes::{ByteStringOrLong, ByteStringSequenceOrLongOrString, ByteStringSequenceOrLong}; use dom::bindings::codegen::UnionTypes::{EventOrUSVString, HTMLElementOrLong}; use dom::bindings::codegen::UnionTypes::{HTMLElementOrUnsignedLongOrStringOrBoolean, LongSequenceOrBoolean}; use dom::bindings::codegen::UnionTypes::{StringOrLongSequence, StringOrStringSequence, StringSequenceOrUnsignedLong}; @@ -132,6 +133,10 @@ impl TestBindingMethods for TestBinding { BlobOrUnsignedLong::UnsignedLong(0u32) } fn SetUnion8Attribute(&self, _: BlobOrUnsignedLong) {} + fn Union9Attribute(&self) -> ByteStringOrLong { + ByteStringOrLong::ByteString(ByteString::new(vec!())) + } + fn SetUnion9Attribute(&self, _: ByteStringOrLong) {} fn ArrayAttribute(&self, _: *mut JSContext) -> *mut JSObject { NullValue().to_object_or_null() } fn AnyAttribute(&self, _: *mut JSContext) -> JSVal { NullValue() } fn SetAnyAttribute(&self, _: *mut JSContext, _: HandleValue) {} @@ -210,6 +215,10 @@ impl TestBindingMethods for TestBinding { Some(StringOrBoolean::Boolean(true)) } fn SetUnion5AttributeNullable(&self, _: Option<StringOrBoolean>) {} + fn GetUnion6AttributeNullable(&self) -> Option<ByteStringOrLong> { + Some(ByteStringOrLong::ByteString(ByteString::new(vec!()))) + } + fn SetUnion6AttributeNullable(&self, _: Option<ByteStringOrLong>) {} fn BinaryRenamedMethod(&self) -> () {} fn ReceiveVoid(&self) -> () {} fn ReceiveBoolean(&self) -> bool { false } @@ -245,6 +254,10 @@ impl TestBindingMethods for TestBinding { fn ReceiveUnion9(&self) -> HTMLElementOrUnsignedLongOrStringOrBoolean { HTMLElementOrUnsignedLongOrStringOrBoolean::Boolean(true) } + fn ReceiveUnion10(&self) -> ByteStringOrLong { ByteStringOrLong::ByteString(ByteString::new(vec!())) } + fn ReceiveUnion11(&self) -> ByteStringSequenceOrLongOrString { + ByteStringSequenceOrLongOrString::ByteStringSequence(vec!(ByteString::new(vec!()))) + } fn ReceiveSequence(&self) -> Vec<i32> { vec![1] } fn ReceiveInterfaceSequence(&self) -> Vec<Root<Blob>> { vec![Blob::new(self.global().r(), BlobImpl::new_from_bytes(vec![]), "".to_owned())] @@ -286,6 +299,9 @@ impl TestBindingMethods for TestBinding { fn ReceiveNullableUnion5(&self) -> Option<UnsignedLongOrBoolean> { Some(UnsignedLongOrBoolean::UnsignedLong(0u32)) } + fn ReceiveNullableUnion6(&self) -> Option<ByteStringOrLong> { + Some(ByteStringOrLong::ByteString(ByteString::new(vec!()))) + } fn ReceiveNullableSequence(&self) -> Option<Vec<i32>> { Some(vec![1]) } fn ReceiveTestDictionaryWithSuccessOnKeyword(&self) -> TestDictionary { TestDictionary { @@ -382,6 +398,7 @@ impl TestBindingMethods for TestBinding { fn PassUnion5(&self, _: StringOrBoolean) {} fn PassUnion6(&self, _: UnsignedLongOrBoolean) {} fn PassUnion7(&self, _: StringSequenceOrUnsignedLong) {} + fn PassUnion8(&self, _: ByteStringSequenceOrLong) {} fn PassAny(&self, _: *mut JSContext, _: HandleValue) {} fn PassObject(&self, _: *mut JSContext, _: *mut JSObject) {} fn PassCallbackFunction(&self, _: Rc<Function>) {} @@ -414,6 +431,7 @@ impl TestBindingMethods for TestBinding { fn PassNullableUnion3(&self, _: Option<StringOrLongSequence>) {} fn PassNullableUnion4(&self, _: Option<LongSequenceOrBoolean>) {} fn PassNullableUnion5(&self, _: Option<UnsignedLongOrBoolean>) {} + fn PassNullableUnion6(&self, _: Option<ByteStringOrLong>) {} fn PassNullableCallbackFunction(&self, _: Option<Rc<Function>>) {} fn PassNullableCallbackInterface(&self, _: Option<Rc<EventListener>>) {} fn PassNullableSequence(&self, _: Option<Vec<i32>>) {} @@ -441,6 +459,7 @@ impl TestBindingMethods for TestBinding { fn PassOptionalUnion3(&self, _: Option<StringOrLongSequence>) {} fn PassOptionalUnion4(&self, _: Option<LongSequenceOrBoolean>) {} fn PassOptionalUnion5(&self, _: Option<UnsignedLongOrBoolean>) {} + fn PassOptionalUnion6(&self, _: Option<ByteStringOrLong>) {} fn PassOptionalAny(&self, _: *mut JSContext, _: HandleValue) {} fn PassOptionalObject(&self, _: *mut JSContext, _: Option<*mut JSObject>) {} fn PassOptionalCallbackFunction(&self, _: Option<Rc<Function>>) {} @@ -471,6 +490,7 @@ impl TestBindingMethods for TestBinding { fn PassOptionalNullableUnion3(&self, _: Option<Option<StringOrLongSequence>>) {} fn PassOptionalNullableUnion4(&self, _: Option<Option<LongSequenceOrBoolean>>) {} fn PassOptionalNullableUnion5(&self, _: Option<Option<UnsignedLongOrBoolean>>) {} + fn PassOptionalNullableUnion6(&self, _: Option<Option<ByteStringOrLong>>) {} fn PassOptionalNullableCallbackFunction(&self, _: Option<Option<Rc<Function>>>) {} fn PassOptionalNullableCallbackInterface(&self, _: Option<Option<Rc<EventListener>>>) {} fn PassOptionalNullableSequence(&self, _: Option<Option<Vec<i32>>>) {} @@ -555,6 +575,7 @@ impl TestBindingMethods for TestBinding { fn PassVariadicUnion4(&self, _: Vec<BlobOrBoolean>) {} fn PassVariadicUnion5(&self, _: Vec<StringOrUnsignedLong>) {} fn PassVariadicUnion6(&self, _: Vec<UnsignedLongOrBoolean>) {} + fn PassVariadicUnion7(&self, _: Vec<ByteStringOrLong>) {} fn PassVariadicAny(&self, _: *mut JSContext, _: Vec<HandleValue>) {} fn PassVariadicObject(&self, _: *mut JSContext, _: Vec<*mut JSObject>) {} fn BooleanMozPreference(&self, pref_name: DOMString) -> bool { diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs index 81c806de806..768dabf1475 100644 --- a/components/script/dom/url.rs +++ b/components/script/dom/url.rs @@ -14,9 +14,9 @@ use dom::blob::Blob; use dom::urlhelper::UrlHelper; use dom::urlsearchparams::URLSearchParams; use ipc_channel::ipc; -use net_traits::IpcSend; use net_traits::blob_url_store::{get_blob_origin, parse_blob_url}; use net_traits::filemanager_thread::{SelectedFileId, FileManagerThreadMsg}; +use net_traits::{IpcSend, CoreResourceMsg}; use std::borrow::ToOwned; use std::default::Default; use url::quirks::domain_to_unicode; @@ -145,11 +145,11 @@ impl URL { if let Ok(url) = Url::parse(&url) { if let Ok((id, _, _)) = parse_blob_url(&url) { - let filemanager = global.resource_threads().sender(); + let resource_threads = global.resource_threads(); let id = SelectedFileId(id.simple().to_string()); let (tx, rx) = ipc::channel().unwrap(); let msg = FileManagerThreadMsg::RevokeBlobURL(id, origin, tx); - let _ = filemanager.send(msg); + let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)); let _ = rx.recv().unwrap(); } diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index b42e8b676c3..d4cf1609568 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -29,6 +29,7 @@ use dom::htmliframeelement::HTMLIFrameElement; use dom::htmlimageelement::HTMLImageElement; use dom::htmlinputelement::HTMLInputElement; use dom::htmllabelelement::HTMLLabelElement; +use dom::htmllielement::HTMLLIElement; use dom::htmllinkelement::HTMLLinkElement; use dom::htmlmediaelement::HTMLMediaElement; use dom::htmlmetaelement::HTMLMetaElement; @@ -179,6 +180,9 @@ pub fn vtable_for(node: &Node) -> &VirtualMethods { NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => { node.downcast::<HTMLLabelElement>().unwrap() as &VirtualMethods } + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLIElement)) => { + node.downcast::<HTMLLIElement>().unwrap() as &VirtualMethods + } NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => { node.downcast::<HTMLLinkElement>().unwrap() as &VirtualMethods } diff --git a/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl b/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl index cd0d393e22e..53996ee3965 100644 --- a/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl +++ b/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl @@ -8,4 +8,6 @@ [Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/); attribute EventHandler onmessage; + + void close(); }; diff --git a/components/script/dom/webidls/FileReaderSync.webidl b/components/script/dom/webidls/FileReaderSync.webidl new file mode 100644 index 00000000000..cbc18a47921 --- /dev/null +++ b/components/script/dom/webidls/FileReaderSync.webidl @@ -0,0 +1,15 @@ +/* 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/. */ + +// https://w3c.github.io/FileAPI/#FileReaderSync + +[Constructor, Exposed=Worker] +interface FileReaderSync { + // Synchronously return strings + + // ArrayBuffer readAsArrayBuffer(Blob blob); + // DOMString readAsBinaryString(Blob blob); + // DOMString readAsText(Blob blob, optional DOMString label); + // DOMString readAsDataURL(Blob blob); +}; diff --git a/components/script/dom/webidls/HTMLAnchorElement.webidl b/components/script/dom/webidls/HTMLAnchorElement.webidl index c728744e495..f78d1dae6dd 100644 --- a/components/script/dom/webidls/HTMLAnchorElement.webidl +++ b/components/script/dom/webidls/HTMLAnchorElement.webidl @@ -11,7 +11,6 @@ */ // https://html.spec.whatwg.org/multipage/#htmlanchorelement -[Exposed=(Window,Worker)] interface HTMLAnchorElement : HTMLElement { attribute DOMString target; // attribute DOMString download; diff --git a/components/script/dom/webidls/HTMLAppletElement.webidl b/components/script/dom/webidls/HTMLAppletElement.webidl index efb3d24b2e7..9cfeb4183df 100644 --- a/components/script/dom/webidls/HTMLAppletElement.webidl +++ b/components/script/dom/webidls/HTMLAppletElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlappletelement -[Exposed=(Window,Worker)] interface HTMLAppletElement : HTMLElement { // attribute DOMString align; // attribute DOMString alt; diff --git a/components/script/dom/webidls/HTMLAreaElement.webidl b/components/script/dom/webidls/HTMLAreaElement.webidl index f39db4fa4d2..14883df3613 100644 --- a/components/script/dom/webidls/HTMLAreaElement.webidl +++ b/components/script/dom/webidls/HTMLAreaElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlareaelement -[Exposed=(Window,Worker)] interface HTMLAreaElement : HTMLElement { // attribute DOMString alt; // attribute DOMString coords; diff --git a/components/script/dom/webidls/HTMLAudioElement.webidl b/components/script/dom/webidls/HTMLAudioElement.webidl index df0710b1856..09ad8a7cdb3 100644 --- a/components/script/dom/webidls/HTMLAudioElement.webidl +++ b/components/script/dom/webidls/HTMLAudioElement.webidl @@ -4,5 +4,4 @@ // https://html.spec.whatwg.org/multipage/#htmlaudioelement //[NamedConstructor=Audio(optional DOMString src)] -[Exposed=(Window,Worker)] interface HTMLAudioElement : HTMLMediaElement {}; diff --git a/components/script/dom/webidls/HTMLBRElement.webidl b/components/script/dom/webidls/HTMLBRElement.webidl index 4d811f3e285..ab277396bdd 100644 --- a/components/script/dom/webidls/HTMLBRElement.webidl +++ b/components/script/dom/webidls/HTMLBRElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbrelement -[Exposed=(Window,Worker)] interface HTMLBRElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLBaseElement.webidl b/components/script/dom/webidls/HTMLBaseElement.webidl index dee9895c8ef..a13be544cb9 100644 --- a/components/script/dom/webidls/HTMLBaseElement.webidl +++ b/components/script/dom/webidls/HTMLBaseElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbaseelement -[Exposed=(Window,Worker)] interface HTMLBaseElement : HTMLElement { attribute DOMString href; // attribute DOMString target; diff --git a/components/script/dom/webidls/HTMLBodyElement.webidl b/components/script/dom/webidls/HTMLBodyElement.webidl index 31097e75614..36c6f4d64e3 100644 --- a/components/script/dom/webidls/HTMLBodyElement.webidl +++ b/components/script/dom/webidls/HTMLBodyElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#the-body-element -[Exposed=(Window,Worker)] interface HTMLBodyElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLButtonElement.webidl b/components/script/dom/webidls/HTMLButtonElement.webidl index a5c689cbc46..7f663fd305f 100644 --- a/components/script/dom/webidls/HTMLButtonElement.webidl +++ b/components/script/dom/webidls/HTMLButtonElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbuttonelement -[Exposed=(Window,Worker)] interface HTMLButtonElement : HTMLElement { // attribute boolean autofocus; attribute boolean disabled; diff --git a/components/script/dom/webidls/HTMLDListElement.webidl b/components/script/dom/webidls/HTMLDListElement.webidl index e0420cf8418..b6275107db5 100644 --- a/components/script/dom/webidls/HTMLDListElement.webidl +++ b/components/script/dom/webidls/HTMLDListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldlistelement -[Exposed=(Window,Worker)] interface HTMLDListElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLDataElement.webidl b/components/script/dom/webidls/HTMLDataElement.webidl index e0b2aa2cafa..be932250678 100644 --- a/components/script/dom/webidls/HTMLDataElement.webidl +++ b/components/script/dom/webidls/HTMLDataElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldataelement -[Exposed=(Window,Worker)] interface HTMLDataElement : HTMLElement { // attribute DOMString value; }; diff --git a/components/script/dom/webidls/HTMLDataListElement.webidl b/components/script/dom/webidls/HTMLDataListElement.webidl index c970ae495fb..b8673b21c77 100644 --- a/components/script/dom/webidls/HTMLDataListElement.webidl +++ b/components/script/dom/webidls/HTMLDataListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldatalistelement -[Exposed=(Window,Worker)] interface HTMLDataListElement : HTMLElement { readonly attribute HTMLCollection options; }; diff --git a/components/script/dom/webidls/HTMLDetailsElement.webidl b/components/script/dom/webidls/HTMLDetailsElement.webidl index 8dbffdea064..811465c1c02 100644 --- a/components/script/dom/webidls/HTMLDetailsElement.webidl +++ b/components/script/dom/webidls/HTMLDetailsElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldetailselement -[Exposed=(Window,Worker)] interface HTMLDetailsElement : HTMLElement { attribute boolean open; }; diff --git a/components/script/dom/webidls/HTMLDialogElement.webidl b/components/script/dom/webidls/HTMLDialogElement.webidl index 82d11ea2cae..78a14e1e2a0 100644 --- a/components/script/dom/webidls/HTMLDialogElement.webidl +++ b/components/script/dom/webidls/HTMLDialogElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldialogelement -[Exposed=(Window,Worker)] interface HTMLDialogElement : HTMLElement { attribute boolean open; attribute DOMString returnValue; diff --git a/components/script/dom/webidls/HTMLDirectoryElement.webidl b/components/script/dom/webidls/HTMLDirectoryElement.webidl index 4a1d8af74ab..5df65cd90c2 100644 --- a/components/script/dom/webidls/HTMLDirectoryElement.webidl +++ b/components/script/dom/webidls/HTMLDirectoryElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldirectoryelement -[Exposed=(Window,Worker)] interface HTMLDirectoryElement : HTMLElement { // attribute boolean compact; }; diff --git a/components/script/dom/webidls/HTMLDivElement.webidl b/components/script/dom/webidls/HTMLDivElement.webidl index 827dfe7ab49..46ee67ee0e5 100644 --- a/components/script/dom/webidls/HTMLDivElement.webidl +++ b/components/script/dom/webidls/HTMLDivElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldivelement -[Exposed=(Window,Worker)] interface HTMLDivElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLEmbedElement.webidl b/components/script/dom/webidls/HTMLEmbedElement.webidl index 3e4063c9377..26fa4c3ea5a 100644 --- a/components/script/dom/webidls/HTMLEmbedElement.webidl +++ b/components/script/dom/webidls/HTMLEmbedElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlembedelement -[Exposed=(Window,Worker)] interface HTMLEmbedElement : HTMLElement { // attribute DOMString src; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLFieldSetElement.webidl b/components/script/dom/webidls/HTMLFieldSetElement.webidl index 6c05b23f9ae..d041cdd612f 100644 --- a/components/script/dom/webidls/HTMLFieldSetElement.webidl +++ b/components/script/dom/webidls/HTMLFieldSetElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlfieldsetelement -[Exposed=(Window,Worker)] interface HTMLFieldSetElement : HTMLElement { attribute boolean disabled; readonly attribute HTMLFormElement? form; diff --git a/components/script/dom/webidls/HTMLFontElement.webidl b/components/script/dom/webidls/HTMLFontElement.webidl index 7c524eb0a4d..74db3f45057 100644 --- a/components/script/dom/webidls/HTMLFontElement.webidl +++ b/components/script/dom/webidls/HTMLFontElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlfontelement -[Exposed=(Window,Worker)] interface HTMLFontElement : HTMLElement { [TreatNullAs=EmptyString] attribute DOMString color; attribute DOMString face; diff --git a/components/script/dom/webidls/HTMLFrameElement.webidl b/components/script/dom/webidls/HTMLFrameElement.webidl index 0de80f7df1e..ecac61f6860 100644 --- a/components/script/dom/webidls/HTMLFrameElement.webidl +++ b/components/script/dom/webidls/HTMLFrameElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlframeelement -[Exposed=(Window,Worker)] interface HTMLFrameElement : HTMLElement { // attribute DOMString name; // attribute DOMString scrolling; diff --git a/components/script/dom/webidls/HTMLFrameSetElement.webidl b/components/script/dom/webidls/HTMLFrameSetElement.webidl index 34ab7a42289..5addd41d253 100644 --- a/components/script/dom/webidls/HTMLFrameSetElement.webidl +++ b/components/script/dom/webidls/HTMLFrameSetElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlframesetelement -[Exposed=(Window,Worker)] interface HTMLFrameSetElement : HTMLElement { // attribute DOMString cols; // attribute DOMString rows; diff --git a/components/script/dom/webidls/HTMLHRElement.webidl b/components/script/dom/webidls/HTMLHRElement.webidl index 84ab2a423c6..56e2f6ae19b 100644 --- a/components/script/dom/webidls/HTMLHRElement.webidl +++ b/components/script/dom/webidls/HTMLHRElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlhrelement -[Exposed=(Window,Worker)] interface HTMLHRElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLHeadingElement.webidl b/components/script/dom/webidls/HTMLHeadingElement.webidl index 8185fcb961e..2c47d6fa10f 100644 --- a/components/script/dom/webidls/HTMLHeadingElement.webidl +++ b/components/script/dom/webidls/HTMLHeadingElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlheadingelement -[Exposed=(Window,Worker)] interface HTMLHeadingElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLHtmlElement.webidl b/components/script/dom/webidls/HTMLHtmlElement.webidl index d25b22702b3..ed409b1b84c 100644 --- a/components/script/dom/webidls/HTMLHtmlElement.webidl +++ b/components/script/dom/webidls/HTMLHtmlElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlhtmlelement -[Exposed=(Window,Worker)] interface HTMLHtmlElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl b/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl index 46336743a53..3ff0418b13f 100644 --- a/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl +++ b/components/script/dom/webidls/HTMLHyperlinkElementUtils.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlhyperlinkelementutils -[NoInterfaceObject, Exposed=(Window,Worker)] +[NoInterfaceObject] interface HTMLHyperlinkElementUtils { // stringifier attribute USVString href; attribute USVString href; diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl index 58a9af38d9c..ced089391d2 100644 --- a/components/script/dom/webidls/HTMLIFrameElement.webidl +++ b/components/script/dom/webidls/HTMLIFrameElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmliframeelement -[Exposed=(Window,Worker)] interface HTMLIFrameElement : HTMLElement { attribute DOMString src; // attribute DOMString srcdoc; diff --git a/components/script/dom/webidls/HTMLImageElement.webidl b/components/script/dom/webidls/HTMLImageElement.webidl index d3e2a419132..88e0dae8d3b 100644 --- a/components/script/dom/webidls/HTMLImageElement.webidl +++ b/components/script/dom/webidls/HTMLImageElement.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlimageelement -[NamedConstructor=Image(optional unsigned long width, optional unsigned long height), Exposed=(Window,Worker)] +[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)] interface HTMLImageElement : HTMLElement { attribute DOMString alt; attribute DOMString src; diff --git a/components/script/dom/webidls/HTMLInputElement.webidl b/components/script/dom/webidls/HTMLInputElement.webidl index d5b3a3985ed..1d6160b14cd 100644 --- a/components/script/dom/webidls/HTMLInputElement.webidl +++ b/components/script/dom/webidls/HTMLInputElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlinputelement -[Exposed=(Window,Worker)] interface HTMLInputElement : HTMLElement { attribute DOMString accept; attribute DOMString alt; diff --git a/components/script/dom/webidls/HTMLLIElement.webidl b/components/script/dom/webidls/HTMLLIElement.webidl index 944029bfb04..ea7d574eba4 100644 --- a/components/script/dom/webidls/HTMLLIElement.webidl +++ b/components/script/dom/webidls/HTMLLIElement.webidl @@ -3,9 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmllielement -[Exposed=(Window,Worker)] interface HTMLLIElement : HTMLElement { - // attribute long value; + attribute long value; // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLLabelElement.webidl b/components/script/dom/webidls/HTMLLabelElement.webidl index 5a194998747..8acb1f312c8 100644 --- a/components/script/dom/webidls/HTMLLabelElement.webidl +++ b/components/script/dom/webidls/HTMLLabelElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmllabelelement -[Exposed=(Window,Worker)] interface HTMLLabelElement : HTMLElement { readonly attribute HTMLFormElement? form; attribute DOMString htmlFor; diff --git a/components/script/dom/webidls/HTMLLegendElement.webidl b/components/script/dom/webidls/HTMLLegendElement.webidl index 4c79ce2ecc6..c137d6db66a 100644 --- a/components/script/dom/webidls/HTMLLegendElement.webidl +++ b/components/script/dom/webidls/HTMLLegendElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmllegendelement -[Exposed=(Window,Worker)] interface HTMLLegendElement : HTMLElement { readonly attribute HTMLFormElement? form; diff --git a/components/script/dom/webidls/HTMLParagraphElement.webidl b/components/script/dom/webidls/HTMLParagraphElement.webidl index ff2facc455d..a96c6dc6f81 100644 --- a/components/script/dom/webidls/HTMLParagraphElement.webidl +++ b/components/script/dom/webidls/HTMLParagraphElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlparagraphelement -[Exposed=(Window,Worker)] interface HTMLParagraphElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLParamElement.webidl b/components/script/dom/webidls/HTMLParamElement.webidl index 1b0805480a6..9648c9f87ce 100644 --- a/components/script/dom/webidls/HTMLParamElement.webidl +++ b/components/script/dom/webidls/HTMLParamElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlparamelement -[Exposed=(Window,Worker)] interface HTMLParamElement : HTMLElement { // attribute DOMString name; // attribute DOMString value; diff --git a/components/script/dom/webidls/HTMLPreElement.webidl b/components/script/dom/webidls/HTMLPreElement.webidl index 7d65e225d4f..ea0df151020 100644 --- a/components/script/dom/webidls/HTMLPreElement.webidl +++ b/components/script/dom/webidls/HTMLPreElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlpreelement -[Exposed=(Window,Worker)] interface HTMLPreElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLProgressElement.webidl b/components/script/dom/webidls/HTMLProgressElement.webidl index 852e683b1f7..cf69566ecdd 100644 --- a/components/script/dom/webidls/HTMLProgressElement.webidl +++ b/components/script/dom/webidls/HTMLProgressElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlprogresselement -[Exposed=(Window,Worker)] interface HTMLProgressElement : HTMLElement { // attribute double value; // attribute double max; diff --git a/components/script/dom/webidls/HTMLQuoteElement.webidl b/components/script/dom/webidls/HTMLQuoteElement.webidl index 6741d7b4041..e546f151d49 100644 --- a/components/script/dom/webidls/HTMLQuoteElement.webidl +++ b/components/script/dom/webidls/HTMLQuoteElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlquoteelement -[Exposed=(Window,Worker)] interface HTMLQuoteElement : HTMLElement { // attribute DOMString cite; }; diff --git a/components/script/dom/webidls/HTMLSelectElement.webidl b/components/script/dom/webidls/HTMLSelectElement.webidl index 2bcbbf098e4..ba84d183a72 100644 --- a/components/script/dom/webidls/HTMLSelectElement.webidl +++ b/components/script/dom/webidls/HTMLSelectElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlselectelement -[Exposed=(Window,Worker)] interface HTMLSelectElement : HTMLElement { // attribute boolean autofocus; attribute boolean disabled; diff --git a/components/script/dom/webidls/HTMLSourceElement.webidl b/components/script/dom/webidls/HTMLSourceElement.webidl index a631876b42e..738a545713a 100644 --- a/components/script/dom/webidls/HTMLSourceElement.webidl +++ b/components/script/dom/webidls/HTMLSourceElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlsourceelement -[Exposed=(Window,Worker)] interface HTMLSourceElement : HTMLElement { // attribute DOMString src; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLSpanElement.webidl b/components/script/dom/webidls/HTMLSpanElement.webidl index 082ba45cf8b..a74967536a1 100644 --- a/components/script/dom/webidls/HTMLSpanElement.webidl +++ b/components/script/dom/webidls/HTMLSpanElement.webidl @@ -3,5 +3,4 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlspanelement -[Exposed=(Window,Worker)] interface HTMLSpanElement : HTMLElement {}; diff --git a/components/script/dom/webidls/HTMLStyleElement.webidl b/components/script/dom/webidls/HTMLStyleElement.webidl index 4bc4430a38c..dd766f41d22 100644 --- a/components/script/dom/webidls/HTMLStyleElement.webidl +++ b/components/script/dom/webidls/HTMLStyleElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlstyleelement -[Exposed=(Window,Worker)] interface HTMLStyleElement : HTMLElement { // attribute DOMString media; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLTableCaptionElement.webidl b/components/script/dom/webidls/HTMLTableCaptionElement.webidl index 0860aa7e796..b405d23ed40 100644 --- a/components/script/dom/webidls/HTMLTableCaptionElement.webidl +++ b/components/script/dom/webidls/HTMLTableCaptionElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecaptionelement -[Exposed=(Window,Worker)] interface HTMLTableCaptionElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableCellElement.webidl b/components/script/dom/webidls/HTMLTableCellElement.webidl index 2264d56b5e2..33863b3dc20 100644 --- a/components/script/dom/webidls/HTMLTableCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableCellElement.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecellelement -[Abstract, Exposed=(Window,Worker)] +[Abstract] interface HTMLTableCellElement : HTMLElement { attribute unsigned long colSpan; // attribute unsigned long rowSpan; diff --git a/components/script/dom/webidls/HTMLTableColElement.webidl b/components/script/dom/webidls/HTMLTableColElement.webidl index 3868de31272..69188251443 100644 --- a/components/script/dom/webidls/HTMLTableColElement.webidl +++ b/components/script/dom/webidls/HTMLTableColElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecolelement -[Exposed=(Window,Worker)] interface HTMLTableColElement : HTMLElement { // attribute unsigned long span; diff --git a/components/script/dom/webidls/HTMLTableDataCellElement.webidl b/components/script/dom/webidls/HTMLTableDataCellElement.webidl index 7c286df77e4..208ed76d692 100644 --- a/components/script/dom/webidls/HTMLTableDataCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableDataCellElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltabledatacellelement -[Exposed=(Window,Worker)] interface HTMLTableDataCellElement : HTMLTableCellElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableElement.webidl b/components/script/dom/webidls/HTMLTableElement.webidl index c97d24fd57b..f0d8e19d0eb 100644 --- a/components/script/dom/webidls/HTMLTableElement.webidl +++ b/components/script/dom/webidls/HTMLTableElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltableelement -[Exposed=(Window,Worker)] interface HTMLTableElement : HTMLElement { attribute HTMLTableCaptionElement? caption; HTMLTableCaptionElement createCaption(); @@ -20,7 +19,7 @@ interface HTMLTableElement : HTMLElement { HTMLTableSectionElement createTBody(); readonly attribute HTMLCollection rows; [Throws] HTMLTableRowElement insertRow(optional long index = -1); - //void deleteRow(long index); + [Throws] void deleteRow(long index); // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl b/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl index fb3e7126672..9bf8f1fc950 100644 --- a/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltableheadercellelement -[Exposed=(Window,Worker)] interface HTMLTableHeaderCellElement : HTMLTableCellElement { // attribute DOMString scope; // attribute DOMString abbr; diff --git a/components/script/dom/webidls/HTMLTableRowElement.webidl b/components/script/dom/webidls/HTMLTableRowElement.webidl index 75898c577e1..9d4b0655cad 100644 --- a/components/script/dom/webidls/HTMLTableRowElement.webidl +++ b/components/script/dom/webidls/HTMLTableRowElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablerowelement -[Exposed=(Window,Worker)] interface HTMLTableRowElement : HTMLElement { readonly attribute long rowIndex; readonly attribute long sectionRowIndex; diff --git a/components/script/dom/webidls/HTMLTableSectionElement.webidl b/components/script/dom/webidls/HTMLTableSectionElement.webidl index dd9d1c654f1..979d8030ffd 100644 --- a/components/script/dom/webidls/HTMLTableSectionElement.webidl +++ b/components/script/dom/webidls/HTMLTableSectionElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablesectionelement -[Exposed=(Window,Worker)] interface HTMLTableSectionElement : HTMLElement { readonly attribute HTMLCollection rows; [Throws] diff --git a/components/script/dom/webidls/HTMLTemplateElement.webidl b/components/script/dom/webidls/HTMLTemplateElement.webidl index 7506f9a28e0..b3383de69d2 100644 --- a/components/script/dom/webidls/HTMLTemplateElement.webidl +++ b/components/script/dom/webidls/HTMLTemplateElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltemplateelement -[Exposed=(Window,Worker)] interface HTMLTemplateElement : HTMLElement { readonly attribute DocumentFragment content; }; diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 32a2ba43ccf..f92e662c354 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltextareaelement -[Exposed=(Window,Worker)] interface HTMLTextAreaElement : HTMLElement { // attribute DOMString autocomplete; // attribute boolean autofocus; diff --git a/components/script/dom/webidls/HTMLTimeElement.webidl b/components/script/dom/webidls/HTMLTimeElement.webidl index dbd80686b0c..21f9dcf090e 100644 --- a/components/script/dom/webidls/HTMLTimeElement.webidl +++ b/components/script/dom/webidls/HTMLTimeElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltimeelement -[Exposed=(Window,Worker)] interface HTMLTimeElement : HTMLElement { // attribute DOMString dateTime; }; diff --git a/components/script/dom/webidls/HTMLTitleElement.webidl b/components/script/dom/webidls/HTMLTitleElement.webidl index 9332cae40a7..10373be7e4b 100644 --- a/components/script/dom/webidls/HTMLTitleElement.webidl +++ b/components/script/dom/webidls/HTMLTitleElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltitleelement -[Exposed=(Window,Worker)] interface HTMLTitleElement : HTMLElement { [Pure] attribute DOMString text; diff --git a/components/script/dom/webidls/HTMLTrackElement.webidl b/components/script/dom/webidls/HTMLTrackElement.webidl index 9828139bee2..55733235321 100644 --- a/components/script/dom/webidls/HTMLTrackElement.webidl +++ b/components/script/dom/webidls/HTMLTrackElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltrackelement -[Exposed=(Window,Worker)] interface HTMLTrackElement : HTMLElement { // attribute DOMString kind; // attribute DOMString src; diff --git a/components/script/dom/webidls/HTMLUListElement.webidl b/components/script/dom/webidls/HTMLUListElement.webidl index 6abaf544b7f..91a79c7f925 100644 --- a/components/script/dom/webidls/HTMLUListElement.webidl +++ b/components/script/dom/webidls/HTMLUListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlulistelement -[Exposed=(Window,Worker)] interface HTMLUListElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLUnknownElement.webidl b/components/script/dom/webidls/HTMLUnknownElement.webidl index 624d7d8541d..acf5a47a996 100644 --- a/components/script/dom/webidls/HTMLUnknownElement.webidl +++ b/components/script/dom/webidls/HTMLUnknownElement.webidl @@ -11,6 +11,5 @@ * and create derivative works of this document. */ -[Exposed=(Window,Worker)] interface HTMLUnknownElement : HTMLElement { }; diff --git a/components/script/dom/webidls/HTMLVideoElement.webidl b/components/script/dom/webidls/HTMLVideoElement.webidl index 3af425cc06b..5e7c9cb9fce 100644 --- a/components/script/dom/webidls/HTMLVideoElement.webidl +++ b/components/script/dom/webidls/HTMLVideoElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlvideoelement -[Exposed=(Window,Worker)] interface HTMLVideoElement : HTMLMediaElement { // attribute unsigned long width; // attribute unsigned long height; diff --git a/components/script/dom/webidls/Headers.webidl b/components/script/dom/webidls/Headers.webidl index 038dbe46f74..6696bf64731 100644 --- a/components/script/dom/webidls/Headers.webidl +++ b/components/script/dom/webidls/Headers.webidl @@ -4,19 +4,21 @@ // https://fetch.spec.whatwg.org/#headers-class -/* typedef (Headers or sequence<sequence<ByteString>>) HeadersInit; */ - -/* [Constructor(optional HeadersInit init),*/ - [Exposed=(Window,Worker)] +// TODO support OpenEndedDictionary<ByteString> +typedef (Headers or sequence<sequence<ByteString>>) HeadersInit; +[Constructor(optional HeadersInit init), + Exposed=(Window,Worker)] interface Headers { [Throws] void append(ByteString name, ByteString value); + [Throws] + void delete(ByteString name); + [Throws] + ByteString? get(ByteString name); + [Throws] + boolean has(ByteString name); + [Throws] + void set(ByteString name, ByteString value); + // iterable<ByteString, ByteString>; // TODO see issue #12628 }; - -/* void delete(ByteString name); - * ByteString? get(ByteString name); - * boolean has(ByteString name); - * void set(ByteString name, ByteString value); - * iterable<ByteString, ByteString>; - * }; */ diff --git a/components/script/dom/webidls/History.webidl b/components/script/dom/webidls/History.webidl new file mode 100644 index 00000000000..c0c1635264a --- /dev/null +++ b/components/script/dom/webidls/History.webidl @@ -0,0 +1,18 @@ +/* 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/. */ + +// enum ScrollRestoration { "auto", "manual" }; + +// https://html.spec.whatwg.org/multipage/#the-history-interface +[Exposed=(Window,Worker)] +interface History { + readonly attribute unsigned long length; + // attribute ScrollRestoration scrollRestoration; + // readonly attribute any state; + void go(optional long delta = 0); + void back(); + void forward(); + // void pushState(any data, DOMString title, optional USVString? url = null); + // void replaceState(any data, DOMString title, optional USVString? url = null); +}; diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index 50240b9793d..9fc8a9e3bb6 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -110,6 +110,7 @@ interface TestBinding { attribute (unsigned long or boolean) union6Attribute; attribute (Blob or boolean) union7Attribute; attribute (Blob or unsigned long) union8Attribute; + attribute (ByteString or long) union9Attribute; readonly attribute Uint8ClampedArray arrayAttribute; attribute any anyAttribute; attribute object objectAttribute; @@ -139,6 +140,7 @@ interface TestBinding { attribute (Blob or boolean)? union3AttributeNullable; attribute (unsigned long or boolean)? union4AttributeNullable; attribute (DOMString or boolean)? union5AttributeNullable; + attribute (ByteString or long)? union6AttributeNullable; [BinaryName="BinaryRenamedAttribute"] attribute DOMString attrToBinaryRename; [BinaryName="BinaryRenamedAttribute2"] attribute DOMString attr-to-binary-rename; attribute DOMString attr-to-automatically-rename; @@ -177,6 +179,8 @@ interface TestBinding { (DOMString or boolean) receiveUnion7(); (unsigned long or boolean) receiveUnion8(); (HTMLElement or unsigned long or DOMString or boolean) receiveUnion9(); + (ByteString or long) receiveUnion10(); + (sequence<ByteString> or long or DOMString) receiveUnion11(); sequence<long> receiveSequence(); sequence<Blob> receiveInterfaceSequence(); @@ -204,6 +208,7 @@ interface TestBinding { (DOMString or sequence<long>)? receiveNullableUnion3(); (sequence<long> or boolean)? receiveNullableUnion4(); (unsigned long or boolean)? receiveNullableUnion5(); + (ByteString or long)? receiveNullableUnion6(); sequence<long>? receiveNullableSequence(); TestDictionary receiveTestDictionaryWithSuccessOnKeyword(); boolean dictMatchesPassedValues(TestDictionary arg); @@ -233,6 +238,7 @@ interface TestBinding { void passUnion5((DOMString or boolean) data); void passUnion6((unsigned long or boolean) bool); void passUnion7((sequence<DOMString> or unsigned long) arg); + void passUnion8((sequence<ByteString> or long) arg); void passAny(any arg); void passObject(object arg); void passCallbackFunction(Function fun); @@ -265,6 +271,7 @@ interface TestBinding { void passNullableUnion3((DOMString or sequence<long>)? data); void passNullableUnion4((sequence<long> or boolean)? bool); void passNullableUnion5((unsigned long or boolean)? arg); + void passNullableUnion6((ByteString or long)? arg); void passNullableCallbackFunction(Function? fun); void passNullableCallbackInterface(EventListener? listener); void passNullableSequence(sequence<long>? seq); @@ -292,6 +299,7 @@ interface TestBinding { void passOptionalUnion3(optional (DOMString or sequence<long>) arg); void passOptionalUnion4(optional (sequence<long> or boolean) data); void passOptionalUnion5(optional (unsigned long or boolean) bool); + void passOptionalUnion6(optional (ByteString or long) arg); void passOptionalAny(optional any arg); void passOptionalObject(optional object arg); void passOptionalCallbackFunction(optional Function fun); @@ -322,6 +330,7 @@ interface TestBinding { void passOptionalNullableUnion3(optional (DOMString or sequence<long>)? arg); void passOptionalNullableUnion4(optional (sequence<long> or boolean)? data); void passOptionalNullableUnion5(optional (unsigned long or boolean)? bool); + void passOptionalNullableUnion6(optional (ByteString or long)? arg); void passOptionalNullableCallbackFunction(optional Function? fun); void passOptionalNullableCallbackInterface(optional EventListener? listener); void passOptionalNullableSequence(optional sequence<long>? seq); @@ -406,6 +415,7 @@ interface TestBinding { void passVariadicUnion4((Blob or boolean)... args); void passVariadicUnion5((DOMString or unsigned long)... args); void passVariadicUnion6((unsigned long or boolean)... args); + void passVariadicUnion7((ByteString or long)... args); void passVariadicAny(any... args); void passVariadicObject(object... args); diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index bda73c9479a..7057a4541a6 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -11,7 +11,7 @@ [Unforgeable] readonly attribute Document document; // attribute DOMString name; [/*PutForwards=href, */Unforgeable] readonly attribute Location location; - //readonly attribute History history; + readonly attribute History history; //[Replaceable] readonly attribute BarProp locationbar; //[Replaceable] readonly attribute BarProp menubar; //[Replaceable] readonly attribute BarProp personalbar; @@ -54,6 +54,8 @@ void cancelAnimationFrame(unsigned long handle); //void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer); + [Throws] + void postMessage(any message, DOMString targetOrigin); // also has obsolete members }; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 1a34096f26b..3b3652040e9 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -461,6 +461,8 @@ struct ConnectionEstablishedTask { } impl Runnable for ConnectionEstablishedTask { + fn name(&self) -> &'static str { "ConnectionEstablishedTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); let global = ws.r().global(); @@ -510,6 +512,8 @@ impl Runnable for BufferedAmountTask { // To be compliant with standards, we need to reset bufferedAmount only when the event loop // reaches step 1. In our implementation, the bytes will already have been sent on a background // thread. + fn name(&self) -> &'static str { "BufferedAmountTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); @@ -526,6 +530,8 @@ struct CloseTask { } impl Runnable for CloseTask { + fn name(&self) -> &'static str { "CloseTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); let ws = ws.r(); @@ -568,6 +574,8 @@ struct MessageReceivedTask { } impl Runnable for MessageReceivedTask { + fn name(&self) -> &'static str { "MessageReceivedTask" } + #[allow(unsafe_code)] fn handler(self: Box<Self>) { let ws = self.address.root(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index b4984bb2a4a..c25c826b4ec 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -19,8 +19,10 @@ use dom::bindings::global::{GlobalRef, global_root_from_object}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::num::Finite; +use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; +use dom::bindings::structuredclone::StructuredCloneData; use dom::bindings::utils::{GlobalStaticData, WindowProxyHandler}; use dom::browsingcontext::BrowsingContext; use dom::console::Console; @@ -30,8 +32,10 @@ use dom::document::Document; use dom::element::Element; use dom::event::Event; use dom::eventtarget::EventTarget; +use dom::history::History; use dom::htmliframeelement::build_mozbrowser_custom_event; use dom::location::Location; +use dom::messageevent::MessageEvent; use dom::navigator::Navigator; use dom::node::{Node, from_untrusted_node_address, window_from_node}; use dom::performance::Performance; @@ -42,6 +46,7 @@ use gfx_traits::LayerId; use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSContext}; use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy}; +use js::jsval::UndefinedValue; use js::rust::CompileOptionsWrapper; use js::rust::Runtime; use libc; @@ -52,6 +57,7 @@ use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; use net_traits::storage_thread::StorageType; use num_traits::ToPrimitive; use open; +use origin::Origin; use profile_traits::mem; use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType}; use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile}; @@ -61,9 +67,9 @@ use script_layout_interface::message::{Msg, Reflow, ReflowQueryType, ScriptReflo use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; use script_layout_interface::rpc::{MarginStyleResponse, ResolvedStyleResponse}; -use script_runtime::{ScriptChan, ScriptPort, maybe_take_panic_result}; +use script_runtime::{ScriptChan, ScriptPort, CommonScriptMsg, ScriptThreadEventCategory, maybe_take_panic_result}; use script_thread::SendableMainThreadScriptChan; -use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper}; +use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper, Runnable}; use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; use script_traits::{ConstellationControlMsg, MozBrowserEvent, UntrustedNodeAddress}; use script_traits::{DocumentState, MsDuration, TimerEvent, TimerEventId}; @@ -94,7 +100,7 @@ use task_source::networking::NetworkingTaskSource; use task_source::user_interaction::UserInteractionTaskSource; use time; use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback}; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use tinyfiledialogs::{self, MessageBoxIcon}; use url::Url; use util::geometry::{self, MAX_RECT}; @@ -158,6 +164,7 @@ pub struct Window { #[ignore_heap_size_of = "channels are hard"] image_cache_chan: ImageCacheChan, browsing_context: MutNullableHeap<JS<BrowsingContext>>, + history: MutNullableHeap<JS<History>>, performance: MutNullableHeap<JS<Performance>>, navigation_start: u64, navigation_start_precise: f64, @@ -359,14 +366,14 @@ impl Window { } } -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn display_alert_dialog(message: &str) { tinyfiledialogs::message_box_ok("Alert!", message, MessageBoxIcon::Warning); } -#[cfg(not(any(target_os = "macos", target_os = "linux")))] +#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] fn display_alert_dialog(_message: &str) { - // tinyfiledialogs not supported on Windows + // tinyfiledialogs not supported on Android } // https://html.spec.whatwg.org/multipage/#atob @@ -448,13 +455,15 @@ impl WindowMethods for Window { // Right now, just print to the console // Ensure that stderr doesn't trample through the alert() we use to // communicate test results (see executorservo.py in wptrunner). - let stderr = stderr(); - let mut stderr = stderr.lock(); - let stdout = stdout(); - let mut stdout = stdout.lock(); - writeln!(&mut stdout, "ALERT: {}", s).unwrap(); - stdout.flush().unwrap(); - stderr.flush().unwrap(); + { + let stderr = stderr(); + let mut stderr = stderr.lock(); + let stdout = stdout(); + let mut stdout = stdout.lock(); + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); + stdout.flush().unwrap(); + stderr.flush().unwrap(); + } let (sender, receiver) = ipc::channel().unwrap(); self.constellation_chan().send(ConstellationMsg::Alert(self.pipeline(), s.to_string(), sender)).unwrap(); @@ -475,6 +484,11 @@ impl WindowMethods for Window { self.browsing_context().active_document() } + // https://html.spec.whatwg.org/multipage/#dom-history + fn History(&self) -> Root<History> { + self.history.or_init(|| History::new(self)) + } + // https://html.spec.whatwg.org/multipage/#dom-location fn Location(&self) -> Root<Location> { self.Document().GetLocation().unwrap() @@ -641,6 +655,38 @@ impl WindowMethods for Window { doc.cancel_animation_frame(ident); } + // https://html.spec.whatwg.org/multipage/#dom-window-postmessage + fn PostMessage(&self, + cx: *mut JSContext, + message: HandleValue, + origin: DOMString) + -> ErrorResult { + // Step 3-5. + let origin = match &origin[..] { + "*" => None, + "/" => { + // TODO(#12715): Should be the origin of the incumbent settings + // object, not self's. + Some(self.Document().origin().copy()) + }, + url => match Url::parse(&url) { + Ok(url) => Some(Origin::new(&url)), + Err(_) => return Err(Error::Syntax), + } + }; + + // Step 1-2, 6-8. + // TODO(#12717): Should implement the `transfer` argument. + let data = try!(StructuredCloneData::write(cx, message)); + + // Step 9. + let runnable = PostMessageHandler::new(self, origin, data); + let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::DomEvent, box runnable); + // TODO(#12718): Use the "posted message task source". + let _ = self.script_chan.send(msg); + Ok(()) + } + // https://html.spec.whatwg.org/multipage/#dom-window-captureevents fn CaptureEvents(&self) { // This method intentionally does nothing @@ -1648,6 +1694,7 @@ impl Window { mem_profiler_chan: mem_profiler_chan, time_profiler_chan: time_profiler_chan, devtools_chan: devtools_chan, + history: Default::default(), browsing_context: Default::default(), performance: Default::default(), navigation_start: (current_time.sec * 1000 + current_time.nsec as i64 / 1000000) as u64, @@ -1757,3 +1804,50 @@ fn debug_reflow_events(id: PipelineId, goal: &ReflowGoal, query_type: &ReflowQue println!("{}", debug_msg); } + +struct PostMessageHandler { + destination: Trusted<Window>, + origin: Option<Origin>, + message: StructuredCloneData, +} + +impl PostMessageHandler { + fn new(window: &Window, + origin: Option<Origin>, + message: StructuredCloneData) -> PostMessageHandler { + PostMessageHandler { + destination: Trusted::new(window), + origin: origin, + message: message, + } + } +} + +impl Runnable for PostMessageHandler { + // https://html.spec.whatwg.org/multipage/#dom-window-postmessage steps 10-12. + fn handler(self: Box<PostMessageHandler>) { + let this = *self; + let window = this.destination.root(); + + // Step 10. + let doc = window.Document(); + if let Some(source) = this.origin { + if !source.same_origin(doc.origin()) { + return; + } + } + + let cx = window.get_cx(); + let globalhandle = window.reflector().get_jsobject(); + let _ac = JSAutoCompartment::new(cx, globalhandle.get()); + + rooted!(in(cx) let mut message = UndefinedValue()); + this.message.read(GlobalRef::Window(&*window), message.handle_mut()); + + // Step 11-12. + // TODO(#12719): set the other attributes. + MessageEvent::dispatch_jsval(window.upcast(), + GlobalRef::Window(&*window), + message.handle()); + } +} diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index c318672fb7a..c1ad7cf5a96 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -27,6 +27,7 @@ use js::jsapi::{HandleValue, JSContext, JSAutoCompartment}; use js::jsval::UndefinedValue; use script_thread::Runnable; use script_traits::WorkerScriptLoadOrigin; +use std::cell::Cell; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Sender, channel}; use std::sync::{Arc, Mutex}; @@ -43,7 +44,8 @@ pub struct Worker { sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, closing: Arc<AtomicBool>, #[ignore_heap_size_of = "Defined in rust-mozjs"] - runtime: Arc<Mutex<Option<SharedRt>>> + runtime: Arc<Mutex<Option<SharedRt>>>, + terminated: Cell<bool>, } impl Worker { @@ -53,7 +55,8 @@ impl Worker { eventtarget: EventTarget::new_inherited(), sender: sender, closing: closing, - runtime: Arc::new(Mutex::new(None)) + runtime: Arc::new(Mutex::new(None)), + terminated: Cell::new(false), } } @@ -112,11 +115,15 @@ impl Worker { self.closing.load(Ordering::SeqCst) } + pub fn is_terminated(&self) -> bool { + self.terminated.get() + } + pub fn handle_message(address: TrustedWorkerAddress, data: StructuredCloneData) { let worker = address.root(); - if worker.is_closing() { + if worker.is_terminated() { return; } @@ -137,7 +144,7 @@ impl Worker { filename: DOMString, lineno: u32, colno: u32) { let worker = address.root(); - if worker.is_closing() { + if worker.is_terminated() { return; } @@ -169,7 +176,10 @@ impl WorkerMethods for Worker { return; } - // Step 4 + // Step 2 + self.terminated.set(true); + + // Step 3 if let Some(runtime) = *self.runtime.lock().unwrap() { runtime.request_interrupt(); } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 154705fe145..16388d54d73 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -444,4 +444,10 @@ impl WorkerGlobalScope { pub fn set_devtools_wants_updates(&self, value: bool) { self.devtools_wants_updates.set(value); } + + pub fn close(&self) { + if let Some(ref closing) = self.closing { + closing.store(true, Ordering::SeqCst); + } + } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 5cef702c01a..b35ffef73c5 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -594,6 +594,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest { origin: self.global().r().get_url(), referer_url: self.referrer_url.clone(), referrer_policy: self.referrer_policy.clone(), + pipeline_id: self.pipeline_id(), }; if bypass_cross_origin_check { |