diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 84 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 109 | ||||
-rw-r--r-- | components/script/dom/bindings/interface.rs | 92 | ||||
-rw-r--r-- | components/script/dom/bindings/proxyhandler.rs | 21 | ||||
-rw-r--r-- | components/script/dom/bluetooth.rs | 18 | ||||
-rw-r--r-- | components/script/dom/bluetoothremotegattcharacteristic.rs | 16 | ||||
-rw-r--r-- | components/script/dom/bluetoothremotegattdescriptor.rs | 6 | ||||
-rw-r--r-- | components/script/dom/bluetoothremotegattserver.rs | 10 | ||||
-rw-r--r-- | components/script/dom/bluetoothremotegattservice.rs | 10 | ||||
-rw-r--r-- | components/script/dom/browsingcontext.rs | 25 | ||||
-rw-r--r-- | components/script/dom/document.rs | 21 | ||||
-rw-r--r-- | components/script/dom/htmlcollection.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmltableelement.rs | 60 | ||||
-rw-r--r-- | components/script/dom/node.rs | 50 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLTableElement.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/window.rs | 16 |
16 files changed, 349 insertions, 193 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 8360dfc322a..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); @@ -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, diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index d0074335c23..bd63ba84fb1 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(cx: *mut JSContext, 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(cx, 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/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/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/document.rs b/components/script/dom/document.rs index 28edce553ad..78ccbbdf1f5 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -376,6 +376,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 +1372,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 +1398,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 +1489,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>) { @@ -2908,16 +2911,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/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/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/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/webidls/HTMLTableElement.webidl b/components/script/dom/webidls/HTMLTableElement.webidl index 596f5abd188..f0d8e19d0eb 100644 --- a/components/script/dom/webidls/HTMLTableElement.webidl +++ b/components/script/dom/webidls/HTMLTableElement.webidl @@ -19,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/window.rs b/components/script/dom/window.rs index f28f823dab4..ebd9550d117 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -450,13 +450,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(); |