aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/attr.rs6
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py40
-rw-r--r--components/script/dom/bindings/conversions.rs36
-rw-r--r--components/script/dom/bindings/error.rs19
-rw-r--r--components/script/dom/bindings/interface.rs8
-rw-r--r--components/script/dom/bindings/utils.rs27
-rw-r--r--components/script/dom/bluetooth.rs172
-rw-r--r--components/script/dom/bluetoothdevice.rs12
-rw-r--r--components/script/dom/bluetoothremotegattcharacteristic.rs114
-rw-r--r--components/script/dom/bluetoothremotegattdescriptor.rs42
-rw-r--r--components/script/dom/bluetoothremotegattserver.rs58
-rw-r--r--components/script/dom/bluetoothremotegattservice.rs73
-rw-r--r--components/script/dom/bluetoothuuid.rs10
-rw-r--r--components/script/dom/browsingcontext.rs5
-rw-r--r--components/script/dom/comment.rs6
-rw-r--r--components/script/dom/css.rs4
-rw-r--r--components/script/dom/cssfontfacerule.rs9
-rw-r--r--components/script/dom/cssgroupingrule.rs21
-rw-r--r--components/script/dom/csskeyframerule.rs9
-rw-r--r--components/script/dom/csskeyframesrule.rs23
-rw-r--r--components/script/dom/cssmediarule.rs29
-rw-r--r--components/script/dom/cssnamespacerule.rs9
-rw-r--r--components/script/dom/cssrule.rs47
-rw-r--r--components/script/dom/cssrulelist.rs133
-rw-r--r--components/script/dom/cssstylerule.rs9
-rw-r--r--components/script/dom/cssstylesheet.rs6
-rw-r--r--components/script/dom/cssviewportrule.rs8
-rw-r--r--components/script/dom/document.rs125
-rw-r--r--components/script/dom/documentfragment.rs6
-rw-r--r--components/script/dom/domparser.rs5
-rw-r--r--components/script/dom/element.rs98
-rw-r--r--components/script/dom/extendableevent.rs10
-rw-r--r--components/script/dom/extendablemessageevent.rs4
-rw-r--r--components/script/dom/focusevent.rs4
-rw-r--r--components/script/dom/globalscope.rs15
-rw-r--r--components/script/dom/htmlcanvaselement.rs2
-rw-r--r--components/script/dom/htmlcollection.rs8
-rw-r--r--components/script/dom/htmliframeelement.rs148
-rw-r--r--components/script/dom/htmlimageelement.rs6
-rw-r--r--components/script/dom/htmlmetaelement.rs6
-rw-r--r--components/script/dom/htmlscriptelement.rs56
-rw-r--r--components/script/dom/keyboardevent.rs5
-rw-r--r--components/script/dom/medialist.rs122
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/mouseevent.rs5
-rw-r--r--components/script/dom/node.rs90
-rw-r--r--components/script/dom/range.rs18
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs2
-rw-r--r--components/script/dom/servoparser/mod.rs255
-rw-r--r--components/script/dom/servoparser/xml.rs2
-rw-r--r--components/script/dom/text.rs6
-rw-r--r--components/script/dom/transitionevent.rs4
-rw-r--r--components/script/dom/uievent.rs5
-rw-r--r--components/script/dom/webglactiveinfo.rs6
-rw-r--r--components/script/dom/webglbuffer.rs10
-rw-r--r--components/script/dom/webglcontextevent.rs14
-rw-r--r--components/script/dom/webglframebuffer.rs10
-rw-r--r--components/script/dom/webglobject.rs6
-rw-r--r--components/script/dom/webglprogram.rs14
-rw-r--r--components/script/dom/webglrenderbuffer.rs10
-rw-r--r--components/script/dom/webglrenderingcontext.rs51
-rw-r--r--components/script/dom/webglshader.rs13
-rw-r--r--components/script/dom/webglshaderprecisionformat.rs6
-rw-r--r--components/script/dom/webgltexture.rs10
-rw-r--r--components/script/dom/webgluniformlocation.rs6
-rw-r--r--components/script/dom/webidls/Bluetooth.webidl3
-rw-r--r--components/script/dom/webidls/BluetoothDevice.webidl9
-rw-r--r--components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl11
-rw-r--r--components/script/dom/webidls/BluetoothRemoteGATTService.webidl13
-rw-r--r--components/script/dom/webidls/CSSMediaRule.webidl2
-rw-r--r--components/script/dom/webidls/CSSStyleDeclaration.webidl8
-rw-r--r--components/script/dom/webidls/DOMMatrix.webidl7
-rw-r--r--components/script/dom/webidls/DOMMatrixReadOnly.webidl7
-rw-r--r--components/script/dom/webidls/Document.webidl6
-rw-r--r--components/script/dom/webidls/MediaList.webidl13
-rw-r--r--components/script/dom/webidls/WebGLActiveInfo.webidl1
-rw-r--r--components/script/dom/webidls/WebGLBuffer.webidl1
-rw-r--r--components/script/dom/webidls/WebGLContextEvent.webidl3
-rw-r--r--components/script/dom/webidls/WebGLFramebuffer.webidl1
-rw-r--r--components/script/dom/webidls/WebGLObject.webidl1
-rw-r--r--components/script/dom/webidls/WebGLProgram.webidl1
-rw-r--r--components/script/dom/webidls/WebGLRenderbuffer.webidl1
-rw-r--r--components/script/dom/webidls/WebGLRenderingContext.webidl3
-rw-r--r--components/script/dom/webidls/WebGLShader.webidl1
-rw-r--r--components/script/dom/webidls/WebGLShaderPrecisionFormat.webidl1
-rw-r--r--components/script/dom/webidls/WebGLTexture.webidl1
-rw-r--r--components/script/dom/webidls/WebGLUniformLocation.webidl1
-rw-r--r--components/script/dom/workerglobalscope.rs8
-rw-r--r--components/script/layout_wrapper.rs8
-rw-r--r--components/script/lib.rs1
-rw-r--r--components/script/script_runtime.rs32
-rw-r--r--components/script/script_thread.rs72
93 files changed, 1470 insertions, 846 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 57fd5626195..293c2aefe02 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -61,6 +61,7 @@ plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"}
rand = "0.3"
range = {path = "../range"}
+ref_filter_map = "1.0.1"
ref_slice = "1.0"
regex = "0.1.43"
rustc-serialize = "0.3"
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
index 2aae65af920..8b9587c9151 100644
--- a/components/script/dom/attr.rs
+++ b/components/script/dom/attr.rs
@@ -81,8 +81,8 @@ impl Attr {
}
#[inline]
- pub fn prefix(&self) -> &Option<Prefix> {
- &self.identifier.prefix
+ pub fn prefix(&self) -> Option<&Prefix> {
+ self.identifier.prefix.as_ref()
}
}
@@ -153,7 +153,7 @@ impl AttrMethods for Attr {
// https://dom.spec.whatwg.org/#dom-attr-prefix
fn GetPrefix(&self) -> Option<DOMString> {
// FIXME(ajeffrey): convert directly from LocalName to DOMString
- self.prefix().as_ref().map(|p| DOMString::from(&**p))
+ self.prefix().map(|p| DOMString::from(&**p))
}
// https://dom.spec.whatwg.org/#dom-attr-ownerelement
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index b67ab0bd716..28d0d9af459 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -2377,8 +2377,8 @@ class CGAbstractMethod(CGThing):
if self.catchPanic:
body = CGWrapper(CGIndenter(body),
- pre="return wrap_panic(|| {\n",
- post=("""}, %s);""" % ("()" if self.returnType == "void" else "false")))
+ pre="return wrap_panic(panic::AssertUnwindSafe(|| {\n",
+ post=("""}), %s);""" % ("()" if self.returnType == "void" else "false")))
return CGWrapper(CGIndenter(body),
pre=self.definition_prologue(),
@@ -2537,7 +2537,7 @@ class CGWrapMethod(CGAbstractMethod):
return CGGeneric("""\
let scope = scope.reflector().get_jsobject();
assert!(!scope.get().is_null());
-assert!(((*JS_GetClass(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
+assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
rooted!(in(cx) let mut proto = ptr::null_mut());
let _ac = JSAutoCompartment::new(cx, scope.get());
@@ -2954,7 +2954,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
def definition_body(self):
return CGGeneric("""
-assert!(((*JS_GetClass(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
+assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
/* Check to see whether the interface objects are already installed */
let proto_or_iface_array = get_proto_or_iface_array(global.get());
@@ -3168,7 +3168,7 @@ class CGCallGenerator(CGThing):
if isFallible:
if static:
- glob = "&global"
+ glob = "global.upcast::<GlobalScope>()"
else:
glob = "&this.global()"
@@ -3378,12 +3378,13 @@ class CGAbstractStaticBindingMethod(CGAbstractMethod):
Argument('*mut JSVal', 'vp'),
]
CGAbstractMethod.__init__(self, descriptor, name, "bool", args, extern=True)
+ self.exposureSet = descriptor.interface.exposureSet
def definition_body(self):
- preamble = CGGeneric("""\
-let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());
-""")
- return CGList([preamble, self.generate_code()])
+ preamble = "let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n"
+ if len(self.exposureSet) == 1:
+ preamble += "let global = Root::downcast::<dom::types::%s>(global).unwrap();\n" % list(self.exposureSet)[0]
+ return CGList([CGGeneric(preamble), self.generate_code()])
def generate_code(self):
raise NotImplementedError # Override me!
@@ -5245,12 +5246,14 @@ class CGClassConstructHook(CGAbstractExternMethod):
assert constructor
CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args)
self.constructor = constructor
+ self.exposureSet = descriptor.interface.exposureSet
def definition_body(self):
- preamble = CGGeneric("""\
-let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());
-let args = CallArgs::from_vp(vp, argc);
-""")
+ preamble = """let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n"""
+ if len(self.exposureSet) == 1:
+ preamble += "let global = Root::downcast::<dom::types::%s>(global).unwrap();\n" % list(self.exposureSet)[0]
+ preamble += """let args = CallArgs::from_vp(vp, argc);\n"""
+ preamble = CGGeneric(preamble)
name = self.constructor.identifier.name
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
callGenerator = CGMethodCall(["&global"], nativeName, True,
@@ -5448,7 +5451,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsapi::JS_DefineProperty',
'js::jsapi::JS_DefinePropertyById2',
'js::jsapi::JS_ForwardGetPropertyTo',
- 'js::jsapi::JS_GetClass',
'js::jsapi::JS_GetErrorPrototype',
'js::jsapi::JS_GetFunctionPrototype',
'js::jsapi::JS_GetGlobalForObject',
@@ -5496,9 +5498,12 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::glue::RUST_JSID_IS_STRING',
'js::glue::RUST_SYMBOL_TO_JSID',
'js::glue::int_to_jsid',
+ 'js::panic::maybe_resume_unwind',
+ 'js::panic::wrap_panic',
'js::rust::GCMethods',
'js::rust::define_methods',
'js::rust::define_properties',
+ 'js::rust::get_object_class',
'dom',
'dom::bindings',
'dom::bindings::codegen::InterfaceObjectMap',
@@ -5547,7 +5552,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'dom::bindings::utils::resolve_global',
'dom::bindings::utils::set_dictionary_property',
'dom::bindings::utils::trace_global',
- 'dom::bindings::utils::wrap_panic',
'dom::bindings::trace::JSTraceable',
'dom::bindings::trace::RootedTraceable',
'dom::bindings::callback::CallSetup',
@@ -5581,6 +5585,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'dom::bindings::error::throw_dom_exception',
'dom::bindings::guard::Condition',
'dom::bindings::guard::Guard',
+ 'dom::bindings::inheritance::Castable',
'dom::bindings::proxyhandler',
'dom::bindings::proxyhandler::ensure_expando_object',
'dom::bindings::proxyhandler::fill_property_descriptor',
@@ -5599,7 +5604,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'mem::heap_size_of_raw_self_and_children',
'libc',
'util::prefs::PREFS',
- 'script_runtime::maybe_take_panic_result',
'std::borrow::ToOwned',
'std::cmp',
'std::mem',
@@ -6596,9 +6600,7 @@ class CallbackMethod(CallbackMember):
" length_: ${argc} as ::libc::size_t,\n"
" elements_: ${argv}\n"
" }, rval.handle_mut());\n"
- "if let Some(error) = maybe_take_panic_result() {\n"
- " panic::resume_unwind(error);\n"
- "}\n"
+ "maybe_resume_unwind();\n"
"if !ok {\n"
" return Err(JSFailed);\n"
"}\n").substitute(replacements)
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index 9143c9cb75b..ba67ad11a7e 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -46,14 +46,14 @@ use js::error::throw_type_error;
use js::glue::{GetProxyPrivate, IsWrapper};
use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
-use js::jsapi::{HandleId, HandleObject, HandleValue, JSClass, JSContext};
-use js::jsapi::{JSObject, JSString, JS_GetArrayBufferViewType, JS_GetClass};
+use js::jsapi::{HandleId, HandleObject, HandleValue, JSContext};
+use js::jsapi::{JSObject, JSString, JS_GetArrayBufferViewType};
use js::jsapi::{JS_GetLatin1StringCharsAndLength, JS_GetObjectAsArrayBuffer, JS_GetObjectAsArrayBufferView};
-use js::jsapi::{JS_GetReservedSlot, JS_GetTwoByteStringCharsAndLength, ToWindowProxyIfWindow};
+use js::jsapi::{JS_GetReservedSlot, JS_GetTwoByteStringCharsAndLength};
use js::jsapi::{JS_IsArrayObject, JS_NewStringCopyN, JS_StringHasLatin1Chars};
-use js::jsapi::{JS_WrapValue, MutableHandleValue, Type, IsObjectInContextCompartment};
+use js::jsapi::{MutableHandleValue, Type};
use js::jsval::{ObjectValue, StringValue};
-use js::rust::ToString;
+use js::rust::{ToString, get_object_class, is_dom_class, is_dom_object, maybe_wrap_value};
use libc;
use num_traits::Float;
use std::{char, mem, ptr, slice};
@@ -308,23 +308,8 @@ impl ToJSValConvertible for Reflector {
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
let obj = self.get_jsobject().get();
assert!(!obj.is_null());
- let same_compartment = IsObjectInContextCompartment(obj, cx);
- if same_compartment {
- rval.set(ObjectValue(ToWindowProxyIfWindow(obj)));
- } else {
- rval.set(ObjectValue(obj));
-
- if !JS_WrapValue(cx, rval) {
- panic!("JS_WrapValue failed.");
- }
- }
- }
-}
-
-/// Returns whether the given `clasp` is one for a DOM object.
-pub fn is_dom_class(clasp: *const JSClass) -> bool {
- unsafe {
- ((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0
+ rval.set(ObjectValue(obj));
+ maybe_wrap_value(cx, rval);
}
}
@@ -332,7 +317,7 @@ pub fn is_dom_class(clasp: *const JSClass) -> bool {
pub fn is_dom_proxy(obj: *mut JSObject) -> bool {
use js::glue::IsProxyHandlerFamily;
unsafe {
- let clasp = JS_GetClass(obj);
+ let clasp = get_object_class(obj);
((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj) != 0
}
}
@@ -345,8 +330,7 @@ pub const DOM_OBJECT_SLOT: u32 = 0;
/// Get the private pointer of a DOM object from a given reflector.
pub unsafe fn private_from_object(obj: *mut JSObject) -> *const libc::c_void {
- let clasp = JS_GetClass(obj);
- let value = if is_dom_class(clasp) {
+ let value = if is_dom_object(obj) {
JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
} else {
debug_assert!(is_dom_proxy(obj));
@@ -364,7 +348,7 @@ pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result<&'static DOMClass, ()>
use dom::bindings::utils::DOMJSClass;
use js::glue::GetProxyHandlerExtra;
- let clasp = JS_GetClass(obj);
+ let clasp = get_object_class(obj);
if is_dom_class(&*clasp) {
trace!("plain old dom object");
let domjsclass: *const DOMJSClass = clasp as *const DOMJSClass;
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index 3b179e85d1d..d38a55c31be 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -214,15 +214,16 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
JS_ClearPendingException(cx);
let error_info = if value.is_object() {
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()));
- match error_info {
- Some(error_info) => error_info,
- None => {
- error!("Uncaught exception: failed to extract information");
- return;
- }
- }
+ ErrorInfo::from_native_error(cx, object.handle())
+ .or_else(|| ErrorInfo::from_dom_exception(object.handle()))
+ .unwrap_or_else(|| {
+ ErrorInfo {
+ message: format!("uncaught exception: unknown (can't convert to string)"),
+ filename: String::new(),
+ lineno: 0,
+ column: 0,
+ }
+ })
} else {
match USVString::from_jsval(cx, value.handle(), ()) {
Ok(ConversionResult::Success(USVString(string))) => {
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs
index cae5da97887..517adbde425 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script/dom/bindings/interface.rs
@@ -19,14 +19,14 @@ use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING};
use js::jsapi::{JSPropertySpec, JSString, JSTracer, JSVersion, JS_AtomizeAndPinString};
use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_DefineProperty2};
use js::jsapi::{JS_DefineProperty4, JS_DefinePropertyById3, JS_FireOnNewGlobalObject};
-use js::jsapi::{JS_GetClass, JS_GetFunctionObject, JS_GetPrototype};
+use js::jsapi::{JS_GetFunctionObject, JS_GetPrototype};
use js::jsapi::{JS_LinkConstructorAndPrototype, JS_NewFunction, JS_NewGlobalObject};
use js::jsapi::{JS_NewObject, JS_NewObjectWithUniqueType, JS_NewPlainObject};
use js::jsapi::{JS_NewStringCopyN, JS_SetReservedSlot, MutableHandleObject};
use js::jsapi::{MutableHandleValue, ObjectOps, OnNewGlobalHookOption, SymbolCode};
use js::jsapi::{TrueHandleValue, Value};
use js::jsval::{JSVal, PrivateValue};
-use js::rust::{define_methods, define_properties};
+use js::rust::{define_methods, define_properties, get_object_class};
use libc;
use std::ptr;
@@ -352,7 +352,7 @@ unsafe extern "C" fn fun_to_string_hook(cx: *mut JSContext,
obj: HandleObject,
_indent: u32)
-> *mut JSString {
- let js_class = JS_GetClass(obj.get());
+ let js_class = get_object_class(obj.get());
assert!(!js_class.is_null());
let repr = (*(js_class as *const NonCallbackInterfaceObjectClass)).representation;
assert!(!repr.is_empty());
@@ -388,7 +388,7 @@ unsafe fn has_instance(
}
rooted!(in(cx) let mut value = value.to_object());
- let js_class = JS_GetClass(interface_object.get());
+ let js_class = get_object_class(interface_object.get());
let object_class = &*(js_class as *const NonCallbackInterfaceObjectClass);
if let Ok(dom_class) = get_dom_class(UncheckedUnwrapObject(value.get(),
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index 4a7d4d698fb..de1ac8fcbfd 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -7,7 +7,7 @@
use dom::bindings::codegen::InterfaceObjectMap;
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::{MAX_PROTO_CHAIN_LENGTH, PROTO_OR_IFACE_LENGTH};
-use dom::bindings::conversions::{is_dom_class, jsstring_to_str, private_from_proto_check};
+use dom::bindings::conversions::{jsstring_to_str, private_from_proto_check};
use dom::bindings::error::throw_invalid_this;
use dom::bindings::inheritance::TopTypeId;
use dom::bindings::str::DOMString;
@@ -24,19 +24,16 @@ use js::jsapi::{CallArgs, DOMCallbacks, GetGlobalForObjectCrossCompartment};
use js::jsapi::{HandleId, HandleObject, HandleValue, Heap, JSAutoCompartment, JSContext};
use js::jsapi::{JSJitInfo, JSObject, JSTracer, JSWrapObjectCallbacks};
use js::jsapi::{JS_DeletePropertyById, JS_EnumerateStandardClasses};
-use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetClass, JS_GetLatin1StringCharsAndLength};
+use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetLatin1StringCharsAndLength};
use js::jsapi::{JS_GetProperty, JS_GetPrototype, JS_GetReservedSlot, JS_HasProperty};
use js::jsapi::{JS_HasPropertyById, JS_IsExceptionPending, JS_IsGlobalObject};
use js::jsapi::{JS_ResolveStandardClass, JS_SetProperty, ToWindowProxyIfWindow};
use js::jsapi::{JS_StringHasLatin1Chars, MutableHandleValue, ObjectOpResult};
use js::jsval::{JSVal, UndefinedValue};
-use js::rust::{GCMethods, ToString};
+use js::rust::{GCMethods, ToString, get_object_class, is_dom_class};
use libc;
-use script_runtime::store_panic_result;
use std::ffi::CString;
use std::os::raw::c_void;
-use std::panic;
-use std::panic::AssertUnwindSafe;
use std::ptr;
use std::slice;
@@ -118,7 +115,7 @@ unsafe impl Sync for DOMJSClass {}
/// Fails if `global` is not a DOM global object.
pub fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray {
unsafe {
- assert!(((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0);
+ assert!(((*get_object_class(global)).flags & JSCLASS_DOM_GLOBAL) != 0);
JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT).to_private() as *mut ProtoOrIfaceArray
}
}
@@ -201,7 +198,7 @@ pub unsafe fn find_enum_string_index(cx: *mut JSContext,
pub fn is_platform_object(obj: *mut JSObject) -> bool {
unsafe {
// Fast-path the common case
- let mut clasp = JS_GetClass(obj);
+ let mut clasp = get_object_class(obj);
if is_dom_class(&*clasp) {
return true;
}
@@ -211,7 +208,7 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool {
if unwrapped_obj.is_null() {
return false;
}
- clasp = js::jsapi::JS_GetClass(obj);
+ clasp = get_object_class(obj);
}
// TODO also check if JS_IsArrayBufferObject
is_dom_class(&*clasp)
@@ -516,15 +513,3 @@ unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::
pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
};
-
-/// Generic wrapper for JS engine callbacks panic-catching
-pub fn wrap_panic<T: FnMut() -> R, R>(function: T, generic_return_type: R) -> R {
- let result = panic::catch_unwind(AssertUnwindSafe(function));
- match result {
- Ok(result) => result,
- Err(error) => {
- store_panic_result(error);
- generic_return_type
- }
- }
-}
diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs
index afee568d735..aa2c4c4639a 100644
--- a/components/script/dom/bluetooth.rs
+++ b/components/script/dom/bluetooth.rs
@@ -11,12 +11,13 @@ use core::clone::Clone;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BluetoothBinding::{self, BluetoothDataFilterInit, BluetoothLEScanFilterInit};
use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, RequestDeviceOptions};
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::UnionTypes::StringOrUnsignedLong;
use dom::bindings::error::Error::{self, NotFound, Security, Type};
use dom::bindings::error::Fallible;
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::refcounted::{Trusted, TrustedPromise};
-use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
use dom::bluetoothdevice::BluetoothDevice;
@@ -24,6 +25,7 @@ use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
+use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::{self, IpcSender};
@@ -76,6 +78,8 @@ impl<Listener: AsyncBluetoothListener + Reflectable> BluetoothResponseListener f
let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
match response {
Ok(response) => self.receiver.root().handle_response(response, promise_cx, &promise),
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
+ // Step 3 - 4.
Err(error) => promise.reject_error(promise_cx, Error::from(error)),
}
}
@@ -84,7 +88,7 @@ impl<Listener: AsyncBluetoothListener + Reflectable> BluetoothResponseListener f
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
#[dom_struct]
pub struct Bluetooth {
- reflector_: Reflector,
+ eventtarget: EventTarget,
device_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothDevice>>>>,
service_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTService>>>>,
characteristic_instance_map: DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTCharacteristic>>>>,
@@ -94,7 +98,7 @@ pub struct Bluetooth {
impl Bluetooth {
pub fn new_inherited() -> Bluetooth {
Bluetooth {
- reflector_: Reflector::new(),
+ eventtarget: EventTarget::new_inherited(),
device_instance_map: DOMRefCell::new(HashMap::new()),
service_instance_map: DOMRefCell::new(HashMap::new()),
characteristic_instance_map: DOMRefCell::new(HashMap::new()),
@@ -132,18 +136,60 @@ impl Bluetooth {
optional_services: &Option<Vec<BluetoothServiceUUID>>) {
// TODO: Step 1: Triggered by user activation.
- // Step 2.
- let option = match convert_request_device_options(filters, optional_services) {
- Ok(o) => o,
- Err(e) => {
- p.reject_error(p.global().get_cx(), e);
+ // Step 2.2: There are no requiredServiceUUIDS, we scan for all devices.
+ let mut uuid_filters = vec!();
+
+ if let &Some(ref filters) = filters {
+ // Step 2.1.
+ if filters.is_empty() {
+ p.reject_error(p.global().get_cx(), Type(FILTER_EMPTY_ERROR.to_owned()));
return;
}
- };
- // TODO: Step 3-5: Implement the permission API.
+ // Step 2.3: There are no requiredServiceUUIDS, we scan for all devices.
+
+ // Step 2.4.
+ for filter in filters {
+ // Step 2.4.1.
+ match canonicalize_filter(&filter) {
+ // Step 2.4.2.
+ Ok(f) => uuid_filters.push(f),
+ Err(e) => {
+ p.reject_error(p.global().get_cx(), e);
+ return;
+ },
+ }
+ // Step 2.4.3: There are no requiredServiceUUIDS, we scan for all devices.
+ }
+ }
+
+ let mut optional_services_uuids = vec!();
+ if let &Some(ref opt_services) = optional_services {
+ for opt_service in opt_services {
+ // Step 2.5 - 2.6.
+ let uuid = match BluetoothUUID::service(opt_service.clone()) {
+ Ok(u) => u.to_string(),
+ Err(e) => {
+ p.reject_error(p.global().get_cx(), e);
+ return;
+ },
+ };
+
+ // Step 2.7.
+ // Note: What we are doing here, is adding the not blocklisted UUIDs to the result vector,
+ // instead of removing them from an already filled vector.
+ if !uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
+ optional_services_uuids.push(uuid);
+ }
+ }
+ }
+
+ let option = RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters),
+ ServiceUUIDSequence::new(optional_services_uuids));
+
+ // TODO: Step 3 - 5: Implement the permission API.
- // Note: Steps 6-8 are implemented in
+ // Note: Steps 6 - 8 are implemented in
// components/net/bluetooth_thread.rs in request_device function.
let sender = response_async(p, self);
self.get_bluetooth_thread().send(BluetoothRequest::RequestDevice(option, sender)).unwrap();
@@ -170,50 +216,9 @@ pub fn response_async<T: AsyncBluetoothListener + Reflectable + 'static>(
action_sender
}
-// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
-fn convert_request_device_options(filters: &Option<Vec<BluetoothLEScanFilterInit>>,
- optional_services: &Option<Vec<BluetoothServiceUUID>>)
- -> Fallible<RequestDeviceoptions> {
- // Step 2.2: There is no requiredServiceUUIDS, we scan for all devices.
- let mut uuid_filters = vec!();
-
- if let &Some(ref filters) = filters {
- // Step 2.1.
- if filters.is_empty() {
- return Err(Type(FILTER_EMPTY_ERROR.to_owned()));
- }
-
- // Step 2.3: There is no requiredServiceUUIDS, we scan for all devices.
-
- // Step 2.4.
- for filter in filters {
- // Step 2.4.8.
- uuid_filters.push(try!(canonicalize_filter(&filter)));
- }
- }
-
- let mut optional_services_uuids = vec!();
- if let &Some(ref opt_services) = optional_services {
- for opt_service in opt_services {
- // Step 2.5 - 2.6.
- let uuid = try!(BluetoothUUID::service(opt_service.clone())).to_string();
-
- // Step 2.7.
- // Note: What we are doing here is adding the not blocklisted UUIDs to the result vector,
- // insted of removing them from an already filled vector.
- if !uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
- optional_services_uuids.push(uuid);
- }
- }
- }
-
- Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters),
- ServiceUUIDSequence::new(optional_services_uuids)))
-}
-
-// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
+// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothlescanfilterinit-canonicalizing
fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<BluetoothScanfilter> {
- // Step 2.4.1.
+ // Step 1.
if filter.services.is_none() &&
filter.name.is_none() &&
filter.namePrefix.is_none() &&
@@ -222,13 +227,13 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
return Err(Type(FILTER_ERROR.to_owned()));
}
- // Step 2.4.2: There is no empty canonicalizedFilter member,
+ // Step 2: There is no empty canonicalizedFilter member,
// we create a BluetoothScanfilter instance at the end of the function.
- // Step 2.4.3.
+ // Step 3.
let services_vec = match filter.services {
Some(ref services) => {
- // Step 2.4.3.1.
+ // Step 3.1.
if services.is_empty() {
return Err(Type(SERVICE_ERROR.to_owned()));
}
@@ -236,27 +241,26 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
let mut services_vec = vec!();
for service in services {
- // Step 2.4.3.2 - 2.4.3.3.
+ // Step 3.2 - 3.3.
let uuid = try!(BluetoothUUID::service(service.clone())).to_string();
- // Step 2.4.3.4.
+ // Step 3.4.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
return Err(Security)
}
services_vec.push(uuid);
}
- // Step 2.4.3.5.
+ // Step 3.5.
services_vec
- // Step 2.4.3.6: There is no requiredServiceUUIDS, we scan for all devices.
},
None => vec!(),
};
- // Step 2.4.4.
+ // Step 4.
let name = match filter.name {
Some(ref name) => {
- // Step 2.4.4.1.
+ // Step 4.1.
// Note: DOMString::len() gives back the size in bytes.
if name.len() > MAX_DEVICE_NAME_LENGTH {
return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
@@ -265,16 +269,16 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
return Err(NotFound);
}
- // Step 2.4.4.2.
+ // Step 4.2.
Some(name.to_string())
},
None => None,
};
- // Step 2.4.5.
+ // Step 5.
let name_prefix = match filter.namePrefix {
Some(ref name_prefix) => {
- // Step 2.4.5.1.
+ // Step 5.1.
if name_prefix.is_empty() {
return Err(Type(NAME_PREFIX_ERROR.to_owned()));
}
@@ -285,24 +289,30 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
return Err(NotFound);
}
- // Step 2.4.5.2.
+ // Step 5.2.
name_prefix.to_string()
},
None => String::new(),
};
- // Step 2.4.6 - 2.4.7
+ // Step 6 - 7.
let manufacturer_data = match filter.manufacturerData {
Some(ref manufacturer_data_map) => {
+ // Note: If manufacturer_data_map is empty, that means there are no key values in it.
if manufacturer_data_map.is_empty() {
return Err(Type(MANUFACTURER_DATA_ERROR.to_owned()));
}
let mut map = HashMap::new();
for (key, bdfi) in manufacturer_data_map.iter() {
+ // Step 7.1 - 7.2.
let manufacturer_id = match u16::from_str(key.as_ref()) {
Ok(id) => id,
Err(err) => return Err(Type(format!("{} {} {}", KEY_CONVERSION_ERROR, key, err))),
};
+
+ // Step 7.3: No need to convert to IDL values since this is only used by native code.
+
+ // Step 7.4 - 7.5.
map.insert(manufacturer_id, try!(canonicalize_bluetooth_data_filter_init(bdfi)));
}
Some(map)
@@ -310,22 +320,33 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
None => None,
};
- // Step 2.4.8 -2.4.9
+ // Step 8 - 9.
let service_data = match filter.serviceData {
Some(ref service_data_map) => {
+ // Note: If service_data_map is empty, that means there are no key values in it.
if service_data_map.is_empty() {
return Err(Type(SERVICE_DATA_ERROR.to_owned()));
}
let mut map = HashMap::new();
for (key, bdfi) in service_data_map.iter() {
let service_name = match u32::from_str(key.as_ref()) {
+ // Step 9.1.
Ok(number) => StringOrUnsignedLong::UnsignedLong(number),
+ // Step 9.2.
_ => StringOrUnsignedLong::String(key.clone())
};
+
+ // Step 9.3 - 9.4.
let service = try!(BluetoothUUID::service(service_name)).to_string();
+
+ // Step 9.5.
if uuid_is_blocklisted(service.as_ref(), Blocklist::All) {
return Err(Security);
}
+
+ // Step 9.6: No need to convert to IDL values since this is only used by native code.
+
+ // Step 9.7 - 9.8.
map.insert(service, try!(canonicalize_bluetooth_data_filter_init(bdfi)));
}
Some(map)
@@ -341,14 +362,17 @@ fn canonicalize_filter(filter: &BluetoothLEScanFilterInit) -> Fallible<Bluetooth
fn canonicalize_bluetooth_data_filter_init(bdfi: &BluetoothDataFilterInit) -> Fallible<(Vec<u8>, Vec<u8>)> {
// Step 1.
let data_prefix = bdfi.dataPrefix.clone().unwrap_or(vec![]);
+
// Step 2.
// If no mask present, mask will be a sequence of 0xFF bytes the same length as dataPrefix.
// Masking dataPrefix with this, leaves dataPrefix untouched.
let mask = bdfi.mask.clone().unwrap_or(vec![0xFF; data_prefix.len()]);
+
// Step 3.
if mask.len() != data_prefix.len() {
return Err(Type(MASK_LENGTH_ERROR.to_owned()));
}
+
// Step 4.
Ok((data_prefix, mask))
}
@@ -377,16 +401,22 @@ impl BluetoothMethods for Bluetooth {
p.reject_error(p.global().get_cx(), Error::Type(OPTIONS_ERROR.to_owned()));
return p;
}
+
// Step 2.
self.request_bluetooth_devices(&p, &option.filters, &option.optionalServices);
- // TODO(#4282): Step 3-5: Reject and resolve promise.
+ //Note: Step 3 - 4. in response function, Step 5. in handle_response function.
return p;
}
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged
+ event_handler!(availabilitychanged, GetOnavailabilitychanged, SetOnavailabilitychanged);
}
impl AsyncBluetoothListener for Bluetooth {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
+ // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
+ // Step 13 - 14.
BluetoothResponse::RequestDevice(device) => {
let mut device_instance_map = self.device_instance_map.borrow_mut();
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
@@ -402,6 +432,8 @@ impl AsyncBluetoothListener for Bluetooth {
&ad_data,
&self);
device_instance_map.insert(device.id, MutHeap::new(&bt_device));
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
+ // Step 5.
promise.resolve_native(promise_cx, &bt_device);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
diff --git a/components/script/dom/bluetoothdevice.rs b/components/script/dom/bluetoothdevice.rs
index 39706befad6..4af6b2a4f59 100644
--- a/components/script/dom/bluetoothdevice.rs
+++ b/components/script/dom/bluetoothdevice.rs
@@ -4,18 +4,20 @@
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding;
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::js::{JS, Root, MutHeap, MutNullableHeap};
-use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetooth::Bluetooth;
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer;
+use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdevice
#[dom_struct]
pub struct BluetoothDevice {
- reflector_: Reflector,
+ eventtarget: EventTarget,
id: DOMString,
name: Option<DOMString>,
ad_data: MutHeap<JS<BluetoothAdvertisingData>>,
@@ -30,7 +32,7 @@ impl BluetoothDevice {
context: &Bluetooth)
-> BluetoothDevice {
BluetoothDevice {
- reflector_: Reflector::new(),
+ eventtarget: EventTarget::new_inherited(),
id: id,
name: name,
ad_data: MutHeap::new(ad_data),
@@ -76,8 +78,12 @@ impl BluetoothDeviceMethods for BluetoothDevice {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
fn Gatt(&self) -> Root<BluetoothRemoteGATTServer> {
+ // TODO: Step 1 - 2: Implement the Permission API.
self.gatt.or_init(|| {
BluetoothRemoteGATTServer::new(&self.global(), self)
})
}
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected
+ event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected);
}
diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs
index 390878342db..3c3c86001fb 100644
--- a/components/script/dom/bluetoothremotegattcharacteristic.rs
+++ b/components/script/dom/bluetoothremotegattcharacteristic.rs
@@ -13,15 +13,18 @@ use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
BluetoothRemoteGATTCharacteristicMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::error::Error::{self, InvalidModification, Network, NotSupported, Security};
+use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutHeap, Root};
-use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::{ByteString, DOMString};
use dom::bluetooth::{AsyncBluetoothListener, response_async};
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
use dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID};
+use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::IpcSender;
@@ -35,7 +38,7 @@ pub const MAXIMUM_ATTRIBUTE_LENGTH: usize = 512;
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
#[dom_struct]
pub struct BluetoothRemoteGATTCharacteristic {
- reflector_: Reflector,
+ eventtarget: EventTarget,
service: MutHeap<JS<BluetoothRemoteGATTService>>,
uuid: DOMString,
properties: MutHeap<JS<BluetoothCharacteristicProperties>>,
@@ -50,7 +53,7 @@ impl BluetoothRemoteGATTCharacteristic {
instance_id: String)
-> BluetoothRemoteGATTCharacteristic {
BluetoothRemoteGATTCharacteristic {
- reflector_: Reflector::new(),
+ eventtarget: EventTarget::new_inherited(),
service: MutHeap::new(service),
uuid: uuid,
properties: MutHeap::new(properties),
@@ -100,9 +103,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
let uuid = match BluetoothUUID::descriptor(descriptor) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
@@ -110,14 +116,23 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
return p;
}
};
+
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 3 - 4.
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedService internal slot for BluetoothRemoteGATTService.
+
+ // Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptor function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetDescriptor(self.get_instance_id(), uuid, sender)).unwrap();
@@ -126,6 +141,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
fn GetDescriptors(&self,
descriptor: Option<BluetoothDescriptorUUID>)
-> Rc<Promise> {
@@ -133,6 +149,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(d) = descriptor {
+ // Step 1.
uuid = match BluetoothUUID::descriptor(d) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
@@ -141,16 +158,24 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
}
};
if let Some(ref uuid) = uuid {
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
+
+ // Step 3 - 4.
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedService internal slot for BluetoothRemoteGATTService.
+
+ // Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptors function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetDescriptors(self.get_instance_id(), uuid, sender)).unwrap();
@@ -167,18 +192,31 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
fn ReadValue(&self) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 2.
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 3 - 4: Implement representedCharacteristic internal slot for BluetoothRemoteGATTCharacteristic.
+
+ // TODO: Step 5: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
+
+ // Step 5.1.
if !self.Properties().Read() {
p.reject_error(p_cx, NotSupported);
return p;
}
+
+ // Note: Remaining substeps of Step 5 are implemented in components/bluetooth/lib.rs in readValue function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
@@ -190,25 +228,39 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 2 - 3.
if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
p.reject_error(p_cx, InvalidModification);
return p;
}
+
+ // Step 4.
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+ // TODO: Step 5 - 6: Implement representedCharacteristic internal slot for BluetoothRemoteGATTCharacteristic.
+
+ // TODO: Step 7: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
+
+ // Step 7.1.
if !(self.Properties().Write() ||
self.Properties().WriteWithoutResponse() ||
self.Properties().AuthenticatedSignedWrites()) {
p.reject_error(p_cx, NotSupported);
return p;
}
+
+ // Note: Remaining substeps of Step 7 are implemented in components/bluetooth/lib.rs in writeValue function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap();
@@ -220,22 +272,32 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
fn StartNotifications(&self) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
// Step 1.
if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
p.reject_error(p_cx, Security);
return p;
}
- // Step 3.
+
+ // TODO: Step 2 - 3: Implement representedCharacteristic internal slot for BluetoothRemoteGATTCharacteristic.
+
+ // Step 4.
if !(self.Properties().Notify() ||
self.Properties().Indicate()) {
p.reject_error(p_cx, NotSupported);
return p;
}
+
+ // TODO: Step 5: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
+
// Step 6.
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // Note: Steps 7 - 11 are implemented in components/bluetooth/lib.rs in enable_notification function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::EnableNotification(self.get_instance_id(),
@@ -249,17 +311,29 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
fn StopNotifications(&self) -> Rc<Promise> {
let p = Promise::new(&self.global());
let sender = response_async(&p, self);
+
+ // TODO: Step 1 - 4: Implement representedCharacteristic internal slot and
+ // `active notification context set` for BluetoothRemoteGATTCharacteristic,
+
+ // Note: Part of Step 4 and Step 5 are implemented in components/bluetooth/lib.rs in enable_notification
+ // function and in handle_response function.
self.get_bluetooth_thread().send(
BluetoothRequest::EnableNotification(self.get_instance_id(),
false,
sender)).unwrap();
return p;
}
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged
+ event_handler!(characteristicvaluechanged, GetOncharacteristicvaluechanged, SetOncharacteristicvaluechanged);
}
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetDescriptor(descriptor) => {
let context = self.service.get().get_device().get_context();
let mut descriptor_map = context.get_descriptor_map().borrow_mut();
@@ -273,6 +347,9 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor));
promise.resolve_native(promise_cx, &bt_descriptor);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetDescriptors(descriptors_vec) => {
let mut descriptors = vec!();
let context = self.service.get().get_device().get_context();
@@ -294,17 +371,40 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
}
promise.resolve_native(promise_cx, &descriptors);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
BluetoothResponse::ReadValue(result) => {
+ // TODO: Step 5.5.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // Step 5.5.2.
+ // TODO(#5014): Replace ByteString with ArrayBuffer when it is implemented.
let value = ByteString::new(result);
*self.value.borrow_mut() = Some(value.clone());
+
+ // Step 5.5.3.
+ self.upcast::<EventTarget>().fire_bubbling_event(atom!("characteristicvaluechanged"));
+
+ // Step 5.5.4.
promise.resolve_native(promise_cx, &value);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
BluetoothResponse::WriteValue(result) => {
- let value = ByteString::new(result);
- *self.value.borrow_mut() = Some(value.clone());
- promise.resolve_native(promise_cx, &value);
+ // TODO: Step 7.5.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // Step 7.5.2.
+ // TODO(#5014): Replace ByteString with an ArrayBuffer wrapped in a DataView.
+ *self.value.borrow_mut() = Some(ByteString::new(result));
+
+ // Step 7.5.3.
+ promise.resolve_native(promise_cx, &());
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-stopnotifications
BluetoothResponse::EnableNotification(_result) => {
+ // (StartNotification) TODO: Step 10: Implement `active notification context set`
+ // for BluetoothRemoteGATTCharacteristic.
+
+ // (StartNotification) Step 11.
+ // (StopNotification) Step 5.
promise.resolve_native(promise_cx, self);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
diff --git a/components/script/dom/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetoothremotegattdescriptor.rs
index ffe66c23bec..8f092c6cad5 100644
--- a/components/script/dom/bluetoothremotegattdescriptor.rs
+++ b/components/script/dom/bluetoothremotegattdescriptor.rs
@@ -90,14 +90,24 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
fn ReadValue(&self) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 2.
if !self.Characteristic().Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 3 - 4: Implement representedDescriptor internal slot for BluetoothRemoteGATTDescriptor.
+
+ // TODO: Step 5: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
+ // Note: Substeps of Step 5 are implemented in components/bluetooth/lib.rs in readValue function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
@@ -109,18 +119,30 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 2 - 3.
if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
p.reject_error(p_cx, InvalidModification);
return p;
}
+
+ // Step 4.
if !self.Characteristic().Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5 - 6: Implement representedCharacteristic internal slot for BluetoothRemoteGATTCharacteristic.
+
+ // TODO: Step 7: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
+ // Note: Substeps of Step 7 are implemented in components/bluetooth/lib.rs in writeValue function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap();
@@ -131,15 +153,29 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
BluetoothResponse::ReadValue(result) => {
+ // TODO: Step 5.4.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // Step 5.4.2.
+ // TODO(#5014): Replace ByteString with ArrayBuffer when it is implemented.
let value = ByteString::new(result);
*self.value.borrow_mut() = Some(value.clone());
+
+ // Step 5.4.3.
promise.resolve_native(promise_cx, &value);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
BluetoothResponse::WriteValue(result) => {
- let value = ByteString::new(result);
- *self.value.borrow_mut() = Some(value.clone());
- promise.resolve_native(promise_cx, &value);
+ // TODO: Step 7.4.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // Step 7.4.2.
+ // TODO(#5014): Replace ByteString with an ArrayBuffer wrapped in a DataView.
+ *self.value.borrow_mut() = Some(ByteString::new(result));
+
+ // Step 7.4.3.
+ // TODO: Resolve promise with undefined instead of a value.
+ promise.resolve_native(promise_cx, &());
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
}
diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs
index f8424ad6241..06c11f0aa21 100644
--- a/components/script/dom/bluetoothremotegattserver.rs
+++ b/components/script/dom/bluetoothremotegattserver.rs
@@ -65,19 +65,42 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
fn Connect(&self) -> Rc<Promise> {
+ // Step 1.
let p = Promise::new(&self.global());
let sender = response_async(&p, self);
+
+ // TODO: Step 2: Implement representedDevice internal slot for BluetoothDevice.
+
+ // TODO: Step 3: Check if the UA is currently using the Bluetooth system.
+
+ // TODO: Step 4: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // TODO: Step 5.1 - 5.2: Implement activeAlgorithms, representedDevice internal slots
+ // and the` garbage-collect the connection` algorithm.
+
+ // Note: Steps 5.1.1 and 5.1.3 are in components/bluetooth/lib.rs in the gatt_server_connect function.
+ // Steps 5.2.4 - 5.2.5 are in response function.
self.get_bluetooth_thread().send(
BluetoothRequest::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap();
+ // Step 5: return promise.
return p;
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
fn Disconnect(&self) -> ErrorResult {
+ // TODO: Step 1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // TODO: Step 2: Check if this.connected is false here too.
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothRequest::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap();
let server = receiver.recv().unwrap();
+
+ // TODO: Step 3: Implement the `clean up the disconnected device` algorithm.
+
+ // TODO: Step 4: Implement representedDevice internal slot for BluetoothDevice.
+
+ // TODO: Step 5: Implement the `garbage-collect the connection` algorithm.
match server {
Ok(connected) => {
self.connected.set(connected);
@@ -92,8 +115,12 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
+ // TODO: Step 1: Implement the Permission API and the allowedServices BluetoothDevice internal slot.
+ // Subsequent steps are relative to https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
let uuid = match BluetoothUUID::service(service) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
@@ -101,14 +128,23 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
return p;
}
};
+
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 3 - 4.
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedDevice internal slot for BluetoothDevice.
+
+ // Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_primary_service function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetPrimaryService(String::from(self.Device().Id()), uuid, sender)).unwrap();
@@ -118,10 +154,14 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
+ // TODO: Step 1: Implement the Permission API and the allowedServices BluetoothDevice internal slot.
+ // Subsequent steps are relative to https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
let mut uuid: Option<String> = None;
if let Some(s) = service {
+ // Step 1.
uuid = match BluetoothUUID::service(s) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
@@ -130,16 +170,24 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
}
};
if let Some(ref uuid) = uuid {
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
+
+ // Step 3 - 4.
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedDevice internal slot for BluetoothDevice.
+
+ // Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_primary_services function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetPrimaryServices(String::from(self.Device().Id()), uuid, sender)).unwrap();
@@ -150,10 +198,17 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
BluetoothResponse::GATTServerConnect(connected) => {
+ // Step 5.2.4.
self.connected.set(connected);
+
+ // Step 5.2.5.
promise.resolve_native(promise_cx, self);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetPrimaryService(service) => {
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
@@ -168,6 +223,9 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
promise.resolve_native(promise_cx, &bt_service);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetPrimaryServices(services_vec) => {
let mut services = vec!();
let context = self.device.get().get_context();
diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs
index 69593e2c390..ef922e9b385 100644
--- a/components/script/dom/bluetoothremotegattservice.rs
+++ b/components/script/dom/bluetoothremotegattservice.rs
@@ -8,15 +8,17 @@ use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMet
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::error::Error::{self, Network, Security};
use dom::bindings::js::{JS, MutHeap, Root};
-use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetooth::{AsyncBluetoothListener, response_async};
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
use dom::bluetoothdevice::BluetoothDevice;
use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID};
+use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::IpcSender;
@@ -26,7 +28,7 @@ use std::rc::Rc;
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
#[dom_struct]
pub struct BluetoothRemoteGATTService {
- reflector_: Reflector,
+ eventtarget: EventTarget,
device: MutHeap<JS<BluetoothDevice>>,
uuid: DOMString,
is_primary: bool,
@@ -40,7 +42,7 @@ impl BluetoothRemoteGATTService {
instance_id: String)
-> BluetoothRemoteGATTService {
BluetoothRemoteGATTService {
- reflector_: Reflector::new(),
+ eventtarget: EventTarget::new_inherited(),
device: MutHeap::new(device),
uuid: uuid,
is_primary: is_primary,
@@ -93,11 +95,14 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
fn GetCharacteristic(&self,
characteristic: BluetoothCharacteristicUUID)
-> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
let uuid = match BluetoothUUID::characteristic(characteristic) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
@@ -105,14 +110,23 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
return p;
}
};
+
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 3 - 4.
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedService internal slot for BluetootRemoteGATTService.
+
+ // Note: Steps 6 - 7 are implemented is components/bluetooth/lib.rs in get_characteristic function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetCharacteristic(self.get_instance_id(), uuid, sender)).unwrap();
@@ -121,6 +135,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
fn GetCharacteristics(&self,
characteristic: Option<BluetoothCharacteristicUUID>)
-> Rc<Promise> {
@@ -128,6 +143,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(c) = characteristic {
+ // Step 1.
uuid = match BluetoothUUID::characteristic(c) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
@@ -136,16 +152,24 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
}
};
if let Some(ref uuid) = uuid {
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
+
+ // Step 3 - 4.
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedService internal slot for BluetootRemoteGATTService.
+
+ // Note: Steps 6 - 7 are implemented is components/bluetooth/lib.rs in get_characteristics function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetCharacteristics(self.get_instance_id(), uuid, sender)).unwrap();
@@ -154,11 +178,14 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
fn GetIncludedService(&self,
service: BluetoothServiceUUID)
-> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
+
+ // Step 1.
let uuid = match BluetoothUUID::service(service) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
@@ -166,14 +193,23 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
return p;
}
};
+
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
+
+ // Step 3 - 4.
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedService internal slot for BluetootRemoteGATTService.
+
+ // Note: Steps 6 - 7 are implemented is components/bluetooth/lib.rs in get_included_service function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetIncludedService(self.get_instance_id(),
@@ -185,6 +221,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
fn GetIncludedServices(&self,
service: Option<BluetoothServiceUUID>)
-> Rc<Promise> {
@@ -192,6 +229,7 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(s) = service {
+ // Step 1.
uuid = match BluetoothUUID::service(s) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
@@ -200,16 +238,24 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
}
};
if let Some(ref uuid) = uuid {
+ // Step 2.
if uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
+
+ // Step 3 - 4.
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
+
+ // TODO: Step 5: Implement representedService internal slot for BluetootRemoteGATTService.
+
+ // Note: Steps 6 - 7 are implemented is components/bluetooth/lib.rs in get_included_services function
+ // and in handle_response function.
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetIncludedServices(self.get_instance_id(),
@@ -217,11 +263,23 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
sender)).unwrap();
return p;
}
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
+ event_handler!(serviceadded, GetOnserviceadded, SetOnserviceadded);
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onservicechanged
+ event_handler!(servicechanged, GetOnservicechanged, SetOnservicechanged);
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceremoved
+ event_handler!(serviceremoved, GetOnserviceremoved, SetOnserviceremoved);
}
impl AsyncBluetoothListener for BluetoothRemoteGATTService {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetCharacteristic(characteristic) => {
let context = self.device.get().get_context();
let mut characteristic_map = context.get_characteristic_map().borrow_mut();
@@ -247,6 +305,9 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
characteristic_map.insert(characteristic.instance_id, MutHeap::new(&bt_characteristic));
promise.resolve_native(promise_cx, &bt_characteristic);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetCharacteristics(characteristics_vec) => {
let mut characteristics = vec!();
let context = self.device.get().get_context();
@@ -281,6 +342,9 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
}
promise.resolve_native(promise_cx, &characteristics);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetIncludedService(service) => {
let s =
BluetoothRemoteGATTService::new(&self.global(),
@@ -290,6 +354,9 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTService {
service.instance_id);
promise.resolve_native(promise_cx, &s);
},
+ // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
+ // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
+ // Step 7.
BluetoothResponse::GetIncludedServices(services_vec) => {
let s: Vec<Root<BluetoothRemoteGATTService>> =
services_vec.into_iter()
diff --git a/components/script/dom/bluetoothuuid.rs b/components/script/dom/bluetoothuuid.rs
index 11fb7af94cb..fbf49142aa3 100644
--- a/components/script/dom/bluetoothuuid.rs
+++ b/components/script/dom/bluetoothuuid.rs
@@ -7,7 +7,7 @@ use dom::bindings::error::Error::Syntax;
use dom::bindings::error::Fallible;
use dom::bindings::reflector::Reflector;
use dom::bindings::str::DOMString;
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
use regex::Regex;
pub type UUID = DOMString;
@@ -271,22 +271,22 @@ const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-
impl BluetoothUUID {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-canonicaluuid
- pub fn CanonicalUUID(_: &GlobalScope, alias: u32) -> UUID {
+ pub fn CanonicalUUID(_: &Window, alias: u32) -> UUID {
canonical_uuid(alias)
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getservice
- pub fn GetService(_: &GlobalScope, name: BluetoothServiceUUID) -> Fallible<UUID> {
+ pub fn GetService(_: &Window, name: BluetoothServiceUUID) -> Fallible<UUID> {
Self::service(name)
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getcharacteristic
- pub fn GetCharacteristic(_: &GlobalScope, name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
+ pub fn GetCharacteristic(_: &Window, name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
Self::characteristic(name)
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getdescriptor
- pub fn GetDescriptor(_: &GlobalScope, name: BluetoothDescriptorUUID) -> Fallible<UUID> {
+ pub fn GetDescriptor(_: &Window, name: BluetoothDescriptorUUID) -> Fallible<UUID> {
Self::descriptor(name)
}
}
diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs
index 1409c9c5dcf..2434ab76819 100644
--- a/components/script/dom/browsingcontext.rs
+++ b/components/script/dom/browsingcontext.rs
@@ -20,11 +20,12 @@ use js::glue::{GetProxyPrivate, SetProxyExtra, GetProxyExtra};
use js::jsapi::{Handle, HandleId, HandleObject, HandleValue};
use js::jsapi::{JSAutoCompartment, JSContext, JSErrNum, JSFreeOp, JSObject};
use js::jsapi::{JSPROP_READONLY, JSTracer, JS_DefinePropertyById};
-use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass};
+use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo};
use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById};
use js::jsapi::{MutableHandle, MutableHandleObject, MutableHandleValue};
use js::jsapi::{ObjectOpResult, PropertyDescriptor};
use js::jsval::{UndefinedValue, PrivateValue};
+use js::rust::get_object_class;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
@@ -67,7 +68,7 @@ impl BrowsingContext {
let cx = window.get_cx();
let parent = window.reflector().get_jsobject();
assert!(!parent.get().is_null());
- assert!(((*JS_GetClass(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
+ assert!(((*get_object_class(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
let _ac = JSAutoCompartment::new(cx, parent.get());
rooted!(in(cx) let window_proxy = NewWindowProxy(cx, parent, handler));
assert!(!window_proxy.is_null());
diff --git a/components/script/dom/comment.rs b/components/script/dom/comment.rs
index b135def6e2a..9efe8c8164c 100644
--- a/components/script/dom/comment.rs
+++ b/components/script/dom/comment.rs
@@ -9,8 +9,8 @@ use dom::bindings::js::Root;
use dom::bindings::str::DOMString;
use dom::characterdata::CharacterData;
use dom::document::Document;
-use dom::globalscope::GlobalScope;
use dom::node::Node;
+use dom::window::Window;
/// An HTML comment.
#[dom_struct]
@@ -31,8 +31,8 @@ impl Comment {
CommentBinding::Wrap)
}
- pub fn Constructor(global: &GlobalScope, data: DOMString) -> Fallible<Root<Comment>> {
- let document = global.as_window().Document();
+ pub fn Constructor(window: &Window, data: DOMString) -> Fallible<Root<Comment>> {
+ let document = window.Document();
Ok(Comment::new(data, &document))
}
}
diff --git a/components/script/dom/css.rs b/components/script/dom/css.rs
index f2256007aeb..2e04aed50bc 100644
--- a/components/script/dom/css.rs
+++ b/components/script/dom/css.rs
@@ -6,7 +6,7 @@ use cssparser::serialize_identifier;
use dom::bindings::error::Fallible;
use dom::bindings::reflector::Reflector;
use dom::bindings::str::DOMString;
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
#[dom_struct]
pub struct CSS {
@@ -15,7 +15,7 @@ pub struct CSS {
impl CSS {
// http://dev.w3.org/csswg/cssom/#serialize-an-identifier
- pub fn Escape(_: &GlobalScope, ident: DOMString) -> Fallible<DOMString> {
+ pub fn Escape(_: &Window, ident: DOMString) -> Fallible<DOMString> {
let mut escaped = String::new();
serialize_identifier(&ident, &mut escaped).unwrap();
Ok(DOMString::from(escaped))
diff --git a/components/script/dom/cssfontfacerule.rs b/components/script/dom/cssfontfacerule.rs
index 60022b7ba8f..61234f8846a 100644
--- a/components/script/dom/cssfontfacerule.rs
+++ b/components/script/dom/cssfontfacerule.rs
@@ -22,17 +22,18 @@ pub struct CSSFontFaceRule {
}
impl CSSFontFaceRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, fontfacerule: Arc<RwLock<FontFaceRule>>) -> CSSFontFaceRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>)
+ -> CSSFontFaceRule {
CSSFontFaceRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
fontfacerule: fontfacerule,
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> {
- reflect_dom_object(box CSSFontFaceRule::new_inherited(parent, fontfacerule),
+ reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule),
window,
CSSFontFaceRuleBinding::Wrap)
}
diff --git a/components/script/dom/cssgroupingrule.rs b/components/script/dom/cssgroupingrule.rs
index cd55cd358b6..7176dda8d12 100644
--- a/components/script/dom/cssgroupingrule.rs
+++ b/components/script/dom/cssgroupingrule.rs
@@ -4,7 +4,6 @@
use dom::bindings::codegen::Bindings::CSSGroupingRuleBinding;
use dom::bindings::codegen::Bindings::CSSGroupingRuleBinding::CSSGroupingRuleMethods;
-use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleBinding::CSSRuleMethods;
use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
@@ -14,38 +13,40 @@ use dom::cssrule::CSSRule;
use dom::cssrulelist::{CSSRuleList, RulesSource};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
use style::stylesheets::CssRules as StyleCssRules;
#[dom_struct]
pub struct CSSGroupingRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
- rules: StyleCssRules,
+ rules: Arc<RwLock<StyleCssRules>>,
rulelist: MutNullableHeap<JS<CSSRuleList>>,
}
impl CSSGroupingRule {
- pub fn new_inherited(parent: Option<&CSSStyleSheet>,
- rules: StyleCssRules) -> CSSGroupingRule {
+ pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
+ rules: Arc<RwLock<StyleCssRules>>) -> CSSGroupingRule {
CSSGroupingRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
rules: rules,
rulelist: MutNullableHeap::new(None),
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, rules: StyleCssRules) -> Root<CSSGroupingRule> {
- reflect_dom_object(box CSSGroupingRule::new_inherited(parent, rules),
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
+ rules: Arc<RwLock<StyleCssRules>>) -> Root<CSSGroupingRule> {
+ reflect_dom_object(box CSSGroupingRule::new_inherited(parent_stylesheet, rules),
window,
CSSGroupingRuleBinding::Wrap)
}
fn rulelist(&self) -> Root<CSSRuleList> {
- let sheet = self.upcast::<CSSRule>().GetParentStyleSheet();
- let sheet = sheet.as_ref().map(|s| &**s);
+ let parent_stylesheet = self.upcast::<CSSRule>().parent_stylesheet();
self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(),
- sheet,
+ parent_stylesheet,
RulesSource::Rules(self.rules.clone())))
}
}
diff --git a/components/script/dom/csskeyframerule.rs b/components/script/dom/csskeyframerule.rs
index e09099e1135..78916d339ab 100644
--- a/components/script/dom/csskeyframerule.rs
+++ b/components/script/dom/csskeyframerule.rs
@@ -22,17 +22,18 @@ pub struct CSSKeyframeRule {
}
impl CSSKeyframeRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, keyframerule: Arc<RwLock<Keyframe>>) -> CSSKeyframeRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<RwLock<Keyframe>>)
+ -> CSSKeyframeRule {
CSSKeyframeRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
keyframerule: keyframerule,
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
keyframerule: Arc<RwLock<Keyframe>>) -> Root<CSSKeyframeRule> {
- reflect_dom_object(box CSSKeyframeRule::new_inherited(parent, keyframerule),
+ reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule),
window,
CSSKeyframeRuleBinding::Wrap)
}
diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs
index b7baf6b85a9..259819189a9 100644
--- a/components/script/dom/csskeyframesrule.rs
+++ b/components/script/dom/csskeyframesrule.rs
@@ -5,8 +5,6 @@
use cssparser::Parser;
use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding;
use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding::CSSKeyframesRuleMethods;
-use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
-use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
@@ -20,7 +18,7 @@ use parking_lot::RwLock;
use std::sync::Arc;
use style::keyframes::{Keyframe, KeyframeSelector};
use style::parser::ParserContextExtraData;
-use style::stylesheets::{KeyframesRule, Origin};
+use style::stylesheets::KeyframesRule;
use style_traits::ToCss;
#[dom_struct]
@@ -32,28 +30,28 @@ pub struct CSSKeyframesRule {
}
impl CSSKeyframesRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, keyframesrule: Arc<RwLock<KeyframesRule>>) -> CSSKeyframesRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>)
+ -> CSSKeyframesRule {
CSSKeyframesRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
keyframesrule: keyframesrule,
rulelist: MutNullableHeap::new(None),
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> {
- reflect_dom_object(box CSSKeyframesRule::new_inherited(parent, keyframesrule),
+ reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule),
window,
CSSKeyframesRuleBinding::Wrap)
}
fn rulelist(&self) -> Root<CSSRuleList> {
self.rulelist.or_init(|| {
- let sheet = self.upcast::<CSSRule>().GetParentStyleSheet();
- let sheet = sheet.as_ref().map(|s| &**s);
+ let parent_stylesheet = &self.upcast::<CSSRule>().parent_stylesheet();
CSSRuleList::new(self.global().as_window(),
- sheet,
+ parent_stylesheet,
RulesSource::Keyframes(self.keyframesrule.clone()))
})
}
@@ -82,10 +80,7 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-appendrule
fn AppendRule(&self, rule: DOMString) {
- let global = self.global();
- let window = global.as_window();
- let doc = window.Document();
- let rule = Keyframe::parse(&rule, Origin::Author, doc.url().clone(),
+ let rule = Keyframe::parse(&rule, self.cssrule.parent_stylesheet().style_stylesheet(),
ParserContextExtraData::default());
if let Ok(rule) = rule {
self.keyframesrule.write().keyframes.push(rule);
diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs
index 67933fccd3b..7f4f43f3d5b 100644
--- a/components/script/dom/cssmediarule.rs
+++ b/components/script/dom/cssmediarule.rs
@@ -3,12 +3,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::Bindings::CSSMediaRuleBinding;
-use dom::bindings::js::Root;
-use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::codegen::Bindings::CSSMediaRuleBinding::CSSMediaRuleMethods;
+use dom::bindings::js::{JS, MutNullableHeap, Root};
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::cssgroupingrule::CSSGroupingRule;
use dom::cssrule::SpecificCSSRule;
use dom::cssstylesheet::CSSStyleSheet;
+use dom::medialist::MediaList;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
@@ -20,24 +22,32 @@ pub struct CSSMediaRule {
cssrule: CSSGroupingRule,
#[ignore_heap_size_of = "Arc"]
mediarule: Arc<RwLock<MediaRule>>,
+ medialist: MutNullableHeap<JS<MediaList>>,
}
impl CSSMediaRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, mediarule: Arc<RwLock<MediaRule>>) -> CSSMediaRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>)
+ -> CSSMediaRule {
let list = mediarule.read().rules.clone();
CSSMediaRule {
- cssrule: CSSGroupingRule::new_inherited(parent, list),
+ cssrule: CSSGroupingRule::new_inherited(parent_stylesheet, list),
mediarule: mediarule,
+ medialist: MutNullableHeap::new(None),
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> {
- reflect_dom_object(box CSSMediaRule::new_inherited(parent, mediarule),
+ reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule),
window,
CSSMediaRuleBinding::Wrap)
}
+
+ fn medialist(&self) -> Root<MediaList> {
+ self.medialist.or_init(|| MediaList::new(self.global().as_window(),
+ self.mediarule.read().media_queries.clone()))
+ }
}
impl SpecificCSSRule for CSSMediaRule {
@@ -50,3 +60,10 @@ impl SpecificCSSRule for CSSMediaRule {
self.mediarule.read().to_css_string().into()
}
}
+
+impl CSSMediaRuleMethods for CSSMediaRule {
+ // https://drafts.csswg.org/cssom/#dom-cssgroupingrule-media
+ fn Media(&self) -> Root<MediaList> {
+ self.medialist()
+ }
+}
diff --git a/components/script/dom/cssnamespacerule.rs b/components/script/dom/cssnamespacerule.rs
index 4e93eea2e1f..5f451d3b798 100644
--- a/components/script/dom/cssnamespacerule.rs
+++ b/components/script/dom/cssnamespacerule.rs
@@ -23,17 +23,18 @@ pub struct CSSNamespaceRule {
}
impl CSSNamespaceRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, namespacerule: Arc<RwLock<NamespaceRule>>) -> CSSNamespaceRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>)
+ -> CSSNamespaceRule {
CSSNamespaceRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
namespacerule: namespacerule,
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> {
- reflect_dom_object(box CSSNamespaceRule::new_inherited(parent, namespacerule),
+ reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule),
window,
CSSNamespaceRuleBinding::Wrap)
}
diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs
index ca1e52b77f0..603354c8621 100644
--- a/components/script/dom/cssrule.rs
+++ b/components/script/dom/cssrule.rs
@@ -5,7 +5,7 @@
use dom::bindings::codegen::Bindings::CSSRuleBinding;
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{JS, MutNullableHeap, Root};
+use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::cssfontfacerule::CSSFontFaceRule;
@@ -17,27 +17,34 @@ use dom::cssstylerule::CSSStyleRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::cssviewportrule::CSSViewportRule;
use dom::window::Window;
+use std::cell::Cell;
use style::stylesheets::CssRule as StyleCssRule;
#[dom_struct]
pub struct CSSRule {
reflector_: Reflector,
- parent: MutNullableHeap<JS<CSSStyleSheet>>,
+ parent_stylesheet: JS<CSSStyleSheet>,
+
+ /// Whether the parentStyleSheet attribute should return null.
+ /// We keep parent_stylesheet in that case because insertRule needs it
+ /// for the stylesheet’s base URL and namespace prefixes.
+ parent_stylesheet_removed: Cell<bool>,
}
impl CSSRule {
#[allow(unrooted_must_root)]
- pub fn new_inherited(parent: Option<&CSSStyleSheet>) -> CSSRule {
+ pub fn new_inherited(parent_stylesheet: &CSSStyleSheet) -> CSSRule {
CSSRule {
reflector_: Reflector::new(),
- parent: MutNullableHeap::new(parent),
+ parent_stylesheet: JS::from_ref(parent_stylesheet),
+ parent_stylesheet_removed: Cell::new(false),
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>) -> Root<CSSRule> {
- reflect_dom_object(box CSSRule::new_inherited(parent),
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet) -> Root<CSSRule> {
+ reflect_dom_object(box CSSRule::new_inherited(parent_stylesheet),
window,
CSSRuleBinding::Wrap)
}
@@ -64,16 +71,16 @@ impl CSSRule {
// Given a StyleCssRule, create a new instance of a derived class of
// CSSRule based on which rule it is
- pub fn new_specific(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new_specific(window: &Window, parent_stylesheet: &CSSStyleSheet,
rule: StyleCssRule) -> Root<CSSRule> {
// be sure to update the match in as_specific when this is updated
match rule {
- StyleCssRule::Style(s) => Root::upcast(CSSStyleRule::new(window, parent, s)),
- StyleCssRule::FontFace(s) => Root::upcast(CSSFontFaceRule::new(window, parent, s)),
- StyleCssRule::Keyframes(s) => Root::upcast(CSSKeyframesRule::new(window, parent, s)),
- StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent, s)),
- StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent, s)),
- StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent, s)),
+ StyleCssRule::Style(s) => Root::upcast(CSSStyleRule::new(window, parent_stylesheet, s)),
+ StyleCssRule::FontFace(s) => Root::upcast(CSSFontFaceRule::new(window, parent_stylesheet, s)),
+ StyleCssRule::Keyframes(s) => Root::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s)),
+ StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent_stylesheet, s)),
+ StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s)),
+ StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent_stylesheet, s)),
}
}
@@ -85,12 +92,16 @@ impl CSSRule {
/// Sets owner sheet to null (and does the same for all children)
pub fn deparent(&self) {
- self.parent.set(None);
+ self.parent_stylesheet_removed.set(true);
// https://github.com/w3c/csswg-drafts/issues/722
// Spec doesn't ask us to do this, but it makes sense
// and browsers implement this behavior
self.as_specific().deparent_children();
}
+
+ pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
+ &self.parent_stylesheet
+ }
}
impl CSSRuleMethods for CSSRule {
@@ -101,7 +112,11 @@ impl CSSRuleMethods for CSSRule {
// https://drafts.csswg.org/cssom/#dom-cssrule-parentstylesheet
fn GetParentStyleSheet(&self) -> Option<Root<CSSStyleSheet>> {
- self.parent.get()
+ if self.parent_stylesheet_removed.get() {
+ None
+ } else {
+ Some(Root::from_ref(&*self.parent_stylesheet))
+ }
}
// https://drafts.csswg.org/cssom/#dom-cssrule-csstext
@@ -118,7 +133,7 @@ impl CSSRuleMethods for CSSRule {
pub trait SpecificCSSRule {
fn ty(&self) -> u16;
fn get_css(&self) -> DOMString;
- /// Remove CSSStyleSheet parent from all transitive children
+ /// Remove parentStylesheet from all transitive children
fn deparent_children(&self) {
// most CSSRules do nothing here
}
diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs
index deb6b93e8b1..5f594c27d8c 100644
--- a/components/script/dom/cssrulelist.rs
+++ b/components/script/dom/cssrulelist.rs
@@ -5,7 +5,6 @@
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CSSRuleListBinding;
use dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods;
-use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
@@ -15,33 +14,42 @@ use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
-use style::parser::ParserContextExtraData;
-use style::stylesheets::{CssRules, KeyframesRule, Origin};
-use style::stylesheets::CssRule as StyleCssRule;
+use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError};
no_jsmanaged_fields!(RulesSource);
no_jsmanaged_fields!(CssRules);
+impl From<RulesMutateError> for Error {
+ fn from(other: RulesMutateError) -> Self {
+ match other {
+ RulesMutateError::Syntax => Error::Syntax,
+ RulesMutateError::IndexSize => Error::IndexSize,
+ RulesMutateError::HierarchyRequest => Error::HierarchyRequest,
+ RulesMutateError::InvalidState => Error::InvalidState,
+ }
+ }
+}
+
#[dom_struct]
pub struct CSSRuleList {
reflector_: Reflector,
- sheet: MutNullableHeap<JS<CSSStyleSheet>>,
+ parent_stylesheet: JS<CSSStyleSheet>,
#[ignore_heap_size_of = "Arc"]
rules: RulesSource,
dom_rules: DOMRefCell<Vec<MutNullableHeap<JS<CSSRule>>>>
}
pub enum RulesSource {
- Rules(CssRules),
+ Rules(Arc<RwLock<CssRules>>),
Keyframes(Arc<RwLock<KeyframesRule>>),
}
impl CSSRuleList {
#[allow(unrooted_must_root)]
- pub fn new_inherited(sheet: Option<&CSSStyleSheet>, rules: RulesSource) -> CSSRuleList {
+ pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
let dom_rules = match rules {
RulesSource::Rules(ref rules) => {
- rules.0.read().iter().map(|_| MutNullableHeap::new(None)).collect()
+ rules.read().0.iter().map(|_| MutNullableHeap::new(None)).collect()
}
RulesSource::Keyframes(ref rules) => {
rules.read().keyframes.iter().map(|_| MutNullableHeap::new(None)).collect()
@@ -50,35 +58,23 @@ impl CSSRuleList {
CSSRuleList {
reflector_: Reflector::new(),
- sheet: MutNullableHeap::new(sheet),
+ parent_stylesheet: JS::from_ref(parent_stylesheet),
rules: rules,
dom_rules: DOMRefCell::new(dom_rules),
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, sheet: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
rules: RulesSource) -> Root<CSSRuleList> {
- reflect_dom_object(box CSSRuleList::new_inherited(sheet, rules),
+ reflect_dom_object(box CSSRuleList::new_inherited(parent_stylesheet, rules),
window,
CSSRuleListBinding::Wrap)
}
- /// https://drafts.csswg.org/cssom/#insert-a-css-rule
- ///
/// Should only be called for CssRules-backed rules. Use append_lazy_rule
/// for keyframes-backed rules.
pub fn insert_rule(&self, rule: &str, idx: u32, nested: bool) -> Fallible<u32> {
- use style::stylesheets::SingleRuleParseError;
- /// Insert an item into a vector, appending if it is out of bounds
- fn insert<T>(vec: &mut Vec<T>, index: usize, item: T) {
- if index >= vec.len() {
- vec.push(item);
- } else {
- vec.insert(index, item);
- }
- }
-
let css_rules = if let RulesSource::Rules(ref rules) = self.rules {
rules
} else {
@@ -87,95 +83,25 @@ impl CSSRuleList {
let global = self.global();
let window = global.as_window();
- let doc = window.Document();
let index = idx as usize;
+ let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
+ let new_rule = css_rules.write().insert_rule(rule, parent_stylesheet, index, nested)?;
- let new_rule = {
- let rules = css_rules.0.read();
- let state = if nested {
- None
- } else {
- Some(CssRules::state_at_index(&rules, index))
- };
-
- let rev_state = CssRules::state_at_index_rev(&rules, index);
-
- // Step 1, 2
- // XXXManishearth get url from correct location
- // XXXManishearth should we also store the namespace map?
- let parse_result = StyleCssRule::parse(&rule, Origin::Author,
- doc.url().clone(),
- ParserContextExtraData::default(),
- state);
-
- if let Err(SingleRuleParseError::Syntax) = parse_result {
- return Err(Error::Syntax)
- }
-
- // Step 3, 4
- if index > rules.len() {
- return Err(Error::IndexSize);
- }
-
- let (new_rule, new_state) = try!(parse_result.map_err(|_| Error::HierarchyRequest));
-
- if new_state > rev_state {
- // We inserted a rule too early, e.g. inserting
- // a regular style rule before @namespace rules
- return Err((Error::HierarchyRequest));
- }
-
- // Step 6
- if let StyleCssRule::Namespace(..) = new_rule {
- if !CssRules::only_ns_or_import(&rules) {
- return Err(Error::InvalidState);
- }
- }
-
- new_rule
- };
-
- insert(&mut css_rules.0.write(), index, new_rule.clone());
- let sheet = self.sheet.get();
- let sheet = sheet.as_ref().map(|sheet| &**sheet);
- let dom_rule = CSSRule::new_specific(&window, sheet, new_rule);
- insert(&mut self.dom_rules.borrow_mut(),
- index, MutNullableHeap::new(Some(&*dom_rule)));
+ let parent_stylesheet = &*self.parent_stylesheet;
+ let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
+ self.dom_rules.borrow_mut().insert(index, MutNullableHeap::new(Some(&*dom_rule)));
Ok((idx))
}
- // https://drafts.csswg.org/cssom/#remove-a-css-rule
- // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule
// In case of a keyframe rule, index must be valid.
pub fn remove_rule(&self, index: u32) -> ErrorResult {
let index = index as usize;
match self.rules {
RulesSource::Rules(ref css_rules) => {
- // https://drafts.csswg.org/cssom/#remove-a-css-rule
- {
- let rules = css_rules.0.read();
-
- // Step 1, 2
- if index >= rules.len() {
- return Err(Error::IndexSize);
- }
-
- // Step 3
- let ref rule = rules[index];
-
- // Step 4
- if let StyleCssRule::Namespace(..) = *rule {
- if !CssRules::only_ns_or_import(&rules) {
- return Err(Error::InvalidState);
- }
- }
- }
-
- // Step 5, 6
+ css_rules.write().remove_rule(index)?;
let mut dom_rules = self.dom_rules.borrow_mut();
- css_rules.0.write().remove(index);
dom_rules[index].get().map(|r| r.detach());
dom_rules.remove(index);
Ok(())
@@ -201,17 +127,16 @@ impl CSSRuleList {
pub fn item(&self, idx: u32) -> Option<Root<CSSRule>> {
self.dom_rules.borrow().get(idx as usize).map(|rule| {
rule.or_init(|| {
- let sheet = self.sheet.get();
- let sheet = sheet.as_ref().map(|sheet| &**sheet);
+ let parent_stylesheet = &self.parent_stylesheet;
match self.rules {
RulesSource::Rules(ref rules) => {
CSSRule::new_specific(self.global().as_window(),
- sheet,
- rules.0.read()[idx as usize].clone())
+ parent_stylesheet,
+ rules.read().0[idx as usize].clone())
}
RulesSource::Keyframes(ref rules) => {
Root::upcast(CSSKeyframeRule::new(self.global().as_window(),
- sheet,
+ parent_stylesheet,
rules.read()
.keyframes[idx as usize]
.clone()))
diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs
index 7d776655147..091704f42d5 100644
--- a/components/script/dom/cssstylerule.rs
+++ b/components/script/dom/cssstylerule.rs
@@ -22,17 +22,18 @@ pub struct CSSStyleRule {
}
impl CSSStyleRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, stylerule: Arc<RwLock<StyleRule>>) -> CSSStyleRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>)
+ -> CSSStyleRule {
CSSStyleRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
stylerule: stylerule,
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> {
- reflect_dom_object(box CSSStyleRule::new_inherited(parent, stylerule),
+ reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule),
window,
CSSStyleRuleBinding::Wrap)
}
diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs
index 32413ea0298..93aefa8f852 100644
--- a/components/script/dom/cssstylesheet.rs
+++ b/components/script/dom/cssstylesheet.rs
@@ -53,7 +53,7 @@ impl CSSStyleSheet {
fn rulelist(&self) -> Root<CSSRuleList> {
self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(),
- Some(self),
+ self,
RulesSource::Rules(self.style_stylesheet
.rules.clone())))
}
@@ -67,6 +67,10 @@ impl CSSStyleSheet {
self.global().as_window().Document().invalidate_stylesheets();
}
}
+
+ pub fn style_stylesheet(&self) -> &StyleStyleSheet {
+ &self.style_stylesheet
+ }
}
impl CSSStyleSheetMethods for CSSStyleSheet {
diff --git a/components/script/dom/cssviewportrule.rs b/components/script/dom/cssviewportrule.rs
index b324b0c64f5..25ca1b292c8 100644
--- a/components/script/dom/cssviewportrule.rs
+++ b/components/script/dom/cssviewportrule.rs
@@ -22,17 +22,17 @@ pub struct CSSViewportRule {
}
impl CSSViewportRule {
- fn new_inherited(parent: Option<&CSSStyleSheet>, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule {
+ fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule {
CSSViewportRule {
- cssrule: CSSRule::new_inherited(parent),
+ cssrule: CSSRule::new_inherited(parent_stylesheet),
viewportrule: viewportrule,
}
}
#[allow(unrooted_must_root)]
- pub fn new(window: &Window, parent: Option<&CSSStyleSheet>,
+ pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> {
- reflect_dom_object(box CSSViewportRule::new_inherited(parent, viewportrule),
+ reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule),
window,
CSSViewportRuleBinding::Wrap)
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 5870e4c1320..8b66d2db75d 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -136,18 +136,12 @@ pub enum TouchEventResult {
Forwarded,
}
-#[derive(JSTraceable, PartialEq, HeapSizeOf)]
+#[derive(Clone, Copy, Debug, HeapSizeOf, JSTraceable, PartialEq)]
pub enum IsHTMLDocument {
HTMLDocument,
NonHTMLDocument,
}
-#[derive(PartialEq)]
-enum ParserBlockedByScript {
- Blocked,
- Unblocked,
-}
-
#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct StylesheetInDocument {
@@ -287,6 +281,8 @@ pub struct Document {
/// https://w3c.github.io/uievents/#event-type-dblclick
#[ignore_heap_size_of = "Defined in std"]
last_click_info: DOMRefCell<Option<(Instant, Point2D<f32>)>>,
+ /// https://html.spec.whatwg.org/multipage/#ignore-destructive-writes-counter
+ ignore_destructive_writes_counter: Cell<u32>,
}
#[derive(JSTraceable, HeapSizeOf)]
@@ -378,15 +374,16 @@ impl Document {
self.trigger_mozbrowser_event(MozBrowserEvent::SecurityChange(https_state));
}
+ // https://html.spec.whatwg.org/multipage/#active-document
+ pub fn is_active(&self) -> bool {
+ self.browsing_context().map_or(false, |context| {
+ self == &*context.active_document()
+ })
+ }
+
// https://html.spec.whatwg.org/multipage/#fully-active
pub fn is_fully_active(&self) -> bool {
- let browsing_context = match self.browsing_context() {
- Some(browsing_context) => browsing_context,
- None => return false,
- };
- let active_document = browsing_context.active_document();
-
- if self != &*active_document {
+ if !self.is_active() {
return false;
}
// FIXME: It should also check whether the browser context is top-level or not
@@ -1545,15 +1542,13 @@ impl Document {
self.process_asap_scripts();
}
- if self.maybe_execute_parser_blocking_script() == ParserBlockedByScript::Blocked {
- return;
- }
-
- // A finished resource load can potentially unblock parsing. In that case, resume the
- // parser so its loop can find out.
if let Some(parser) = self.get_current_parser() {
- if parser.is_suspended() {
- parser.resume();
+ if let Some(script) = self.pending_parsing_blocking_script.get() {
+ if self.script_blocking_stylesheets_count.get() > 0 || !script.is_ready_to_be_executed() {
+ return;
+ }
+ self.pending_parsing_blocking_script.set(None);
+ parser.resume_with_pending_parsing_blocking_script(&script);
}
} else if self.reflow_timeout.get().is_none() {
// If we don't have a parser, and the reflow timer has been reset, explicitly
@@ -1576,23 +1571,6 @@ impl Document {
}
}
- /// If document parsing is blocked on a script, and that script is ready to run,
- /// execute it.
- /// https://html.spec.whatwg.org/multipage/#ready-to-be-parser-executed
- fn maybe_execute_parser_blocking_script(&self) -> ParserBlockedByScript {
- let script = match self.pending_parsing_blocking_script.get() {
- None => return ParserBlockedByScript::Unblocked,
- Some(script) => script,
- };
-
- if self.script_blocking_stylesheets_count.get() == 0 && script.is_ready_to_be_executed() {
- self.pending_parsing_blocking_script.set(None);
- script.execute();
- return ParserBlockedByScript::Unblocked;
- }
- ParserBlockedByScript::Blocked
- }
-
/// https://html.spec.whatwg.org/multipage/#the-end step 3
pub fn process_deferred_scripts(&self) {
if self.ready_state.get() != DocumentReadyState::Interactive {
@@ -1901,15 +1879,15 @@ impl Document {
referrer_policy: Cell::new(referrer_policy),
target_element: MutNullableHeap::new(None),
last_click_info: DOMRefCell::new(None),
+ ignore_destructive_writes_counter: Default::default(),
}
}
// https://dom.spec.whatwg.org/#dom-document
- pub fn Constructor(global: &GlobalScope) -> Fallible<Root<Document>> {
- let win = global.as_window();
- let doc = win.Document();
+ pub fn Constructor(window: &Window) -> Fallible<Root<Document>> {
+ let doc = window.Document();
let docloader = DocumentLoader::new(&*doc.loader());
- Ok(Document::new(win,
+ Ok(Document::new(window,
None,
None,
IsHTMLDocument::NonHTMLDocument,
@@ -2077,6 +2055,16 @@ impl Document {
ReflowQueryType::NoQuery,
ReflowReason::ElementStateChanged);
}
+
+ pub fn incr_ignore_destructive_writes_counter(&self) {
+ self.ignore_destructive_writes_counter.set(
+ self.ignore_destructive_writes_counter.get() + 1);
+ }
+
+ pub fn decr_ignore_destructive_writes_counter(&self) {
+ self.ignore_destructive_writes_counter.set(
+ self.ignore_destructive_writes_counter.get() - 1);
+ }
}
@@ -2437,7 +2425,7 @@ impl DocumentMethods for Document {
)
)),
"webglcontextevent" =>
- Ok(Root::upcast(WebGLContextEvent::new_uninitialized(self.window.upcast()))),
+ Ok(Root::upcast(WebGLContextEvent::new_uninitialized(&self.window))),
"storageevent" => {
let USVString(url) = self.URL();
Ok(Root::upcast(StorageEvent::new_uninitialized(&self.window, DOMString::from(url))))
@@ -3043,6 +3031,55 @@ impl DocumentMethods for Document {
elements
}
+ // https://html.spec.whatwg.org/multipage/#dom-document-write
+ fn Write(&self, text: Vec<DOMString>) -> ErrorResult {
+ if !self.is_html_document() {
+ // Step 1.
+ return Err(Error::InvalidState);
+ }
+
+ // Step 2.
+ // TODO: handle throw-on-dynamic-markup-insertion counter.
+
+ if !self.is_active() {
+ // Step 3.
+ return Ok(());
+ }
+
+ let parser = self.get_current_parser();
+ let parser = match parser.as_ref() {
+ Some(parser) if parser.script_nesting_level() > 0 => parser,
+ _ => {
+ // Either there is no parser, which means the parsing ended;
+ // or script nesting level is 0, which means the method was
+ // called from outside a parser-executed script.
+ if self.ignore_destructive_writes_counter.get() > 0 {
+ // Step 4.
+ // TODO: handle ignore-opens-during-unload counter.
+ return Ok(());
+ }
+ // Step 5.
+ // TODO: call document.open().
+ return Err(Error::InvalidState);
+ }
+ };
+
+ // Step 7.
+ // TODO: handle reload override buffer.
+
+ // Steps 6-8.
+ parser.write(text);
+
+ // Step 9.
+ Ok(())
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-document-writeln
+ fn Writeln(&self, mut text: Vec<DOMString>) -> ErrorResult {
+ text.push("\n".into());
+ self.Write(text)
+ }
+
// https://html.spec.whatwg.org/multipage/#documentandelementeventhandlers
document_and_element_event_handlers!();
}
diff --git a/components/script/dom/documentfragment.rs b/components/script/dom/documentfragment.rs
index 334e083f1b7..554fb8fe3b3 100644
--- a/components/script/dom/documentfragment.rs
+++ b/components/script/dom/documentfragment.rs
@@ -12,10 +12,10 @@ use dom::bindings::js::Root;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::Element;
-use dom::globalscope::GlobalScope;
use dom::htmlcollection::HTMLCollection;
use dom::node::{Node, window_from_node};
use dom::nodelist::NodeList;
+use dom::window::Window;
use servo_atoms::Atom;
// https://dom.spec.whatwg.org/#documentfragment
@@ -38,8 +38,8 @@ impl DocumentFragment {
DocumentFragmentBinding::Wrap)
}
- pub fn Constructor(global: &GlobalScope) -> Fallible<Root<DocumentFragment>> {
- let document = global.as_window().Document();
+ pub fn Constructor(window: &Window) -> Fallible<Root<DocumentFragment>> {
+ let document = window.Document();
Ok(DocumentFragment::new(&document))
}
diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs
index 2a770aeb3a0..0ce2d50e09a 100644
--- a/components/script/dom/domparser.rs
+++ b/components/script/dom/domparser.rs
@@ -17,7 +17,6 @@ use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::document::{Document, IsHTMLDocument};
use dom::document::DocumentSource;
-use dom::globalscope::GlobalScope;
use dom::servoparser::ServoParser;
use dom::window::Window;
@@ -41,8 +40,8 @@ impl DOMParser {
DOMParserBinding::Wrap)
}
- pub fn Constructor(global: &GlobalScope) -> Fallible<Root<DOMParser>> {
- Ok(DOMParser::new(global.as_window()))
+ pub fn Constructor(window: &Window) -> Fallible<Root<DOMParser>> {
+ Ok(DOMParser::new(window))
}
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index d8f0dd601a7..c384001e33a 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -30,6 +30,7 @@ use dom::bindings::xmlname::XMLName::InvalidXMLName;
use dom::characterdata::CharacterData;
use dom::create::create_element;
use dom::document::{Document, LayoutDocumentHelpers};
+use dom::documentfragment::DocumentFragment;
use dom::domrect::DOMRect;
use dom::domrectlist::DOMRectList;
use dom::domtokenlist::DOMTokenList;
@@ -61,6 +62,7 @@ use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
use dom::node::{document_from_node, window_from_node};
use dom::nodelist::NodeList;
+use dom::servoparser::ServoParser;
use dom::text::Text;
use dom::validation::Validatable;
use dom::virtualmethods::{VirtualMethods, vtable_for};
@@ -71,6 +73,7 @@ use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks};
use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
use parking_lot::RwLock;
+use ref_filter_map::ref_filter_map;
use selectors::matching::{ElementFlags, MatchingReason, matches};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
use selectors::parser::{AttrSelector, NamespaceConstraint};
@@ -712,12 +715,52 @@ impl Element {
&self.namespace
}
- pub fn prefix(&self) -> &Option<DOMString> {
- &self.prefix
+ pub fn prefix(&self) -> Option<&DOMString> {
+ self.prefix.as_ref()
}
- pub fn attrs(&self) -> Ref<Vec<JS<Attr>>> {
- self.attrs.borrow()
+ pub fn attrs(&self) -> Ref<[JS<Attr>]> {
+ Ref::map(self.attrs.borrow(), |attrs| &**attrs)
+ }
+
+ // Element branch of https://dom.spec.whatwg.org/#locate-a-namespace
+ pub fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
+ let prefix = prefix.map(String::from).map(LocalName::from);
+
+ let inclusive_ancestor_elements =
+ self.upcast::<Node>()
+ .inclusive_ancestors()
+ .filter_map(Root::downcast::<Self>);
+
+ // Steps 3-4.
+ for element in inclusive_ancestor_elements {
+ // Step 1.
+ if element.namespace() != &ns!() && element.prefix().map(|p| &**p) == prefix.as_ref().map(|p| &**p) {
+ return element.namespace().clone();
+ }
+
+ // Step 2.
+ let attr = ref_filter_map(self.attrs(), |attrs| {
+ attrs.iter().find(|attr| {
+ if attr.namespace() != &ns!(xmlns) {
+ return false;
+ }
+ match (attr.prefix(), prefix.as_ref()) {
+ (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
+ attr.local_name() == prefix
+ },
+ (None, None) => attr.local_name() == &local_name!("xmlns"),
+ _ => false,
+ }
+ })
+ });
+
+ if let Some(attr) = attr {
+ return (**attr.value()).into();
+ }
+ }
+
+ ns!()
}
pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>> {
@@ -818,7 +861,7 @@ impl Element {
// Step 2.
for attr in element.attrs.borrow().iter() {
- if *attr.prefix() == Some(namespace_prefix!("xmlns")) &&
+ if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
**attr.value() == *namespace {
return Some(attr.LocalName());
}
@@ -1230,6 +1273,33 @@ impl Element {
// Step 11
win.scroll_node(node.to_trusted_node_address(), x, y, behavior);
}
+
+ // https://w3c.github.io/DOM-Parsing/#parsing
+ pub fn parse_fragment(&self, markup: DOMString) -> Fallible<Root<DocumentFragment>> {
+ // Steps 1-2.
+ let context_document = document_from_node(self);
+ // TODO(#11995): XML case.
+ let new_children = ServoParser::parse_html_fragment(self, markup);
+ // Step 3.
+ let fragment = DocumentFragment::new(&context_document);
+ // Step 4.
+ for child in new_children {
+ fragment.upcast::<Node>().AppendChild(&child).unwrap();
+ }
+ // Step 5.
+ Ok(fragment)
+ }
+
+ pub fn fragment_parsing_context(owner_doc: &Document, element: Option<&Self>) -> Root<Self> {
+ match element {
+ Some(elem) if elem.local_name() != &local_name!("html") || !elem.html_element_in_html_document() => {
+ Root::from_ref(elem)
+ },
+ _ => {
+ Root::upcast(HTMLBodyElement::new(local_name!("body"), None, owner_doc))
+ }
+ }
+ }
}
impl ElementMethods for Element {
@@ -1757,15 +1827,14 @@ impl ElementMethods for Element {
/// https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML
fn SetInnerHTML(&self, value: DOMString) -> ErrorResult {
- let context_node = self.upcast::<Node>();
// Step 1.
- let frag = try!(context_node.parse_fragment(value));
+ let frag = try!(self.parse_fragment(value));
// Step 2.
// https://github.com/w3c/DOM-Parsing/issues/1
let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
Root::upcast(template.Content())
} else {
- Root::from_ref(context_node)
+ Root::from_ref(self.upcast())
};
Node::replace_all(Some(frag.upcast()), &target);
Ok(())
@@ -1776,7 +1845,7 @@ impl ElementMethods for Element {
self.serialize(IncludeNode)
}
- // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-outerHTML
+ // https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml
fn SetOuterHTML(&self, value: DOMString) -> ErrorResult {
let context_document = document_from_node(self);
let context_node = self.upcast::<Node>();
@@ -1800,7 +1869,7 @@ impl ElementMethods for Element {
ElementCreator::ScriptCreated);
Root::upcast(body_elem)
},
- _ => context_node.GetParentNode().unwrap()
+ _ => context_node.GetParentElement().unwrap()
};
// Step 5.
@@ -1957,14 +2026,11 @@ impl ElementMethods for Element {
};
// Step 2.
- let context = match context.downcast::<Element>() {
- Some(elem) if elem.local_name() != &local_name!("html") ||
- !elem.html_element_in_html_document() => Root::from_ref(elem),
- _ => Root::upcast(HTMLBodyElement::new(local_name!("body"), None, &*context.owner_doc())),
- };
+ let context = Element::fragment_parsing_context(
+ &context.owner_doc(), context.downcast::<Element>());
// Step 3.
- let fragment = try!(context.upcast::<Node>().parse_fragment(text));
+ let fragment = try!(context.parse_fragment(text));
// Step 4.
self.insert_adjacent(position, fragment.upcast()).map(|_| ())
diff --git a/components/script/dom/extendableevent.rs b/components/script/dom/extendableevent.rs
index 55e9500a8e4..0a7db40b6d5 100644
--- a/components/script/dom/extendableevent.rs
+++ b/components/script/dom/extendableevent.rs
@@ -10,7 +10,7 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::Event;
-use dom::globalscope::GlobalScope;
+use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use js::jsapi::{HandleValue, JSContext};
use servo_atoms::Atom;
@@ -28,12 +28,12 @@ impl ExtendableEvent {
extensions_allowed: true
}
}
- pub fn new(global: &GlobalScope,
+ pub fn new(worker: &ServiceWorkerGlobalScope,
type_: Atom,
bubbles: bool,
cancelable: bool)
-> Root<ExtendableEvent> {
- let ev = reflect_dom_object(box ExtendableEvent::new_inherited(), global, ExtendableEventBinding::Wrap);
+ let ev = reflect_dom_object(box ExtendableEvent::new_inherited(), worker, ExtendableEventBinding::Wrap);
{
let event = ev.upcast::<Event>();
event.init_event(type_, bubbles, cancelable);
@@ -41,10 +41,10 @@ impl ExtendableEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(worker: &ServiceWorkerGlobalScope,
type_: DOMString,
init: &ExtendableEventBinding::ExtendableEventInit) -> Fallible<Root<ExtendableEvent>> {
- Ok(ExtendableEvent::new(global,
+ Ok(ExtendableEvent::new(worker,
Atom::from(type_),
init.parent.bubbles,
init.parent.cancelable))
diff --git a/components/script/dom/extendablemessageevent.rs b/components/script/dom/extendablemessageevent.rs
index fbbdd59cbd3..8f156a8f4d3 100644
--- a/components/script/dom/extendablemessageevent.rs
+++ b/components/script/dom/extendablemessageevent.rs
@@ -13,6 +13,7 @@ use dom::event::Event;
use dom::eventtarget::EventTarget;
use dom::extendableevent::ExtendableEvent;
use dom::globalscope::GlobalScope;
+use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use js::jsapi::{HandleValue, Heap, JSContext};
use js::jsval::JSVal;
use servo_atoms::Atom;
@@ -46,10 +47,11 @@ impl ExtendableMessageEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(worker: &ServiceWorkerGlobalScope,
type_: DOMString,
init: &ExtendableMessageEventBinding::ExtendableMessageEventInit)
-> Fallible<Root<ExtendableMessageEvent>> {
+ let global = worker.upcast::<GlobalScope>();
rooted!(in(global.get_cx()) let data = init.data);
let ev = ExtendableMessageEvent::new(global,
Atom::from(type_),
diff --git a/components/script/dom/focusevent.rs b/components/script/dom/focusevent.rs
index d06b725286d..1eb3983737d 100644
--- a/components/script/dom/focusevent.rs
+++ b/components/script/dom/focusevent.rs
@@ -53,12 +53,12 @@ impl FocusEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(window: &Window,
type_: DOMString,
init: &FocusEventBinding::FocusEventInit) -> Fallible<Root<FocusEvent>> {
let bubbles = EventBubbles::from(init.parent.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.parent.cancelable);
- let event = FocusEvent::new(global.as_window(),
+ let event = FocusEvent::new(window,
type_,
bubbles,
cancelable,
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 0251bd8143e..7cd092e0683 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -24,15 +24,15 @@ use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
use js::glue::{IsWrapper, UnwrapObject};
use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment};
use js::jsapi::{HandleValue, Evaluate2, JSAutoCompartment, JSContext};
-use js::jsapi::{JSObject, JS_GetClass, JS_GetContext};
+use js::jsapi::{JSObject, JS_GetContext};
use js::jsapi::{JS_GetObjectRuntime, MutableHandleValue};
-use js::rust::CompileOptionsWrapper;
+use js::panic::maybe_resume_unwind;
+use js::rust::{CompileOptionsWrapper, get_object_class};
use libc;
use msg::constellation_msg::PipelineId;
use net_traits::{CoreResourceThread, ResourceThreads, IpcSend};
use profile_traits::{mem, time};
-use script_runtime::{CommonScriptMsg, EnqueuedPromiseCallback, ScriptChan};
-use script_runtime::{ScriptPort, maybe_take_panic_result};
+use script_runtime::{CommonScriptMsg, EnqueuedPromiseCallback, ScriptChan, ScriptPort};
use script_thread::{MainThreadScriptChan, RunnableWrapper, ScriptThread};
use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEvent};
use script_traits::{TimerEventId, TimerEventRequest, TimerSource};
@@ -41,7 +41,6 @@ use std::cell::Cell;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ffi::CString;
-use std::panic;
use task_source::file_reading::FileReadingTaskSource;
use task_source::networking::NetworkingTaskSource;
use time::{Timespec, get_time};
@@ -376,9 +375,7 @@ impl GlobalScope {
}
}
- if let Some(error) = maybe_take_panic_result() {
- panic::resume_unwind(error);
- }
+ maybe_resume_unwind();
}
)
}
@@ -519,7 +516,7 @@ fn timestamp_in_ms(time: Timespec) -> u64 {
#[allow(unsafe_code)]
unsafe fn global_scope_from_global(global: *mut JSObject) -> Root<GlobalScope> {
assert!(!global.is_null());
- let clasp = JS_GetClass(global);
+ let clasp = get_object_class(global);
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
root_from_object(global).unwrap()
}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index b5621364c13..b9d7731d652 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -177,7 +177,7 @@ impl HTMLCanvasElement {
GLContextAttributes::default()
};
- let maybe_ctx = WebGLRenderingContext::new(window.upcast(), self, size, attrs);
+ let maybe_ctx = WebGLRenderingContext::new(&window, self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_ref(&*ctx)));
}
diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs
index 71fc6a1ecf1..959265e82e0 100644
--- a/components/script/dom/htmlcollection.rs
+++ b/components/script/dom/htmlcollection.rs
@@ -151,11 +151,11 @@ impl HTMLCollection {
}
fn match_element(elem: &Element, qualified_name: &LocalName) -> bool {
- match *elem.prefix() {
+ match elem.prefix() {
None => elem.local_name() == qualified_name,
- Some(ref prefix) => qualified_name.starts_with(prefix as &str) &&
- qualified_name.find(":") == Some((prefix as &str).len()) &&
- qualified_name.ends_with(elem.local_name() as &str),
+ Some(prefix) => qualified_name.starts_with(&**prefix) &&
+ qualified_name.find(":") == Some(prefix.len()) &&
+ qualified_name.ends_with(&**elem.local_name()),
}
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index a31baa9f045..c322b96a555 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -20,6 +20,7 @@ use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
+use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
use dom::browsingcontext::BrowsingContext;
@@ -42,14 +43,16 @@ use js::jsval::{NullValue, UndefinedValue};
use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection};
use net_traits::response::HttpsState;
use script_layout_interface::message::ReflowQueryType;
-use script_thread::ScriptThread;
-use script_traits::{IFrameLoadInfo, LoadData, MozBrowserEvent, ScriptMsg as ConstellationMsg};
+use script_thread::{ScriptThread, Runnable};
+use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData};
+use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg};
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::cell::Cell;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::context::ReflowGoal;
+use task_source::TaskSource;
use util::prefs::PREFS;
use util::servo_version;
@@ -66,6 +69,12 @@ bitflags! {
}
}
+#[derive(PartialEq)]
+enum ProcessingMode {
+ FirstTime,
+ NotFirstTime,
+}
+
#[dom_struct]
pub struct HTMLIFrameElement {
htmlelement: HTMLElement,
@@ -131,20 +140,46 @@ impl HTMLIFrameElement {
let global_scope = window.upcast::<GlobalScope>();
let load_info = IFrameLoadInfo {
- load_data: load_data,
parent_pipeline_id: global_scope.pipeline_id(),
frame_id: self.frame_id,
- old_pipeline_id: old_pipeline_id,
new_pipeline_id: new_pipeline_id,
- sandbox: sandboxed,
is_private: private_iframe,
frame_type: frame_type,
replace: replace,
};
- global_scope
- .constellation_chan()
- .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info))
- .unwrap();
+
+ if load_data.as_ref().map_or(false, |d| d.url.as_str() == "about:blank") {
+ let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
+
+ global_scope
+ .constellation_chan()
+ .send(ConstellationMsg::ScriptLoadedAboutBlankInIFrame(load_info, pipeline_sender))
+ .unwrap();
+
+ let new_layout_info = NewLayoutInfo {
+ parent_info: Some((global_scope.pipeline_id(), frame_type)),
+ new_pipeline_id: new_pipeline_id,
+ frame_id: self.frame_id,
+ load_data: load_data.unwrap(),
+ pipeline_port: pipeline_receiver,
+ content_process_shutdown_chan: None,
+ window_size: None,
+ layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
+ };
+
+ ScriptThread::process_attach_layout(new_layout_info);
+ } else {
+ let load_info = IFrameLoadInfoWithData {
+ info: load_info,
+ load_data: load_data,
+ old_pipeline_id: old_pipeline_id,
+ sandbox: sandboxed,
+ };
+ global_scope
+ .constellation_chan()
+ .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info))
+ .unwrap();
+ }
if PREFS.is_mozbrowser_enabled() {
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
@@ -152,9 +187,23 @@ impl HTMLIFrameElement {
}
}
- pub fn process_the_iframe_attributes(&self) {
+ /// https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes
+ fn process_the_iframe_attributes(&self, mode: ProcessingMode) {
+ // TODO: srcdoc
+
+ // https://github.com/whatwg/html/issues/490
+ if mode == ProcessingMode::FirstTime && !self.upcast::<Element>().has_attribute(&local_name!("src")) {
+ let window = window_from_node(self);
+ let event_loop = window.dom_manipulation_task_source();
+ let _ = event_loop.queue(box IframeLoadEventSteps::new(self),
+ window.upcast());
+ return;
+ }
+
let url = self.get_url();
+ // TODO: check ancestor browsing contexts for same URL
+
let document = document_from_node(self);
self.navigate_or_reload_child_browsing_context(
Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url()))), false);
@@ -171,6 +220,16 @@ impl HTMLIFrameElement {
}
}
+ fn create_nested_browsing_context(&self) {
+ // Synchronously create a new context and navigate it to about:blank.
+ let url = ServoUrl::parse("about:blank").unwrap();
+ let document = document_from_node(self);
+ let load_data = LoadData::new(url,
+ document.get_referrer_policy(),
+ Some(document.url().clone()));
+ self.navigate_or_reload_child_browsing_context(Some(load_data), false);
+ }
+
pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId) {
self.pipeline_id.set(Some(new_pipeline_id));
@@ -272,7 +331,11 @@ impl HTMLIFrameElement {
self.pipeline_id.get()
.and_then(|pipeline_id| ScriptThread::find_document(pipeline_id))
.and_then(|document| {
- if self.global().get_url().origin() == document.global().get_url().origin() {
+ // FIXME(#10964): this should use the Document's origin and the
+ // origin of the incumbent settings object.
+ let contained_url = document.global().get_url();
+ if self.global().get_url().origin() == contained_url.origin() ||
+ contained_url.as_str() == "about:blank" {
Some(Root::from_ref(document.window()))
} else {
None
@@ -458,18 +521,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument
fn GetContentDocument(&self) -> Option<Root<Document>> {
- self.get_content_window().and_then(|window| {
- // FIXME(#10964): this should use the Document's origin and the
- // origin of the incumbent settings object.
- let self_url = self.get_url();
- let win_url = window_from_node(self).get_url();
-
- if UrlHelper::SameOrigin(&self_url, &win_url) {
- Some(window.Document())
- } else {
- None
- }
- })
+ self.get_content_window().map(|window| window.Document())
}
// Experimental mozbrowser implementation is based on the webidl
@@ -601,19 +653,17 @@ impl VirtualMethods for HTMLIFrameElement {
}));
},
&local_name!("src") => {
- if let AttributeMutation::Set(_) = mutation {
- // https://html.spec.whatwg.org/multipage/#the-iframe-element
- // "Similarly, whenever an iframe element with a non-null nested browsing context
- // but with no srcdoc attribute specified has its src attribute set, changed, or removed,
- // the user agent must process the iframe attributes,"
- // but we can't check that directly, since the child browsing context
- // may be in a different script thread. Instread, we check to see if the parent
- // is in a document tree and has a browsing context, which is what causes
- // the child browsing context to be created.
- if self.upcast::<Node>().is_in_doc_with_browsing_context() {
- debug!("iframe {} src set while in browsing context.", self.frame_id);
- self.process_the_iframe_attributes();
- }
+ // https://html.spec.whatwg.org/multipage/#the-iframe-element
+ // "Similarly, whenever an iframe element with a non-null nested browsing context
+ // but with no srcdoc attribute specified has its src attribute set, changed, or removed,
+ // the user agent must process the iframe attributes,"
+ // but we can't check that directly, since the child browsing context
+ // may be in a different script thread. Instread, we check to see if the parent
+ // is in a document tree and has a browsing context, which is what causes
+ // the child browsing context to be created.
+ if self.upcast::<Node>().is_in_doc_with_browsing_context() {
+ debug!("iframe {} src set while in browsing context.", self.frame_id);
+ self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
}
},
_ => {},
@@ -642,7 +692,8 @@ impl VirtualMethods for HTMLIFrameElement {
// iframe attributes for the "first time"."
if self.upcast::<Node>().is_in_doc_with_browsing_context() {
debug!("iframe {} bound to browsing context.", self.frame_id);
- self.process_the_iframe_attributes();
+ self.create_nested_browsing_context();
+ self.process_the_iframe_attributes(ProcessingMode::FirstTime);
}
}
@@ -667,7 +718,7 @@ impl VirtualMethods for HTMLIFrameElement {
// HTMLIFrameElement::contentDocument.
let self_url = self.get_url();
let win_url = window_from_node(self).get_url();
- UrlHelper::SameOrigin(&self_url, &win_url)
+ UrlHelper::SameOrigin(&self_url, &win_url) || self_url.as_str() == "about:blank"
};
let (sender, receiver) = if same_origin {
(None, None)
@@ -690,3 +741,24 @@ impl VirtualMethods for HTMLIFrameElement {
}
}
}
+
+struct IframeLoadEventSteps {
+ frame_element: Trusted<HTMLIFrameElement>,
+ pipeline_id: PipelineId,
+}
+
+impl IframeLoadEventSteps {
+ fn new(frame_element: &HTMLIFrameElement) -> IframeLoadEventSteps {
+ IframeLoadEventSteps {
+ frame_element: Trusted::new(frame_element),
+ pipeline_id: frame_element.pipeline_id().unwrap(),
+ }
+ }
+}
+
+impl Runnable for IframeLoadEventSteps {
+ fn handler(self: Box<IframeLoadEventSteps>) {
+ let this = self.frame_element.root();
+ this.iframe_load_event_steps(self.pipeline_id);
+ }
+}
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 3b58b383bf4..a86f0258918 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -16,11 +16,11 @@ use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::eventtarget::EventTarget;
-use dom::globalscope::GlobalScope;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeDamage, document_from_node, window_from_node};
use dom::values::UNSIGNED_LONG_MAX;
use dom::virtualmethods::VirtualMethods;
+use dom::window::Window;
use html5ever_atoms::LocalName;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
@@ -220,10 +220,10 @@ impl HTMLImageElement {
HTMLImageElementBinding::Wrap)
}
- pub fn Image(global: &GlobalScope,
+ pub fn Image(window: &Window,
width: Option<u32>,
height: Option<u32>) -> Fallible<Root<HTMLImageElement>> {
- let document = global.as_window().Document();
+ let document = window.Document();
let image = HTMLImageElement::new(local_name!("img"), None, &document);
if let Some(w) = width {
image.SetWidth(w);
diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs
index fa2fe7846c1..bcf112cce94 100644
--- a/components/script/dom/htmlmetaelement.rs
+++ b/components/script/dom/htmlmetaelement.rs
@@ -24,7 +24,7 @@ use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use style::attr::AttrValue;
use style::str::HTML_SPACE_CHARACTERS;
-use style::stylesheets::{Stylesheet, CssRule, Origin};
+use style::stylesheets::{Stylesheet, CssRule, CssRules, Origin};
use style::viewport::ViewportRule;
#[dom_struct]
@@ -98,8 +98,10 @@ impl HTMLMetaElement {
if !content.is_empty() {
if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
*self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
- rules: vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))].into(),
+ rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]),
origin: Origin::Author,
+ base_url: window_from_node(self).get_url(),
+ namespaces: Default::default(),
media: Default::default(),
// Viewport constraints are always recomputed on resize; they don't need to
// force all styles to be recomputed.
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index 6dd6349b185..255137a939d 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -274,12 +274,10 @@ fn fetch_a_classic_script(script: &HTMLScriptElement,
impl HTMLScriptElement {
/// https://html.spec.whatwg.org/multipage/#prepare-a-script
- ///
- /// Returns true if tokenization should continue, false otherwise.
- pub fn prepare(&self) -> bool {
+ pub fn prepare(&self) {
// Step 1.
if self.already_started.get() {
- return true;
+ return;
}
// Step 2.
@@ -297,17 +295,17 @@ impl HTMLScriptElement {
// Step 4.
let text = self.Text();
if text.is_empty() && !element.has_attribute(&local_name!("src")) {
- return true;
+ return;
}
// Step 5.
if !self.upcast::<Node>().is_in_doc() {
- return true;
+ return;
}
// Step 6.
if !self.is_javascript() {
- return true;
+ return;
}
// Step 7.
@@ -322,12 +320,12 @@ impl HTMLScriptElement {
// Step 9.
let doc = document_from_node(self);
if self.parser_inserted.get() && &*self.parser_document != &*doc {
- return true;
+ return;
}
// Step 10.
if !doc.is_scripting_enabled() {
- return true;
+ return;
}
// TODO(#4577): Step 11: CSP.
@@ -340,13 +338,13 @@ impl HTMLScriptElement {
let for_value = for_attribute.value().to_ascii_lowercase();
let for_value = for_value.trim_matches(HTML_SPACE_CHARACTERS);
if for_value != "window" {
- return true;
+ return;
}
let event_value = event_attribute.value().to_ascii_lowercase();
let event_value = event_value.trim_matches(HTML_SPACE_CHARACTERS);
if event_value != "onload" && event_value != "onload()" {
- return true;
+ return;
}
},
(_, _) => (),
@@ -381,7 +379,7 @@ impl HTMLScriptElement {
// Step 18.2.
if src.is_empty() {
self.queue_error_event();
- return true;
+ return;
}
// Step 18.4-18.5.
@@ -389,7 +387,7 @@ impl HTMLScriptElement {
Err(_) => {
warn!("error parsing URL for script {}", &**src);
self.queue_error_event();
- return true;
+ return;
}
Ok(url) => url,
};
@@ -412,7 +410,6 @@ impl HTMLScriptElement {
!async {
doc.add_deferred_script(self);
// Second part implemented in Document::process_deferred_scripts.
- return true;
// Step 20.b: classic, has src, was parser-inserted, is not async.
} else if is_external &&
was_parser_inserted &&
@@ -432,7 +429,7 @@ impl HTMLScriptElement {
// Step 20.e: doesn't have src, was parser-inserted, is blocked on stylesheet.
} else if !is_external &&
was_parser_inserted &&
- // TODO: check for script nesting levels.
+ doc.get_current_parser().map_or(false, |parser| parser.script_nesting_level() <= 1) &&
doc.get_script_blocking_stylesheets_count() > 0 {
doc.set_pending_parsing_blocking_script(Some(self));
*self.load.borrow_mut() = Some(Ok(ScriptOrigin::internal(text, base_url)));
@@ -443,16 +440,7 @@ impl HTMLScriptElement {
self.ready_to_be_parser_executed.set(true);
*self.load.borrow_mut() = Some(Ok(ScriptOrigin::internal(text, base_url)));
self.execute();
- return true;
}
-
- // TODO: make this suspension happen automatically.
- if was_parser_inserted {
- if let Some(parser) = doc.get_current_parser() {
- parser.suspend();
- }
- }
- false
}
pub fn is_ready_to_be_executed(&self) -> bool {
@@ -481,19 +469,20 @@ impl HTMLScriptElement {
Ok(script) => script,
};
- if script.external {
- debug!("loading external script, url = {}", script.url);
- }
-
// TODO(#12446): beforescriptexecute.
if self.dispatch_before_script_execute_event() == EventStatus::Canceled {
return;
}
// Step 3.
- // TODO: If the script is from an external file, then increment the
- // ignore-destructive-writes counter of the script element's node
- // document. Let neutralised doc be that Document.
+ let neutralized_doc = if script.external {
+ debug!("loading external script, url = {}", script.url);
+ let doc = document_from_node(self);
+ doc.incr_ignore_destructive_writes_counter();
+ Some(doc)
+ } else {
+ None
+ };
// Step 4.
let document = document_from_node(self);
@@ -512,8 +501,9 @@ impl HTMLScriptElement {
document.set_current_script(old_script.r());
// Step 7.
- // TODO: Decrement the ignore-destructive-writes counter of neutralised
- // doc, if it was incremented in the earlier step.
+ if let Some(doc) = neutralized_doc {
+ doc.decr_ignore_destructive_writes_counter();
+ }
// TODO(#12446): afterscriptexecute.
self.dispatch_after_script_execute_event();
diff --git a/components/script/dom/keyboardevent.rs b/components/script/dom/keyboardevent.rs
index 4da24309e18..99cc61e021f 100644
--- a/components/script/dom/keyboardevent.rs
+++ b/components/script/dom/keyboardevent.rs
@@ -12,7 +12,6 @@ use dom::bindings::js::{Root, RootedReference};
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::Event;
-use dom::globalscope::GlobalScope;
use dom::uievent::UIEvent;
use dom::window::Window;
use msg::constellation_msg;
@@ -101,10 +100,10 @@ impl KeyboardEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(window: &Window,
type_: DOMString,
init: &KeyboardEventBinding::KeyboardEventInit) -> Fallible<Root<KeyboardEvent>> {
- let event = KeyboardEvent::new(global.as_window(),
+ let event = KeyboardEvent::new(window,
type_,
init.parent.parent.parent.bubbles,
init.parent.parent.parent.cancelable,
diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs
new file mode 100644
index 00000000000..b6e5fd9c1ee
--- /dev/null
+++ b/components/script/dom/medialist.rs
@@ -0,0 +1,122 @@
+/* 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 core::default::Default;
+use cssparser::Parser;
+use dom::bindings::codegen::Bindings::MediaListBinding;
+use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::media_queries::{MediaQuery, parse_media_query_list};
+use style::media_queries::MediaList as StyleMediaList;
+use style_traits::ToCss;
+
+#[dom_struct]
+pub struct MediaList {
+ reflector_: Reflector,
+ #[ignore_heap_size_of = "Arc"]
+ media_queries: Arc<RwLock<StyleMediaList>>,
+}
+
+impl MediaList {
+ #[allow(unrooted_must_root)]
+ pub fn new_inherited(media_queries: Arc<RwLock<StyleMediaList>>) -> MediaList {
+ MediaList {
+ reflector_: Reflector::new(),
+ media_queries: media_queries,
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(window: &Window, media_queries: Arc<RwLock<StyleMediaList>>)
+ -> Root<MediaList> {
+ reflect_dom_object(box MediaList::new_inherited(media_queries),
+ window,
+ MediaListBinding::Wrap)
+ }
+
+}
+
+impl MediaListMethods for MediaList {
+ // https://drafts.csswg.org/cssom/#dom-medialist-mediatext
+ fn MediaText(&self) -> DOMString {
+ DOMString::from(self.media_queries.read().to_css_string())
+ }
+
+ // https://drafts.csswg.org/cssom/#dom-medialist-mediatext
+ fn SetMediaText(&self, value: DOMString) {
+ let mut media_queries = self.media_queries.write();
+ // Step 2
+ if value.is_empty() {
+ // Step 1
+ *media_queries = StyleMediaList::default();
+ return;
+ }
+ // Step 3
+ let mut parser = Parser::new(&value);
+ *media_queries = parse_media_query_list(&mut parser);
+ }
+
+ // https://drafts.csswg.org/cssom/#dom-medialist-length
+ fn Length(&self) -> u32 {
+ self.media_queries.read().media_queries.len() as u32
+ }
+
+ // https://drafts.csswg.org/cssom/#dom-medialist-item
+ fn Item(&self, index: u32) -> Option<DOMString> {
+ self.media_queries.read().media_queries.get(index as usize)
+ .and_then(|query| {
+ let mut s = String::new();
+ query.to_css(&mut s).unwrap();
+ Some(DOMString::from_string(s))
+ })
+ }
+
+ // https://drafts.csswg.org/cssom/#dom-medialist-item
+ fn IndexedGetter(&self, index: u32) -> Option<DOMString> {
+ self.Item(index)
+ }
+
+ // https://drafts.csswg.org/cssom/#dom-medialist-appendmedium
+ fn AppendMedium(&self, medium: DOMString) {
+ // Step 1
+ let mut parser = Parser::new(&medium);
+ let m = MediaQuery::parse(&mut parser);
+ // Step 2
+ if let Err(_) = m {
+ return;
+ }
+ // Step 3
+ let m_serialized = m.clone().unwrap().to_css_string();
+ let any = self.media_queries.read().media_queries.iter()
+ .any(|q| m_serialized == q.to_css_string());
+ if any {
+ return;
+ }
+ // Step 4
+ self.media_queries.write().media_queries.push(m.unwrap());
+ }
+
+ // https://drafts.csswg.org/cssom/#dom-medialist-deletemedium
+ fn DeleteMedium(&self, medium: DOMString) {
+ // Step 1
+ let mut parser = Parser::new(&medium);
+ let m = MediaQuery::parse(&mut parser);
+ // Step 2
+ if let Err(_) = m {
+ return;
+ }
+ // Step 3
+ let m_serialized = m.unwrap().to_css_string();
+ let mut media_list = self.media_queries.write();
+ let new_vec = media_list.media_queries.drain(..)
+ .filter(|q| m_serialized != q.to_css_string())
+ .collect();
+ media_list.media_queries = new_vec;
+ }
+}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 23209d89e07..9a0190cb57e 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -368,6 +368,7 @@ pub mod imagedata;
pub mod keyboardevent;
pub mod location;
pub mod mediaerror;
+pub mod medialist;
pub mod mediaquerylist;
pub mod messageevent;
pub mod mimetype;
diff --git a/components/script/dom/mouseevent.rs b/components/script/dom/mouseevent.rs
index 27a61c79400..2b39d555204 100644
--- a/components/script/dom/mouseevent.rs
+++ b/components/script/dom/mouseevent.rs
@@ -12,7 +12,6 @@ use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
-use dom::globalscope::GlobalScope;
use dom::uievent::UIEvent;
use dom::window::Window;
use std::cell::Cell;
@@ -82,12 +81,12 @@ impl MouseEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(window: &Window,
type_: DOMString,
init: &MouseEventBinding::MouseEventInit) -> Fallible<Root<MouseEvent>> {
let bubbles = EventBubbles::from(init.parent.parent.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.parent.parent.cancelable);
- let event = MouseEvent::new(global.as_window(),
+ let event = MouseEvent::new(window,
type_,
bubbles,
cancelable,
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 983e2e8d403..f08b1480eef 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -7,8 +7,6 @@
use app_units::Au;
use devtools_traits::NodeInfo;
use document_loader::DocumentLoader;
-use dom::attr::Attr;
-use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
@@ -51,7 +49,6 @@ use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHel
use dom::nodelist::NodeList;
use dom::processinginstruction::ProcessingInstruction;
use dom::range::WeakRangeVec;
-use dom::servoparser::ServoParser;
use dom::svgsvgelement::{SVGSVGElement, LayoutSVGSVGElementHelpers};
use dom::text::Text;
use dom::virtualmethods::{VirtualMethods, vtable_for};
@@ -61,7 +58,7 @@ use euclid::rect::Rect;
use euclid::size::Size2D;
use heapsize::{HeapSizeOf, heap_size_of};
use html5ever::tree_builder::QuirksMode;
-use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
+use html5ever_atoms::{Prefix, Namespace, QualName};
use js::jsapi::{JSContext, JSObject, JSRuntime};
use libc::{self, c_void, uintptr_t};
use msg::constellation_msg::PipelineId;
@@ -799,19 +796,6 @@ impl Node {
}
}
- // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#dfn-concept-parse-fragment
- pub fn parse_fragment(&self, markup: DOMString) -> Fallible<Root<DocumentFragment>> {
- let context_document = document_from_node(self);
- let fragment = DocumentFragment::new(&context_document);
- if context_document.is_html_document() {
- ServoParser::parse_html_fragment(self.upcast(), markup, fragment.upcast());
- } else {
- // FIXME: XML case
- unimplemented!();
- }
- Ok(fragment)
- }
-
/// Used by `HTMLTableSectionElement::InsertRow` and `HTMLTableRowElement::InsertCell`
pub fn insert_cell_or_row<F, G, I>(&self, index: i32, get_items: F, new_child: G) -> Fallible<Root<HTMLElement>>
where F: Fn() -> Root<HTMLCollection>,
@@ -1752,7 +1736,7 @@ impl Node {
local: element.local_name().clone()
};
let element = Element::create(name,
- element.prefix().as_ref().map(|p| Prefix::from(&**p)),
+ element.prefix().map(|p| Prefix::from(&**p)),
&document, ElementCreator::ScriptCreated);
Root::upcast::<Node>(element)
},
@@ -1782,7 +1766,7 @@ impl Node {
attr.value().clone(),
attr.name().clone(),
attr.namespace().clone(),
- attr.prefix().clone());
+ attr.prefix().cloned());
}
},
_ => ()
@@ -1825,68 +1809,20 @@ impl Node {
// https://dom.spec.whatwg.org/#locate-a-namespace
pub fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
- fn attr_defines_namespace(attr: &Attr,
- defined_prefix: &Option<LocalName>) -> bool {
- *attr.namespace() == ns!(xmlns) &&
- match (attr.prefix(), defined_prefix) {
- (&Some(ref attr_prefix), &Some(ref defined_prefix)) =>
- attr_prefix == &namespace_prefix!("xmlns") &&
- attr.local_name() == defined_prefix,
- (&None, &None) => *attr.local_name() == local_name!("xmlns"),
- _ => false
- }
- }
-
match node.type_id() {
NodeTypeId::Element(_) => {
- let element = node.downcast::<Element>().unwrap();
- // Step 1.
- if *element.namespace() != ns!() && *element.prefix() == prefix {
- return element.namespace().clone()
- }
-
- // Even though this is conceptually a namespace prefix,
- // in the `xmlns:foo="https://example.net/namespace" declaration
- // it is a local name.
- // FIXME(ajeffrey): directly convert DOMString to LocalName
- let prefix_atom = prefix.as_ref().map(|s| LocalName::from(&**s));
-
- // Step 2.
- let attrs = element.attrs();
- let namespace_attr = attrs.iter().find(|attr| {
- attr_defines_namespace(attr, &prefix_atom)
- });
-
- // Steps 2.1-2.
- if let Some(attr) = namespace_attr {
- return namespace_from_domstring(Some(attr.Value()));
- }
-
- match node.GetParentElement() {
- // Step 3.
- None => ns!(),
- // Step 4.
- Some(parent) => Node::locate_namespace(parent.upcast(), prefix)
- }
+ node.downcast::<Element>().unwrap().locate_namespace(prefix)
},
NodeTypeId::Document(_) => {
- match node.downcast::<Document>().unwrap().GetDocumentElement().r() {
- // Step 1.
- None => ns!(),
- // Step 2.
- Some(document_element) => {
- Node::locate_namespace(document_element.upcast(), prefix)
- }
- }
+ node.downcast::<Document>().unwrap()
+ .GetDocumentElement().as_ref()
+ .map_or(ns!(), |elem| elem.locate_namespace(prefix))
},
- NodeTypeId::DocumentType => ns!(),
- NodeTypeId::DocumentFragment => ns!(),
- _ => match node.GetParentElement() {
- // Step 1.
- None => ns!(),
- // Step 2.
- Some(parent) => Node::locate_namespace(parent.upcast(), prefix)
- }
+ NodeTypeId::DocumentType | NodeTypeId::DocumentFragment => ns!(),
+ _ => {
+ node.GetParentElement().as_ref()
+ .map_or(ns!(), |elem| elem.locate_namespace(prefix))
+ }
}
}
}
@@ -2250,7 +2186,7 @@ impl NodeMethods for Node {
let element = node.downcast::<Element>().unwrap();
let other_element = other.downcast::<Element>().unwrap();
(*element.namespace() == *other_element.namespace()) &&
- (*element.prefix() == *other_element.prefix()) &&
+ (element.prefix() == other_element.prefix()) &&
(*element.local_name() == *other_element.local_name()) &&
(element.attrs().len() == other_element.attrs().len())
}
diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs
index 8e8b9888b87..b2507aeab3b 100644
--- a/components/script/dom/range.rs
+++ b/components/script/dom/range.rs
@@ -22,11 +22,10 @@ use dom::characterdata::CharacterData;
use dom::document::Document;
use dom::documentfragment::DocumentFragment;
use dom::element::Element;
-use dom::globalscope::GlobalScope;
-use dom::htmlbodyelement::HTMLBodyElement;
use dom::htmlscriptelement::HTMLScriptElement;
use dom::node::{Node, UnbindContext};
use dom::text::Text;
+use dom::window::Window;
use heapsize::HeapSizeOf;
use js::jsapi::JSTracer;
use std::cell::{Cell, UnsafeCell};
@@ -70,8 +69,8 @@ impl Range {
}
// https://dom.spec.whatwg.org/#dom-range
- pub fn Constructor(global: &GlobalScope) -> Fallible<Root<Range>> {
- let document = global.as_window().Document();
+ pub fn Constructor(window: &Window) -> Fallible<Root<Range>> {
+ let document = window.Document();
Ok(Range::new_with_doc(&document))
}
@@ -901,6 +900,7 @@ impl RangeMethods for Range {
fn CreateContextualFragment(&self, fragment: DOMString) -> Fallible<Root<DocumentFragment>> {
// Step 1.
let node = self.StartContainer();
+ let owner_doc = node.owner_doc();
let element = match node.type_id() {
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment => None,
NodeTypeId::Element(_) => Some(Root::downcast::<Element>(node).unwrap()),
@@ -911,15 +911,7 @@ impl RangeMethods for Range {
};
// Step 2.
- let should_create_body = element.as_ref().map_or(true, |elem| {
- let elem = elem.downcast::<Element>().unwrap();
- elem.local_name() == &local_name!("html") && elem.html_element_in_html_document()
- });
- let element: Root<Node> = if should_create_body {
- Root::upcast(HTMLBodyElement::new(local_name!("body"), None, &self.StartContainer().owner_doc()))
- } else {
- Root::upcast(element.unwrap())
- };
+ let element = Element::fragment_parsing_context(&owner_doc, element.r());
// Step 3.
let fragment_node = try!(element.parse_fragment(fragment));
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index a3877064131..b39faeb5694 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -319,7 +319,7 @@ impl ServiceWorkerGlobalScope {
}
fn dispatch_activate(&self) {
- let event = ExtendableEvent::new(self.upcast(), atom!("activate"), false, false);
+ let event = ExtendableEvent::new(self, atom!("activate"), false, false);
let event = (&*event).upcast::<Event>();
self.upcast::<EventTarget>().dispatch_event(event);
}
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index fe650477123..c6f4364925b 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -14,11 +14,12 @@ use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::document::{Document, DocumentSource, IsHTMLDocument};
+use dom::element::Element;
use dom::globalscope::GlobalScope;
use dom::htmlformelement::HTMLFormElement;
use dom::htmlimageelement::HTMLImageElement;
use dom::htmlscriptelement::HTMLScriptElement;
-use dom::node::{Node, document_from_node, window_from_node};
+use dom::node::{Node, NodeSiblingIterator};
use encoding::all::UTF_8;
use encoding::types::{DecoderTrap, Encoding};
use html5ever::tokenizer::buffer_queue::BufferQueue;
@@ -33,12 +34,25 @@ use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
use script_thread::ScriptThread;
use servo_url::ServoUrl;
use std::cell::Cell;
+use std::mem;
use util::resource_files::read_resource_file;
mod html;
mod xml;
#[dom_struct]
+/// The parser maintains two input streams: one for input from script through
+/// document.write(), and one for input from network.
+///
+/// There is no concrete representation of the insertion point, instead it
+/// always points to just before the next character from the network input,
+/// with all of the script input before itself.
+///
+/// ```text
+/// ... script input ... | ... network input ...
+/// ^
+/// insertion point
+/// ```
pub struct ServoParser {
reflector: Reflector,
/// The document associated with this parser.
@@ -46,15 +60,20 @@ pub struct ServoParser {
/// The pipeline associated with this parse, unavailable if this parse
/// does not correspond to a page load.
pipeline: Option<PipelineId>,
- /// Input chunks received but not yet passed to the parser.
+ /// Input received from network.
#[ignore_heap_size_of = "Defined in html5ever"]
- pending_input: DOMRefCell<BufferQueue>,
+ network_input: DOMRefCell<BufferQueue>,
+ /// Input received from script. Used only to support document.write().
+ #[ignore_heap_size_of = "Defined in html5ever"]
+ script_input: DOMRefCell<BufferQueue>,
/// The tokenizer of this parser.
tokenizer: DOMRefCell<Tokenizer>,
/// Whether to expect any further input from the associated network request.
last_chunk_received: Cell<bool>,
/// Whether this parser should avoid passing any further data to the tokenizer.
suspended: Cell<bool>,
+ /// https://html.spec.whatwg.org/multipage/#script-nesting-level
+ script_nesting_level: Cell<usize>,
}
#[derive(PartialEq)]
@@ -78,17 +97,15 @@ impl ServoParser {
}
// https://html.spec.whatwg.org/multipage/#parsing-html-fragments
- pub fn parse_html_fragment(
- context_node: &Node,
- input: DOMString,
- output: &Node) {
- let window = window_from_node(context_node);
- let context_document = document_from_node(context_node);
+ pub fn parse_html_fragment(context: &Element, input: DOMString) -> FragmentParsingResult {
+ let context_node = context.upcast::<Node>();
+ let context_document = context_node.owner_doc();
+ let window = context_document.window();
let url = context_document.url();
// Step 1.
let loader = DocumentLoader::new(&*context_document.loader());
- let document = Document::new(&window, None, Some(url.clone()),
+ let document = Document::new(window, None, Some(url.clone()),
IsHTMLDocument::HTMLDocument,
None, None,
DocumentSource::FromParser,
@@ -116,9 +133,7 @@ impl ServoParser {
// Step 14.
let root_element = document.GetDocumentElement().expect("no document element");
- for child in root_element.upcast::<Node>().children() {
- output.AppendChild(&child).unwrap();
- }
+ FragmentParsingResult { inner: root_element.upcast::<Node>().children() }
}
pub fn parse_xml_document(
@@ -134,6 +149,84 @@ impl ServoParser {
parser.parse_chunk(String::from(input));
}
+ pub fn script_nesting_level(&self) -> usize {
+ self.script_nesting_level.get()
+ }
+
+ /// Corresponds to the latter part of the "Otherwise" branch of the 'An end
+ /// tag whose tag name is "script"' of
+ /// https://html.spec.whatwg.org/multipage/#parsing-main-incdata
+ ///
+ /// This first moves everything from the script input to the beginning of
+ /// the network input, effectively resetting the insertion point to just
+ /// before the next character to be consumed.
+ ///
+ ///
+ /// ```text
+ /// | ... script input ... network input ...
+ /// ^
+ /// insertion point
+ /// ```
+ pub fn resume_with_pending_parsing_blocking_script(&self, script: &HTMLScriptElement) {
+ assert!(self.suspended.get());
+ self.suspended.set(false);
+
+ mem::swap(&mut *self.script_input.borrow_mut(), &mut *self.network_input.borrow_mut());
+ while let Some(chunk) = self.script_input.borrow_mut().pop_front() {
+ self.network_input.borrow_mut().push_back(chunk);
+ }
+
+ let script_nesting_level = self.script_nesting_level.get();
+ assert_eq!(script_nesting_level, 0);
+
+ self.script_nesting_level.set(script_nesting_level + 1);
+ script.execute();
+ self.script_nesting_level.set(script_nesting_level);
+
+ if !self.suspended.get() {
+ self.parse_sync();
+ }
+ }
+
+ /// Steps 6-8 of https://html.spec.whatwg.org/multipage/#document.write()
+ pub fn write(&self, text: Vec<DOMString>) {
+ assert!(self.script_nesting_level.get() > 0);
+
+ if self.document.get_pending_parsing_blocking_script().is_some() {
+ // There is already a pending parsing blocking script so the
+ // parser is suspended, we just append everything to the
+ // script input and abort these steps.
+ for chunk in text {
+ self.script_input.borrow_mut().push_back(String::from(chunk).into());
+ }
+ return;
+ }
+
+ // There is no pending parsing blocking script, so all previous calls
+ // to document.write() should have seen their entire input tokenized
+ // and process, with nothing pushed to the parser script input.
+ assert!(self.script_input.borrow().is_empty());
+
+ let mut input = BufferQueue::new();
+ for chunk in text {
+ input.push_back(String::from(chunk).into());
+ }
+
+ self.tokenize(|tokenizer| tokenizer.feed(&mut input));
+
+ if self.suspended.get() {
+ // Parser got suspended, insert remaining input at end of
+ // script input, following anything written by scripts executed
+ // reentrantly during this call.
+ while let Some(chunk) = input.pop_front() {
+ self.script_input.borrow_mut().push_back(chunk);
+ }
+ return;
+ }
+
+ assert!(input.is_empty());
+ }
+
#[allow(unrooted_must_root)]
fn new_inherited(
document: &Document,
@@ -145,10 +238,12 @@ impl ServoParser {
reflector: Reflector::new(),
document: JS::from_ref(document),
pipeline: pipeline,
- pending_input: DOMRefCell::new(BufferQueue::new()),
+ network_input: DOMRefCell::new(BufferQueue::new()),
+ script_input: DOMRefCell::new(BufferQueue::new()),
tokenizer: DOMRefCell::new(tokenizer),
last_chunk_received: Cell::new(last_chunk_state == LastChunkState::Received),
suspended: Default::default(),
+ script_nesting_level: Default::default(),
}
}
@@ -165,111 +260,109 @@ impl ServoParser {
ServoParserBinding::Wrap)
}
- pub fn document(&self) -> &Document {
- &self.document
- }
-
- pub fn pipeline(&self) -> Option<PipelineId> {
- self.pipeline
- }
-
- fn has_pending_input(&self) -> bool {
- !self.pending_input.borrow().is_empty()
- }
-
fn push_input_chunk(&self, chunk: String) {
- self.pending_input.borrow_mut().push_back(chunk.into());
- }
-
- fn last_chunk_received(&self) -> bool {
- self.last_chunk_received.get()
- }
-
- fn mark_last_chunk_received(&self) {
- self.last_chunk_received.set(true)
- }
-
- fn set_plaintext_state(&self) {
- self.tokenizer.borrow_mut().set_plaintext_state()
- }
-
- pub fn suspend(&self) {
- assert!(!self.suspended.get());
- self.suspended.set(true);
- }
-
- pub fn resume(&self) {
- assert!(self.suspended.get());
- self.suspended.set(false);
- self.parse_sync();
- }
-
- pub fn is_suspended(&self) -> bool {
- self.suspended.get()
+ self.network_input.borrow_mut().push_back(chunk.into());
}
fn parse_sync(&self) {
let metadata = TimerMetadata {
- url: self.document().url().as_str().into(),
+ url: self.document.url().as_str().into(),
iframe: TimerMetadataFrameType::RootWindow,
incremental: TimerMetadataReflowType::FirstReflow,
};
let profiler_category = self.tokenizer.borrow().profiler_category();
profile(profiler_category,
Some(metadata),
- self.document().window().upcast::<GlobalScope>().time_profiler_chan().clone(),
+ self.document.window().upcast::<GlobalScope>().time_profiler_chan().clone(),
|| self.do_parse_sync())
}
fn do_parse_sync(&self) {
+ assert!(self.script_input.borrow().is_empty());
+
// This parser will continue to parse while there is either pending input or
// the parser remains unsuspended.
- loop {
- self.document().reflow_if_reflow_timer_expired();
- if let Err(script) = self.tokenizer.borrow_mut().feed(&mut *self.pending_input.borrow_mut()) {
- if script.prepare() {
- continue;
- }
- }
- // Document parsing is blocked on an external resource.
- if self.suspended.get() {
- return;
- }
+ self.tokenize(|tokenizer| tokenizer.feed(&mut *self.network_input.borrow_mut()));
- if !self.has_pending_input() {
- break;
- }
+ if self.suspended.get() {
+ return;
}
- if self.last_chunk_received() {
+ assert!(self.network_input.borrow().is_empty());
+
+ if self.last_chunk_received.get() {
self.finish();
}
}
fn parse_chunk(&self, input: String) {
- self.document().set_current_parser(Some(self));
+ self.document.set_current_parser(Some(self));
self.push_input_chunk(input);
- if !self.is_suspended() {
+ if !self.suspended.get() {
self.parse_sync();
}
}
+ fn tokenize<F>(&self, mut feed: F)
+ where F: FnMut(&mut Tokenizer) -> Result<(), Root<HTMLScriptElement>>
+ {
+ loop {
+ assert!(!self.suspended.get());
+
+ self.document.reflow_if_reflow_timer_expired();
+ let script = match feed(&mut *self.tokenizer.borrow_mut()) {
+ Ok(()) => return,
+ Err(script) => script,
+ };
+
+ let script_nesting_level = self.script_nesting_level.get();
+
+ self.script_nesting_level.set(script_nesting_level + 1);
+ script.prepare();
+ self.script_nesting_level.set(script_nesting_level);
+
+ if self.document.get_pending_parsing_blocking_script().is_some() {
+ self.suspended.set(true);
+ return;
+ }
+ }
+ }
+
fn finish(&self) {
assert!(!self.suspended.get());
- assert!(!self.has_pending_input());
+ assert!(self.last_chunk_received.get());
+ assert!(self.script_input.borrow().is_empty());
+ assert!(self.network_input.borrow().is_empty());
self.tokenizer.borrow_mut().end();
debug!("finished parsing");
- self.document().set_current_parser(None);
+ self.document.set_current_parser(None);
- if let Some(pipeline) = self.pipeline() {
+ if let Some(pipeline) = self.pipeline {
ScriptThread::parsing_complete(pipeline);
}
}
}
+pub struct FragmentParsingResult {
+ inner: NodeSiblingIterator,
+}
+
+impl Iterator for FragmentParsingResult {
+ type Item = Root<Node>;
+
+ fn next(&mut self) -> Option<Root<Node>> {
+ let next = match self.inner.next() {
+ Some(next) => next,
+ None => return None,
+ };
+ next.remove_self();
+ Some(next)
+ }
+}
+
#[derive(HeapSizeOf, JSTraceable)]
#[must_root]
enum Tokenizer {
@@ -372,7 +465,7 @@ impl FetchResponseListener for ParserContext {
parser.push_input_chunk(page);
parser.parse_sync();
- let doc = parser.document();
+ let doc = &parser.document;
let doc_body = Root::upcast::<Node>(doc.GetBody().unwrap());
let img = HTMLImageElement::new(local_name!("img"), None, doc);
img.SetSrc(DOMString::from(self.url.to_string()));
@@ -384,7 +477,7 @@ impl FetchResponseListener for ParserContext {
let page = "<pre>\n".into();
parser.push_input_chunk(page);
parser.parse_sync();
- parser.set_plaintext_state();
+ parser.tokenizer.borrow_mut().set_plaintext_state();
},
Some(ContentType(Mime(TopLevel::Text, SubLevel::Html, _))) => { // Handle text/html
if let Some(reason) = ssl_error {
@@ -449,11 +542,11 @@ impl FetchResponseListener for ParserContext {
debug!("Failed to load page URL {}, error: {:?}", self.url, err);
}
- parser.document()
+ parser.document
.finish_load(LoadType::PageSource(self.url.clone()));
- parser.mark_last_chunk_received();
- if !parser.is_suspended() {
+ parser.last_chunk_received.set(true);
+ if !parser.suspended.get() {
parser.parse_sync();
}
}
diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs
index 4f233bd80ec..9d527ce21d1 100644
--- a/components/script/dom/servoparser/xml.rs
+++ b/components/script/dom/servoparser/xml.rs
@@ -114,7 +114,7 @@ impl<'a> TreeSink for Sink {
let elem = target.downcast::<Element>()
.expect("tried to get name of non-Element in XML parsing");
QName {
- prefix: elem.prefix().as_ref().map_or(namespace_prefix!(""), |p| Prefix::from(&**p)),
+ prefix: elem.prefix().map_or(namespace_prefix!(""), |p| Prefix::from(&**p)),
namespace_url: elem.namespace().clone(),
local: elem.local_name().clone(),
}
diff --git a/components/script/dom/text.rs b/components/script/dom/text.rs
index a6034a7dad5..cfa670d9acb 100644
--- a/components/script/dom/text.rs
+++ b/components/script/dom/text.rs
@@ -14,8 +14,8 @@ use dom::bindings::js::RootedReference;
use dom::bindings::str::DOMString;
use dom::characterdata::CharacterData;
use dom::document::Document;
-use dom::globalscope::GlobalScope;
use dom::node::Node;
+use dom::window::Window;
/// An HTML text node.
#[dom_struct]
@@ -35,8 +35,8 @@ impl Text {
document, TextBinding::Wrap)
}
- pub fn Constructor(global: &GlobalScope, text: DOMString) -> Fallible<Root<Text>> {
- let document = global.as_window().Document();
+ pub fn Constructor(window: &Window, text: DOMString) -> Fallible<Root<Text>> {
+ let document = window.Document();
Ok(Text::new(text, &document))
}
}
diff --git a/components/script/dom/transitionevent.rs b/components/script/dom/transitionevent.rs
index 1f487cb38a5..cc17e77eae1 100644
--- a/components/script/dom/transitionevent.rs
+++ b/components/script/dom/transitionevent.rs
@@ -13,6 +13,7 @@ use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::Event;
use dom::globalscope::GlobalScope;
+use dom::window::Window;
use servo_atoms::Atom;
#[dom_struct]
@@ -46,9 +47,10 @@ impl TransitionEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(window: &Window,
type_: DOMString,
init: &TransitionEventInit) -> Fallible<Root<TransitionEvent>> {
+ let global = window.upcast::<GlobalScope>();
Ok(TransitionEvent::new(global, Atom::from(type_), init))
}
}
diff --git a/components/script/dom/uievent.rs b/components/script/dom/uievent.rs
index 08e1b0c912c..289088b2977 100644
--- a/components/script/dom/uievent.rs
+++ b/components/script/dom/uievent.rs
@@ -12,7 +12,6 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::{Event, EventBubbles, EventCancelable};
-use dom::globalscope::GlobalScope;
use dom::window::Window;
use servo_atoms::Atom;
use std::cell::Cell;
@@ -52,12 +51,12 @@ impl UIEvent {
ev
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(window: &Window,
type_: DOMString,
init: &UIEventBinding::UIEventInit) -> Fallible<Root<UIEvent>> {
let bubbles = EventBubbles::from(init.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.cancelable);
- let event = UIEvent::new(global.as_window(),
+ let event = UIEvent::new(window,
type_,
bubbles, cancelable,
init.view.r(), init.detail);
diff --git a/components/script/dom/webglactiveinfo.rs b/components/script/dom/webglactiveinfo.rs
index ff82ce3b05f..515d6afa4a0 100644
--- a/components/script/dom/webglactiveinfo.rs
+++ b/components/script/dom/webglactiveinfo.rs
@@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::WebGLActiveInfoBinding::WebGLActiveInfoMet
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
#[dom_struct]
pub struct WebGLActiveInfo {
@@ -29,8 +29,8 @@ impl WebGLActiveInfo {
}
}
- pub fn new(global: &GlobalScope, size: i32, ty: u32, name: DOMString) -> Root<WebGLActiveInfo> {
- reflect_dom_object(box WebGLActiveInfo::new_inherited(size, ty, name), global, WebGLActiveInfoBinding::Wrap)
+ pub fn new(window: &Window, size: i32, ty: u32, name: DOMString) -> Root<WebGLActiveInfo> {
+ reflect_dom_object(box WebGLActiveInfo::new_inherited(size, ty, name), window, WebGLActiveInfoBinding::Wrap)
}
}
diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs
index 6e19c00ae9f..752511df67a 100644
--- a/components/script/dom/webglbuffer.rs
+++ b/components/script/dom/webglbuffer.rs
@@ -7,8 +7,8 @@ use canvas_traits::CanvasMsg;
use dom::bindings::codegen::Bindings::WebGLBufferBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
-use dom::globalscope::GlobalScope;
use dom::webglobject::WebGLObject;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use std::cell::Cell;
use webrender_traits;
@@ -40,21 +40,21 @@ impl WebGLBuffer {
}
}
- pub fn maybe_new(global: &GlobalScope, renderer: IpcSender<CanvasMsg>)
+ pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>)
-> Option<Root<WebGLBuffer>> {
let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap();
renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateBuffer(sender))).unwrap();
let result = receiver.recv().unwrap();
- result.map(|buffer_id| WebGLBuffer::new(global, renderer, buffer_id))
+ result.map(|buffer_id| WebGLBuffer::new(window, renderer, buffer_id))
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
renderer: IpcSender<CanvasMsg>,
id: WebGLBufferId)
-> Root<WebGLBuffer> {
reflect_dom_object(box WebGLBuffer::new_inherited(renderer, id),
- global, WebGLBufferBinding::Wrap)
+ window, WebGLBufferBinding::Wrap)
}
}
diff --git a/components/script/dom/webglcontextevent.rs b/components/script/dom/webglcontextevent.rs
index c128515e81a..9d13fc8f64a 100644
--- a/components/script/dom/webglcontextevent.rs
+++ b/components/script/dom/webglcontextevent.rs
@@ -12,7 +12,7 @@ use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::{Event, EventBubbles, EventCancelable};
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
use servo_atoms::Atom;
#[dom_struct]
@@ -41,25 +41,25 @@ impl WebGLContextEvent {
}
}
- pub fn new_uninitialized(global_ref: &GlobalScope) -> Root<WebGLContextEvent> {
+ pub fn new_uninitialized(window: &Window) -> Root<WebGLContextEvent> {
// according to https://www.khronos.org/registry/webgl/specs/1.0/#5.15 this is
// additional information or the empty string if no additional information is
// available.
let status_message = DOMString::new();
reflect_dom_object(
box WebGLContextEvent::new_inherited(status_message),
- global_ref,
+ window,
WebGLContextEventBinding::Wrap)
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
type_: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable,
status_message: DOMString) -> Root<WebGLContextEvent> {
let event = reflect_dom_object(
box WebGLContextEvent::new_inherited(status_message),
- global,
+ window,
WebGLContextEventBinding::Wrap);
{
@@ -70,7 +70,7 @@ impl WebGLContextEvent {
event
}
- pub fn Constructor(global: &GlobalScope,
+ pub fn Constructor(window: &Window,
type_: DOMString,
init: &WebGLContextEventInit) -> Fallible<Root<WebGLContextEvent>> {
let status_message = match init.statusMessage.as_ref() {
@@ -82,7 +82,7 @@ impl WebGLContextEvent {
let cancelable = EventCancelable::from(init.parent.cancelable);
- Ok(WebGLContextEvent::new(global,
+ Ok(WebGLContextEvent::new(window,
Atom::from(type_),
bubbles,
cancelable,
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs
index 643661d67d4..02a767958e2 100644
--- a/components/script/dom/webglframebuffer.rs
+++ b/components/script/dom/webglframebuffer.rs
@@ -9,10 +9,10 @@ use dom::bindings::codegen::Bindings::WebGLFramebufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::js::{HeapGCValue, JS, Root};
use dom::bindings::reflector::reflect_dom_object;
-use dom::globalscope::GlobalScope;
use dom::webglobject::WebGLObject;
use dom::webglrenderbuffer::WebGLRenderbuffer;
use dom::webgltexture::WebGLTexture;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use std::cell::Cell;
use webrender_traits;
@@ -66,21 +66,21 @@ impl WebGLFramebuffer {
}
}
- pub fn maybe_new(global: &GlobalScope, renderer: IpcSender<CanvasMsg>)
+ pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>)
-> Option<Root<WebGLFramebuffer>> {
let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap();
renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateFramebuffer(sender))).unwrap();
let result = receiver.recv().unwrap();
- result.map(|fb_id| WebGLFramebuffer::new(global, renderer, fb_id))
+ result.map(|fb_id| WebGLFramebuffer::new(window, renderer, fb_id))
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
renderer: IpcSender<CanvasMsg>,
id: WebGLFramebufferId)
-> Root<WebGLFramebuffer> {
reflect_dom_object(box WebGLFramebuffer::new_inherited(renderer, id),
- global,
+ window,
WebGLFramebufferBinding::Wrap)
}
}
diff --git a/components/script/dom/webglobject.rs b/components/script/dom/webglobject.rs
index 0964fc5d0cf..9c7382ce5b5 100644
--- a/components/script/dom/webglobject.rs
+++ b/components/script/dom/webglobject.rs
@@ -6,7 +6,7 @@
use dom::bindings::codegen::Bindings::WebGLObjectBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
#[dom_struct]
pub struct WebGLObject {
@@ -20,7 +20,7 @@ impl WebGLObject {
}
}
- pub fn new(global: &GlobalScope) -> Root<WebGLObject> {
- reflect_dom_object(box WebGLObject::new_inherited(), global, WebGLObjectBinding::Wrap)
+ pub fn new(window: &Window) -> Root<WebGLObject> {
+ reflect_dom_object(box WebGLObject::new_inherited(), window, WebGLObjectBinding::Wrap)
}
}
diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs
index 47807a8086e..2e5188269fa 100644
--- a/components/script/dom/webglprogram.rs
+++ b/components/script/dom/webglprogram.rs
@@ -9,11 +9,11 @@ use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderi
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
-use dom::globalscope::GlobalScope;
use dom::webglactiveinfo::WebGLActiveInfo;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN;
use dom::webglshader::WebGLShader;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use std::cell::Cell;
use webrender_traits;
@@ -49,21 +49,21 @@ impl WebGLProgram {
}
}
- pub fn maybe_new(global: &GlobalScope, renderer: IpcSender<CanvasMsg>)
+ pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>)
-> Option<Root<WebGLProgram>> {
let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap();
renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateProgram(sender))).unwrap();
let result = receiver.recv().unwrap();
- result.map(|program_id| WebGLProgram::new(global, renderer, program_id))
+ result.map(|program_id| WebGLProgram::new(window, renderer, program_id))
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
renderer: IpcSender<CanvasMsg>,
id: WebGLProgramId)
-> Root<WebGLProgram> {
reflect_dom_object(box WebGLProgram::new_inherited(renderer, id),
- global,
+ window,
WebGLProgramBinding::Wrap)
}
}
@@ -231,7 +231,7 @@ impl WebGLProgram {
.unwrap();
receiver.recv().unwrap().map(|(size, ty, name)|
- WebGLActiveInfo::new(&self.global(), size, ty, DOMString::from(name)))
+ WebGLActiveInfo::new(self.global().as_window(), size, ty, DOMString::from(name)))
}
/// glGetActiveAttrib
@@ -245,7 +245,7 @@ impl WebGLProgram {
.unwrap();
receiver.recv().unwrap().map(|(size, ty, name)|
- WebGLActiveInfo::new(&self.global(), size, ty, DOMString::from(name)))
+ WebGLActiveInfo::new(self.global().as_window(), size, ty, DOMString::from(name)))
}
/// glGetAttribLocation
diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs
index d74d045363a..b9d36f33d1c 100644
--- a/components/script/dom/webglrenderbuffer.rs
+++ b/components/script/dom/webglrenderbuffer.rs
@@ -8,8 +8,8 @@ use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
-use dom::globalscope::GlobalScope;
use dom::webglobject::WebGLObject;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use std::cell::Cell;
use webrender_traits;
@@ -42,21 +42,21 @@ impl WebGLRenderbuffer {
}
}
- pub fn maybe_new(global: &GlobalScope, renderer: IpcSender<CanvasMsg>)
+ pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>)
-> Option<Root<WebGLRenderbuffer>> {
let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap();
renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateRenderbuffer(sender))).unwrap();
let result = receiver.recv().unwrap();
- result.map(|renderbuffer_id| WebGLRenderbuffer::new(global, renderer, renderbuffer_id))
+ result.map(|renderbuffer_id| WebGLRenderbuffer::new(window, renderer, renderbuffer_id))
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
renderer: IpcSender<CanvasMsg>,
id: WebGLRenderbufferId)
-> Root<WebGLRenderbuffer> {
reflect_dom_object(box WebGLRenderbuffer::new_inherited(renderer, id),
- global,
+ window,
WebGLRenderbufferBinding::Wrap)
}
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index f43576fba63..76bfd9e10ce 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -34,6 +34,7 @@ use dom::webglrenderbuffer::WebGLRenderbuffer;
use dom::webglshader::WebGLShader;
use dom::webgltexture::{TexParameterValue, WebGLTexture};
use dom::webgluniformlocation::WebGLUniformLocation;
+use dom::window::Window;
use euclid::size::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use js::conversions::ConversionBehavior;
@@ -132,16 +133,20 @@ pub struct WebGLRenderingContext {
current_program: MutNullableHeap<JS<WebGLProgram>>,
#[ignore_heap_size_of = "Because it's small"]
current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>,
+ #[ignore_heap_size_of = "Because it's small"]
+ current_scissor: Cell<(i32, i32, i32, i32)>,
+ #[ignore_heap_size_of = "Because it's small"]
+ current_clear_color: Cell<(f32, f32, f32, f32)>,
}
impl WebGLRenderingContext {
- fn new_inherited(global: &GlobalScope,
+ fn new_inherited(window: &Window,
canvas: &HTMLCanvasElement,
size: Size2D<i32>,
attrs: GLContextAttributes)
-> Result<WebGLRenderingContext, String> {
let (sender, receiver) = ipc::channel().unwrap();
- let constellation_chan = global.constellation_chan();
+ let constellation_chan = window.upcast::<GlobalScope>().constellation_chan();
constellation_chan.send(ConstellationMsg::CreateWebGLPaintThread(size, attrs, sender))
.unwrap();
let result = receiver.recv().unwrap();
@@ -162,18 +167,20 @@ impl WebGLRenderingContext {
bound_renderbuffer: MutNullableHeap::new(None),
current_program: MutNullableHeap::new(None),
current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)),
+ current_scissor: Cell::new((0, 0, size.width, size.height)),
+ current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0))
}
})
}
#[allow(unrooted_must_root)]
- pub fn new(global: &GlobalScope, canvas: &HTMLCanvasElement, size: Size2D<i32>, attrs: GLContextAttributes)
+ pub fn new(window: &Window, canvas: &HTMLCanvasElement, size: Size2D<i32>, attrs: GLContextAttributes)
-> Option<Root<WebGLRenderingContext>> {
- match WebGLRenderingContext::new_inherited(global, canvas, size, attrs) {
- Ok(ctx) => Some(reflect_dom_object(box ctx, global, WebGLRenderingContextBinding::Wrap)),
+ match WebGLRenderingContext::new_inherited(window, canvas, size, attrs) {
+ Ok(ctx) => Some(reflect_dom_object(box ctx, window, WebGLRenderingContextBinding::Wrap)),
Err(msg) => {
error!("Couldn't create WebGLRenderingContext: {}", msg);
- let event = WebGLContextEvent::new(global,
+ let event = WebGLContextEvent::new(window,
atom!("webglcontextcreationerror"),
EventBubbles::DoesNotBubble,
EventCancelable::Cancelable,
@@ -202,6 +209,22 @@ impl WebGLRenderingContext {
pub fn recreate(&self, size: Size2D<i32>) {
self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap();
+
+ // ClearColor needs to be restored because after a resize the GLContext is recreated
+ // and the framebuffer is cleared using the default black transparent color.
+ let color = self.current_clear_color.get();
+ self.ipc_renderer
+ .send(CanvasMsg::WebGL(WebGLCommand::ClearColor(color.0, color.1, color.2, color.3)))
+ .unwrap();
+
+ // WebGL Spec: Scissor rect must not change if the canvas is resized.
+ // See: webgl/conformance-1.0.3/conformance/rendering/gl-scissor-canvas-dimensions.html
+ // NativeContext handling library changes the scissor after a resize, so we need to reset the
+ // default scissor when the canvas was created or the last scissor that the user set.
+ let rect = self.current_scissor.get();
+ self.ipc_renderer
+ .send(CanvasMsg::WebGL(WebGLCommand::Scissor(rect.0, rect.1, rect.2, rect.3)))
+ .unwrap()
}
pub fn ipc_renderer(&self) -> IpcSender<CanvasMsg> {
@@ -1135,6 +1158,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn ClearColor(&self, red: f32, green: f32, blue: f32, alpha: f32) {
+ self.current_clear_color.set((red, green, blue, alpha));
self.ipc_renderer
.send(CanvasMsg::WebGL(WebGLCommand::ClearColor(red, green, blue, alpha)))
.unwrap()
@@ -1248,27 +1272,27 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// generated objects, either here or in the webgl thread
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn CreateBuffer(&self) -> Option<Root<WebGLBuffer>> {
- WebGLBuffer::maybe_new(&self.global(), self.ipc_renderer.clone())
+ WebGLBuffer::maybe_new(self.global().as_window(), self.ipc_renderer.clone())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
fn CreateFramebuffer(&self) -> Option<Root<WebGLFramebuffer>> {
- WebGLFramebuffer::maybe_new(&self.global(), self.ipc_renderer.clone())
+ WebGLFramebuffer::maybe_new(self.global().as_window(), self.ipc_renderer.clone())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7
fn CreateRenderbuffer(&self) -> Option<Root<WebGLRenderbuffer>> {
- WebGLRenderbuffer::maybe_new(&self.global(), self.ipc_renderer.clone())
+ WebGLRenderbuffer::maybe_new(self.global().as_window(), self.ipc_renderer.clone())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn CreateTexture(&self) -> Option<Root<WebGLTexture>> {
- WebGLTexture::maybe_new(&self.global(), self.ipc_renderer.clone())
+ WebGLTexture::maybe_new(self.global().as_window(), self.ipc_renderer.clone())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn CreateProgram(&self) -> Option<Root<WebGLProgram>> {
- WebGLProgram::maybe_new(&self.global(), self.ipc_renderer.clone())
+ WebGLProgram::maybe_new(self.global().as_window(), self.ipc_renderer.clone())
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@@ -1280,7 +1304,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return None;
}
}
- WebGLShader::maybe_new(&self.global(), self.ipc_renderer.clone(), shader_type)
+ WebGLShader::maybe_new(self.global().as_window(), self.ipc_renderer.clone(), shader_type)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
@@ -1612,7 +1636,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
name: DOMString) -> Option<Root<WebGLUniformLocation>> {
program.and_then(|p| {
handle_potential_webgl_error!(self, p.get_uniform_location(name), None)
- .map(|location| WebGLUniformLocation::new(&self.global(), location, p.id()))
+ .map(|location| WebGLUniformLocation::new(self.global().as_window(), location, p.id()))
})
}
@@ -1902,6 +1926,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return self.webgl_error(InvalidValue)
}
+ self.current_scissor.set((x, y, width, height));
self.ipc_renderer
.send(CanvasMsg::WebGL(WebGLCommand::Scissor(x, y, width, height)))
.unwrap()
diff --git a/components/script/dom/webglshader.rs b/components/script/dom/webglshader.rs
index 93da1ca0bc5..d846ac34aa7 100644
--- a/components/script/dom/webglshader.rs
+++ b/components/script/dom/webglshader.rs
@@ -10,8 +10,8 @@ use dom::bindings::codegen::Bindings::WebGLShaderBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
-use dom::globalscope::GlobalScope;
use dom::webglobject::WebGLObject;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use std::cell::Cell;
use std::sync::{ONCE_INIT, Once};
@@ -66,23 +66,24 @@ impl WebGLShader {
}
}
- pub fn maybe_new(global: &GlobalScope,
+ pub fn maybe_new(window: &Window,
renderer: IpcSender<CanvasMsg>,
- shader_type: u32) -> Option<Root<WebGLShader>> {
+ shader_type: u32)
+ -> Option<Root<WebGLShader>> {
let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap();
renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateShader(shader_type, sender))).unwrap();
let result = receiver.recv().unwrap();
- result.map(|shader_id| WebGLShader::new(global, renderer, shader_id, shader_type))
+ result.map(|shader_id| WebGLShader::new(window, renderer, shader_id, shader_type))
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
renderer: IpcSender<CanvasMsg>,
id: WebGLShaderId,
shader_type: u32)
-> Root<WebGLShader> {
reflect_dom_object(box WebGLShader::new_inherited(renderer, id, shader_type),
- global,
+ window,
WebGLShaderBinding::Wrap)
}
}
diff --git a/components/script/dom/webglshaderprecisionformat.rs b/components/script/dom/webglshaderprecisionformat.rs
index 18ba8c189a5..c0f954c8d4d 100644
--- a/components/script/dom/webglshaderprecisionformat.rs
+++ b/components/script/dom/webglshaderprecisionformat.rs
@@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::WebGLShaderPrecisionFormatBinding;
use dom::bindings::codegen::Bindings::WebGLShaderPrecisionFormatBinding::WebGLShaderPrecisionFormatMethods;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
#[dom_struct]
pub struct WebGLShaderPrecisionFormat {
@@ -27,13 +27,13 @@ impl WebGLShaderPrecisionFormat {
}
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
range_min: i32,
range_max: i32,
precision: i32) -> Root<WebGLShaderPrecisionFormat> {
reflect_dom_object(
box WebGLShaderPrecisionFormat::new_inherited(range_min, range_max, precision),
- global,
+ window,
WebGLShaderPrecisionFormatBinding::Wrap)
}
}
diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs
index 26cf14f7972..9a1e4663152 100644
--- a/components/script/dom/webgltexture.rs
+++ b/components/script/dom/webgltexture.rs
@@ -9,9 +9,9 @@ use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderi
use dom::bindings::codegen::Bindings::WebGLTextureBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
-use dom::globalscope::GlobalScope;
use dom::webgl_validations::types::{TexImageTarget, TexFormat, TexDataType};
use dom::webglobject::WebGLObject;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use std::cell::Cell;
use std::cmp;
@@ -61,21 +61,21 @@ impl WebGLTexture {
}
}
- pub fn maybe_new(global: &GlobalScope, renderer: IpcSender<CanvasMsg>)
+ pub fn maybe_new(window: &Window, renderer: IpcSender<CanvasMsg>)
-> Option<Root<WebGLTexture>> {
let (sender, receiver) = webrender_traits::channel::msg_channel().unwrap();
renderer.send(CanvasMsg::WebGL(WebGLCommand::CreateTexture(sender))).unwrap();
let result = receiver.recv().unwrap();
- result.map(|texture_id| WebGLTexture::new(global, renderer, texture_id))
+ result.map(|texture_id| WebGLTexture::new(window, renderer, texture_id))
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
renderer: IpcSender<CanvasMsg>,
id: WebGLTextureId)
-> Root<WebGLTexture> {
reflect_dom_object(box WebGLTexture::new_inherited(renderer, id),
- global,
+ window,
WebGLTextureBinding::Wrap)
}
}
diff --git a/components/script/dom/webgluniformlocation.rs b/components/script/dom/webgluniformlocation.rs
index 6e0683ec833..1b355bd8582 100644
--- a/components/script/dom/webgluniformlocation.rs
+++ b/components/script/dom/webgluniformlocation.rs
@@ -6,7 +6,7 @@
use dom::bindings::codegen::Bindings::WebGLUniformLocationBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
-use dom::globalscope::GlobalScope;
+use dom::window::Window;
use webrender_traits::WebGLProgramId;
#[dom_struct]
@@ -27,12 +27,12 @@ impl WebGLUniformLocation {
}
}
- pub fn new(global: &GlobalScope,
+ pub fn new(window: &Window,
id: i32,
program_id: WebGLProgramId)
-> Root<WebGLUniformLocation> {
reflect_dom_object(box WebGLUniformLocation::new_inherited(id, program_id),
- global,
+ window,
WebGLUniformLocationBinding::Wrap)
}
diff --git a/components/script/dom/webidls/Bluetooth.webidl b/components/script/dom/webidls/Bluetooth.webidl
index b925e0b0b25..de2b95c3fbb 100644
--- a/components/script/dom/webidls/Bluetooth.webidl
+++ b/components/script/dom/webidls/Bluetooth.webidl
@@ -28,9 +28,10 @@ dictionary RequestDeviceOptions {
};
[Pref="dom.bluetooth.enabled"]
-interface Bluetooth {
+interface Bluetooth : EventTarget {
// [SecureContext]
// readonly attribute BluetoothDevice? referringDevice;
+ attribute EventHandler onavailabilitychanged;
// [SecureContext]
// Promise<boolean> getAvailability();
// [SecureContext]
diff --git a/components/script/dom/webidls/BluetoothDevice.webidl b/components/script/dom/webidls/BluetoothDevice.webidl
index 34a77230850..0e7843db109 100644
--- a/components/script/dom/webidls/BluetoothDevice.webidl
+++ b/components/script/dom/webidls/BluetoothDevice.webidl
@@ -5,7 +5,7 @@
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdevice
[Pref="dom.bluetooth.enabled"]
-interface BluetoothDevice {
+interface BluetoothDevice : EventTarget {
readonly attribute DOMString id;
readonly attribute DOMString? name;
// TODO: remove this after BluetoothAdvertisingEvent implemented.
@@ -17,7 +17,12 @@ interface BluetoothDevice {
// readonly attribute boolean watchingAdvertisements;
};
+[NoInterfaceObject]
+interface BluetoothDeviceEventHandlers {
+ attribute EventHandler ongattserverdisconnected;
+};
+
// BluetoothDevice implements EventTarget;
-// BluetoothDevice implements BluetoothDeviceEventHandlers;
+BluetoothDevice implements BluetoothDeviceEventHandlers;
// BluetoothDevice implements CharacteristicEventHandlers;
// BluetoothDevice implements ServiceEventHandlers;
diff --git a/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl b/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl
index d1d937475b4..55d7bf0a43c 100644
--- a/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl
+++ b/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl
@@ -5,7 +5,7 @@
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
[Pref="dom.bluetooth.enabled"]
-interface BluetoothRemoteGATTCharacteristic {
+interface BluetoothRemoteGATTCharacteristic : EventTarget {
readonly attribute BluetoothRemoteGATTService service;
readonly attribute DOMString uuid;
readonly attribute BluetoothCharacteristicProperties properties;
@@ -21,5 +21,10 @@ interface BluetoothRemoteGATTCharacteristic {
Promise<BluetoothRemoteGATTCharacteristic> stopNotifications();
};
-//BluetootRemoteGATTCharacteristic implements EventTarget;
-//BluetootRemoteGATTCharacteristic implements CharacteristicEventHandlers;
+[NoInterfaceObject]
+interface CharacteristicEventHandlers {
+ attribute EventHandler oncharacteristicvaluechanged;
+};
+
+// BluetoothRemoteGATTCharacteristic implements EventTarget;
+BluetoothRemoteGATTCharacteristic implements CharacteristicEventHandlers;
diff --git a/components/script/dom/webidls/BluetoothRemoteGATTService.webidl b/components/script/dom/webidls/BluetoothRemoteGATTService.webidl
index 715c2acbe1e..c39dcc1447a 100644
--- a/components/script/dom/webidls/BluetoothRemoteGATTService.webidl
+++ b/components/script/dom/webidls/BluetoothRemoteGATTService.webidl
@@ -5,7 +5,7 @@
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
[Pref="dom.bluetooth.enabled"]
-interface BluetoothRemoteGATTService {
+interface BluetoothRemoteGATTService : EventTarget {
readonly attribute BluetoothDevice device;
readonly attribute DOMString uuid;
readonly attribute boolean isPrimary;
@@ -15,3 +15,14 @@ interface BluetoothRemoteGATTService {
Promise<BluetoothRemoteGATTService> getIncludedService(BluetoothServiceUUID service);
Promise<sequence<BluetoothRemoteGATTService>> getIncludedServices(optional BluetoothServiceUUID service);
};
+
+[NoInterfaceObject]
+interface ServiceEventHandlers {
+ attribute EventHandler onserviceadded;
+ attribute EventHandler onservicechanged;
+ attribute EventHandler onserviceremoved;
+};
+
+// BluetoothRemoteGATTService implements EventTarget;
+// BluetoothRemoteGATTService implements CharacteristicEventHandlers;
+BluetoothRemoteGATTService implements ServiceEventHandlers;
diff --git a/components/script/dom/webidls/CSSMediaRule.webidl b/components/script/dom/webidls/CSSMediaRule.webidl
index e2b89dee723..9ed133fb065 100644
--- a/components/script/dom/webidls/CSSMediaRule.webidl
+++ b/components/script/dom/webidls/CSSMediaRule.webidl
@@ -5,5 +5,5 @@
// https://drafts.csswg.org/cssom/#the-cssmediarule-interface
[Exposed=Window]
interface CSSMediaRule : CSSGroupingRule {
- // [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
+ [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
};
diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl
index 0f0b483d0b1..4314eca74f9 100644
--- a/components/script/dom/webidls/CSSStyleDeclaration.webidl
+++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl
@@ -321,6 +321,14 @@ partial interface CSSStyleDeclaration {
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString right;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString left;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString bottom;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offset-block-start;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offsetBlockStart;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offset-block-end;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offsetBlockEnd;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offset-inline-start;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offsetInlineStart;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offset-inline-end;
+ [SetterThrows, TreatNullAs=EmptyString] attribute DOMString offsetInlineEnd;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString height;
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString minHeight;
diff --git a/components/script/dom/webidls/DOMMatrix.webidl b/components/script/dom/webidls/DOMMatrix.webidl
index d8306d315fb..d1dd65e8a63 100644
--- a/components/script/dom/webidls/DOMMatrix.webidl
+++ b/components/script/dom/webidls/DOMMatrix.webidl
@@ -11,10 +11,9 @@
*/
[Constructor,
-// Constructor(DOMString transformList),
-Constructor(sequence<unrestricted double> numberSequence)
-// Exposed=(Window,Worker)
-]
+ // Constructor(DOMString transformList),
+ Constructor(sequence<unrestricted double> numberSequence),
+ Exposed=(Window,Worker)]
interface DOMMatrix : DOMMatrixReadOnly {
[NewObject, Throws] static DOMMatrix fromMatrix(optional DOMMatrixInit other);
diff --git a/components/script/dom/webidls/DOMMatrixReadOnly.webidl b/components/script/dom/webidls/DOMMatrixReadOnly.webidl
index 6d92a6b0828..9261002e348 100644
--- a/components/script/dom/webidls/DOMMatrixReadOnly.webidl
+++ b/components/script/dom/webidls/DOMMatrixReadOnly.webidl
@@ -11,10 +11,9 @@
*/
[Constructor,
-// Constructor(DOMString transformList)
-Constructor(sequence<unrestricted double> numberSequence),
-// Exposed=(Window,Worker)
-]
+ // Constructor(DOMString transformList)
+ Constructor(sequence<unrestricted double> numberSequence),
+ Exposed=(Window,Worker)]
interface DOMMatrixReadOnly {
[NewObject, Throws] static DOMMatrixReadOnly fromMatrix(optional DOMMatrixInit other);
diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl
index 192c3d03714..1e8725d8b86 100644
--- a/components/script/dom/webidls/Document.webidl
+++ b/components/script/dom/webidls/Document.webidl
@@ -114,8 +114,10 @@ partial /*sealed*/ interface Document {
// Document open(optional DOMString type = "text/html", optional DOMString replace = "");
// WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace = false);
// void close();
- // void write(DOMString... text);
- // void writeln(DOMString... text);
+ [Throws]
+ void write(DOMString... text);
+ [Throws]
+ void writeln(DOMString... text);
// user interaction
readonly attribute Window?/*Proxy?*/ defaultView;
diff --git a/components/script/dom/webidls/MediaList.webidl b/components/script/dom/webidls/MediaList.webidl
new file mode 100644
index 00000000000..f397badfd52
--- /dev/null
+++ b/components/script/dom/webidls/MediaList.webidl
@@ -0,0 +1,13 @@
+/* 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://drafts.csswg.org/cssom/#the-medialist-interface
+// [LegacyArrayClass]
+interface MediaList {
+ [TreatNullAs=EmptyString] /* stringifier */ attribute DOMString mediaText;
+ readonly attribute unsigned long length;
+ getter DOMString? item(unsigned long index);
+ void appendMedium(DOMString medium);
+ void deleteMedium(DOMString medium);
+};
diff --git a/components/script/dom/webidls/WebGLActiveInfo.webidl b/components/script/dom/webidls/WebGLActiveInfo.webidl
index 7195e8bacaa..be9e6f4e2db 100644
--- a/components/script/dom/webidls/WebGLActiveInfo.webidl
+++ b/components/script/dom/webidls/WebGLActiveInfo.webidl
@@ -6,6 +6,7 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.7
//
+[Exposed=Window]
interface WebGLActiveInfo {
readonly attribute GLint size;
readonly attribute GLenum type;
diff --git a/components/script/dom/webidls/WebGLBuffer.webidl b/components/script/dom/webidls/WebGLBuffer.webidl
index 344850d42e6..ca2697bb9be 100644
--- a/components/script/dom/webidls/WebGLBuffer.webidl
+++ b/components/script/dom/webidls/WebGLBuffer.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.4
//
+[Exposed=Window]
interface WebGLBuffer : WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLContextEvent.webidl b/components/script/dom/webidls/WebGLContextEvent.webidl
index 6a699754d2c..b5c70b8b17f 100644
--- a/components/script/dom/webidls/WebGLContextEvent.webidl
+++ b/components/script/dom/webidls/WebGLContextEvent.webidl
@@ -3,7 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15
-[Constructor(DOMString type, optional WebGLContextEventInit eventInit)]
+[Constructor(DOMString type, optional WebGLContextEventInit eventInit),
+ Exposed=Window]
interface WebGLContextEvent : Event {
readonly attribute DOMString statusMessage;
};
diff --git a/components/script/dom/webidls/WebGLFramebuffer.webidl b/components/script/dom/webidls/WebGLFramebuffer.webidl
index 2f21edafc0a..306e2c479ed 100644
--- a/components/script/dom/webidls/WebGLFramebuffer.webidl
+++ b/components/script/dom/webidls/WebGLFramebuffer.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.7
//
+[Exposed=Window]
interface WebGLFramebuffer : WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLObject.webidl b/components/script/dom/webidls/WebGLObject.webidl
index 040c76be0c7..3ac7514830a 100644
--- a/components/script/dom/webidls/WebGLObject.webidl
+++ b/components/script/dom/webidls/WebGLObject.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.3
//
+[Exposed=Window]
interface WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLProgram.webidl b/components/script/dom/webidls/WebGLProgram.webidl
index 0c9ede907e0..2ee21b2a6a1 100644
--- a/components/script/dom/webidls/WebGLProgram.webidl
+++ b/components/script/dom/webidls/WebGLProgram.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.6
//
+[Exposed=Window]
interface WebGLProgram : WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLRenderbuffer.webidl b/components/script/dom/webidls/WebGLRenderbuffer.webidl
index 451621ec30c..3024dc7513e 100644
--- a/components/script/dom/webidls/WebGLRenderbuffer.webidl
+++ b/components/script/dom/webidls/WebGLRenderbuffer.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.5
//
+[Exposed=Window]
interface WebGLRenderbuffer : WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl
index 3f20d89ce96..dd91d53d2d7 100644
--- a/components/script/dom/webidls/WebGLRenderingContext.webidl
+++ b/components/script/dom/webidls/WebGLRenderingContext.webidl
@@ -41,7 +41,7 @@ dictionary WebGLContextAttributes {
GLboolean failIfMajorPerformanceCaveat = false;
};
-[NoInterfaceObject]
+[Exposed=Window, NoInterfaceObject]
interface WebGLRenderingContextBase
{
@@ -762,6 +762,7 @@ interface WebGLRenderingContextBase
void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
};
+[Exposed=Window]
interface WebGLRenderingContext
{
};
diff --git a/components/script/dom/webidls/WebGLShader.webidl b/components/script/dom/webidls/WebGLShader.webidl
index f160602cba7..671da6405ff 100644
--- a/components/script/dom/webidls/WebGLShader.webidl
+++ b/components/script/dom/webidls/WebGLShader.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.8
//
+[Exposed=Window]
interface WebGLShader : WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLShaderPrecisionFormat.webidl b/components/script/dom/webidls/WebGLShaderPrecisionFormat.webidl
index 2d299232e90..eb7b1370b31 100644
--- a/components/script/dom/webidls/WebGLShaderPrecisionFormat.webidl
+++ b/components/script/dom/webidls/WebGLShaderPrecisionFormat.webidl
@@ -6,6 +6,7 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.7
//
+[Exposed=Window]
interface WebGLShaderPrecisionFormat {
readonly attribute GLint rangeMin;
readonly attribute GLint rangeMax;
diff --git a/components/script/dom/webidls/WebGLTexture.webidl b/components/script/dom/webidls/WebGLTexture.webidl
index f1b7fa20f1e..42313c98683 100644
--- a/components/script/dom/webidls/WebGLTexture.webidl
+++ b/components/script/dom/webidls/WebGLTexture.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/#5.9
//
+[Exposed=Window]
interface WebGLTexture : WebGLObject {
};
diff --git a/components/script/dom/webidls/WebGLUniformLocation.webidl b/components/script/dom/webidls/WebGLUniformLocation.webidl
index 467c2d00572..f068eead6e2 100644
--- a/components/script/dom/webidls/WebGLUniformLocation.webidl
+++ b/components/script/dom/webidls/WebGLUniformLocation.webidl
@@ -6,5 +6,6 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.10
//
+[Exposed=Window]
interface WebGLUniformLocation {
};
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 81004a9dbd2..7b140b14d8f 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -26,17 +26,17 @@ use fetch;
use ipc_channel::ipc::IpcSender;
use js::jsapi::{HandleValue, JSAutoCompartment, JSContext, JSRuntime};
use js::jsval::UndefinedValue;
+use js::panic::maybe_resume_unwind;
use js::rust::Runtime;
use net_traits::{IpcSend, load_whole_resource};
use net_traits::request::{CredentialsMode, Destination, RequestInit as NetRequestInit, Type as RequestType};
-use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, maybe_take_panic_result};
+use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort};
use script_runtime::{ScriptThreadEventCategory, PromiseJobQueue, EnqueuedPromiseCallback};
use script_thread::{Runnable, RunnableWrapper};
use script_traits::{TimerEvent, TimerEventId};
use script_traits::WorkerGlobalScopeInit;
use servo_url::ServoUrl;
use std::default::Default;
-use std::panic;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
@@ -232,9 +232,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
let result = self.runtime.evaluate_script(
self.reflector().get_jsobject(), &source, url.as_str(), 1, rval.handle_mut());
- if let Some(error) = maybe_take_panic_result() {
- panic::resume_unwind(error);
- }
+ maybe_resume_unwind();
match result {
Ok(_) => (),
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index a386d5c8563..8838787defc 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -175,14 +175,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
unsafe { self.get_jsmanaged().opaque() }
}
- fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<ServoLayoutElement<'ln>> {
- if self.opaque() == reflow_root {
- None
- } else {
- self.parent_node().and_then(|x| x.as_element())
- }
- }
-
fn debug_id(self) -> usize {
self.opaque().0
}
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 0d726a723af..cf3aadf1658 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -74,6 +74,7 @@ extern crate phf;
extern crate profile_traits;
extern crate rand;
extern crate range;
+extern crate ref_filter_map;
extern crate ref_slice;
extern crate regex;
extern crate rustc_serialize;
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index 603e24a1468..154353c71e8 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -20,17 +20,17 @@ use js::jsapi::{JSGCInvocationKind, JSGCStatus, JS_AddExtraGCRootsTracer, JS_Set
use js::jsapi::{JSGCMode, JSGCParamKey, JS_SetGCParameter, JS_SetGlobalJitCompilerOption};
use js::jsapi::{JSJitCompilerOption, JS_SetOffthreadIonCompilationEnabled, JS_SetParallelParsingEnabled};
use js::jsapi::{JSObject, RuntimeOptionsRef, SetPreserveWrapperCallback, SetEnqueuePromiseJobCallback};
+use js::panic::wrap_panic;
use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use profile_traits::mem::{Report, ReportKind, ReportsChan};
use script_thread::{Runnable, STACK_ROOTS, trace_thread};
-use std::any::Any;
-use std::cell::{RefCell, Cell};
+use std::cell::Cell;
use std::io::{Write, stdout};
use std::marker::PhantomData;
use std::os;
use std::os::raw::c_void;
-use std::panic::{self, AssertUnwindSafe};
+use std::panic::AssertUnwindSafe;
use std::ptr;
use std::rc::Rc;
use style::thread_state;
@@ -176,7 +176,7 @@ unsafe extern "C" fn enqueue_job(_cx: *mut JSContext,
job: HandleObject,
_allocation_site: HandleObject,
_data: *mut c_void) -> bool {
- let result = panic::catch_unwind(AssertUnwindSafe(|| {
+ wrap_panic(AssertUnwindSafe(|| {
let global = GlobalScope::from_object(job.get());
let pipeline = global.pipeline_id();
global.enqueue_promise_job(EnqueuedPromiseCallback {
@@ -184,14 +184,7 @@ unsafe extern "C" fn enqueue_job(_cx: *mut JSContext,
pipeline: pipeline,
});
true
- }));
- match result {
- Ok(result) => result,
- Err(error) => {
- store_panic_result(error);
- return false;
- }
- }
+ }), false)
}
#[allow(unsafe_code)]
@@ -421,21 +414,6 @@ pub fn get_reports(cx: *mut JSContext, path_seg: String) -> Vec<Report> {
reports
}
-thread_local!(static PANIC_RESULT: RefCell<Option<Box<Any + Send>>> = RefCell::new(None));
-
-pub fn store_panic_result(error: Box<Any + Send>) {
- PANIC_RESULT.with(|result| {
- assert!(result.borrow().is_none());
- *result.borrow_mut() = Some(error);
- });
-}
-
-pub fn maybe_take_panic_result() -> Option<Box<Any + Send>> {
- PANIC_RESULT.with(|result| {
- result.borrow_mut().take()
- })
-}
-
thread_local!(static GC_CYCLE_START: Cell<Option<Tm>> = Cell::new(None));
thread_local!(static GC_SLICE_START: Cell<Option<Tm>> = Cell::new(None));
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index b902c6df101..983d6fc8e36 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -71,7 +71,8 @@ use js::rust::Runtime;
use layout_wrapper::ServoLayoutNode;
use mem::heap_size_of_self_and_children;
use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
-use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
+use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener};
+use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
use net_traits::request::{CredentialsMode, Destination, RequestInit};
use net_traits::storage_thread::StorageType;
@@ -82,7 +83,7 @@ use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryTyp
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue};
use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
-use script_traits::{InitialScriptState, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
+use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
@@ -434,6 +435,9 @@ pub struct ScriptThread {
/// For communicating load url messages to the constellation
constellation_chan: IpcSender<ConstellationMsg>,
+ /// A sender for new layout threads to communicate to the constellation.
+ layout_to_constellation_chan: IpcSender<LayoutMsg>,
+
/// The port on which we receive messages from the image cache
image_cache_port: Receiver<ImageCacheResult>,
@@ -602,6 +606,17 @@ impl ScriptThread {
});
}
+ pub fn process_attach_layout(new_layout_info: NewLayoutInfo) {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ if let Some(script_thread) = root.get() {
+ let script_thread = unsafe { &*script_thread };
+ script_thread.profile_event(ScriptThreadEventCategory::AttachLayout, || {
+ script_thread.handle_new_layout(new_layout_info);
+ })
+ }
+ });
+ }
+
pub fn find_document(id: PipelineId) -> Option<Root<Document>> {
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
let script_thread = unsafe { &*script_thread };
@@ -681,6 +696,8 @@ impl ScriptThread {
content_process_shutdown_chan: state.content_process_shutdown_chan,
promise_job_queue: PromiseJobQueue::new(),
+
+ layout_to_constellation_chan: state.layout_to_constellation_chan,
}
}
@@ -1179,7 +1196,6 @@ impl ScriptThread {
load_data,
window_size,
pipeline_port,
- layout_to_constellation_chan,
content_process_shutdown_chan,
layout_threads,
} = new_layout_info;
@@ -1193,7 +1209,7 @@ impl ScriptThread {
is_parent: false,
layout_pair: layout_pair,
pipeline_port: pipeline_port,
- constellation_chan: layout_to_constellation_chan,
+ constellation_chan: self.layout_to_constellation_chan.clone(),
script_chan: self.control_chan.clone(),
image_cache_thread: self.image_cache_thread.clone(),
content_process_shutdown_chan: content_process_shutdown_chan,
@@ -1215,7 +1231,11 @@ impl ScriptThread {
let new_load = InProgressLoad::new(new_pipeline_id, frame_id, parent_info,
layout_chan, window_size,
load_data.url.clone());
- self.start_page_load(new_load, load_data);
+ if load_data.url.as_str() == "about:blank" {
+ self.start_page_load_about_blank(new_load);
+ } else {
+ self.start_page_load(new_load, load_data);
+ }
}
fn handle_loads_complete(&self, pipeline: PipelineId) {
@@ -1641,7 +1661,8 @@ impl ScriptThread {
/// Notify the containing document of a child frame that has completed loading.
fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) {
- match self.documents.borrow().find_iframe(parent_id, frame_id) {
+ let iframe = self.documents.borrow().find_iframe(parent_id, frame_id);
+ match iframe {
Some(iframe) => iframe.iframe_load_event_steps(child_id),
None => warn!("Message sent to closed pipeline {}.", parent_id),
}
@@ -1730,9 +1751,12 @@ impl ScriptThread {
Some(incomplete.url.clone()));
let is_html_document = match metadata.content_type {
+ Some(Serde(ContentType(Mime(TopLevel::Application, SubLevel::Ext(ref sub_level), _))))
+ if sub_level.ends_with("+xml") => IsHTMLDocument::NonHTMLDocument,
+
Some(Serde(ContentType(Mime(TopLevel::Application, SubLevel::Xml, _)))) |
- Some(Serde(ContentType(Mime(TopLevel::Text, SubLevel::Xml, _)))) =>
- IsHTMLDocument::NonHTMLDocument,
+ Some(Serde(ContentType(Mime(TopLevel::Text, SubLevel::Xml, _)))) => IsHTMLDocument::NonHTMLDocument,
+
_ => IsHTMLDocument::HTMLDocument,
};
@@ -1823,17 +1847,7 @@ impl ScriptThread {
document.set_https_state(metadata.https_state);
- let is_xml = match metadata.content_type {
- Some(Serde(ContentType(Mime(TopLevel::Application, SubLevel::Ext(ref sub_level), _))))
- if sub_level.ends_with("+xml") => true,
-
- Some(Serde(ContentType(Mime(TopLevel::Application, SubLevel::Xml, _)))) |
- Some(Serde(ContentType(Mime(TopLevel::Text, SubLevel::Xml, _)))) => true,
-
- _ => false,
- };
-
- if is_xml {
+ if is_html_document == IsHTMLDocument::NonHTMLDocument {
ServoParser::parse_xml_document(
&document,
parse_input,
@@ -2014,7 +2028,8 @@ impl ScriptThread {
replace: bool) {
match frame_id {
Some(frame_id) => {
- if let Some(iframe) = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id) {
+ let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id);
+ if let Some(iframe) = iframe {
iframe.navigate_or_reload_child_browsing_context(Some(load_data), replace);
}
}
@@ -2092,6 +2107,23 @@ impl ScriptThread {
self.incomplete_loads.borrow_mut().push(incomplete);
}
+ /// Synchronously fetch `about:blank`. Stores the `InProgressLoad`
+ /// argument until a notification is received that the fetch is complete.
+ fn start_page_load_about_blank(&self, incomplete: InProgressLoad) {
+ let id = incomplete.pipeline_id;
+
+ self.incomplete_loads.borrow_mut().push(incomplete);
+
+ let url = ServoUrl::parse("about:blank").unwrap();
+ let mut context = ParserContext::new(id, url.clone());
+
+ let mut meta = Metadata::default(url);
+ meta.set_content_type(Some(&mime!(Text / Html)));
+ context.process_response(Ok(FetchMetadata::Unfiltered(meta)));
+ context.process_response_chunk(vec![]);
+ context.process_response_eof(Ok(()));
+ }
+
fn handle_parsing_complete(&self, id: PipelineId) {
let document = match self.documents.borrow().find_document(id) {
Some(document) => document,