diff options
Diffstat (limited to 'components/script/dom')
172 files changed, 2899 insertions, 1460 deletions
diff --git a/components/script/dom/abstractworker.rs b/components/script/dom/abstractworker.rs index f9ff583a0dd..28c755d4f03 100644 --- a/components/script/dom/abstractworker.rs +++ b/components/script/dom/abstractworker.rs @@ -8,40 +8,14 @@ use dom::bindings::str::DOMString; use dom::bindings::structuredclone::StructuredCloneData; use js::jsapi::{JSRuntime, JS_RequestInterruptCallback}; use js::rust::Runtime; -use msg::constellation_msg::{PipelineId, ReferrerPolicy}; -use net_traits::{LoadOrigin, RequestSource}; use script_runtime::CommonScriptMsg; -use url::Url; /// Messages used to control the worker event loops pub enum WorkerScriptMsg { /// Common variants associated with the script messages Common(CommonScriptMsg), /// Message sent through Worker.postMessage - DOMMessage(StructuredCloneData), -} - -#[derive(Clone)] -pub struct WorkerScriptLoadOrigin { - pub referrer_url: Option<Url>, - pub referrer_policy: Option<ReferrerPolicy>, - pub request_source: RequestSource, - pub pipeline_id: Option<PipelineId> -} - -impl LoadOrigin for WorkerScriptLoadOrigin { - fn referrer_url(&self) -> Option<Url> { - self.referrer_url.clone() - } - fn referrer_policy(&self) -> Option<ReferrerPolicy> { - self.referrer_policy.clone() - } - fn request_source(&self) -> RequestSource { - self.request_source.clone() - } - fn pipeline_id(&self) -> Option<PipelineId> { - self.pipeline_id.clone() - } + DOMMessage(StructuredCloneData) } pub struct SimpleWorkerErrorHandler<T: Reflectable> { diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 2513b5b92eb..8360dfc322a 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -8,6 +8,7 @@ from collections import defaultdict from itertools import groupby import operator +import os import re import string import textwrap @@ -87,6 +88,11 @@ def stripTrailingWhitespace(text): return '\n'.join(lines) + tail +def innerSequenceType(type): + assert type.isSequence() + return type.inner.inner if type.nullable() else type.inner + + def MakeNativeName(name): return name[0].upper() + name[1:] @@ -713,7 +719,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, raise TypeError("Can't handle array arguments yet") if type.isSequence(): - innerInfo = getJSToNativeConversionInfo(type.unroll(), descriptorProvider) + innerInfo = getJSToNativeConversionInfo(innerSequenceType(type), descriptorProvider) declType = CGWrapper(innerInfo.declType, pre="Vec<", post=">") config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs) @@ -1302,8 +1308,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.isObject() or returnType.isSpiderMonkeyInterface(): return CGGeneric("*mut JSObject") if returnType.isSequence(): - inner = returnType.unroll() - result = getRetvalDeclarationForType(inner, descriptorProvider) + result = getRetvalDeclarationForType(innerSequenceType(returnType), descriptorProvider) result = CGWrapper(result, pre="Vec<", post=">") if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") @@ -2072,7 +2077,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config): 'dom::bindings::conversions::root_from_handlevalue', 'dom::bindings::error::throw_not_in_union', 'dom::bindings::js::Root', - 'dom::bindings::str::{DOMString, USVString}', + 'dom::bindings::str::{ByteString, DOMString, USVString}', 'dom::types::*', 'js::jsapi::JSContext', 'js::jsapi::{HandleValue, MutableHandleValue}', @@ -3743,12 +3748,15 @@ def getUnionTypeTemplateVars(type, descriptorProvider): typeName = name elif type.isSequence(): name = type.name - inner = getUnionTypeTemplateVars(type.unroll(), descriptorProvider) + inner = getUnionTypeTemplateVars(innerSequenceType(type), descriptorProvider) typeName = "Vec<" + inner["typeName"] + ">" elif type.isArray(): name = str(type) # XXXjdm dunno about typeName here typeName = "/*" + type.name + "*/" + elif type.isByteString(): + name = type.name + typeName = "ByteString" elif type.isDOMString(): name = type.name typeName = "DOMString" @@ -6437,3 +6445,36 @@ impl %(base)s { # Done. return curr + + @staticmethod + def SupportedDomApis(config): + descriptors = config.getDescriptors(isExposedConditionally=False) + + base_path = os.path.join('dom', 'bindings', 'codegen') + with open(os.path.join(base_path, 'apis.html.template')) as f: + base_template = f.read() + with open(os.path.join(base_path, 'api.html.template')) as f: + api_template = f.read() + with open(os.path.join(base_path, 'property.html.template')) as f: + property_template = f.read() + with open(os.path.join(base_path, 'interface.html.template')) as f: + interface_template = f.read() + + apis = [] + interfaces = [] + for descriptor in descriptors: + props = [] + for m in descriptor.interface.members: + if PropertyDefiner.getStringAttr(m, 'Pref') or \ + PropertyDefiner.getStringAttr(m, 'Func') or \ + (m.isMethod() and m.isIdentifierLess()): + continue + display = m.identifier.name + ('()' if m.isMethod() else '') + props += [property_template.replace('${name}', display)] + name = descriptor.interface.identifier.name + apis += [(api_template.replace('${interface}', name) + .replace('${properties}', '\n'.join(props)))] + interfaces += [interface_template.replace('${interface}', name)] + + return CGGeneric((base_template.replace('${apis}', '\n'.join(apis)) + .replace('${interfaces}', '\n'.join(interfaces)))) diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 9a39b1bc623..4074736a462 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -87,6 +87,8 @@ class Configuration: getter = lambda x: x.interface.isJSImplemented() elif key == 'isGlobal': getter = lambda x: x.isGlobal() + elif key == 'isExposedConditionally': + getter = lambda x: x.interface.isExposedConditionally() else: getter = lambda x: getattr(x, key) curr = filter(lambda x: getter(x) == val, curr) diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py index 72a2faa71e4..23779d9e6d5 100644 --- a/components/script/dom/bindings/codegen/GlobalGen.py +++ b/components/script/dom/bindings/codegen/GlobalGen.py @@ -32,6 +32,8 @@ def main(): o = OptionParser(usage=usageString) o.add_option("--cachedir", dest='cachedir', default=None, help="Directory in which to cache lex/parse tables.") + o.add_option("--only-html", dest='only_html', action="store_true", + help="Only generate HTML from WebIDL inputs") (options, args) = o.parse_args() if len(args) < 2: @@ -51,24 +53,30 @@ def main(): parser.parse(''.join(lines), fullPath) parserResults = parser.finish() - # Write the parser results out to a pickle. - resultsPath = os.path.join(outputdir, 'ParserResults.pkl') - with open(resultsPath, 'wb') as resultsFile: - cPickle.dump(parserResults, resultsFile, -1) + if not options.only_html: + # Write the parser results out to a pickle. + resultsPath = os.path.join(outputdir, 'ParserResults.pkl') + with open(resultsPath, 'wb') as resultsFile: + cPickle.dump(parserResults, resultsFile, -1) # Load the configuration. config = Configuration(configFile, parserResults) to_generate = [ - ('PrototypeList', 'PrototypeList.rs'), - ('RegisterBindings', 'RegisterBindings.rs'), - ('InterfaceObjectMap', 'InterfaceObjectMap.rs'), - ('InterfaceTypes', 'InterfaceTypes.rs'), - ('InheritTypes', 'InheritTypes.rs'), - ('Bindings', os.path.join('Bindings', 'mod.rs')), - ('UnionTypes', 'UnionTypes.rs'), + ('SupportedDomApis', 'apis.html'), ] + if not options.only_html: + to_generate = [ + ('PrototypeList', 'PrototypeList.rs'), + ('RegisterBindings', 'RegisterBindings.rs'), + ('InterfaceObjectMap', 'InterfaceObjectMap.rs'), + ('InterfaceTypes', 'InterfaceTypes.rs'), + ('InheritTypes', 'InheritTypes.rs'), + ('Bindings', os.path.join('Bindings', 'mod.rs')), + ('UnionTypes', 'UnionTypes.rs'), + ] + for name, filename in to_generate: generate_file(config, name, os.path.join(outputdir, filename)) diff --git a/components/script/dom/bindings/codegen/api.html.template b/components/script/dom/bindings/codegen/api.html.template new file mode 100644 index 00000000000..807392693a4 --- /dev/null +++ b/components/script/dom/bindings/codegen/api.html.template @@ -0,0 +1,6 @@ +<table id="${interface}"> +<tr> +<th>${interface}</th> +</tr> +${properties} +</table> diff --git a/components/script/dom/bindings/codegen/apis.html.template b/components/script/dom/bindings/codegen/apis.html.template new file mode 100644 index 00000000000..a6f1e59d4ab --- /dev/null +++ b/components/script/dom/bindings/codegen/apis.html.template @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="generator" content="rustdoc"> + <meta name="description" content="API documentation for the Rust `servo` crate."> + <meta name="keywords" content="rust, rustlang, rust-lang, servo"> + <title>Supported DOM APIs - servo - Rust</title> + <link rel="stylesheet" type="text/css" href="../rustdoc.css"> + <link rel="stylesheet" type="text/css" href="../main.css"> +</head> +<body class="rustdoc"> + <!--[if lte IE 8]> + <div class="warning"> + This old browser is unsupported and will most likely display funky + things. + </div> + <![endif]--> + <nav class='sidebar'> + <div class='block crate'> + <h3>Interfaces</h3> + <ul> + ${interfaces} + </ul> + </div> + </nav> + <section id='main' class="content mod"> + <h1 class='fqn'><span class='in-band'>DOM APIs currently supported in <a class='mod' href=''>Servo</a></span></h1> + <div id='properties' class='docblock'> + ${apis} + </div> + </section> +</body> +</html> diff --git a/components/script/dom/bindings/codegen/interface.html.template b/components/script/dom/bindings/codegen/interface.html.template new file mode 100644 index 00000000000..92b023165e2 --- /dev/null +++ b/components/script/dom/bindings/codegen/interface.html.template @@ -0,0 +1 @@ +<li><a href="#${interface}">${interface}</a></li> diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index acedc38ae5d..da32340dda6 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -158,6 +158,9 @@ class IDLObject(object): def isInterface(self): return False + def isNamespace(self): + return False + def isEnum(self): return False @@ -585,8 +588,8 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): return set() -class IDLPartialInterface(IDLObject): - def __init__(self, location, name, members, nonPartialInterface): +class IDLPartialInterfaceOrNamespace(IDLObject): + def __init__(self, location, name, members, nonPartialInterfaceOrNamespace): assert isinstance(name, IDLUnresolvedIdentifier) IDLObject.__init__(self, location) @@ -595,9 +598,10 @@ class IDLPartialInterface(IDLObject): # propagatedExtendedAttrs are the ones that should get # propagated to our non-partial interface. self.propagatedExtendedAttrs = [] - self._nonPartialInterface = nonPartialInterface + self._haveSecureContextExtendedAttribute = False + self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace self._finished = False - nonPartialInterface.addPartialInterface(self) + nonPartialInterfaceOrNamespace.addPartialInterface(self) def addExtendedAttributes(self, attrs): for attr in attrs: @@ -605,6 +609,16 @@ class IDLPartialInterface(IDLObject): if identifier in ["Constructor", "NamedConstructor"]: self.propagatedExtendedAttrs.append(attr) + elif identifier == "SecureContext": + self._haveSecureContextExtendedAttribute = True + # This gets propagated to all our members. + for member in self.members: + if member.getExtendedAttribute("SecureContext"): + raise WebIDLError("[SecureContext] specified on both a " + "partial interface member and on the " + "partial interface itself", + [member.location, attr.location]) + member.addExtendedAttributes([attr]) elif identifier == "Exposed": # This just gets propagated to all our members. for member in self.members: @@ -623,9 +637,23 @@ class IDLPartialInterface(IDLObject): if self._finished: return self._finished = True - # Need to make sure our non-partial interface gets finished so it can - # report cases when we only have partial interfaces. - self._nonPartialInterface.finish(scope) + if (not self._haveSecureContextExtendedAttribute and + self._nonPartialInterfaceOrNamespace.getExtendedAttribute("SecureContext")): + # This gets propagated to all our members. + for member in self.members: + if member.getExtendedAttribute("SecureContext"): + raise WebIDLError("[SecureContext] specified on both a " + "partial interface member and on the " + "non-partial interface", + [member.location, + self._nonPartialInterfaceOrNamespace.location]) + member.addExtendedAttributes( + [IDLExtendedAttribute(self._nonPartialInterfaceOrNamespace.location, + ("SecureContext",))]) + # Need to make sure our non-partial interface or namespace gets + # finished so it can report cases when we only have partial + # interfaces/namespaces. + self._nonPartialInterfaceOrNamespace.finish(scope) def validate(self): pass @@ -645,7 +673,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): exposureSet.update(globalScope.globalNameMapping[name]) -class IDLInterface(IDLObjectWithScope, IDLExposureMixins): +class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial): assert isinstance(parentScope, IDLScope) @@ -691,9 +719,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): if isKnownNonPartial: self.setNonPartial(location, parent, members) - def __str__(self): - return "Interface '%s'" % self.identifier.name - def ctor(self): identifier = IDLUnresolvedIdentifier(self.location, "constructor", allowForbidden=True) @@ -789,6 +814,20 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): assert iter(self.members) + if self.isNamespace(): + assert not self.parent + for m in self.members: + if m.isAttr() or m.isMethod(): + if m.isStatic(): + raise WebIDLError("Don't mark things explicitly static " + "in namespaces", + [self.location, m.location]) + # Just mark all our methods/attributes as static. The other + # option is to duplicate the relevant InterfaceMembers + # production bits but modified to produce static stuff to + # start with, but that sounds annoying. + m.forceStatic() + if self.parent: self.parent.finish(scope) self.parent._hasChildInterfaces = True @@ -843,6 +882,17 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): self.parent.identifier.name), [self.location, self.parent.location]) + # Interfaces that are not [SecureContext] can't inherit + # from [SecureContext] interfaces. + if (self.parent.getExtendedAttribute("SecureContext") and + not self.getExtendedAttribute("SecureContext")): + raise WebIDLError("Interface %s does not have " + "[SecureContext] but inherits from " + "interface %s which does" % + (self.identifier.name, + self.parent.identifier.name), + [self.location, self.parent.location]) + for iface in self.implementedInterfaces: iface.finish(scope) @@ -1211,6 +1261,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): member.getExtendedAttribute("ChromeOnly") or member.getExtendedAttribute("Pref") or member.getExtendedAttribute("Func") or + member.getExtendedAttribute("SecureContext") or member.getExtendedAttribute("AvailableIn") or member.getExtendedAttribute("CheckAnyPermissions") or member.getExtendedAttribute("CheckAllPermissions")): @@ -1285,9 +1336,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): [self.location, iterableDecl.location, indexedGetter.location]) - def isInterface(self): - return True - def isExternal(self): return False @@ -1338,7 +1386,172 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): return not hasattr(self, "_noInterfaceObject") def hasInterfacePrototypeObject(self): - return not self.isCallback() and self.getUserData('hasConcreteDescendant', False) + return (not self.isCallback() and not self.isNamespace() + and self.getUserData('hasConcreteDescendant', False)) + + def addImplementedInterface(self, implementedInterface): + assert(isinstance(implementedInterface, IDLInterface)) + self.implementedInterfaces.add(implementedInterface) + + def getInheritedInterfaces(self): + """ + Returns a list of the interfaces this interface inherits from + (not including this interface itself). The list is in order + from most derived to least derived. + """ + assert(self._finished) + if not self.parent: + return [] + parentInterfaces = self.parent.getInheritedInterfaces() + parentInterfaces.insert(0, self.parent) + return parentInterfaces + + def getConsequentialInterfaces(self): + assert(self._finished) + # The interfaces we implement directly + consequentialInterfaces = set(self.implementedInterfaces) + + # And their inherited interfaces + for iface in self.implementedInterfaces: + consequentialInterfaces |= set(iface.getInheritedInterfaces()) + + # And now collect up the consequential interfaces of all of those + temp = set() + for iface in consequentialInterfaces: + temp |= iface.getConsequentialInterfaces() + + return consequentialInterfaces | temp + + def findInterfaceLoopPoint(self, otherInterface): + """ + Finds an interface, amongst our ancestors and consequential interfaces, + that inherits from otherInterface or implements otherInterface + directly. If there is no such interface, returns None. + """ + if self.parent: + if self.parent == otherInterface: + return self + loopPoint = self.parent.findInterfaceLoopPoint(otherInterface) + if loopPoint: + return loopPoint + if otherInterface in self.implementedInterfaces: + return self + for iface in self.implementedInterfaces: + loopPoint = iface.findInterfaceLoopPoint(otherInterface) + if loopPoint: + return loopPoint + return None + + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) + + def setNonPartial(self, location, parent, members): + assert not parent or isinstance(parent, IDLIdentifierPlaceholder) + if self._isKnownNonPartial: + raise WebIDLError("Two non-partial definitions for the " + "same %s" % + ("interface" if self.isInterface() + else "namespace"), + [location, self.location]) + self._isKnownNonPartial = True + # Now make it look like we were parsed at this new location, since + # that's the place where the interface is "really" defined + self.location = location + assert not self.parent + self.parent = parent + # Put the new members at the beginning + self.members = members + self.members + + def addPartialInterface(self, partial): + assert self.identifier.name == partial.identifier.name + self._partialInterfaces.append(partial) + + def getJSImplementation(self): + classId = self.getExtendedAttribute("JSImplementation") + if not classId: + return classId + assert isinstance(classId, list) + assert len(classId) == 1 + return classId[0] + + def isJSImplemented(self): + return bool(self.getJSImplementation()) + + def isProbablyShortLivingObject(self): + current = self + while current: + if current.getExtendedAttribute("ProbablyShortLivingObject"): + return True + current = current.parent + return False + + def isNavigatorProperty(self): + naviProp = self.getExtendedAttribute("NavigatorProperty") + if not naviProp: + return False + assert len(naviProp) == 1 + assert isinstance(naviProp, list) + assert len(naviProp[0]) != 0 + return True + + def getNavigatorProperty(self): + naviProp = self.getExtendedAttribute("NavigatorProperty") + if not naviProp: + return None + assert len(naviProp) == 1 + assert isinstance(naviProp, list) + assert len(naviProp[0]) != 0 + conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterfaceOrNamespace.conditionExtendedAttributes + attr = IDLAttribute(self.location, + IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), naviProp[0]), + IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)), + True, + extendedAttrDict={ a: self._extendedAttrDict[a] for a in conditionExtendedAttributes }, + navigatorObjectGetter=True) + attr._exposureGlobalNames = self._exposureGlobalNames + # We're abusing Constant a little bit here, because we need Cached. The + # getter will create a new object every time, but we're never going to + # clear the cached value. + extendedAttrs = [ IDLExtendedAttribute(self.location, ("Throws", )), + IDLExtendedAttribute(self.location, ("Cached", )), + IDLExtendedAttribute(self.location, ("Constant", )) ] + attr.addExtendedAttributes(extendedAttrs) + return attr + + def hasChildInterfaces(self): + return self._hasChildInterfaces + + def isOnGlobalProtoChain(self): + return self._isOnGlobalProtoChain + + def _getDependentObjects(self): + deps = set(self.members) + deps.update(self.implementedInterfaces) + if self.parent: + deps.add(self.parent) + return deps + + def hasMembersInSlots(self): + return self._ownMembersInSlots != 0 + + conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn", + "SecureContext", + "CheckAnyPermissions", + "CheckAllPermissions" ] + def isExposedConditionally(self): + return any(self.getExtendedAttribute(a) for a in self.conditionExtendedAttributes) + +class IDLInterface(IDLInterfaceOrNamespace): + def __init__(self, location, parentScope, name, parent, members, + isKnownNonPartial): + IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, + parent, members, isKnownNonPartial) + + def __str__(self): + return "Interface '%s'" % self.identifier.name + + def isInterface(self): + return True def addExtendedAttributes(self, attrs): for attr in attrs: @@ -1469,6 +1682,18 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): self.parentScope.globalNames.add(self.identifier.name) self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name) self._isOnGlobalProtoChain = True + elif identifier == "SecureContext": + if not attr.noArguments(): + raise WebIDLError("[%s] must take no arguments" % identifier, + [attr.location]) + # This gets propagated to all our members. + for member in self.members: + if member.getExtendedAttribute("SecureContext"): + raise WebIDLError("[SecureContext] specified on both " + "an interface member and on the " + "interface itself", + [member.location, attr.location]) + member.addExtendedAttributes([attr]) elif (identifier == "NeedResolve" or identifier == "OverrideBuiltins" or identifier == "ChromeOnly" or @@ -1506,154 +1731,46 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True - def addImplementedInterface(self, implementedInterface): - assert(isinstance(implementedInterface, IDLInterface)) - self.implementedInterfaces.add(implementedInterface) - - def getInheritedInterfaces(self): - """ - Returns a list of the interfaces this interface inherits from - (not including this interface itself). The list is in order - from most derived to least derived. - """ - assert(self._finished) - if not self.parent: - return [] - parentInterfaces = self.parent.getInheritedInterfaces() - parentInterfaces.insert(0, self.parent) - return parentInterfaces - - def getConsequentialInterfaces(self): - assert(self._finished) - # The interfaces we implement directly - consequentialInterfaces = set(self.implementedInterfaces) - - # And their inherited interfaces - for iface in self.implementedInterfaces: - consequentialInterfaces |= set(iface.getInheritedInterfaces()) - - # And now collect up the consequential interfaces of all of those - temp = set() - for iface in consequentialInterfaces: - temp |= iface.getConsequentialInterfaces() - - return consequentialInterfaces | temp - - def findInterfaceLoopPoint(self, otherInterface): - """ - Finds an interface, amongst our ancestors and consequential interfaces, - that inherits from otherInterface or implements otherInterface - directly. If there is no such interface, returns None. - """ - if self.parent: - if self.parent == otherInterface: - return self - loopPoint = self.parent.findInterfaceLoopPoint(otherInterface) - if loopPoint: - return loopPoint - if otherInterface in self.implementedInterfaces: - return self - for iface in self.implementedInterfaces: - loopPoint = iface.findInterfaceLoopPoint(otherInterface) - if loopPoint: - return loopPoint - return None - - def getExtendedAttribute(self, name): - return self._extendedAttrDict.get(name, None) - - def setNonPartial(self, location, parent, members): - assert not parent or isinstance(parent, IDLIdentifierPlaceholder) - if self._isKnownNonPartial: - raise WebIDLError("Two non-partial definitions for the " - "same interface", - [location, self.location]) - self._isKnownNonPartial = True - # Now make it look like we were parsed at this new location, since - # that's the place where the interface is "really" defined - self.location = location - assert not self.parent - self.parent = parent - # Put the new members at the beginning - self.members = members + self.members - - def addPartialInterface(self, partial): - assert self.identifier.name == partial.identifier.name - self._partialInterfaces.append(partial) - def getJSImplementation(self): - classId = self.getExtendedAttribute("JSImplementation") - if not classId: - return classId - assert isinstance(classId, list) - assert len(classId) == 1 - return classId[0] - - def isJSImplemented(self): - return bool(self.getJSImplementation()) +class IDLNamespace(IDLInterfaceOrNamespace): + def __init__(self, location, parentScope, name, members, isKnownNonPartial): + IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, + None, members, isKnownNonPartial) - def isProbablyShortLivingObject(self): - current = self - while current: - if current.getExtendedAttribute("ProbablyShortLivingObject"): - return True - current = current.parent - return False + def __str__(self): + return "Namespace '%s'" % self.identifier.name - def isNavigatorProperty(self): - naviProp = self.getExtendedAttribute("NavigatorProperty") - if not naviProp: - return False - assert len(naviProp) == 1 - assert isinstance(naviProp, list) - assert len(naviProp[0]) != 0 + def isNamespace(self): return True - def getNavigatorProperty(self): - naviProp = self.getExtendedAttribute("NavigatorProperty") - if not naviProp: - return None - assert len(naviProp) == 1 - assert isinstance(naviProp, list) - assert len(naviProp[0]) != 0 - conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterface.conditionExtendedAttributes - attr = IDLAttribute(self.location, - IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), naviProp[0]), - IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)), - True, - extendedAttrDict={ a: self._extendedAttrDict[a] for a in conditionExtendedAttributes }, - navigatorObjectGetter=True) - attr._exposureGlobalNames = self._exposureGlobalNames - # We're abusing Constant a little bit here, because we need Cached. The - # getter will create a new object every time, but we're never going to - # clear the cached value. - extendedAttrs = [ IDLExtendedAttribute(self.location, ("Throws", )), - IDLExtendedAttribute(self.location, ("Cached", )), - IDLExtendedAttribute(self.location, ("Constant", )) ] - attr.addExtendedAttributes(extendedAttrs) - return attr - - def hasChildInterfaces(self): - return self._hasChildInterfaces - - def isOnGlobalProtoChain(self): - return self._isOnGlobalProtoChain - - def _getDependentObjects(self): - deps = set(self.members) - deps.update(self.implementedInterfaces) - if self.parent: - deps.add(self.parent) - return deps + def addExtendedAttributes(self, attrs): + # The set of things namespaces support is small enough it's simpler + # to factor out into a separate method than it is to sprinkle + # isNamespace() checks all through + # IDLInterfaceOrNamespace.addExtendedAttributes. + for attr in attrs: + identifier = attr.identifier() - def hasMembersInSlots(self): - return self._ownMembersInSlots != 0 + if identifier == "Exposed": + convertExposedAttrToGlobalNameSet(attr, + self._exposureGlobalNames) + elif identifier == "ClassString": + # Takes a string value to override the default "Object" if + # desired. + if not attr.hasValue(): + raise WebIDLError("[%s] must have a value" % identifier, + [attr.location]) + elif identifier == "ProtoObjectHack": + if not attr.noArguments(): + raise WebIDLError("[%s] must not have arguments" % identifier, + [attr.location]) + else: + raise WebIDLError("Unknown extended attribute %s on namespace" % + identifier, + [attr.location]) - conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn", - "CheckAnyPermissions", - "CheckAllPermissions" ] - def isExposedConditionally(self): - return any(self.getExtendedAttribute(a) for a in self.conditionExtendedAttributes) + attrlist = attr.listValue() + self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True class IDLDictionary(IDLObjectWithScope): @@ -2066,7 +2183,30 @@ class IDLUnresolvedType(IDLType): "distinguishable from other things") -class IDLNullableType(IDLType): +class IDLParameterizedType(IDLType): + def __init__(self, location, name, innerType): + IDLType.__init__(self, location, name) + self.builtin = False + self.inner = innerType + + def includesRestrictedFloat(self): + return self.inner.includesRestrictedFloat() + + def resolveType(self, parentScope): + assert isinstance(parentScope, IDLScope) + self.inner.resolveType(parentScope) + + def isComplete(self): + return self.inner.isComplete() + + def unroll(self): + return self.inner.unroll() + + def _getDependentObjects(self): + return self.inner._getDependentObjects() + + +class IDLNullableType(IDLParameterizedType): def __init__(self, location, innerType): assert not innerType.isVoid() assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] @@ -2074,9 +2214,7 @@ class IDLNullableType(IDLType): name = innerType.name if innerType.isComplete(): name += "OrNull" - IDLType.__init__(self, location, name) - self.inner = innerType - self.builtin = False + IDLParameterizedType.__init__(self, location, name, innerType) def __eq__(self, other): return isinstance(other, IDLNullableType) and self.inner == other.inner @@ -2117,9 +2255,6 @@ class IDLNullableType(IDLType): def isUnrestricted(self): return self.inner.isUnrestricted() - def includesRestrictedFloat(self): - return self.inner.includesRestrictedFloat() - def isInteger(self): return self.inner.isInteger() @@ -2174,13 +2309,6 @@ class IDLNullableType(IDLType): def tag(self): return self.inner.tag() - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - def complete(self, scope): self.inner = self.inner.complete(scope) if self.inner.nullable(): @@ -2196,9 +2324,6 @@ class IDLNullableType(IDLType): self.name = self.inner.name + "OrNull" return self - def unroll(self): - return self.inner.unroll() - def isDistinguishableFrom(self, other): if (other.nullable() or (other.isUnion() and other.hasNullableType) or other.isDictionary()): @@ -2206,17 +2331,12 @@ class IDLNullableType(IDLType): return False return self.inner.isDistinguishableFrom(other) - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLSequenceType(IDLType): +class IDLSequenceType(IDLParameterizedType): def __init__(self, location, parameterType): assert not parameterType.isVoid() - IDLType.__init__(self, location, parameterType.name) - self.inner = parameterType - self.builtin = False + IDLParameterizedType.__init__(self, location, parameterType.name, parameterType) # Need to set self.name up front if our inner type is already complete, # since in that case our .complete() won't be called. if self.inner.isComplete(): @@ -2267,27 +2387,14 @@ class IDLSequenceType(IDLType): def isSerializable(self): return self.inner.isSerializable() - def includesRestrictedFloat(self): - return self.inner.includesRestrictedFloat() - def tag(self): return IDLType.Tags.sequence - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - def complete(self, scope): self.inner = self.inner.complete(scope) self.name = self.inner.name + "Sequence" return self - def unroll(self): - return self.inner.unroll() - def isDistinguishableFrom(self, other): if other.isPromise(): return False @@ -2299,20 +2406,12 @@ class IDLSequenceType(IDLType): other.isDictionary() or other.isCallback() or other.isMozMap()) - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLMozMapType(IDLType): - # XXXbz This is pretty similar to IDLSequenceType in various ways. - # And maybe to IDLNullableType. Should we have a superclass for - # "type containing this other type"? Bug 1015318. +class IDLMozMapType(IDLParameterizedType): def __init__(self, location, parameterType): assert not parameterType.isVoid() - IDLType.__init__(self, location, parameterType.name) - self.inner = parameterType - self.builtin = False + IDLParameterizedType.__init__(self, location, parameterType.name, parameterType) # Need to set self.name up front if our inner type is already complete, # since in that case our .complete() won't be called. if self.inner.isComplete(): @@ -2327,19 +2426,9 @@ class IDLMozMapType(IDLType): def isMozMap(self): return True - def includesRestrictedFloat(self): - return self.inner.includesRestrictedFloat() - def tag(self): return IDLType.Tags.mozmap - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - def complete(self, scope): self.inner = self.inner.complete(scope) self.name = self.inner.name + "MozMap" @@ -2363,9 +2452,6 @@ class IDLMozMapType(IDLType): def isExposedInAllOf(self, exposureSet): return self.inner.unroll().isExposedInAllOf(exposureSet) - def _getDependentObjects(self): - return self.inner._getDependentObjects() - class IDLUnionType(IDLType): def __init__(self, location, memberTypes): @@ -3877,6 +3963,7 @@ class IDLConst(IDLInterfaceMember): elif (identifier == "Pref" or identifier == "ChromeOnly" or identifier == "Func" or + identifier == "SecureContext" or identifier == "AvailableIn" or identifier == "CheckAnyPermissions" or identifier == "CheckAllPermissions"): @@ -3903,7 +3990,7 @@ class IDLAttribute(IDLInterfaceMember): self.type = type self.readonly = readonly self.inherit = inherit - self.static = static + self._static = static self.lenientThis = False self._unforgeable = False self.stringifier = stringifier @@ -3925,7 +4012,10 @@ class IDLAttribute(IDLInterfaceMember): [self.location]) def isStatic(self): - return self.static + return self._static + + def forceStatic(self): + self._static = True def __str__(self): return "'%s' attribute '%s'" % (self.type, self.identifier) @@ -3979,16 +4069,53 @@ class IDLAttribute(IDLInterfaceMember): "interface type as its type", [self.location]) def validate(self): + def typeContainsChromeOnlyDictionaryMember(type): + if (type.nullable() or + type.isSequence() or + type.isMozMap()): + return typeContainsChromeOnlyDictionaryMember(type.inner) + + if type.isUnion(): + for memberType in type.flatMemberTypes: + (contains, location) = typeContainsChromeOnlyDictionaryMember(memberType) + if contains: + return (True, location) + + if type.isDictionary(): + dictionary = type.inner + while dictionary: + (contains, location) = dictionaryContainsChromeOnlyMember(dictionary) + if contains: + return (True, location) + dictionary = dictionary.parent + + return (False, None) + + def dictionaryContainsChromeOnlyMember(dictionary): + for member in dictionary.members: + if member.getExtendedAttribute("ChromeOnly"): + return (True, member.location) + (contains, location) = typeContainsChromeOnlyDictionaryMember(member.type) + if contains: + return (True, location) + return (False, None) + IDLInterfaceMember.validate(self) - if ((self.getExtendedAttribute("Cached") or - self.getExtendedAttribute("StoreInSlot")) and - not self.affects == "Nothing"): - raise WebIDLError("Cached attributes and attributes stored in " - "slots must be Constant or Pure or " - "Affects=Nothing, since the getter won't always " - "be called.", - [self.location]) + if (self.getExtendedAttribute("Cached") or + self.getExtendedAttribute("StoreInSlot")): + if not self.affects == "Nothing": + raise WebIDLError("Cached attributes and attributes stored in " + "slots must be Constant or Pure or " + "Affects=Nothing, since the getter won't always " + "be called.", + [self.location]) + (contains, location) = typeContainsChromeOnlyDictionaryMember(self.type) + if contains: + raise WebIDLError("[Cached] and [StoreInSlot] must not be used " + "on an attribute whose type contains a " + "[ChromeOnly] dictionary member", + [self.location, location]) if self.getExtendedAttribute("Frozen"): if (not self.type.isSequence() and not self.type.isDictionary() and not self.type.isMozMap()): @@ -4177,6 +4304,7 @@ class IDLAttribute(IDLInterfaceMember): identifier == "GetterThrows" or identifier == "ChromeOnly" or identifier == "Func" or + identifier == "SecureContext" or identifier == "Frozen" or identifier == "AvailableIn" or identifier == "NewObject" or @@ -4233,6 +4361,7 @@ class IDLArgument(IDLObjectWithIdentifier): self.enforceRange = False self.clamp = False self._allowTreatNonCallableAsNull = False + self._extendedAttrDict = {} assert not variadic or optional assert not variadic or not defaultValue @@ -4262,11 +4391,22 @@ class IDLArgument(IDLObjectWithIdentifier): self.enforceRange = True elif identifier == "TreatNonCallableAsNull": self._allowTreatNonCallableAsNull = True + elif (self.dictionaryMember and + (identifier == "ChromeOnly" or identifier == "Func")): + if not self.optional: + raise WebIDLError("[%s] must not be used on a required " + "dictionary member" % identifier, + [attribute.location]) else: raise WebIDLError("Unhandled extended attribute on %s" % ("a dictionary member" if self.dictionaryMember else "an argument"), [attribute.location]) + attrlist = attribute.listValue() + self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) def isComplete(self): return self._isComplete @@ -4537,6 +4677,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isStatic(self): return self._static + def forceStatic(self): + self._static = True + def isGetter(self): return self._getter @@ -4888,6 +5031,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "Pref" or identifier == "Deprecated" or identifier == "Func" or + identifier == "SecureContext" or identifier == "AvailableIn" or identifier == "CheckAnyPermissions" or identifier == "CheckAllPermissions" or @@ -5115,7 +5259,8 @@ class Tokenizer(object): "or": "OR", "maplike": "MAPLIKE", "setlike": "SETLIKE", - "iterable": "ITERABLE" + "iterable": "ITERABLE", + "namespace": "NAMESPACE" } tokens.extend(keywords.values()) @@ -5212,7 +5357,8 @@ class Parser(Tokenizer): def p_Definition(self, p): """ Definition : CallbackOrInterface - | PartialInterface + | Namespace + | Partial | Dictionary | Exception | Enum @@ -5246,33 +5392,54 @@ class Parser(Tokenizer): assert p[1] p[0] = p[1] - def p_Interface(self, p): + def handleNonPartialObject(self, location, identifier, constructor, + constructorArgs, nonPartialArgs): """ - Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON + This handles non-partial objects (interfaces and namespaces) by + checking for an existing partial object, and promoting it to + non-partial as needed. The return value is the non-partial object. + + constructorArgs are all the args for the constructor except the last + one: isKnownNonPartial. + + nonPartialArgs are the args for the setNonPartial call. """ - location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - members = p[5] - parent = p[3] + # The name of the class starts with "IDL", so strip that off. + # Also, starts with a capital letter after that, so nix that + # as well. + prettyname = constructor.__name__[3:].lower() try: existingObj = self.globalScope()._lookupIdentifier(identifier) if existingObj: - p[0] = existingObj - if not isinstance(p[0], IDLInterface): - raise WebIDLError("Interface has the same name as " - "non-interface object", - [location, p[0].location]) - p[0].setNonPartial(location, parent, members) - return + if not isinstance(existingObj, constructor): + raise WebIDLError("%s has the same name as " + "non-%s object" % + (prettyname.capitalize(), prettyname), + [location, existingObj.location]) + existingObj.setNonPartial(*nonPartialArgs) + return existingObj except Exception, ex: if isinstance(ex, WebIDLError): raise ex pass - iface = IDLInterface(location, self.globalScope(), identifier, parent, - members, isKnownNonPartial=True) - p[0] = iface + # True for isKnownNonPartial + return constructor(*(constructorArgs + [True])) + + def p_Interface(self, p): + """ + Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[5] + parent = p[3] + + p[0] = self.handleNonPartialObject( + location, identifier, IDLInterface, + [location, self.globalScope(), identifier, parent, members], + [location, parent, members]) def p_InterfaceForwardDecl(self, p): """ @@ -5297,34 +5464,100 @@ class Parser(Tokenizer): p[0] = IDLExternalInterface(location, self.globalScope(), identifier) - def p_PartialInterface(self, p): + def p_Namespace(self, p): """ - PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON """ - location = self.getLocation(p, 2) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) - members = p[5] + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handleNonPartialObject( + location, identifier, IDLNamespace, + [location, self.globalScope(), identifier, members], + [location, None, members]) + + def p_Partial(self, p): + """ + Partial : PARTIAL PartialDefinition + """ + p[0] = p[2] + + def p_PartialDefinition(self, p): + """ + PartialDefinition : PartialInterface + | PartialNamespace + """ + p[0] = p[1] + + def handlePartialObject(self, location, identifier, nonPartialConstructor, + nonPartialConstructorArgs, + partialConstructorArgs): + """ + This handles partial objects (interfaces and namespaces) by checking for + an existing non-partial object, and adding ourselves to it as needed. + The return value is our partial object. For now we just use + IDLPartialInterfaceOrNamespace for partial objects. + + nonPartialConstructorArgs are all the args for the non-partial + constructor except the last two: members and isKnownNonPartial. + + partialConstructorArgs are the arguments for the + IDLPartialInterfaceOrNamespace constructor, except the last one (the + non-partial object). + """ + # The name of the class starts with "IDL", so strip that off. + # Also, starts with a capital letter after that, so nix that + # as well. + prettyname = nonPartialConstructor.__name__[3:].lower() - nonPartialInterface = None + nonPartialObject = None try: - nonPartialInterface = self.globalScope()._lookupIdentifier(identifier) - if nonPartialInterface: - if not isinstance(nonPartialInterface, IDLInterface): - raise WebIDLError("Partial interface has the same name as " - "non-interface object", - [location, nonPartialInterface.location]) + nonPartialObject = self.globalScope()._lookupIdentifier(identifier) + if nonPartialObject: + if not isinstance(nonPartialObject, nonPartialConstructor): + raise WebIDLError("Partial %s has the same name as " + "non-%s object" % + (prettyname, prettyname), + [location, nonPartialObject.location]) except Exception, ex: if isinstance(ex, WebIDLError): raise ex pass - if not nonPartialInterface: - nonPartialInterface = IDLInterface(location, self.globalScope(), - identifier, None, - [], isKnownNonPartial=False) - partialInterface = IDLPartialInterface(location, identifier, members, - nonPartialInterface) - p[0] = partialInterface + if not nonPartialObject: + nonPartialObject = nonPartialConstructor( + # No members, False for isKnownNonPartial + *(nonPartialConstructorArgs + [[], False])) + partialInterface = IDLPartialInterfaceOrNamespace( + *(partialConstructorArgs + [nonPartialObject])) + return partialInterface + + def p_PartialInterface(self, p): + """ + PartialInterface : INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handlePartialObject( + location, identifier, IDLInterface, + [location, self.globalScope(), identifier, None], + [location, identifier, members]) + + def p_PartialNamespace(self, p): + """ + PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handlePartialObject( + location, identifier, IDLNamespace, + [location, self.globalScope(), identifier], + [location, identifier, members]) def p_Inheritance(self, p): """ @@ -5985,6 +6218,7 @@ class Parser(Tokenizer): | JSONIFIER | TYPEDEF | UNRESTRICTED + | NAMESPACE """ p[0] = p[1] @@ -6585,19 +6819,21 @@ class Parser(Tokenizer): Tokenizer.__init__(self, outputdir, lexer) logger = SqueakyCleanLogger() - self.parser = yacc.yacc(module=self, - outputdir=outputdir, - tabmodule='webidlyacc', - errorlog=logger, - debug=False - # Pickling the grammar is a speedup in - # some cases (older Python?) but a - # significant slowdown in others. - # We're not pickling for now, until it - # becomes a speedup again. - # , picklefile='WebIDLGrammar.pkl' - ) - logger.reportGrammarErrors() + try: + self.parser = yacc.yacc(module=self, + outputdir=outputdir, + tabmodule='webidlyacc', + errorlog=logger, + debug=False + # Pickling the grammar is a speedup in + # some cases (older Python?) but a + # significant slowdown in others. + # We're not pickling for now, until it + # becomes a speedup again. + # , picklefile='WebIDLGrammar.pkl' + ) + finally: + logger.reportGrammarErrors() self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None) # To make our test harness work, pretend like we have a primary global already. @@ -6668,10 +6904,11 @@ class Parser(Tokenizer): # We're generating a partial interface to add a readonly # property to the Navigator interface for every interface # annotated with NavigatorProperty. - partialInterface = IDLPartialInterface(iface.location, - IDLUnresolvedIdentifier(iface.location, "Navigator"), - [ navigatorProperty ], - navigatorInterface) + partialInterface = IDLPartialInterfaceOrNamespace( + iface.location, + IDLUnresolvedIdentifier(iface.location, "Navigator"), + [ navigatorProperty ], + navigatorInterface) self._productions.append(partialInterface) iterable = None diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch deleted file mode 100644 index a8e2ddcf759..00000000000 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- WebIDL.py -+++ WebIDL.py -@@ -1416,7 +1416,8 @@ - identifier == "LegacyEventInit" or - identifier == "ProbablyShortLivingObject" or - identifier == "LegacyUnenumerableNamedProperties" or -- identifier == "NonOrdinaryGetPrototypeOf"): -+ identifier == "NonOrdinaryGetPrototypeOf" or -+ identifier == "Abstract"): - # Known extended attributes that do not take values - if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, diff --git a/components/script/dom/bindings/codegen/parser/debug.patch b/components/script/dom/bindings/codegen/parser/debug.patch index 85075dea490..ca391c38273 100644 --- a/components/script/dom/bindings/codegen/parser/debug.patch +++ b/components/script/dom/bindings/codegen/parser/debug.patch @@ -1,12 +1,12 @@ --- WebIDL.py +++ WebIDL.py -@@ -6438,7 +6438,8 @@ class Parser(Tokenizer): - self.parser = yacc.yacc(module=self, - outputdir=outputdir, - tabmodule='webidlyacc', -- errorlog=logger -+ errorlog=logger, -+ debug=False - # Pickling the grammar is a speedup in - # some cases (older Python?) but a - # significant slowdown in others. +@@ -6823,7 +6823,8 @@ class Parser(Tokenizer): + self.parser = yacc.yacc(module=self, + outputdir=outputdir, + tabmodule='webidlyacc', +- errorlog=logger ++ errorlog=logger, ++ debug=False + # Pickling the grammar is a speedup in + # some cases (older Python?) but a + # significant slowdown in others. diff --git a/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py b/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py new file mode 100644 index 00000000000..433b7e501a4 --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py @@ -0,0 +1,110 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict { + any foo; + [ChromeOnly] any bar; + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should have a dictionary") + members = results[0].members; + harness.check(len(members), 2, "Should have two members") + # Note that members are ordered lexicographically, so "bar" comes + # before "foo". + harness.ok(members[0].getExtendedAttribute("ChromeOnly"), + "First member is not ChromeOnly") + harness.ok(not members[1].getExtendedAttribute("ChromeOnly"), + "Second member is ChromeOnly") + + parser = parser.reset() + parser.parse(""" + dictionary Dict { + any foo; + any bar; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + harness.check(len(results), 2, "Should have a dictionary and an interface") + + parser = parser.reset() + exception = None + try: + parser.parse(""" + dictionary Dict { + any foo; + [ChromeOnly] any bar; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + except Exception, exception: + pass + + harness.ok(exception, "Should have thrown.") + harness.check(exception.message, + "[Cached] and [StoreInSlot] must not be used on an attribute " + "whose type contains a [ChromeOnly] dictionary member", + "Should have thrown the right exception") + + parser = parser.reset() + exception = None + try: + parser.parse(""" + dictionary ParentDict { + [ChromeOnly] any bar; + }; + + dictionary Dict : ParentDict { + any foo; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + except Exception, exception: + pass + + harness.ok(exception, "Should have thrown (2).") + harness.check(exception.message, + "[Cached] and [StoreInSlot] must not be used on an attribute " + "whose type contains a [ChromeOnly] dictionary member", + "Should have thrown the right exception (2)") + + parser = parser.reset() + exception = None + try: + parser.parse(""" + dictionary GrandParentDict { + [ChromeOnly] any baz; + }; + + dictionary ParentDict : GrandParentDict { + any bar; + }; + + dictionary Dict : ParentDict { + any foo; + }; + + interface Iface { + [Constant, Cached] readonly attribute Dict dict; + }; + """) + results = parser.finish() + except Exception, exception: + pass + + harness.ok(exception, "Should have thrown (3).") + harness.check(exception.message, + "[Cached] and [StoreInSlot] must not be used on an attribute " + "whose type contains a [ChromeOnly] dictionary member", + "Should have thrown the right exception (3)") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_namespace.py b/components/script/dom/bindings/codegen/parser/tests/test_namespace.py new file mode 100644 index 00000000000..74533a1770e --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_namespace.py @@ -0,0 +1,223 @@ +def WebIDLTest(parser, harness): + parser.parse( + """ + namespace MyNamespace { + attribute any foo; + any bar(); + }; + """) + + results = parser.finish() + harness.check(len(results), 1, "Should have a thing.") + harness.ok(results[0].isNamespace(), "Our thing should be a namespace"); + harness.check(len(results[0].members), 2, + "Should have two things in our namespace") + harness.ok(results[0].members[0].isAttr(), "First member is attribute") + harness.ok(results[0].members[0].isStatic(), "Attribute should be static") + harness.ok(results[0].members[1].isMethod(), "Second member is method") + harness.ok(results[0].members[1].isStatic(), "Operation should be static") + + parser = parser.reset() + parser.parse( + """ + namespace MyNamespace { + attribute any foo; + }; + partial namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + harness.check(len(results), 2, "Should have things.") + harness.ok(results[0].isNamespace(), "Our thing should be a namespace"); + harness.check(len(results[0].members), 2, + "Should have two things in our namespace") + harness.ok(results[0].members[0].isAttr(), "First member is attribute") + harness.ok(results[0].members[0].isStatic(), "Attribute should be static"); + harness.ok(results[0].members[1].isMethod(), "Second member is method") + harness.ok(results[0].members[1].isStatic(), "Operation should be static"); + + parser = parser.reset() + parser.parse( + """ + partial namespace MyNamespace { + any bar(); + }; + namespace MyNamespace { + attribute any foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 2, "Should have things.") + harness.ok(results[1].isNamespace(), "Our thing should be a namespace"); + harness.check(len(results[1].members), 2, + "Should have two things in our namespace") + harness.ok(results[1].members[0].isAttr(), "First member is attribute") + harness.ok(results[1].members[0].isStatic(), "Attribute should be static"); + harness.ok(results[1].members[1].isMethod(), "Second member is method") + harness.ok(results[1].members[1].isStatic(), "Operation should be static"); + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + static attribute any foo; + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + static any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + any bar(); + }; + + interface MyNamespace { + any baz(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface MyNamespace { + any baz(); + }; + + namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + any baz(); + }; + + namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + partial namespace MyNamespace { + any baz(); + }; + + interface MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + namespace MyNamespace { + any bar(); + }; + + partial interface MyNamespace { + any baz(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + partial interface MyNamespace { + any baz(); + }; + + namespace MyNamespace { + any bar(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface MyNamespace { + any bar(); + }; + + partial namespace MyNamespace { + any baz(); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py b/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py new file mode 100644 index 00000000000..d907d08449f --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py @@ -0,0 +1,318 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInterface { + const octet TEST_CONSTANT = 0; + readonly attribute byte testAttribute; + void testMethod(byte foo); + }; + partial interface TestSecureContextOnInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 6, "TestSecureContextOnInterface should have six members") + harness.ok(results[0].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members from partial interface") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members from partial interface") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members from partial interface") + + # Same thing, but with the partial interface specified first: + parser = parser.reset() + parser.parse(""" + partial interface TestSecureContextOnInterfaceAfterPartialInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + [SecureContext] + interface TestSecureContextOnInterfaceAfterPartialInterface { + const octet TEST_CONSTANT = 0; + readonly attribute byte testAttribute; + void testMethod(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[1].members), 6, "TestSecureContextOnInterfaceAfterPartialInterface should have six members") + harness.ok(results[1].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[1].members[0].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members") + harness.ok(results[1].members[1].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members") + harness.ok(results[1].members[2].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members") + harness.ok(results[1].members[3].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members from partial interface") + harness.ok(results[1].members[4].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to attribute members from partial interface") + harness.ok(results[1].members[5].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to method members from partial interface") + + parser = parser.reset() + parser.parse(""" + interface TestSecureContextOnPartialInterface { + const octet TEST_CONSTANT = 0; + readonly attribute byte testAttribute; + void testMethod(byte foo); + }; + [SecureContext] + partial interface TestSecureContextOnPartialInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 6, "TestSecureContextOnPartialInterface should have six members") + harness.ok(results[0].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface's constant members") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface's attribute members") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "[SecureContext] should not propagate from a partial interface to the interface's method members") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext"), + "Constant members from [SecureContext] partial interface should be [SecureContext]") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "Attribute members from [SecureContext] partial interface should be [SecureContext]") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext"), + "Method members from [SecureContext] partial interface should be [SecureContext]") + + parser = parser.reset() + parser.parse(""" + interface TestSecureContextOnInterfaceMembers { + const octet TEST_NON_SECURE_CONSTANT_1 = 0; + [SecureContext] + const octet TEST_SECURE_CONSTANT = 1; + const octet TEST_NON_SECURE_CONSTANT_2 = 2; + readonly attribute byte testNonSecureAttribute1; + [SecureContext] + readonly attribute byte testSecureAttribute; + readonly attribute byte testNonSecureAttribute2; + void testNonSecureMethod1(byte foo); + [SecureContext] + void testSecureMethod(byte foo); + void testNonSecureMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 9, "TestSecureContextOnInterfaceMembers should have nine members") + harness.ok(results[0].getExtendedAttribute("SecureContext") is None, + "[SecureContext] on members should not propagate up to the interface") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None, + "Constant should not have [SecureContext] extended attribute") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"), + "Constant should have [SecureContext] extended attribute") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "Constant should not have [SecureContext] extended attribute") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, + "Attribute should not have [SecureContext] extended attribute") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "Attribute should have [SecureContext] extended attribute") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext") is None, + "Attribute should not have [SecureContext] extended attribute") + harness.ok(results[0].members[6].getExtendedAttribute("SecureContext") is None, + "Method should not have [SecureContext] extended attribute") + harness.ok(results[0].members[7].getExtendedAttribute("SecureContext"), + "Method should have [SecureContext] extended attribute") + harness.ok(results[0].members[8].getExtendedAttribute("SecureContext") is None, + "Method should not have [SecureContext] extended attribute") + + parser = parser.reset() + parser.parse(""" + interface TestSecureContextOnPartialInterfaceMembers { + }; + partial interface TestSecureContextOnPartialInterfaceMembers { + const octet TEST_NON_SECURE_CONSTANT_1 = 0; + [SecureContext] + const octet TEST_SECURE_CONSTANT = 1; + const octet TEST_NON_SECURE_CONSTANT_2 = 2; + readonly attribute byte testNonSecureAttribute1; + [SecureContext] + readonly attribute byte testSecureAttribute; + readonly attribute byte testNonSecureAttribute2; + void testNonSecureMethod1(byte foo); + [SecureContext] + void testSecureMethod(byte foo); + void testNonSecureMethod2(byte foo); + }; + """) + results = parser.finish() + harness.check(len(results[0].members), 9, "TestSecureContextOnPartialInterfaceMembers should have nine members") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None, + "Constant from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"), + "Constant from partial interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "Constant from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, + "Attribute from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"), + "Attribute from partial interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[5].getExtendedAttribute("SecureContext") is None, + "Attribute from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[6].getExtendedAttribute("SecureContext") is None, + "Method from partial interface should not have [SecureContext] extended attribute") + harness.ok(results[0].members[7].getExtendedAttribute("SecureContext"), + "Method from partial interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[8].getExtendedAttribute("SecureContext") is None, + "Method from partial interface should not have [SecureContext] extended attribute") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext=something] + interface TestSecureContextTakesNoValue1 { + const octet TEST_SECURE_CONSTANT = 0; + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must take no arguments (testing on interface)") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestSecureContextForOverloads1 { + [SecureContext] + void testSecureMethod(byte foo); + }; + partial interface TestSecureContextForOverloads1 { + void testSecureMethod(byte foo, byte bar); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "If [SecureContext] appears on an overloaded operation, then it MUST appear on all overloads") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestSecureContextForOverloads2 { + [SecureContext] + void testSecureMethod(byte foo); + }; + partial interface TestSecureContextForOverloads2 { + [SecureContext] + void testSecureMethod(byte foo, byte bar); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "[SecureContext] can appear on an overloaded operation if it appears on all overloads") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInterfaceAndMember { + [SecureContext] + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must not appear on an interface and interface member") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + interface TestSecureContextOnPartialInterfaceAndMember { + }; + [SecureContext] + partial interface TestSecureContextOnPartialInterfaceAndMember { + [SecureContext] + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must not appear on a partial interface and one of the partial interface's member's") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInterfaceAndPartialInterfaceMember { + }; + partial interface TestSecureContextOnInterfaceAndPartialInterfaceMember { + [SecureContext] + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must not appear on an interface and one of its partial interface's member's") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [SecureContext] + interface TestSecureContextOnInheritedInterface { + }; + interface TestSecureContextNotOnInheritingInterface : TestSecureContextOnInheritedInterface { + void testSecureMethod(byte foo); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "[SecureContext] must appear on interfaces that inherit from another [SecureContext] interface") + + # Test 'implements'. The behavior tested here may have to change depending + # on the resolution of https://github.com/heycam/webidl/issues/118 + parser = parser.reset() + parser.parse(""" + [SecureContext] + interface TestSecureContextInterfaceThatImplementsNonSecureContextInterface { + const octet TEST_CONSTANT = 0; + }; + interface TestNonSecureContextInterface { + const octet TEST_CONSTANT_2 = 0; + readonly attribute byte testAttribute2; + void testMethod2(byte foo); + }; + TestSecureContextInterfaceThatImplementsNonSecureContextInterface implements TestNonSecureContextInterface; + """) + results = parser.finish() + harness.check(len(results[0].members), 4, "TestSecureContextInterfaceThatImplementsNonSecureContextInterface should have two members") + harness.ok(results[0].getExtendedAttribute("SecureContext"), + "Interface should have [SecureContext] extended attribute") + harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"), + "[SecureContext] should propagate from interface to constant members even when other members are copied from a non-[SecureContext] interface") + harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None, + "Constants copied from non-[SecureContext] interface should not be [SecureContext]") + harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None, + "Attributes copied from non-[SecureContext] interface should not be [SecureContext]") + harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None, + "Methods copied from non-[SecureContext] interface should not be [SecureContext]") + diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index ac4be6c73fd..76a99d9cecb 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -1,4 +1,4 @@ -wget https://mxr.mozilla.org/mozilla-central/source/dom/bindings/parser/WebIDL.py?raw=1 -O WebIDL.py +wget https://hg.mozilla.org/mozilla-central/raw-file/tip/dom/bindings/parser/WebIDL.py -O WebIDL.py patch < abstract.patch patch < debug.patch patch < pref-main-thread.patch diff --git a/components/script/dom/bindings/codegen/property.html.template b/components/script/dom/bindings/codegen/property.html.template new file mode 100644 index 00000000000..7b16aa78d0f --- /dev/null +++ b/components/script/dom/bindings/codegen/property.html.template @@ -0,0 +1,3 @@ +<tr> + <td>${name}</td> +</tr> diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 1040e7b5965..fe81b8a14de 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -18,14 +18,15 @@ use ipc_channel::ipc::IpcSender; use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment}; use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue}; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; -use msg::constellation_msg::{PipelineId, PanicMsg}; +use msg::constellation_msg::PipelineId; use net_traits::filemanager_thread::FileManagerThreadMsg; -use net_traits::{ResourceThreads, CoreResourceThread, RequestSource, IpcSend}; +use net_traits::{ResourceThreads, CoreResourceThread, IpcSend}; use profile_traits::{mem, time}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; -use script_thread::{MainThreadScriptChan, ScriptThread}; +use script_thread::{MainThreadScriptChan, ScriptThread, RunnableWrapper}; use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest}; use task_source::dom_manipulation::DOMManipulationTaskSource; +use task_source::file_reading::FileReadingTaskSource; use timers::{OneshotTimerCallback, OneshotTimerHandle}; use url::Url; @@ -65,14 +66,6 @@ impl<'a> GlobalRef<'a> { } } - /// gets the custom message channel associated with global object - pub fn request_source(&self) -> RequestSource { - match *self { - GlobalRef::Window(ref window) => RequestSource::Window(window.custom_message_chan()), - GlobalRef::Worker(ref worker) => RequestSource::Worker(worker.custom_message_chan()), - } - } - /// Get the `PipelineId` for this global scope. pub fn pipeline(&self) -> PipelineId { match *self { @@ -219,10 +212,10 @@ impl<'a> GlobalRef<'a> { /// `ScriptChan` used to send messages to the event loop of this global's /// thread. - pub fn file_reading_task_source(&self) -> Box<ScriptChan + Send> { + pub fn file_reading_task_source(&self) -> FileReadingTaskSource { match *self { GlobalRef::Window(ref window) => window.file_reading_task_source(), - GlobalRef::Worker(ref worker) => worker.script_chan(), + GlobalRef::Worker(ref worker) => worker.file_reading_task_source(), } } @@ -290,11 +283,12 @@ impl<'a> GlobalRef<'a> { } } - /// Returns an `IpcSender` to report panics on. - pub fn panic_chan(&self) -> &IpcSender<PanicMsg> { + /// Returns a wrapper for runnables to ensure they are cancelled if the global + /// is being destroyed. + pub fn get_runnable_wrapper(&self) -> RunnableWrapper { match *self { - GlobalRef::Window(ref window) => window.panic_chan(), - GlobalRef::Worker(ref worker) => worker.panic_chan(), + GlobalRef::Window(ref window) => window.get_runnable_wrapper(), + GlobalRef::Worker(ref worker) => worker.get_runnable_wrapper(), } } } diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs index 310285a8bcd..c73a08d182b 100644 --- a/components/script/dom/bindings/str.rs +++ b/components/script/dom/bindings/str.rs @@ -15,7 +15,7 @@ use std::str::{Bytes, FromStr}; use string_cache::Atom; /// Encapsulates the IDL `ByteString` type. -#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf)] +#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf, Debug)] pub struct ByteString(Vec<u8>); impl ByteString { @@ -113,6 +113,41 @@ pub fn is_token(s: &[u8]) -> bool { } /// A DOMString. +/// +/// This type corresponds to the [`DOMString`](idl) type in WebIDL. +/// +/// [idl]: https://heycam.github.io/webidl/#idl-DOMString +/// +/// Cenceptually, a DOMString has the same value space as a JavaScript String, +/// i.e., an array of 16-bit *code units* representing UTF-16, potentially with +/// unpaired surrogates present (also sometimes called WTF-16). +/// +/// Currently, this type stores a Rust `String`, in order to avoid issues when +/// integrating with the rest of the Rust ecosystem and even the rest of the +/// browser itself. +/// +/// However, Rust `String`s are guaranteed to be valid UTF-8, and as such have +/// a *smaller value space* than WTF-16 (i.e., some JavaScript String values +/// can not be represented as a Rust `String`). This introduces the question of +/// what to do with values being passed from JavaScript to Rust that contain +/// unpaired surrogates. +/// +/// The hypothesis is that it does not matter much how exactly those values are +/// transformed, because passing unpaired surrogates into the DOM is very rare. +/// In order to test this hypothesis, Servo will panic when encountering any +/// unpaired surrogates on conversion to `DOMString` by default. (The command +/// line option `-Z replace-surrogates` instead causes Servo to replace the +/// unpaired surrogate by a U+FFFD replacement character.) +/// +/// Currently, the lack of crash reports about this issue provides some +/// evidence to support the hypothesis. This evidence will hopefully be used to +/// convince other browser vendors that it would be safe to replace unpaired +/// surrogates at the boundary between JavaScript and native code. (This would +/// unify the `DOMString` and `USVString` types, both in the WebIDL standard +/// and in Servo.) +/// +/// This type is currently `!Send`, in order to help with an independent +/// experiment to store `JSString`s rather than Rust `String`s. #[derive(Clone, Debug, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd)] pub struct DOMString(String); diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index e2c6e540a3d..3c13572bf37 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -79,6 +79,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::{BuildHasher, Hash}; use std::mem; use std::ops::{Deref, DerefMut}; +use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize}; @@ -88,8 +89,7 @@ use string_cache::{Atom, Namespace, QualName}; use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto}; use style::element_state::*; use style::properties::PropertyDeclarationBlock; -use style::restyle_hints::ElementSnapshot; -use style::selector_impl::PseudoElement; +use style::selector_impl::{PseudoElement, ElementSnapshot}; use style::values::specified::Length; use url::Origin as UrlOrigin; use url::Url; @@ -331,6 +331,7 @@ no_jsmanaged_fields!(SystemTime); no_jsmanaged_fields!(SelectedFileId); no_jsmanaged_fields!(RelativePos); no_jsmanaged_fields!(OpaqueStyleAndLayoutData); +no_jsmanaged_fields!(PathBuf); no_jsmanaged_fields!(CSSErrorReporter); no_jsmanaged_fields!(WebGLBufferId); no_jsmanaged_fields!(WebGLFramebufferId); diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index 1b114e90652..ae2b1725319 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -15,17 +15,29 @@ use encoding::all::UTF_8; use encoding::types::{EncoderTrap, Encoding}; use ipc_channel::ipc; use net_traits::IpcSend; -use net_traits::blob_url_store::BlobURLStoreEntry; -use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos}; -use std::ascii::AsciiExt; +use net_traits::blob_url_store::{BlobBuf, get_blob_origin}; +use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos, ReadFileProgress}; use std::cell::Cell; use std::ops::Index; +use std::path::PathBuf; +use uuid::Uuid; +/// File-based blob +#[derive(JSTraceable)] +pub struct FileBlob { + id: SelectedFileId, + name: PathBuf, + cache: DOMRefCell<Option<Vec<u8>>>, + size: u64, +} + + +/// Blob backend implementation #[must_root] #[derive(JSTraceable)] pub enum BlobImpl { - /// File-based blob, including id and possibly cached content - File(SelectedFileId, DOMRefCell<Option<Vec<u8>>>), + /// File-based blob + File(FileBlob), /// Memory-based blob Memory(Vec<u8>), /// Sliced blob, including parent blob and @@ -42,8 +54,13 @@ impl BlobImpl { } /// Construct file-backed BlobImpl from File ID - pub fn new_from_file(file_id: SelectedFileId) -> BlobImpl { - BlobImpl::File(file_id, DOMRefCell::new(None)) + pub fn new_from_file(file_id: SelectedFileId, name: PathBuf, size: u64) -> BlobImpl { + BlobImpl::File(FileBlob { + id: file_id, + name: name, + cache: DOMRefCell::new(None), + size: size, + }) } } @@ -69,7 +86,9 @@ impl Blob { Blob { reflector_: Reflector::new(), blob_impl: DOMRefCell::new(blob_impl), - typeString: typeString, + // NOTE: Guarding the format correctness here, + // https://w3c.github.io/FileAPI/#dfn-type + typeString: normalize_type_string(&typeString), isClosed_: Cell::new(false), } } @@ -79,8 +98,8 @@ impl Blob { relativeContentType: DOMString) -> Root<Blob> { let global = parent.global(); let blob_impl = match *parent.blob_impl.borrow() { - BlobImpl::File(ref id, _) => { - inc_ref_id(global.r(), id.clone()); + BlobImpl::File(ref f) => { + inc_ref_id(global.r(), f.id.clone()); // Create new parent node BlobImpl::Sliced(JS::from_ref(parent), rel_pos) @@ -93,8 +112,8 @@ impl Blob { // Adjust the slicing position, using same parent let new_rel_pos = old_rel_pos.slice_inner(&rel_pos); - if let BlobImpl::File(ref id, _) = *grandparent.blob_impl.borrow() { - inc_ref_id(global.r(), id.clone()); + if let BlobImpl::File(ref f) = *grandparent.blob_impl.borrow() { + inc_ref_id(global.r(), f.id.clone()); } BlobImpl::Sliced(grandparent.clone(), new_rel_pos) @@ -118,28 +137,28 @@ impl Blob { } }; - Ok(Blob::new(global, BlobImpl::new_from_bytes(bytes), blobPropertyBag.get_typestring())) + Ok(Blob::new(global, BlobImpl::new_from_bytes(bytes), blobPropertyBag.type_.to_string())) } /// Get a slice to inner data, this might incur synchronous read and caching pub fn get_bytes(&self) -> Result<Vec<u8>, ()> { match *self.blob_impl.borrow() { - BlobImpl::File(ref id, ref cached) => { - let buffer = match *cached.borrow() { - Some(ref s) => Ok(s.clone()), + BlobImpl::File(ref f) => { + let (buffer, is_new_buffer) = match *f.cache.borrow() { + Some(ref bytes) => (bytes.clone(), false), None => { let global = self.global(); - let s = read_file(global.r(), id.clone())?; - Ok(s) + let bytes = read_file(global.r(), f.id.clone())?; + (bytes, true) } }; // Cache - if let Ok(buf) = buffer.clone() { - *cached.borrow_mut() = Some(buf); + if is_new_buffer { + *f.cache.borrow_mut() = Some(buffer.clone()); } - buffer + Ok(buffer) } BlobImpl::Memory(ref s) => Ok(s.clone()), BlobImpl::Sliced(ref parent, ref rel_pos) => { @@ -155,31 +174,33 @@ impl Blob { /// used by URL.createObjectURL pub fn get_blob_url_id(&self) -> SelectedFileId { match *self.blob_impl.borrow() { - BlobImpl::File(ref id, _) => { + BlobImpl::File(ref f) => { let global = self.global(); - let origin = global.r().get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&global.r().get_url()); let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); - let _ = filemanager.send(FileManagerThreadMsg::ActivateBlobURL(id.clone(), tx, origin.clone())); + let _ = filemanager.send(FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone())); match rx.recv().unwrap() { - Ok(_) => id.clone(), - Err(_) => SelectedFileId("".to_string()) // Return a dummy id on error + Ok(_) => f.id.clone(), + Err(_) => SelectedFileId(Uuid::new_v4().simple().to_string()) // Return a dummy id on error } } - BlobImpl::Memory(ref slice) => self.promote_to_file(slice), + BlobImpl::Memory(ref slice) => { + self.promote(slice, true) + } BlobImpl::Sliced(ref parent, ref rel_pos) => { match *parent.blob_impl.borrow() { BlobImpl::Sliced(_, _) => { debug!("Sliced can't have a sliced parent"); // Return dummy id - SelectedFileId("".to_string()) + SelectedFileId(Uuid::new_v4().simple().to_string()) } - BlobImpl::File(ref parent_id, _) => - self.create_sliced_url_id(parent_id, rel_pos), + BlobImpl::File(ref f) => + self.create_sliced_url_id(&f.id, rel_pos), BlobImpl::Memory(ref bytes) => { - let parent_id = parent.promote_to_file(bytes); + let parent_id = parent.promote(bytes, false); *self.blob_impl.borrow_mut() = BlobImpl::Sliced(parent.clone(), rel_pos.clone()); self.create_sliced_url_id(&parent_id, rel_pos) } @@ -189,25 +210,28 @@ impl Blob { } /// Promite memory-based Blob to file-based, - /// The bytes in data slice will be transferred to file manager thread - fn promote_to_file(&self, bytes: &[u8]) -> SelectedFileId { + /// The bytes in data slice will be transferred to file manager thread. + /// Depending on set_valid, the returned FileID can be part of + /// valid or invalid Blob URL. + fn promote(&self, bytes: &[u8], set_valid: bool) -> SelectedFileId { let global = self.global(); - let origin = global.r().get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&global.r().get_url()); let filemanager = global.r().resource_threads().sender(); - let entry = BlobURLStoreEntry { + let blob_buf = BlobBuf { + filename: None, type_string: self.typeString.clone(), size: self.Size(), bytes: bytes.to_vec(), }; let (tx, rx) = ipc::channel().unwrap(); - let _ = filemanager.send(FileManagerThreadMsg::PromoteMemory(entry, tx, origin.clone())); + let _ = filemanager.send(FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone())); match rx.recv().unwrap() { Ok(new_id) => SelectedFileId(new_id.0), // Dummy id - Err(_) => SelectedFileId("".to_string()), + Err(_) => SelectedFileId(Uuid::new_v4().simple().to_string()), } } @@ -216,7 +240,7 @@ impl Blob { rel_pos: &RelativePos) -> SelectedFileId { let global = self.global(); - let origin = global.r().get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&global.r().get_url()); let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); @@ -232,14 +256,14 @@ impl Blob { /// Cleanups at the time of destruction/closing fn clean_up_file_resource(&self) { - if let BlobImpl::File(ref id, _) = *self.blob_impl.borrow() { + if let BlobImpl::File(ref f) = *self.blob_impl.borrow() { let global = self.global(); - let origin = global.r().get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&global.r().get_url()); let filemanager = global.r().resource_threads().sender(); let (tx, rx) = ipc::channel().unwrap(); - let msg = FileManagerThreadMsg::DecRef(id.clone(), origin, tx); + let msg = FileManagerThreadMsg::DecRef(f.id.clone(), origin, tx); let _ = filemanager.send(msg); let _ = rx.recv().unwrap(); } @@ -257,19 +281,27 @@ impl Drop for Blob { fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<Vec<u8>, ()> { let file_manager = global.filemanager_thread(); let (chan, recv) = ipc::channel().map_err(|_|())?; - let origin = global.get_url().origin().unicode_serialization(); - let msg = FileManagerThreadMsg::ReadFile(chan, id, origin); + let origin = get_blob_origin(&global.get_url()); + let check_url_validity = false; + let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin); let _ = file_manager.send(msg); - let result = match recv.recv() { - Ok(ret) => ret, - Err(e) => { - debug!("File manager thread has problem {:?}", e); - return Err(()) - } - }; + let mut bytes = vec![]; - result.map_err(|_|()) + loop { + match recv.recv().unwrap() { + Ok(ReadFileProgress::Meta(mut blob_buf)) => { + bytes.append(&mut blob_buf.bytes); + } + Ok(ReadFileProgress::Partial(mut bytes_in)) => { + bytes.append(&mut bytes_in); + } + Ok(ReadFileProgress::EOF) => { + return Ok(bytes); + } + Err(_) => return Err(()), + } + } } /// Extract bytes from BlobParts, used by Blob and File constructor @@ -314,20 +346,8 @@ impl BlobMethods for Blob { end: Option<i64>, contentType: Option<DOMString>) -> Root<Blob> { - let relativeContentType = match contentType { - None => DOMString::new(), - Some(mut str) => { - if is_ascii_printable(&str) { - str.make_ascii_lowercase(); - str - } else { - DOMString::new() - } - } - }; - let rel_pos = RelativePos::from_opts(start, end); - Blob::new_sliced(self, rel_pos, relativeContentType) + Blob::new_sliced(self, rel_pos, contentType.unwrap_or(DOMString::from(""))) } // https://w3c.github.io/FileAPI/#dfn-isClosed @@ -350,15 +370,20 @@ impl BlobMethods for Blob { } } -impl BlobBinding::BlobPropertyBag { - /// Get the normalized inner type string - /// https://w3c.github.io/FileAPI/#dfn-type - pub fn get_typestring(&self) -> String { - if is_ascii_printable(&self.type_) { - self.type_.to_lowercase() - } else { - "".to_string() - } +/// Get the normalized, MIME-parsable type string +/// https://w3c.github.io/FileAPI/#dfn-type +/// XXX: We will relax the restriction here, +/// since the spec has some problem over this part. +/// see https://github.com/w3c/FileAPI/issues/43 +fn normalize_type_string(s: &str) -> String { + if is_ascii_printable(s) { + let s_lower = s.to_lowercase(); + // match s_lower.parse() as Result<Mime, ()> { + // Ok(_) => s_lower, + // Err(_) => "".to_string() + s_lower + } else { + "".to_string() } } @@ -371,7 +396,7 @@ fn is_ascii_printable(string: &str) -> bool { /// Bump the reference counter in file manager thread fn inc_ref_id(global: GlobalRef, id: SelectedFileId) { let file_manager = global.filemanager_thread(); - let origin = global.get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&global.get_url()); let msg = FileManagerThreadMsg::IncRef(id, origin); let _ = file_manager.send(msg); } diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs index 0fc9d7a41f2..e3e17b4a0f9 100644 --- a/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -76,7 +76,7 @@ impl BluetoothRemoteGATTCharacteristic { global_ref.as_window().bluetooth_thread() } - pub fn get_instance_id(&self) -> String { + fn get_instance_id(&self) -> String { self.instanceID.clone() } } diff --git a/components/script/dom/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetoothremotegattdescriptor.rs index 035233b01f7..f821d4aca2d 100644 --- a/components/script/dom/bluetoothremotegattdescriptor.rs +++ b/components/script/dom/bluetoothremotegattdescriptor.rs @@ -63,7 +63,7 @@ impl BluetoothRemoteGATTDescriptor { global_ref.as_window().bluetooth_thread() } - pub fn get_instance_id(&self) -> String { + fn get_instance_id(&self) -> String { self.instanceID.clone() } } diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs index cf0f896d3f6..f0954a1c76f 100644 --- a/components/script/dom/bluetoothremotegattservice.rs +++ b/components/script/dom/bluetoothremotegattservice.rs @@ -63,7 +63,7 @@ impl BluetoothRemoteGATTService { global_ref.as_window().bluetooth_thread() } - pub fn get_instance_id(&self) -> String { + fn get_instance_id(&self) -> String { self.instanceID.clone() } } diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 87ac897a4e4..d997a33ebd6 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -4,7 +4,7 @@ use devtools; use devtools_traits::DevtoolScriptControlMsg; -use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg, SharedRt , SimpleWorkerErrorHandler}; +use dom::abstractworker::{WorkerScriptMsg, SharedRt , SimpleWorkerErrorHandler}; use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding; @@ -21,7 +21,6 @@ use dom::bindings::structuredclone::StructuredCloneData; use dom::messageevent::MessageEvent; use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler}; use dom::workerglobalscope::WorkerGlobalScope; -use dom::workerglobalscope::WorkerGlobalScopeInit; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use js::jsapi::{HandleValue, JS_SetInterruptCallback}; @@ -29,17 +28,18 @@ use js::jsapi::{JSAutoCompartment, JSContext}; use js::jsval::UndefinedValue; use js::rust::Runtime; use msg::constellation_msg::PipelineId; -use net_traits::{LoadContext, load_whole_resource, CustomResponse, IpcSend}; +use net_traits::{LoadContext, load_whole_resource, IpcSend}; use rand::random; use script_runtime::ScriptThreadEventCategory::WorkerEvent; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; -use script_traits::{TimerEvent, TimerSource}; +use script_traits::{TimerEvent, TimerSource, WorkerScriptLoadOrigin, WorkerGlobalScopeInit}; use std::mem::replace; +use std::sync::atomic::AtomicBool; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; use std::sync::{Arc, Mutex}; use url::Url; -use util::thread::spawn_named_with_send_on_panic; -use util::thread_state::{IN_WORKER, SCRIPT}; +use util::thread::spawn_named; +use util::thread_state; /// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular /// value for the duration of this object's lifetime. This ensures that the related Worker @@ -70,8 +70,7 @@ impl<'a> Drop for AutoWorkerReset<'a> { enum MixedMessage { FromWorker((TrustedWorkerAddress, WorkerScriptMsg)), FromScheduler((TrustedWorkerAddress, TimerEvent)), - FromDevtools(DevtoolScriptControlMsg), - FromNetwork(IpcSender<Option<CustomResponse>>), + FromDevtools(DevtoolScriptControlMsg) } // https://html.spec.whatwg.org/multipage/#dedicatedworkerglobalscope @@ -102,14 +101,16 @@ impl DedicatedWorkerGlobalScope { own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>, timer_event_chan: IpcSender<TimerEvent>, - timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>) + timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>, + closing: Arc<AtomicBool>) -> DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited(init, worker_url, runtime, from_devtools_receiver, - timer_event_chan), + timer_event_chan, + Some(closing)), id: id, receiver: receiver, own_sender: own_sender, @@ -128,7 +129,8 @@ impl DedicatedWorkerGlobalScope { own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>, timer_event_chan: IpcSender<TimerEvent>, - timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>) + timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>, + closing: Arc<AtomicBool>) -> Root<DedicatedWorkerGlobalScope> { let cx = runtime.cx(); let scope = box DedicatedWorkerGlobalScope::new_inherited(init, @@ -140,7 +142,8 @@ impl DedicatedWorkerGlobalScope { own_sender, receiver, timer_event_chan, - timer_event_port); + timer_event_port, + closing); DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope) } @@ -154,11 +157,14 @@ impl DedicatedWorkerGlobalScope { parent_sender: Box<ScriptChan + Send>, own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>, - worker_load_origin: WorkerScriptLoadOrigin) { + worker_load_origin: WorkerScriptLoadOrigin, + closing: Arc<AtomicBool>) { let serialized_worker_url = worker_url.to_string(); let name = format!("WebWorker for {}", serialized_worker_url); - let panic_chan = init.panic_chan.clone(); - spawn_named_with_send_on_panic(name, SCRIPT | IN_WORKER, move || { + spawn_named(name, move || { + thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER); + PipelineId::install(id); + let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); let (url, source) = match load_whole_resource(LoadContext::Script, @@ -193,7 +199,7 @@ impl DedicatedWorkerGlobalScope { let global = DedicatedWorkerGlobalScope::new( init, url, id, devtools_mpsc_port, runtime, parent_sender.clone(), own_sender, receiver, - timer_ipc_chan, timer_rx); + timer_ipc_chan, timer_rx, closing); // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // registration (#6631), so we instead use a random number and cross our fingers. let scope = global.upcast::<WorkerGlobalScope>(); @@ -221,7 +227,7 @@ impl DedicatedWorkerGlobalScope { global.handle_event(event); } }, reporter_name, parent_sender, CommonScriptMsg::CollectReports); - }, Some(id.clone()), panic_chan); + }); } pub fn script_chan(&self) -> Box<ScriptChan + Send> { @@ -254,20 +260,17 @@ impl DedicatedWorkerGlobalScope { let worker_port = &self.receiver; let timer_event_port = &self.timer_event_port; let devtools_port = scope.from_devtools_receiver(); - let msg_port = scope.custom_message_port(); let sel = Select::new(); let mut worker_handle = sel.handle(worker_port); let mut timer_event_handle = sel.handle(timer_event_port); let mut devtools_handle = sel.handle(devtools_port); - let mut msg_port_handle = sel.handle(msg_port); unsafe { worker_handle.add(); timer_event_handle.add(); if scope.from_devtools_sender().is_some() { devtools_handle.add(); } - msg_port_handle.add(); } let ret = sel.wait(); if ret == worker_handle.id() { @@ -276,8 +279,6 @@ impl DedicatedWorkerGlobalScope { Ok(MixedMessage::FromScheduler(try!(timer_event_port.recv()))) } else if ret == devtools_handle.id() { Ok(MixedMessage::FromDevtools(try!(devtools_port.recv()))) - } else if ret == msg_port_handle.id() { - Ok(MixedMessage::FromNetwork(try!(msg_port.recv()))) } else { panic!("unexpected select result!") } @@ -306,7 +307,7 @@ impl DedicatedWorkerGlobalScope { let path_seg = format!("url({})", scope.get_url()); let reports = get_reports(cx, path_seg); reports_chan.send(reports); - }, + } } } @@ -339,10 +340,6 @@ impl DedicatedWorkerGlobalScope { MixedMessage::FromWorker((linked_worker, msg)) => { let _ar = AutoWorkerReset::new(self, linked_worker); self.handle_script_event(msg); - }, - MixedMessage::FromNetwork(network_sender) => { - // We send None as of now - let _ = network_sender.send(None); } } } @@ -373,6 +370,12 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope { Ok(()) } + // https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-close + fn Close(&self) { + // Step 2 + self.upcast::<WorkerGlobalScope>().close(); + } + // https://html.spec.whatwg.org/multipage/#handler-dedicatedworkerglobalscope-onmessage event_handler!(message, GetOnmessage, SetOnmessage); } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 669c4d9a31a..78ccbbdf1f5 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -122,9 +122,9 @@ use std::sync::Arc; use string_cache::{Atom, QualName}; use style::attr::AttrValue; use style::context::ReflowGoal; -use style::restyle_hints::ElementSnapshot; -use style::servo::Stylesheet; +use style::selector_impl::ElementSnapshot; use style::str::{split_html_space_chars, str_join}; +use style::stylesheets::Stylesheet; use time; use url::Url; use url::percent_encoding::percent_decode; @@ -239,6 +239,8 @@ pub struct Document { origin: Origin, /// https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states referrer_policy: Cell<Option<ReferrerPolicy>>, + /// https://html.spec.whatwg.org/multipage/#dom-document-referrer + referrer: Option<String>, } #[derive(JSTraceable, HeapSizeOf)] @@ -374,6 +376,7 @@ impl Document { // that workable. match self.GetDocumentElement() { Some(root) => { + root.upcast::<Node>().is_dirty() || root.upcast::<Node>().has_dirty_descendants() || !self.modified_elements.borrow().is_empty() } @@ -1279,7 +1282,7 @@ impl Document { if PREFS.is_mozbrowser_enabled() { if let Some((containing_pipeline_id, subpage_id, _)) = self.window.parent_info() { let event = ConstellationMsg::MozBrowserEvent(containing_pipeline_id, - subpage_id, + Some(subpage_id), event); self.window.constellation_chan().send(event).unwrap(); } @@ -1369,6 +1372,7 @@ impl Document { } pub fn finish_load(&self, load: LoadType) { + debug!("Document got finish_load: {:?}", load); // The parser might need the loader, so restrict the lifetime of the borrow. { let mut loader = self.loader.borrow_mut(); @@ -1394,9 +1398,9 @@ impl Document { // If we don't have a parser, and the reflow timer has been reset, explicitly // trigger a reflow. if let LoadType::Stylesheet(_) = load { - self.window().reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::StylesheetLoaded); + self.window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::StylesheetLoaded); } } @@ -1485,23 +1489,25 @@ impl Document { return; } self.domcontentloaded_dispatched.set(true); + assert!(self.ReadyState() != DocumentReadyState::Complete, + "Complete before DOMContentLoaded?"); update_with_current_time_ms(&self.dom_content_loaded_event_start); - self.window().dom_manipulation_task_source().queue_event(self.upcast(), atom!("DOMContentLoaded"), - EventBubbles::Bubbles, EventCancelable::NotCancelable); - self.window().reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::DOMContentLoaded); + let window = self.window(); + window.dom_manipulation_task_source().queue_event(self.upcast(), atom!("DOMContentLoaded"), + EventBubbles::Bubbles, EventCancelable::NotCancelable, window); + window.reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::DOMContentLoaded); update_with_current_time_ms(&self.dom_content_loaded_event_end); } pub fn notify_constellation_load(&self) { let pipeline_id = self.window.pipeline(); - let event = ConstellationMsg::DOMLoad(pipeline_id); - self.window.constellation_chan().send(event).unwrap(); - + let load_event = ConstellationMsg::LoadComplete(pipeline_id); + self.window.constellation_chan().send(load_event).unwrap(); } pub fn set_current_parser(&self, script: Option<ParserRef>) { @@ -1629,7 +1635,9 @@ impl Document { content_type: Option<DOMString>, last_modified: Option<String>, source: DocumentSource, - doc_loader: DocumentLoader) + doc_loader: DocumentLoader, + referrer: Option<String>, + referrer_policy: Option<ReferrerPolicy>) -> Document { let url = url.unwrap_or_else(|| Url::parse("about:blank").unwrap()); @@ -1648,6 +1656,17 @@ impl Document { Origin::opaque_identifier() }; + // TODO: we currently default to Some(NoReferrer) instead of None (i.e. unset) + // for an important reason. Many of the methods by which a referrer policy is communicated + // are currently unimplemented, and so in such cases we may be ignoring the desired policy. + // If the default were left unset, then in Step 7 of the Fetch algorithm we adopt + // no-referrer-when-downgrade. However, since we are potentially ignoring a stricter + // referrer policy, this might be passing too much info. Hence, we default to the + // strictest policy, which is no-referrer. + // Once other delivery methods are implemented, make the unset case really + // unset (i.e. None). + let referrer_policy = referrer_policy.or(Some(ReferrerPolicy::NoReferrer)); + Document { node: Node::new_document_node(), window: JS::from_ref(window), @@ -1714,8 +1733,8 @@ impl Document { https_state: Cell::new(HttpsState::None), touchpad_pressure_phase: Cell::new(TouchpadPressurePhase::BeforeClick), origin: origin, - //TODO - setting this for now so no Referer header set - referrer_policy: Cell::new(Some(ReferrerPolicy::NoReferrer)), + referrer: referrer, + referrer_policy: Cell::new(referrer_policy), } } @@ -1732,7 +1751,9 @@ impl Document { None, None, DocumentSource::NotFromParser, - docloader)) + docloader, + None, + None)) } pub fn new(window: &Window, @@ -1742,7 +1763,9 @@ impl Document { content_type: Option<DOMString>, last_modified: Option<String>, source: DocumentSource, - doc_loader: DocumentLoader) + doc_loader: DocumentLoader, + referrer: Option<String>, + referrer_policy: Option<ReferrerPolicy>) -> Root<Document> { let document = reflect_dom_object(box Document::new_inherited(window, browsing_context, @@ -1751,7 +1774,9 @@ impl Document { content_type, last_modified, source, - doc_loader), + doc_loader, + referrer, + referrer_policy), GlobalRef::Window(window), DocumentBinding::Wrap); { @@ -1815,7 +1840,9 @@ impl Document { None, None, DocumentSource::NotFromParser, - DocumentLoader::new(&self.loader())); + DocumentLoader::new(&self.loader()), + None, + None); new_doc.appropriate_template_contents_owner_document.set(Some(&new_doc)); new_doc }) @@ -1827,7 +1854,10 @@ impl Document { pub fn element_state_will_change(&self, el: &Element) { let mut map = self.modified_elements.borrow_mut(); - let snapshot = map.entry(JS::from_ref(el)).or_insert(ElementSnapshot::new()); + let snapshot = map.entry(JS::from_ref(el)) + .or_insert_with(|| { + ElementSnapshot::new(el.html_element_in_html_document()) + }); if snapshot.state.is_none() { snapshot.state = Some(el.state()); } @@ -1835,7 +1865,10 @@ impl Document { pub fn element_attr_will_change(&self, el: &Element) { let mut map = self.modified_elements.borrow_mut(); - let mut snapshot = map.entry(JS::from_ref(el)).or_insert(ElementSnapshot::new()); + let mut snapshot = map.entry(JS::from_ref(el)) + .or_insert_with(|| { + ElementSnapshot::new(el.html_element_in_html_document()) + }); if snapshot.attrs.is_none() { let attrs = el.attrs() .iter() @@ -1934,6 +1967,14 @@ impl DocumentMethods for Document { } } + // https://html.spec.whatwg.org/multipage/#dom-document-referrer + fn Referrer(&self) -> DOMString { + match self.referrer { + Some(ref referrer) => DOMString::from(referrer.to_string()), + None => DOMString::new() + } + } + // https://dom.spec.whatwg.org/#dom-document-documenturi fn DocumentURI(&self) -> USVString { self.URL() @@ -2831,7 +2872,7 @@ pub fn determine_policy_for_token(token: &str) -> Option<ReferrerPolicy> { let lower = token.to_lowercase(); return match lower.as_ref() { "never" | "no-referrer" => Some(ReferrerPolicy::NoReferrer), - "default" | "no-referrer-when-downgrade" => Some(ReferrerPolicy::NoRefWhenDowngrade), + "default" | "no-referrer-when-downgrade" => Some(ReferrerPolicy::NoReferrerWhenDowngrade), "origin" => Some(ReferrerPolicy::Origin), "same-origin" => Some(ReferrerPolicy::SameOrigin), "origin-when-cross-origin" => Some(ReferrerPolicy::OriginWhenCrossOrigin), @@ -2870,16 +2911,18 @@ impl DocumentProgressHandler { // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart update_with_current_time_ms(&document.load_event_start); + debug!("About to dispatch load for {:?}", document.url()); let _ = wintarget.dispatch_event_with_target(document.upcast(), &event); // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd update_with_current_time_ms(&document.load_event_end); - document.notify_constellation_load(); window.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DocumentLoaded); + + document.notify_constellation_load(); } } diff --git a/components/script/dom/documenttype.rs b/components/script/dom/documenttype.rs index 0f8b688c93b..c48805eed79 100644 --- a/components/script/dom/documenttype.rs +++ b/components/script/dom/documenttype.rs @@ -41,8 +41,9 @@ impl DocumentType { system_id: Option<DOMString>, document: &Document) -> Root<DocumentType> { - let documenttype = DocumentType::new_inherited(name, public_id, system_id, document); - Node::reflect_node(box documenttype, document, DocumentTypeBinding::Wrap) + Node::reflect_node(box DocumentType::new_inherited(name, public_id, system_id, document), + document, + DocumentTypeBinding::Wrap) } #[inline] diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs index 30974ea2f46..824cc0b88cf 100644 --- a/components/script/dom/domimplementation.rs +++ b/components/script/dom/domimplementation.rs @@ -129,7 +129,9 @@ impl DOMImplementationMethods for DOMImplementation { None, None, DocumentSource::NotFromParser, - loader); + loader, + None, + None); { // Step 3. diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs index 346b8f80170..3964c84abcb 100644 --- a/components/script/dom/domparser.rs +++ b/components/script/dom/domparser.rs @@ -68,7 +68,9 @@ impl DOMParserMethods for DOMParser { Some(content_type), None, DocumentSource::FromParser, - loader); + loader, + None, + None); parse_html(document.r(), s, url, ParseContext::Owner(None)); document.set_ready_state(DocumentReadyState::Complete); Ok(document) @@ -82,7 +84,9 @@ impl DOMParserMethods for DOMParser { Some(content_type), None, DocumentSource::NotFromParser, - loader); + loader, + None, + None); parse_xml(document.r(), s, url, xml::ParseContext::Owner(None)); Ok(document) } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 6b671d6fe6b..a4c1ed28583 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -78,6 +78,7 @@ use selectors::parser::{AttrSelector, NamespaceConstraint, parse_author_origin_s use std::ascii::AsciiExt; use std::borrow::Cow; use std::cell::{Cell, Ref}; +use std::convert::TryFrom; use std::default::Default; use std::mem; use std::sync::Arc; @@ -126,8 +127,10 @@ pub enum AdjacentPosition { BeforeEnd, } -impl AdjacentPosition { - pub fn parse(position: &str) -> Fallible<AdjacentPosition> { +impl<'a> TryFrom<&'a str> for AdjacentPosition { + type Err = Error; + + fn try_from(position: &'a str) -> Result<AdjacentPosition, Self::Err> { match_ignore_ascii_case! { &*position, "beforebegin" => Ok(AdjacentPosition::BeforeBegin), "afterbegin" => Ok(AdjacentPosition::AfterBegin), @@ -2028,7 +2031,7 @@ impl ElementMethods for Element { // https://dom.spec.whatwg.org/#dom-element-insertadjacentelement fn InsertAdjacentElement(&self, where_: DOMString, element: &Element) -> Fallible<Option<Root<Element>>> { - let where_ = try!(AdjacentPosition::parse(&*where_)); + let where_ = try!(AdjacentPosition::try_from(&*where_)); let inserted_node = try!(self.insert_adjacent(where_, element.upcast())); Ok(inserted_node.map(|node| Root::downcast(node).unwrap())) } @@ -2040,7 +2043,7 @@ impl ElementMethods for Element { let text = Text::new(data, &document_from_node(self)); // Step 2. - let where_ = try!(AdjacentPosition::parse(&*where_)); + let where_ = try!(AdjacentPosition::try_from(&*where_)); self.insert_adjacent(where_, text.upcast()).map(|_| ()) } @@ -2048,7 +2051,7 @@ impl ElementMethods for Element { fn InsertAdjacentHTML(&self, position: DOMString, text: DOMString) -> ErrorResult { // Step 1. - let position = try!(AdjacentPosition::parse(&*position)); + let position = try!(AdjacentPosition::try_from(&*position)); let context = match position { AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => { diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs index 9174fa2cb3d..da7664e0e19 100644 --- a/components/script/dom/event.rs +++ b/components/script/dom/event.rs @@ -8,9 +8,11 @@ use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethod use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutNullableHeap, Root}; +use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::eventtarget::EventTarget; +use script_thread::Runnable; use std::cell::Cell; use std::default::Default; use string_cache::Atom; @@ -26,7 +28,7 @@ pub enum EventPhase { Bubbling = EventConstants::BUBBLING_PHASE, } -#[derive(PartialEq, HeapSizeOf)] +#[derive(PartialEq, HeapSizeOf, Copy, Clone)] pub enum EventBubbles { Bubbles, DoesNotBubble @@ -50,7 +52,7 @@ impl From<bool> for EventBubbles { } } -#[derive(PartialEq, HeapSizeOf)] +#[derive(PartialEq, HeapSizeOf, Copy, Clone)] pub enum EventCancelable { Cancelable, NotCancelable @@ -297,3 +299,35 @@ impl Event { target.dispatch_event(self) } } + +// https://dom.spec.whatwg.org/#concept-event-fire +pub struct EventRunnable { + pub target: Trusted<EventTarget>, + pub name: Atom, + pub bubbles: EventBubbles, + pub cancelable: EventCancelable, +} + +impl Runnable for EventRunnable { + fn name(&self) -> &'static str { "EventRunnable" } + + fn handler(self: Box<EventRunnable>) { + let target = self.target.root(); + target.fire_event(&*self.name, self.bubbles, self.cancelable); + } +} + +// https://html.spec.whatwg.org/multipage/#fire-a-simple-event +pub struct SimpleEventRunnable { + pub target: Trusted<EventTarget>, + pub name: Atom, +} + +impl Runnable for SimpleEventRunnable { + fn name(&self) -> &'static str { "SimpleEventRunnable" } + + fn handler(self: Box<SimpleEventRunnable>) { + let target = self.target.root(); + target.fire_simple_event(&*self.name); + } +} diff --git a/components/script/dom/file.rs b/components/script/dom/file.rs index 75f73aeda59..f9b181dbf1a 100644 --- a/components/script/dom/file.rs +++ b/components/script/dom/file.rs @@ -54,7 +54,8 @@ impl File { let global = GlobalRef::Window(window); - File::new(global, BlobImpl::new_from_file(selected.id), name, Some(selected.modified as i64), "") + File::new(global, BlobImpl::new_from_file(selected.id, selected.filename, selected.size), + name, Some(selected.modified as i64), &selected.type_string) } // https://w3c.github.io/FileAPI/#file-constructor @@ -69,10 +70,13 @@ impl File { }; let ref blobPropertyBag = filePropertyBag.parent; - let typeString = blobPropertyBag.get_typestring(); + let ref typeString = blobPropertyBag.type_; let modified = filePropertyBag.lastModified; - Ok(File::new(global, BlobImpl::new_from_bytes(bytes), filename, modified, &typeString)) + // NOTE: Following behaviour might be removed in future, + // see https://github.com/w3c/FileAPI/issues/41 + let replaced_filename = DOMString::from_string(filename.replace("/", ":")); + Ok(File::new(global, BlobImpl::new_from_bytes(bytes), replaced_filename, modified, typeString)) } pub fn name(&self) -> &DOMString { diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index be57d67f7c0..a82e4dc47bc 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -23,12 +23,12 @@ use encoding::label::encoding_from_whatwg_label; use encoding::types::{DecoderTrap, EncodingRef}; use hyper::mime::{Attr, Mime}; use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64}; -use script_runtime::ScriptThreadEventCategory::FileRead; -use script_runtime::{ScriptChan, CommonScriptMsg}; -use script_thread::Runnable; +use script_thread::RunnableWrapper; use std::cell::Cell; use std::sync::Arc; use string_cache::Atom; +use task_source::TaskSource; +use task_source::file_reading::{FileReadingTaskSource, FileReadingRunnable, FileReadingTask}; use util::thread::spawn_named; #[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)] @@ -358,10 +358,11 @@ impl FileReader { let fr = Trusted::new(self); let gen_id = self.generation_id.get(); - let script_chan = self.global().r().file_reading_task_source(); + let wrapper = self.global().r().get_runnable_wrapper(); + let task_source = self.global().r().file_reading_task_source(); spawn_named("file reader async operation".to_owned(), move || { - perform_annotated_read_operation(gen_id, load_data, blob_contents, fr, script_chan) + perform_annotated_read_operation(gen_id, load_data, blob_contents, fr, task_source, wrapper) }); Ok(()) } @@ -371,47 +372,20 @@ impl FileReader { } } -#[derive(Clone)] -pub enum FileReaderEvent { - ProcessRead(TrustedFileReader, GenerationId), - ProcessReadData(TrustedFileReader, GenerationId), - ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName), - ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Arc<Vec<u8>>) -} - -impl Runnable for FileReaderEvent { - fn name(&self) -> &'static str { "FileReaderEvent" } - - fn handler(self: Box<FileReaderEvent>) { - let file_reader_event = *self; - match file_reader_event { - FileReaderEvent::ProcessRead(filereader, gen_id) => { - FileReader::process_read(filereader, gen_id); - }, - FileReaderEvent::ProcessReadData(filereader, gen_id) => { - FileReader::process_read_data(filereader, gen_id); - }, - FileReaderEvent::ProcessReadError(filereader, gen_id, error) => { - FileReader::process_read_error(filereader, gen_id, error); - }, - FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents) => { - FileReader::process_read_eof(filereader, gen_id, data, blob_contents); - } - } - } -} - // https://w3c.github.io/FileAPI/#thread-read-operation -fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Arc<Vec<u8>>, - filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) { - let chan = &script_chan; +fn perform_annotated_read_operation(gen_id: GenerationId, + data: ReadMetaData, + blob_contents: Arc<Vec<u8>>, + filereader: TrustedFileReader, + task_source: FileReadingTaskSource, + wrapper: RunnableWrapper) { // Step 4 - let thread = box FileReaderEvent::ProcessRead(filereader.clone(), gen_id); - chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap(); + let task = FileReadingRunnable::new(FileReadingTask::ProcessRead(filereader.clone(), gen_id)); + task_source.queue_with_wrapper(task, &wrapper).unwrap(); - let thread = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id); - chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap(); + let task = FileReadingRunnable::new(FileReadingTask::ProcessReadData(filereader.clone(), gen_id)); + task_source.queue_with_wrapper(task, &wrapper).unwrap(); - let thread = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents); - chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap(); + let task = FileReadingRunnable::new(FileReadingTask::ProcessReadEOF(filereader, gen_id, data, blob_contents)); + task_source.queue_with_wrapper(task, &wrapper).unwrap(); } diff --git a/components/script/dom/headers.rs b/components/script/dom/headers.rs new file mode 100644 index 00000000000..e97edc00572 --- /dev/null +++ b/components/script/dom/headers.rs @@ -0,0 +1,251 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::HeadersBinding; +use dom::bindings::codegen::Bindings::HeadersBinding::HeadersMethods; +use dom::bindings::error::Error; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::Root; +use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::str::{ByteString, is_token}; +use hyper; +use std::result::Result; + +#[dom_struct] +pub struct Headers { + reflector_: Reflector, + guard: Guard, + #[ignore_heap_size_of = "Defined in hyper"] + header_list: DOMRefCell<hyper::header::Headers> +} + +// https://fetch.spec.whatwg.org/#concept-headers-guard +#[derive(JSTraceable, HeapSizeOf, PartialEq)] +pub enum Guard { + Immutable, + Request, + RequestNoCors, + Response, + None, +} + +impl Headers { + pub fn new_inherited() -> Headers { + Headers { + reflector_: Reflector::new(), + guard: Guard::None, + header_list: DOMRefCell::new(hyper::header::Headers::new()), + } + } + + pub fn new(global: GlobalRef) -> Root<Headers> { + reflect_dom_object(box Headers::new_inherited(), global, HeadersBinding::Wrap) + } +} + +impl HeadersMethods for Headers { + // https://fetch.spec.whatwg.org/#concept-headers-append + fn Append(&self, name: ByteString, value: ByteString) -> Result<(), Error> { + // Step 1 + let value = normalize_value(value); + + // Step 2 + let (valid_name, valid_value) = try!(validate_name_and_value(name, value)); + // Step 3 + if self.guard == Guard::Immutable { + return Err(Error::Type("Guard is immutable".to_string())); + } + + // Step 4 + if self.guard == Guard::Request && is_forbidden_header_name(&valid_name) { + return Ok(()); + } + + // Step 5 + if self.guard == Guard::RequestNoCors && !is_cors_safelisted_request_header(&valid_name) { + return Ok(()); + } + + // Step 6 + if self.guard == Guard::Response && is_forbidden_response_header(&valid_name) { + return Ok(()); + } + + // Step 7 + self.header_list.borrow_mut().set_raw(valid_name, vec![valid_value]); + return Ok(()); + } +} + +// TODO +// "Content-Type" once parsed, the value should be +// `application/x-www-form-urlencoded`, `multipart/form-data`, +// or `text/plain`. +// "DPR", "Downlink", "Save-Data", "Viewport-Width", "Width": +// once parsed, the value should not be failure. +// https://fetch.spec.whatwg.org/#cors-safelisted-request-header +fn is_cors_safelisted_request_header(name: &str) -> bool { + match name { + "accept" | + "accept-language" | + "content-language" => true, + _ => false, + } +} + +// https://fetch.spec.whatwg.org/#forbidden-response-header-name +fn is_forbidden_response_header(name: &str) -> bool { + match name { + "set-cookie" | + "set-cookie2" => true, + _ => false, + } +} + +// https://fetch.spec.whatwg.org/#forbidden-header-name +pub fn is_forbidden_header_name(name: &str) -> bool { + let disallowed_headers = + ["accept-charset", "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", "content-length", + "cookie", "cookie2", "date", "dnt", + "expect", "host", "keep-alive", "origin", + "referer", "te", "trailer", "transfer-encoding", + "upgrade", "via"]; + + let disallowed_header_prefixes = ["sec-", "proxy-"]; + + disallowed_headers.iter().any(|header| *header == name) || + disallowed_header_prefixes.iter().any(|prefix| name.starts_with(prefix)) +} + +// There is some unresolved confusion over the definition of a name and a value. +// The fetch spec [1] defines a name as "a case-insensitive byte +// sequence that matches the field-name token production. The token +// productions are viewable in [2]." A field-name is defined as a +// token, which is defined in [3]. +// ISSUE 1: +// It defines a value as "a byte sequence that matches the field-content token production." +// To note, there is a difference between field-content and +// field-value (which is made up of fied-content and obs-fold). The +// current definition does not allow for obs-fold (which are white +// space and newlines) in values. So perhaps a value should be defined +// as "a byte sequence that matches the field-value token production." +// However, this would then allow values made up entirely of white space and newlines. +// RELATED ISSUE 2: +// According to a previously filed Errata ID: 4189 in [4], "the +// specified field-value rule does not allow single field-vchar +// surrounded by whitespace anywhere". They provided a fix for the +// field-content production, but ISSUE 1 has still not been resolved. +// The production definitions likely need to be re-written. +// [1] https://fetch.spec.whatwg.org/#concept-header-value +// [2] https://tools.ietf.org/html/rfc7230#section-3.2 +// [3] https://tools.ietf.org/html/rfc7230#section-3.2.6 +// [4] https://www.rfc-editor.org/errata_search.php?rfc=7230 +fn validate_name_and_value(name: ByteString, value: ByteString) + -> Result<(String, Vec<u8>), Error> { + if !is_field_name(&name) { + return Err(Error::Type("Name is not valid".to_string())); + } + if !is_field_content(&value) { + return Err(Error::Type("Value is not valid".to_string())); + } + match String::from_utf8(name.into()) { + Ok(ns) => Ok((ns, value.into())), + _ => Err(Error::Type("Non-UTF8 header name found".to_string())), + } +} + +// Removes trailing and leading HTTP whitespace bytes. +// https://fetch.spec.whatwg.org/#concept-header-value-normalize +pub fn normalize_value(value: ByteString) -> ByteString { + match (index_of_first_non_whitespace(&value), index_of_last_non_whitespace(&value)) { + (Some(begin), Some(end)) => ByteString::new(value[begin..end + 1].to_owned()), + _ => ByteString::new(vec![]), + } +} + +fn is_HTTP_whitespace(byte: u8) -> bool { + byte == b'\t' || byte == b'\n' || byte == b'\r' || byte == b' ' +} + +fn index_of_first_non_whitespace(value: &ByteString) -> Option<usize> { + for (index, &byte) in value.iter().enumerate() { + if !is_HTTP_whitespace(byte) { + return Some(index); + } + } + None +} + +fn index_of_last_non_whitespace(value: &ByteString) -> Option<usize> { + for (index, &byte) in value.iter().enumerate().rev() { + if !is_HTTP_whitespace(byte) { + return Some(index); + } + } + None +} + +// http://tools.ietf.org/html/rfc7230#section-3.2 +fn is_field_name(name: &ByteString) -> bool { + is_token(&*name) +} + +// https://tools.ietf.org/html/rfc7230#section-3.2 +// http://www.rfc-editor.org/errata_search.php?rfc=7230 +// Errata ID: 4189 +// field-content = field-vchar [ 1*( SP / HTAB / field-vchar ) +// field-vchar ] +fn is_field_content(value: &ByteString) -> bool { + if value.len() == 0 { + return false; + } + if !is_field_vchar(value[0]) { + return false; + } + + for &ch in &value[1..value.len() - 1] { + if !is_field_vchar(ch) || !is_space(ch) || !is_htab(ch) { + return false; + } + } + + if !is_field_vchar(value[value.len() - 1]) { + return false; + } + + return true; +} + +fn is_space(x: u8) -> bool { + x == b' ' +} + +fn is_htab(x: u8) -> bool { + x == b'\t' +} + +// https://tools.ietf.org/html/rfc7230#section-3.2 +fn is_field_vchar(x: u8) -> bool { + is_vchar(x) || is_obs_text(x) +} + +// https://tools.ietf.org/html/rfc5234#appendix-B.1 +fn is_vchar(x: u8) -> bool { + match x { + 0x21...0x7E => true, + _ => false, + } +} + +// http://tools.ietf.org/html/rfc7230#section-3.2.6 +fn is_obs_text(x: u8) -> bool { + match x { + 0x80...0xFF => true, + _ => false, + } +} diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs new file mode 100644 index 00000000000..061d7616f4a --- /dev/null +++ b/components/script/dom/history.rs @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::HistoryBinding; +use dom::bindings::codegen::Bindings::HistoryBinding::HistoryMethods; +use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{JS, Root}; +use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::window::Window; +use msg::constellation_msg::TraversalDirection; +use script_traits::ScriptMsg as ConstellationMsg; + +// https://html.spec.whatwg.org/multipage/#the-history-interface +#[dom_struct] +pub struct History { + reflector_: Reflector, + window: JS<Window>, +} + +impl History { + pub fn new_inherited(window: &Window) -> History { + History { + reflector_: Reflector::new(), + window: JS::from_ref(&window), + } + } + + pub fn new(window: &Window) -> Root<History> { + reflect_dom_object(box History::new_inherited(window), + GlobalRef::Window(window), + HistoryBinding::Wrap) + } +} + +impl History { + fn traverse_history(&self, direction: TraversalDirection) { + let pipeline = self.window.pipeline(); + let msg = ConstellationMsg::TraverseHistory(Some(pipeline), direction); + let _ = self.window.constellation_chan().send(msg); + } +} + +impl HistoryMethods for History { + // https://html.spec.whatwg.org/multipage/#dom-history-go + fn Go(&self, delta: i32) { + let direction = if delta > 0 { + TraversalDirection::Forward(delta as usize) + } else if delta < 0 { + TraversalDirection::Back(-delta as usize) + } else { + self.window.Location().Reload(); + return; + }; + + self.traverse_history(direction); + } + + // https://html.spec.whatwg.org/multipage/#dom-history-back + fn Back(&self) { + self.traverse_history(TraversalDirection::Back(1)); + } + + // https://html.spec.whatwg.org/multipage/#dom-history-forward + fn Forward(&self) { + self.traverse_history(TraversalDirection::Forward(1)); + } +} diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs index 713aa0a92cb..e9df2b6c999 100644 --- a/components/script/dom/htmlanchorelement.rs +++ b/components/script/dom/htmlanchorelement.rs @@ -54,8 +54,9 @@ impl HTMLAnchorElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLAnchorElement> { - let element = HTMLAnchorElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLAnchorElementBinding::Wrap) + Node::reflect_node(box HTMLAnchorElement::new_inherited(localName, prefix, document), + document, + HTMLAnchorElementBinding::Wrap) } // https://html.spec.whatwg.org/multipage/#concept-hyperlink-url-set diff --git a/components/script/dom/htmlappletelement.rs b/components/script/dom/htmlappletelement.rs index 16d7e46b10e..f61a6499ea1 100644 --- a/components/script/dom/htmlappletelement.rs +++ b/components/script/dom/htmlappletelement.rs @@ -33,8 +33,9 @@ impl HTMLAppletElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLAppletElement> { - let element = HTMLAppletElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLAppletElementBinding::Wrap) + Node::reflect_node(box HTMLAppletElement::new_inherited(localName, prefix, document), + document, + HTMLAppletElementBinding::Wrap) } } diff --git a/components/script/dom/htmlareaelement.rs b/components/script/dom/htmlareaelement.rs index 7998333810e..511308dd8fc 100644 --- a/components/script/dom/htmlareaelement.rs +++ b/components/script/dom/htmlareaelement.rs @@ -34,8 +34,9 @@ impl HTMLAreaElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLAreaElement> { - let element = HTMLAreaElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLAreaElementBinding::Wrap) + Node::reflect_node(box HTMLAreaElement::new_inherited(localName, prefix, document), + document, + HTMLAreaElementBinding::Wrap) } } diff --git a/components/script/dom/htmlaudioelement.rs b/components/script/dom/htmlaudioelement.rs index 4db6b013116..ad3062a1077 100644 --- a/components/script/dom/htmlaudioelement.rs +++ b/components/script/dom/htmlaudioelement.rs @@ -29,7 +29,8 @@ impl HTMLAudioElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLAudioElement> { - let element = HTMLAudioElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLAudioElementBinding::Wrap) + Node::reflect_node(box HTMLAudioElement::new_inherited(localName, prefix, document), + document, + HTMLAudioElementBinding::Wrap) } } diff --git a/components/script/dom/htmlbaseelement.rs b/components/script/dom/htmlbaseelement.rs index e0c38b1ab41..9175cc77872 100644 --- a/components/script/dom/htmlbaseelement.rs +++ b/components/script/dom/htmlbaseelement.rs @@ -33,8 +33,9 @@ impl HTMLBaseElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLBaseElement> { - let element = HTMLBaseElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLBaseElementBinding::Wrap) + Node::reflect_node(box HTMLBaseElement::new_inherited(localName, prefix, document), + document, + HTMLBaseElementBinding::Wrap) } /// https://html.spec.whatwg.org/multipage/#frozen-base-url diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index 79dbd1438e4..c8007c39ea8 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -42,8 +42,9 @@ impl HTMLBodyElement { #[allow(unrooted_must_root)] pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLBodyElement> { - let element = HTMLBodyElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap) + Node::reflect_node(box HTMLBodyElement::new_inherited(localName, prefix, document), + document, + HTMLBodyElementBinding::Wrap) } /// https://drafts.csswg.org/cssom-view/#the-html-body-element diff --git a/components/script/dom/htmlbrelement.rs b/components/script/dom/htmlbrelement.rs index e95a667c0c4..b2d0067c3f6 100644 --- a/components/script/dom/htmlbrelement.rs +++ b/components/script/dom/htmlbrelement.rs @@ -26,7 +26,8 @@ impl HTMLBRElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLBRElement> { - let element = HTMLBRElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLBRElementBinding::Wrap) + Node::reflect_node(box HTMLBRElement::new_inherited(localName, prefix, document), + document, + HTMLBRElementBinding::Wrap) } } diff --git a/components/script/dom/htmlbuttonelement.rs b/components/script/dom/htmlbuttonelement.rs index 23b9b79cc5d..6c15cf92150 100644 --- a/components/script/dom/htmlbuttonelement.rs +++ b/components/script/dom/htmlbuttonelement.rs @@ -58,8 +58,9 @@ impl HTMLButtonElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLButtonElement> { - let element = HTMLButtonElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLButtonElementBinding::Wrap) + Node::reflect_node(box HTMLButtonElement::new_inherited(localName, prefix, document), + document, + HTMLButtonElementBinding::Wrap) } } diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index add54917e6d..38969860722 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -67,8 +67,9 @@ impl HTMLCanvasElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLCanvasElement> { - let element = HTMLCanvasElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap) + Node::reflect_node(box HTMLCanvasElement::new_inherited(localName, prefix, document), + document, + HTMLCanvasElementBinding::Wrap) } fn recreate_contexts(&self) { diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index 798d0731b2c..95134556bc0 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -248,7 +248,7 @@ impl<'a> Iterator for HTMLCollectionElementsIter<'a> { .filter_map(Root::downcast) .filter(|element| filter.filter(&element, root)) .next() - } + } } impl HTMLCollectionMethods for HTMLCollection { diff --git a/components/script/dom/htmldataelement.rs b/components/script/dom/htmldataelement.rs index c665fece132..f412fd57570 100644 --- a/components/script/dom/htmldataelement.rs +++ b/components/script/dom/htmldataelement.rs @@ -28,7 +28,8 @@ impl HTMLDataElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLDataElement> { - let element = HTMLDataElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLDataElementBinding::Wrap) + Node::reflect_node(box HTMLDataElement::new_inherited(localName, prefix, document), + document, + HTMLDataElementBinding::Wrap) } } diff --git a/components/script/dom/htmldatalistelement.rs b/components/script/dom/htmldatalistelement.rs index a44e3965d5c..b592457fea2 100644 --- a/components/script/dom/htmldatalistelement.rs +++ b/components/script/dom/htmldatalistelement.rs @@ -34,8 +34,9 @@ impl HTMLDataListElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLDataListElement> { - let element = HTMLDataListElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLDataListElementBinding::Wrap) + Node::reflect_node(box HTMLDataListElement::new_inherited(localName, prefix, document), + document, + HTMLDataListElementBinding::Wrap) } } diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs index f8fc6545f8d..3c86a9fd0d9 100644 --- a/components/script/dom/htmldetailselement.rs +++ b/components/script/dom/htmldetailselement.rs @@ -5,6 +5,7 @@ use dom::attr::Attr; use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding; use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding::HTMLDetailsElementMethods; +use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::refcounted::Trusted; @@ -19,7 +20,6 @@ use script_thread::Runnable; use std::cell::Cell; use string_cache::Atom; use task_source::TaskSource; -use task_source::dom_manipulation::DOMManipulationTask; #[dom_struct] pub struct HTMLDetailsElement { @@ -42,8 +42,9 @@ impl HTMLDetailsElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLDetailsElement> { - let element = HTMLDetailsElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLDetailsElementBinding::Wrap) + Node::reflect_node(box HTMLDetailsElement::new_inherited(localName, prefix, document), + document, + HTMLDetailsElementBinding::Wrap) } pub fn check_toggle_count(&self, number: u32) -> bool { @@ -72,14 +73,13 @@ impl VirtualMethods for HTMLDetailsElement { self.toggle_counter.set(counter); let window = window_from_node(self); - let window = window.r(); let task_source = window.dom_manipulation_task_source(); let details = Trusted::new(self); let runnable = box DetailsNotificationRunnable { element: details, toggle_number: counter }; - let _ = task_source.queue(DOMManipulationTask::Runnable(runnable)); + let _ = task_source.queue(runnable, GlobalRef::Window(&window)); } } } diff --git a/components/script/dom/htmldialogelement.rs b/components/script/dom/htmldialogelement.rs index 70edd6ec7fb..621eefcd8a4 100644 --- a/components/script/dom/htmldialogelement.rs +++ b/components/script/dom/htmldialogelement.rs @@ -33,8 +33,9 @@ impl HTMLDialogElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLDialogElement> { - let element = HTMLDialogElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLDialogElementBinding::Wrap) + Node::reflect_node(box HTMLDialogElement::new_inherited(localName, prefix, document), + document, + HTMLDialogElementBinding::Wrap) } } diff --git a/components/script/dom/htmldirectoryelement.rs b/components/script/dom/htmldirectoryelement.rs index 7a2cbd19c67..82253004650 100644 --- a/components/script/dom/htmldirectoryelement.rs +++ b/components/script/dom/htmldirectoryelement.rs @@ -29,7 +29,8 @@ impl HTMLDirectoryElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLDirectoryElement> { - let element = HTMLDirectoryElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLDirectoryElementBinding::Wrap) + Node::reflect_node(box HTMLDirectoryElement::new_inherited(localName, prefix, document), + document, + HTMLDirectoryElementBinding::Wrap) } } diff --git a/components/script/dom/htmldlistelement.rs b/components/script/dom/htmldlistelement.rs index c29aea80325..dbd67a87398 100644 --- a/components/script/dom/htmldlistelement.rs +++ b/components/script/dom/htmldlistelement.rs @@ -27,7 +27,8 @@ impl HTMLDListElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLDListElement> { - let element = HTMLDListElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLDListElementBinding::Wrap) + Node::reflect_node(box HTMLDListElement::new_inherited(localName, prefix, document), + document, + HTMLDListElementBinding::Wrap) } } diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 87bf5d92ff4..e9d967514d7 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -63,8 +63,9 @@ impl HTMLElement { #[allow(unrooted_must_root)] pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLElement> { - let element = HTMLElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLElementBinding::Wrap) + Node::reflect_node(box HTMLElement::new_inherited(localName, prefix, document), + document, + HTMLElementBinding::Wrap) } fn is_body_or_frameset(&self) -> bool { diff --git a/components/script/dom/htmlembedelement.rs b/components/script/dom/htmlembedelement.rs index fe0ed5424ac..195a82958fb 100644 --- a/components/script/dom/htmlembedelement.rs +++ b/components/script/dom/htmlembedelement.rs @@ -26,7 +26,8 @@ impl HTMLEmbedElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLEmbedElement> { - let element = HTMLEmbedElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLEmbedElementBinding::Wrap) + Node::reflect_node(box HTMLEmbedElement::new_inherited(localName, prefix, document), + document, + HTMLEmbedElementBinding::Wrap) } } diff --git a/components/script/dom/htmlfieldsetelement.rs b/components/script/dom/htmlfieldsetelement.rs index 085b8291ddf..86561581bd7 100644 --- a/components/script/dom/htmlfieldsetelement.rs +++ b/components/script/dom/htmlfieldsetelement.rs @@ -40,8 +40,9 @@ impl HTMLFieldSetElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLFieldSetElement> { - let element = HTMLFieldSetElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLFieldSetElementBinding::Wrap) + Node::reflect_node(box HTMLFieldSetElement::new_inherited(localName, prefix, document), + document, + HTMLFieldSetElementBinding::Wrap) } } diff --git a/components/script/dom/htmlfontelement.rs b/components/script/dom/htmlfontelement.rs index 85dd000d183..7dacde26cf9 100644 --- a/components/script/dom/htmlfontelement.rs +++ b/components/script/dom/htmlfontelement.rs @@ -35,8 +35,9 @@ impl HTMLFontElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLFontElement> { - let element = HTMLFontElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLFontElementBinding::Wrap) + Node::reflect_node(box HTMLFontElement::new_inherited(localName, prefix, document), + document, + HTMLFontElementBinding::Wrap) } } diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 18c30a9d86c..9d7ce208ee2 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -12,6 +12,7 @@ use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMet use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods; use dom::bindings::conversions::DerivedFrom; +use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId}; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::refcounted::Trusted; @@ -53,7 +54,6 @@ use string_cache::Atom; use style::attr::AttrValue; use style::str::split_html_space_chars; use task_source::TaskSource; -use task_source::dom_manipulation::DOMManipulationTask; use url::form_urlencoded; #[derive(JSTraceable, PartialEq, Clone, Copy, HeapSizeOf)] @@ -83,8 +83,9 @@ impl HTMLFormElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLFormElement> { - let element = HTMLFormElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLFormElementBinding::Wrap) + Node::reflect_node(box HTMLFormElement::new_inherited(localName, prefix, document), + document, + HTMLFormElementBinding::Wrap) } pub fn generation_id(&self) -> GenerationId { @@ -484,7 +485,7 @@ impl HTMLFormElement { }; // Step 3 - window.dom_manipulation_task_source().queue(DOMManipulationTask::Runnable(nav)).unwrap(); + window.dom_manipulation_task_source().queue(nav, GlobalRef::Window(window)).unwrap(); } /// Interactively validate the constraints of form elements diff --git a/components/script/dom/htmlframeelement.rs b/components/script/dom/htmlframeelement.rs index 04207c711af..b2b46777843 100644 --- a/components/script/dom/htmlframeelement.rs +++ b/components/script/dom/htmlframeelement.rs @@ -26,7 +26,8 @@ impl HTMLFrameElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLFrameElement> { - let element = HTMLFrameElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLFrameElementBinding::Wrap) + Node::reflect_node(box HTMLFrameElement::new_inherited(localName, prefix, document), + document, + HTMLFrameElementBinding::Wrap) } } diff --git a/components/script/dom/htmlframesetelement.rs b/components/script/dom/htmlframesetelement.rs index 30cfc1fa677..08f23eb1b26 100644 --- a/components/script/dom/htmlframesetelement.rs +++ b/components/script/dom/htmlframesetelement.rs @@ -32,8 +32,9 @@ impl HTMLFrameSetElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLFrameSetElement> { - let element = HTMLFrameSetElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLFrameSetElementBinding::Wrap) + Node::reflect_node(box HTMLFrameSetElement::new_inherited(localName, prefix, document), + document, + HTMLFrameSetElementBinding::Wrap) } } diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index 995f380f442..cc88a4e4c87 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -34,8 +34,9 @@ impl HTMLHeadElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLHeadElement> { - let element = HTMLHeadElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLHeadElementBinding::Wrap) + Node::reflect_node(box HTMLHeadElement::new_inherited(localName, prefix, document), + document, + HTMLHeadElementBinding::Wrap) } /// https://html.spec.whatwg.org/multipage/#meta-referrer diff --git a/components/script/dom/htmlheadingelement.rs b/components/script/dom/htmlheadingelement.rs index 9340cb09d3b..94710294570 100644 --- a/components/script/dom/htmlheadingelement.rs +++ b/components/script/dom/htmlheadingelement.rs @@ -43,7 +43,8 @@ impl HTMLHeadingElement { prefix: Option<DOMString>, document: &Document, level: HeadingLevel) -> Root<HTMLHeadingElement> { - let element = HTMLHeadingElement::new_inherited(localName, prefix, document, level); - Node::reflect_node(box element, document, HTMLHeadingElementBinding::Wrap) + Node::reflect_node(box HTMLHeadingElement::new_inherited(localName, prefix, document, level), + document, + HTMLHeadingElementBinding::Wrap) } } diff --git a/components/script/dom/htmlhrelement.rs b/components/script/dom/htmlhrelement.rs index a3127449fcc..432b56eb345 100644 --- a/components/script/dom/htmlhrelement.rs +++ b/components/script/dom/htmlhrelement.rs @@ -31,8 +31,9 @@ impl HTMLHRElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLHRElement> { - let element = HTMLHRElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLHRElementBinding::Wrap) + Node::reflect_node(box HTMLHRElement::new_inherited(localName, prefix, document), + document, + HTMLHRElementBinding::Wrap) } } diff --git a/components/script/dom/htmlhtmlelement.rs b/components/script/dom/htmlhtmlelement.rs index e513eaa1bcc..3b397c7fd04 100644 --- a/components/script/dom/htmlhtmlelement.rs +++ b/components/script/dom/htmlhtmlelement.rs @@ -26,7 +26,8 @@ impl HTMLHtmlElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLHtmlElement> { - let element = HTMLHtmlElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLHtmlElementBinding::Wrap) + Node::reflect_node(box HTMLHtmlElement::new_inherited(localName, prefix, document), + document, + HTMLHtmlElementBinding::Wrap) } } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index dccba5846cc..73d750cc8dd 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -38,7 +38,7 @@ use dom::window::{ReflowReason, Window}; use ipc_channel::ipc; use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue}; use js::jsval::{UndefinedValue, NullValue}; -use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId}; +use msg::constellation_msg::{FrameType, LoadData, TraversalDirection, PipelineId, SubpageId}; use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; @@ -161,25 +161,11 @@ impl HTMLIFrameElement { #[allow(unsafe_code)] pub fn dispatch_mozbrowser_event(&self, event: MozBrowserEvent) { - // TODO(gw): Support mozbrowser event types that have detail which is not a string. - // See https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API - // for a list of mozbrowser events. assert!(PREFS.is_mozbrowser_enabled()); if self.Mozbrowser() { let window = window_from_node(self); - let custom_event = unsafe { - let cx = window.get_cx(); - let _ac = JSAutoCompartment::new(cx, window.reflector().get_jsobject().get()); - rooted!(in(cx) let mut detail = UndefinedValue()); - let event_name = Atom::from(event.name()); - self.build_mozbrowser_event_detail(event, cx, detail.handle_mut()); - CustomEvent::new(GlobalRef::Window(window.r()), - event_name, - true, - true, - detail.handle()) - }; + let custom_event = build_mozbrowser_custom_event(&window, event); custom_event.upcast::<Event>().fire(self.upcast()); } } @@ -212,8 +198,9 @@ impl HTMLIFrameElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLIFrameElement> { - let element = HTMLIFrameElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLIFrameElementBinding::Wrap) + Node::reflect_node(box HTMLIFrameElement::new_inherited(localName, prefix, document), + document, + HTMLIFrameElementBinding::Wrap) } #[inline] @@ -335,105 +322,108 @@ impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> { } } -pub trait MozBrowserEventDetailBuilder { - #[allow(unsafe_code)] - unsafe fn build_mozbrowser_event_detail(&self, - event: MozBrowserEvent, - cx: *mut JSContext, - rval: MutableHandleValue); +#[allow(unsafe_code)] +pub fn build_mozbrowser_custom_event(window: &Window, event: MozBrowserEvent) -> Root<CustomEvent> { + // TODO(gw): Support mozbrowser event types that have detail which is not a string. + // See https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API + // for a list of mozbrowser events. + let cx = window.get_cx(); + let _ac = JSAutoCompartment::new(cx, window.reflector().get_jsobject().get()); + rooted!(in(cx) let mut detail = UndefinedValue()); + let event_name = Atom::from(event.name()); + unsafe { build_mozbrowser_event_detail(event, cx, detail.handle_mut()); } + CustomEvent::new(GlobalRef::Window(window), + event_name, + true, + true, + detail.handle()) } -impl MozBrowserEventDetailBuilder for HTMLIFrameElement { - #[allow(unsafe_code)] - unsafe fn build_mozbrowser_event_detail(&self, - event: MozBrowserEvent, - cx: *mut JSContext, - rval: MutableHandleValue) { - match event { - MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu | - MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart | - MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch | - MozBrowserEvent::UsernameAndPasswordRequired => { - rval.set(NullValue()); - } - MozBrowserEvent::Error(error_type, description, report) => { - BrowserElementErrorEventDetail { - type_: Some(DOMString::from(error_type.name())), - description: description.map(DOMString::from), - report: report.map(DOMString::from), - version: Some(DOMString::from_string(servo_version().into())), - }.to_jsval(cx, rval); - }, - MozBrowserEvent::SecurityChange(https_state) => { - BrowserElementSecurityChangeDetail { - // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsersecuritychange - state: Some(DOMString::from(match https_state { - HttpsState::Modern => "secure", - HttpsState::Deprecated => "broken", - HttpsState::None => "insecure", - }.to_owned())), - // FIXME - Not supported yet: - trackingContent: None, - mixedContent: None, - trackingState: None, - extendedValidation: None, - mixedState: None, - }.to_jsval(cx, rval); - } - MozBrowserEvent::TitleChange(ref string) => { - string.to_jsval(cx, rval); - } - MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => { - BrowserElementLocationChangeEventDetail { - url: Some(DOMString::from(url)), - canGoBack: Some(can_go_back), - canGoForward: Some(can_go_forward), - }.to_jsval(cx, rval); - } - MozBrowserEvent::OpenTab(url) => { - BrowserElementOpenTabEventDetail { - url: Some(DOMString::from(url)), - }.to_jsval(cx, rval); - } - MozBrowserEvent::OpenWindow(url, target, features) => { - BrowserElementOpenWindowEventDetail { - url: Some(DOMString::from(url)), - target: target.map(DOMString::from), - features: features.map(DOMString::from), - }.to_jsval(cx, rval); - } - MozBrowserEvent::IconChange(rel, href, sizes) => { - BrowserElementIconChangeEventDetail { - rel: Some(DOMString::from(rel)), - href: Some(DOMString::from(href)), - sizes: Some(DOMString::from(sizes)), - }.to_jsval(cx, rval); - } - MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value) => { - BrowserShowModalPromptEventDetail { - promptType: Some(DOMString::from(prompt_type)), - title: Some(DOMString::from(title)), - message: Some(DOMString::from(message)), - returnValue: Some(DOMString::from(return_value)), - }.to_jsval(cx, rval) - } - MozBrowserEvent::VisibilityChange(visibility) => { - BrowserElementVisibilityChangeEventDetail { - visible: Some(visibility), - }.to_jsval(cx, rval); - } +#[allow(unsafe_code)] +unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent, + cx: *mut JSContext, + rval: MutableHandleValue) { + match event { + MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu | + MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart | + MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch | + MozBrowserEvent::UsernameAndPasswordRequired => { + rval.set(NullValue()); + } + MozBrowserEvent::Error(error_type, description, report) => { + BrowserElementErrorEventDetail { + type_: Some(DOMString::from(error_type.name())), + description: Some(DOMString::from(description)), + report: Some(DOMString::from(report)), + version: Some(DOMString::from_string(servo_version().into())), + }.to_jsval(cx, rval); + }, + MozBrowserEvent::SecurityChange(https_state) => { + BrowserElementSecurityChangeDetail { + // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsersecuritychange + state: Some(DOMString::from(match https_state { + HttpsState::Modern => "secure", + HttpsState::Deprecated => "broken", + HttpsState::None => "insecure", + }.to_owned())), + // FIXME - Not supported yet: + trackingContent: None, + mixedContent: None, + trackingState: None, + extendedValidation: None, + mixedState: None, + }.to_jsval(cx, rval); + } + MozBrowserEvent::TitleChange(ref string) => { + string.to_jsval(cx, rval); + } + MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => { + BrowserElementLocationChangeEventDetail { + url: Some(DOMString::from(url)), + canGoBack: Some(can_go_back), + canGoForward: Some(can_go_forward), + }.to_jsval(cx, rval); + } + MozBrowserEvent::OpenTab(url) => { + BrowserElementOpenTabEventDetail { + url: Some(DOMString::from(url)), + }.to_jsval(cx, rval); + } + MozBrowserEvent::OpenWindow(url, target, features) => { + BrowserElementOpenWindowEventDetail { + url: Some(DOMString::from(url)), + target: target.map(DOMString::from), + features: features.map(DOMString::from), + }.to_jsval(cx, rval); + } + MozBrowserEvent::IconChange(rel, href, sizes) => { + BrowserElementIconChangeEventDetail { + rel: Some(DOMString::from(rel)), + href: Some(DOMString::from(href)), + sizes: Some(DOMString::from(sizes)), + }.to_jsval(cx, rval); + } + MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value) => { + BrowserShowModalPromptEventDetail { + promptType: Some(DOMString::from(prompt_type)), + title: Some(DOMString::from(title)), + message: Some(DOMString::from(message)), + returnValue: Some(DOMString::from(return_value)), + }.to_jsval(cx, rval) + } + MozBrowserEvent::VisibilityChange(visibility) => { + BrowserElementVisibilityChangeEventDetail { + visible: Some(visibility), + }.to_jsval(cx, rval); } } } -pub fn Navigate(iframe: &HTMLIFrameElement, direction: NavigationDirection) -> ErrorResult { +pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult { if iframe.Mozbrowser() { if iframe.upcast::<Node>().is_in_doc() { let window = window_from_node(iframe); - - let pipeline_info = Some((window.pipeline(), - iframe.subpage_id().unwrap())); - let msg = ConstellationMsg::Navigate(pipeline_info, direction); + let msg = ConstellationMsg::TraverseHistory(iframe.pipeline(), direction); window.constellation_chan().send(msg).unwrap(); } @@ -506,12 +496,12 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack fn GoBack(&self) -> ErrorResult { - Navigate(self, NavigationDirection::Back(1)) + Navigate(self, TraversalDirection::Back(1)) } // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goForward fn GoForward(&self) -> ErrorResult { - Navigate(self, NavigationDirection::Forward(1)) + Navigate(self, TraversalDirection::Forward(1)) } // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/reload diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 8c28b1e8c8d..cb0f65d0b2b 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -32,7 +32,6 @@ use std::sync::Arc; use string_cache::Atom; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; use task_source::TaskSource; -use task_source::dom_manipulation::DOMManipulationTask; use url::Url; #[derive(JSTraceable, HeapSizeOf)] @@ -141,7 +140,7 @@ impl HTMLImageElement { // Return the image via a message to the script thread, which marks the element // as dirty and triggers a reflow. let image_response = message.to().unwrap(); - let runnable = ImageResponseHandlerRunnable::new( + let runnable = box ImageResponseHandlerRunnable::new( trusted_node.clone(), image_response); let runnable = wrapper.wrap_runnable(runnable); let _ = script_chan.send(CommonScriptMsg::RunnableMsg( @@ -180,12 +179,12 @@ impl HTMLImageElement { } } - let runnable = Box::new(ImgParseErrorRunnable { + let runnable = box ImgParseErrorRunnable { img: Trusted::new(self), src: src.into(), - }); + }; let task = window.dom_manipulation_task_source(); - let _ = task.queue(DOMManipulationTask::Runnable(runnable)); + let _ = task.queue(runnable, GlobalRef::Window(window)); } } } @@ -214,8 +213,9 @@ impl HTMLImageElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLImageElement> { - let element = HTMLImageElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLImageElementBinding::Wrap) + Node::reflect_node(box HTMLImageElement::new_inherited(localName, prefix, document), + document, + HTMLImageElementBinding::Wrap) } pub fn Image(global: GlobalRef, diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 35e2a6f5116..7f524cac29d 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -35,6 +35,7 @@ use ipc_channel::ipc::{self, IpcSender}; use mime_guess; use msg::constellation_msg::Key; use net_traits::IpcSend; +use net_traits::blob_url_store::get_blob_origin; use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; use script_traits::ScriptMsg as ConstellationMsg; use std::borrow::ToOwned; @@ -147,8 +148,9 @@ impl HTMLInputElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLInputElement> { - let element = HTMLInputElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLInputElementBinding::Wrap) + Node::reflect_node(box HTMLInputElement::new_inherited(localName, prefix, document), + document, + HTMLInputElementBinding::Wrap) } pub fn type_(&self) -> Atom { @@ -577,7 +579,8 @@ impl HTMLInputElementMethods for HTMLInputElement { &self.upcast(), atom!("select"), EventBubbles::Bubbles, - EventCancelable::NotCancelable); + EventCancelable::NotCancelable, + window.r()); self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } @@ -747,7 +750,7 @@ impl HTMLInputElement { // Select files by invoking UI or by passed in argument fn select_files(&self, opt_test_paths: Option<Vec<DOMString>>) { let window = window_from_node(self); - let origin = window.get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&window.get_url()); let filemanager = window.resource_threads().sender(); let mut files: Vec<Root<File>> = vec![]; @@ -768,13 +771,6 @@ impl HTMLInputElement { for selected in selected_files { files.push(File::new_from_selected(window.r(), selected)); } - - target.fire_event("input", - EventBubbles::Bubbles, - EventCancelable::NotCancelable); - target.fire_event("change", - EventBubbles::Bubbles, - EventCancelable::NotCancelable); }, Err(err) => error = Some(err), }; @@ -797,13 +793,6 @@ impl HTMLInputElement { match recv.recv().expect("IpcSender side error") { Ok(selected) => { files.push(File::new_from_selected(window.r(), selected)); - - target.fire_event("input", - EventBubbles::Bubbles, - EventCancelable::NotCancelable); - target.fire_event("change", - EventBubbles::Bubbles, - EventCancelable::NotCancelable); }, Err(err) => error = Some(err), }; @@ -814,6 +803,13 @@ impl HTMLInputElement { } else { let filelist = FileList::new(window.r(), files); self.filelist.set(Some(&filelist)); + + target.fire_event("input", + EventBubbles::Bubbles, + EventCancelable::NotCancelable); + target.fire_event("change", + EventBubbles::Bubbles, + EventCancelable::NotCancelable); } } } @@ -1070,7 +1066,8 @@ impl VirtualMethods for HTMLInputElement { &self.upcast(), atom!("input"), EventBubbles::Bubbles, - EventCancelable::NotCancelable); + EventCancelable::NotCancelable, + window.r()); } self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); diff --git a/components/script/dom/htmllabelelement.rs b/components/script/dom/htmllabelelement.rs index 6e808a14fc3..af3b51609a3 100644 --- a/components/script/dom/htmllabelelement.rs +++ b/components/script/dom/htmllabelelement.rs @@ -38,8 +38,9 @@ impl HTMLLabelElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLLabelElement> { - let element = HTMLLabelElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLLabelElementBinding::Wrap) + Node::reflect_node(box HTMLLabelElement::new_inherited(localName, prefix, document), + document, + HTMLLabelElementBinding::Wrap) } } diff --git a/components/script/dom/htmllegendelement.rs b/components/script/dom/htmllegendelement.rs index 7a5a3632eeb..91bc29b4099 100644 --- a/components/script/dom/htmllegendelement.rs +++ b/components/script/dom/htmllegendelement.rs @@ -35,8 +35,9 @@ impl HTMLLegendElement { prefix: Option<DOMString>, document: &Document) -> Root<HTMLLegendElement> { - let element = HTMLLegendElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLLegendElementBinding::Wrap) + Node::reflect_node(box HTMLLegendElement::new_inherited(localName, prefix, document), + document, + HTMLLegendElementBinding::Wrap) } } diff --git a/components/script/dom/htmllielement.rs b/components/script/dom/htmllielement.rs index 64bedf2d8ce..444fc37827c 100644 --- a/components/script/dom/htmllielement.rs +++ b/components/script/dom/htmllielement.rs @@ -26,7 +26,8 @@ impl HTMLLIElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLLIElement> { - let element = HTMLLIElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLLIElementBinding::Wrap) + Node::reflect_node(box HTMLLIElement::new_inherited(localName, prefix, document), + document, + HTMLLIElementBinding::Wrap) } } diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index ea5c25d8d46..d089caed3f5 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -39,9 +39,8 @@ use string_cache::Atom; use style::attr::AttrValue; use style::media_queries::{MediaQueryList, parse_media_query_list}; use style::parser::ParserContextExtraData; -use style::servo::Stylesheet; use style::str::HTML_SPACE_CHARACTERS; -use style::stylesheets::Origin; +use style::stylesheets::{Stylesheet, Origin}; use url::Url; no_jsmanaged_fields!(Stylesheet); @@ -72,8 +71,9 @@ impl HTMLLinkElement { prefix: Option<DOMString>, document: &Document, creator: ElementCreator) -> Root<HTMLLinkElement> { - let element = HTMLLinkElement::new_inherited(localName, prefix, document, creator); - Node::reflect_node(box element, document, HTMLLinkElementBinding::Wrap) + Node::reflect_node(box HTMLLinkElement::new_inherited(localName, prefix, document, creator), + document, + HTMLLinkElementBinding::Wrap) } pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> { diff --git a/components/script/dom/htmlmapelement.rs b/components/script/dom/htmlmapelement.rs index b1a4ff1af4a..ac4b4970bb3 100644 --- a/components/script/dom/htmlmapelement.rs +++ b/components/script/dom/htmlmapelement.rs @@ -28,7 +28,8 @@ impl HTMLMapElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLMapElement> { - let element = HTMLMapElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLMapElementBinding::Wrap) + Node::reflect_node(box HTMLMapElement::new_inherited(localName, prefix, document), + document, + HTMLMapElementBinding::Wrap) } } diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index b38f796e57c..7a94768c13a 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -33,7 +33,6 @@ use std::cell::Cell; use std::sync::{Arc, Mutex}; use string_cache::Atom; use task_source::TaskSource; -use task_source::dom_manipulation::DOMManipulationTask; use time::{self, Timespec, Duration}; use url::Url; @@ -238,11 +237,11 @@ impl HTMLMediaElement { } } - let task = Task { + let task = box Task { elem: Trusted::new(self), }; let win = window_from_node(self); - let _ = win.dom_manipulation_task_source().queue(DOMManipulationTask::Runnable(box task)); + let _ = win.dom_manipulation_task_source().queue(task, GlobalRef::Window(&win)); } // https://html.spec.whatwg.org/multipage/#internal-pause-steps step 2.2 @@ -262,17 +261,17 @@ impl HTMLMediaElement { } } - let task = Task { + let task = box Task { elem: Trusted::new(self), }; let win = window_from_node(self); - let _ = win.dom_manipulation_task_source().queue(DOMManipulationTask::Runnable(box task)); + let _ = win.dom_manipulation_task_source().queue(task, GlobalRef::Window(&win)); } fn queue_fire_simple_event(&self, type_: &'static str) { let win = window_from_node(self); - let task = FireSimpleEventTask::new(self, type_); - let _ = win.dom_manipulation_task_source().queue(DOMManipulationTask::Runnable(box task)); + let task = box FireSimpleEventTask::new(self, type_); + let _ = win.dom_manipulation_task_source().queue(task, GlobalRef::Window(&win)); } fn fire_simple_event(&self, type_: &str) { @@ -498,8 +497,9 @@ impl HTMLMediaElement { } fn queue_dedicated_media_source_failure_steps(&self) { - let _ = window_from_node(self).dom_manipulation_task_source().queue( - DOMManipulationTask::Runnable(box DedicatedMediaSourceFailureTask::new(self))); + let window = window_from_node(self); + let _ = window.dom_manipulation_task_source().queue(box DedicatedMediaSourceFailureTask::new(self), + GlobalRef::Window(&window)); } // https://html.spec.whatwg.org/multipage/#dedicated-media-source-failure-steps @@ -801,6 +801,8 @@ impl PauseIfNotInDocumentTask { } impl Runnable for PauseIfNotInDocumentTask { + fn name(&self) -> &'static str { "PauseIfNotInDocumentTask" } + fn handler(self: Box<PauseIfNotInDocumentTask>) { let elem = self.elem.root(); if !elem.upcast::<Node>().is_in_doc() { diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index 14d8d300bb6..b8c2cd423fa 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -20,9 +20,8 @@ use std::ascii::AsciiExt; use std::sync::Arc; use string_cache::Atom; use style::attr::AttrValue; -use style::servo::Stylesheet; use style::str::HTML_SPACE_CHARACTERS; -use style::stylesheets::{CSSRule, Origin}; +use style::stylesheets::{Stylesheet, CSSRule, Origin}; use style::viewport::ViewportRule; #[dom_struct] @@ -45,8 +44,9 @@ impl HTMLMetaElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLMetaElement> { - let element = HTMLMetaElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLMetaElementBinding::Wrap) + Node::reflect_node(box HTMLMetaElement::new_inherited(localName, prefix, document), + document, + HTMLMetaElementBinding::Wrap) } pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> { diff --git a/components/script/dom/htmlmeterelement.rs b/components/script/dom/htmlmeterelement.rs index 10af136ffa5..e0844d0dd55 100644 --- a/components/script/dom/htmlmeterelement.rs +++ b/components/script/dom/htmlmeterelement.rs @@ -30,8 +30,9 @@ impl HTMLMeterElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLMeterElement> { - let element = HTMLMeterElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLMeterElementBinding::Wrap) + Node::reflect_node(box HTMLMeterElement::new_inherited(localName, prefix, document), + document, + HTMLMeterElementBinding::Wrap) } } diff --git a/components/script/dom/htmlmodelement.rs b/components/script/dom/htmlmodelement.rs index 07d974d46da..c34b27762ca 100644 --- a/components/script/dom/htmlmodelement.rs +++ b/components/script/dom/htmlmodelement.rs @@ -29,7 +29,8 @@ impl HTMLModElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLModElement> { - let element = HTMLModElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLModElementBinding::Wrap) + Node::reflect_node(box HTMLModElement::new_inherited(localName, prefix, document), + document, + HTMLModElementBinding::Wrap) } } diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index 13798632e17..593895461b5 100644 --- a/components/script/dom/htmlobjectelement.rs +++ b/components/script/dom/htmlobjectelement.rs @@ -42,8 +42,9 @@ impl HTMLObjectElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLObjectElement> { - let element = HTMLObjectElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLObjectElementBinding::Wrap) + Node::reflect_node(box HTMLObjectElement::new_inherited(localName, prefix, document), + document, + HTMLObjectElementBinding::Wrap) } } diff --git a/components/script/dom/htmlolistelement.rs b/components/script/dom/htmlolistelement.rs index 85cc77959ea..fe65339bc80 100644 --- a/components/script/dom/htmlolistelement.rs +++ b/components/script/dom/htmlolistelement.rs @@ -28,7 +28,8 @@ impl HTMLOListElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLOListElement> { - let element = HTMLOListElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLOListElementBinding::Wrap) + Node::reflect_node(box HTMLOListElement::new_inherited(localName, prefix, document), + document, + HTMLOListElementBinding::Wrap) } } diff --git a/components/script/dom/htmloptgroupelement.rs b/components/script/dom/htmloptgroupelement.rs index 9665a0cf22f..9a725975d0a 100644 --- a/components/script/dom/htmloptgroupelement.rs +++ b/components/script/dom/htmloptgroupelement.rs @@ -37,8 +37,9 @@ impl HTMLOptGroupElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLOptGroupElement> { - let element = HTMLOptGroupElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLOptGroupElementBinding::Wrap) + Node::reflect_node(box HTMLOptGroupElement::new_inherited(localName, prefix, document), + document, + HTMLOptGroupElementBinding::Wrap) } } diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs index 7d0eeb45752..737bc67bd4c 100644 --- a/components/script/dom/htmloptionelement.rs +++ b/components/script/dom/htmloptionelement.rs @@ -52,8 +52,9 @@ impl HTMLOptionElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLOptionElement> { - let element = HTMLOptionElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLOptionElementBinding::Wrap) + Node::reflect_node(box HTMLOptionElement::new_inherited(localName, prefix, document), + document, + HTMLOptionElementBinding::Wrap) } pub fn set_selectedness(&self, selected: bool) { diff --git a/components/script/dom/htmloutputelement.rs b/components/script/dom/htmloutputelement.rs index b1b51c6d47e..32e123a4700 100644 --- a/components/script/dom/htmloutputelement.rs +++ b/components/script/dom/htmloutputelement.rs @@ -34,8 +34,9 @@ impl HTMLOutputElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLOutputElement> { - let element = HTMLOutputElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLOutputElementBinding::Wrap) + Node::reflect_node(box HTMLOutputElement::new_inherited(localName, prefix, document), + document, + HTMLOutputElementBinding::Wrap) } } diff --git a/components/script/dom/htmlparagraphelement.rs b/components/script/dom/htmlparagraphelement.rs index fc4b342b633..5b913da8801 100644 --- a/components/script/dom/htmlparagraphelement.rs +++ b/components/script/dom/htmlparagraphelement.rs @@ -29,7 +29,8 @@ impl HTMLParagraphElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLParagraphElement> { - let element = HTMLParagraphElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLParagraphElementBinding::Wrap) + Node::reflect_node(box HTMLParagraphElement::new_inherited(localName, prefix, document), + document, + HTMLParagraphElementBinding::Wrap) } } diff --git a/components/script/dom/htmlparamelement.rs b/components/script/dom/htmlparamelement.rs index 9c3d745f612..b2296f7750b 100644 --- a/components/script/dom/htmlparamelement.rs +++ b/components/script/dom/htmlparamelement.rs @@ -29,7 +29,8 @@ impl HTMLParamElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLParamElement> { - let element = HTMLParamElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLParamElementBinding::Wrap) + Node::reflect_node(box HTMLParamElement::new_inherited(localName, prefix, document), + document, + HTMLParamElementBinding::Wrap) } } diff --git a/components/script/dom/htmlpreelement.rs b/components/script/dom/htmlpreelement.rs index f03af0f4c45..d39bb44f21f 100644 --- a/components/script/dom/htmlpreelement.rs +++ b/components/script/dom/htmlpreelement.rs @@ -29,7 +29,8 @@ impl HTMLPreElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLPreElement> { - let element = HTMLPreElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLPreElementBinding::Wrap) + Node::reflect_node(box HTMLPreElement::new_inherited(localName, prefix, document), + document, + HTMLPreElementBinding::Wrap) } } diff --git a/components/script/dom/htmlprogresselement.rs b/components/script/dom/htmlprogresselement.rs index 9fb721b795b..b2f7d818210 100644 --- a/components/script/dom/htmlprogresselement.rs +++ b/components/script/dom/htmlprogresselement.rs @@ -31,8 +31,9 @@ impl HTMLProgressElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLProgressElement> { - let element = HTMLProgressElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLProgressElementBinding::Wrap) + Node::reflect_node(box HTMLProgressElement::new_inherited(localName, prefix, document), + document, + HTMLProgressElementBinding::Wrap) } } diff --git a/components/script/dom/htmlquoteelement.rs b/components/script/dom/htmlquoteelement.rs index d4692f72b9e..81eb0d37864 100644 --- a/components/script/dom/htmlquoteelement.rs +++ b/components/script/dom/htmlquoteelement.rs @@ -29,7 +29,8 @@ impl HTMLQuoteElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLQuoteElement> { - let element = HTMLQuoteElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLQuoteElementBinding::Wrap) + Node::reflect_node(box HTMLQuoteElement::new_inherited(localName, prefix, document), + document, + HTMLQuoteElementBinding::Wrap) } } diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 2d10e5f43d8..442f3063524 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -5,7 +5,6 @@ use document_loader::LoadType; use dom::attr::Attr; use dom::bindings::cell::DOMRefCell; -use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::HTMLScriptElementBinding; use dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods; @@ -35,7 +34,6 @@ use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkEr use network_listener::{NetworkListener, PreInvoke}; use std::ascii::AsciiExt; use std::cell::Cell; -use std::mem; use std::sync::{Arc, Mutex}; use string_cache::Atom; use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec}; @@ -63,11 +61,7 @@ pub struct HTMLScriptElement { parser_document: JS<Document>, /// The source this script was loaded from - load: DOMRefCell<Option<ScriptOrigin>>, - - #[ignore_heap_size_of = "Defined in rust-encoding"] - /// https://html.spec.whatwg.org/multipage/#concept-script-encoding - block_character_encoding: Cell<Option<EncodingRef>>, + load: DOMRefCell<Option<Result<ScriptOrigin, NetworkError>>>, } impl HTMLScriptElement { @@ -82,15 +76,15 @@ impl HTMLScriptElement { ready_to_be_parser_executed: Cell::new(false), parser_document: JS::from_ref(document), load: DOMRefCell::new(None), - block_character_encoding: Cell::new(None), } } #[allow(unrooted_must_root)] pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document, creator: ElementCreator) -> Root<HTMLScriptElement> { - let element = HTMLScriptElement::new_inherited(localName, prefix, document, creator); - Node::reflect_node(box element, document, HTMLScriptElementBinding::Wrap) + Node::reflect_node(box HTMLScriptElement::new_inherited(localName, prefix, document, creator), + document, + HTMLScriptElementBinding::Wrap) } } @@ -117,15 +111,37 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[ ]; #[derive(HeapSizeOf, JSTraceable)] -pub enum ScriptOrigin { - Internal(DOMString, Url), - External(Result<(Metadata, Vec<u8>), NetworkError>), +pub struct ScriptOrigin { + text: DOMString, + url: Url, + external: bool, +} + +impl ScriptOrigin { + fn internal(text: DOMString, url: Url) -> ScriptOrigin { + ScriptOrigin { + text: text, + url: url, + external: false, + } + } + + fn external(text: DOMString, url: Url) -> ScriptOrigin { + ScriptOrigin { + text: text, + url: url, + external: true, + } + } } /// The context required for asynchronously loading an external script source. struct ScriptContext { /// The element that initiated the request. elem: Trusted<HTMLScriptElement>, + /// The (fallback) character encoding argument to the "fetch a classic + /// script" algorithm. + character_encoding: EncodingRef, /// The response body received to date. data: Vec<u8>, /// The response metadata received to date. @@ -161,15 +177,28 @@ impl AsyncResponseListener for ScriptContext { } } + /// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script + /// step 4-9 fn response_complete(&mut self, status: Result<(), NetworkError>) { + // Step 5. let load = status.and(self.status.clone()).map(|_| { - let data = mem::replace(&mut self.data, vec!()); let metadata = self.metadata.take().unwrap(); - (metadata, data) + + // Step 6. + let encoding = metadata.charset + .and_then(|encoding| encoding_from_whatwg_label(&encoding)) + .unwrap_or(self.character_encoding); + + // Step 7. + let source_text = encoding.decode(&self.data, DecoderTrap::Replace).unwrap(); + ScriptOrigin::external(DOMString::from(source_text), metadata.final_url) }); + + // Step 9. + // https://html.spec.whatwg.org/multipage/#prepare-a-script + // Step 18.6 (When the chosen algorithm asynchronously completes). let elem = self.elem.root(); - // TODO: maybe set this to None again after script execution to save memory. - *elem.load.borrow_mut() = Some(ScriptOrigin::External(load)); + *elem.load.borrow_mut() = Some(load); elem.ready_to_be_parser_executed.set(true); let document = document_from_node(elem.r()); @@ -179,6 +208,38 @@ impl AsyncResponseListener for ScriptContext { impl PreInvoke for ScriptContext {} +/// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script +fn fetch_a_classic_script(script: &HTMLScriptElement, + url: Url, + character_encoding: EncodingRef) { + // TODO(#9186): use the fetch infrastructure. + let context = Arc::new(Mutex::new(ScriptContext { + elem: Trusted::new(script), + character_encoding: character_encoding, + data: vec!(), + metadata: None, + url: url.clone(), + status: Ok(()) + })); + + let doc = document_from_node(script); + + let (action_sender, action_receiver) = ipc::channel().unwrap(); + let listener = NetworkListener { + context: context, + script_chan: doc.window().networking_task_source(), + wrapper: Some(doc.window().get_runnable_wrapper()), + }; + let response_target = AsyncResponseTarget { + sender: action_sender, + }; + ROUTER.add_route(action_receiver.to_opaque(), box move |message| { + listener.notify_action(message.to().unwrap()); + }); + + doc.load_async(LoadType::Script(url), response_target); +} + impl HTMLScriptElement { /// https://html.spec.whatwg.org/multipage/#prepare-a-script pub fn prepare(&self) -> NextParserState { @@ -226,13 +287,12 @@ impl HTMLScriptElement { // Step 9. let doc = document_from_node(self); - let document_from_node_ref = doc.r(); - if self.parser_inserted.get() && &*self.parser_document != document_from_node_ref { + if self.parser_inserted.get() && &*self.parser_document != &*doc { return NextParserState::Continue; } // Step 10. - if !document_from_node_ref.is_scripting_enabled() { + if !doc.is_scripting_enabled() { return NextParserState::Continue; } @@ -259,73 +319,51 @@ impl HTMLScriptElement { } // Step 13. - if let Some(ref charset) = element.get_attribute(&ns!(), &atom!("charset")) { - if let Some(encodingRef) = encoding_from_whatwg_label(&charset.Value()) { - self.block_character_encoding.set(Some(encodingRef)); - } - } + let encoding = element.get_attribute(&ns!(), &atom!("charset")) + .and_then(|charset| encoding_from_whatwg_label(&charset.value())) + .unwrap_or_else(|| doc.encoding()); // TODO: Step 14: CORS. - // TODO: Step 15: environment settings object. + // TODO: Step 15: Nonce. + + // TODO: Step 16: Parser state. + + // TODO: Step 17: environment settings object. let base_url = doc.base_url(); let is_external = match element.get_attribute(&ns!(), &atom!("src")) { - // Step 16. + // Step 18. Some(ref src) => { - // Step 16.1. + // Step 18.1. let src = src.value(); - // Step 16.2. + // Step 18.2. if src.is_empty() { self.queue_error_event(); return NextParserState::Continue; } - // Step 16.4-16.5. + // Step 18.4-18.5. let url = match base_url.join(&src) { Err(_) => { - error!("error parsing URL for script {}", &**src); + warn!("error parsing URL for script {}", &**src); self.queue_error_event(); return NextParserState::Continue; } Ok(url) => url, }; - // Step 16.6. - // TODO(#9186): use the fetch infrastructure. - let elem = Trusted::new(self); - - let context = Arc::new(Mutex::new(ScriptContext { - elem: elem, - data: vec!(), - metadata: None, - url: url.clone(), - status: Ok(()) - })); - - let (action_sender, action_receiver) = ipc::channel().unwrap(); - let listener = NetworkListener { - context: context, - script_chan: doc.window().networking_task_source(), - wrapper: Some(doc.window().get_runnable_wrapper()), - }; - let response_target = AsyncResponseTarget { - sender: action_sender, - }; - ROUTER.add_route(action_receiver.to_opaque(), box move |message| { - listener.notify_action(message.to().unwrap()); - }); - - doc.load_async(LoadType::Script(url), response_target); + // Step 18.6. + fetch_a_classic_script(self, url, encoding); true }, None => false, }; - // Step 18. + // Step 20. let deferred = element.has_attribute(&atom!("defer")); - // Step 18.a: has src, has defer, was parser-inserted, is not async. + // Step 20.a: classic, has src, has defer, was parser-inserted, is not async. if is_external && deferred && was_parser_inserted && @@ -333,35 +371,35 @@ impl HTMLScriptElement { doc.add_deferred_script(self); // Second part implemented in Document::process_deferred_scripts. return NextParserState::Continue; - // Step 18.b: has src, was parser-inserted, is not async. + // Step 20.b: classic, has src, was parser-inserted, is not async. } else if is_external && was_parser_inserted && !async { doc.set_pending_parsing_blocking_script(Some(self)); // Second part implemented in the load result handler. - // Step 18.c: has src, isn't async, isn't non-blocking. + // Step 20.c: classic, has src, isn't async, isn't non-blocking. } else if is_external && !async && !self.non_blocking.get() { doc.push_asap_in_order_script(self); // Second part implemented in Document::process_asap_scripts. - // Step 18.d: has src. + // Step 20.d: classic, has src. } else if is_external { doc.add_asap_script(self); // Second part implemented in Document::process_asap_scripts. - // Step 18.e: doesn't have src, was parser-inserted, is blocked on stylesheet. + // 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_script_blocking_stylesheets_count() > 0 { doc.set_pending_parsing_blocking_script(Some(self)); - *self.load.borrow_mut() = Some(ScriptOrigin::Internal(text, base_url)); + *self.load.borrow_mut() = Some(Ok(ScriptOrigin::internal(text, base_url))); self.ready_to_be_parser_executed.set(true); - // Step 18.f: otherwise. + // Step 20.f: otherwise. } else { assert!(!text.is_empty()); self.ready_to_be_parser_executed.set(true); - *self.load.borrow_mut() = Some(ScriptOrigin::Internal(text, base_url)); + *self.load.borrow_mut() = Some(Ok(ScriptOrigin::internal(text, base_url))); self.execute(); return NextParserState::Continue; } @@ -390,82 +428,67 @@ impl HTMLScriptElement { } let load = self.load.borrow_mut().take().unwrap(); - - // Step 2. - let (source, external, url) = match load { - // Step 2.a. - ScriptOrigin::External(Err(e)) => { - error!("error loading script {:?}", e); + let script = match load { + // Step 2. + Err(e) => { + warn!("error loading script {:?}", e); self.dispatch_error_event(); return; } - // Step 2.b.1.a. - ScriptOrigin::External(Ok((metadata, bytes))) => { - debug!("loading external script, url = {}", metadata.final_url); - - let encoding = metadata.charset - .and_then(|encoding| encoding_from_whatwg_label(&encoding)) - .or_else(|| self.block_character_encoding.get()) - .unwrap_or_else(|| self.parser_document.encoding()); - - (DOMString::from(encoding.decode(&*bytes, DecoderTrap::Replace).unwrap()), - true, - metadata.final_url) - }, - - // Step 2.b.1.c. - ScriptOrigin::Internal(text, url) => { - (text, false, url) - } + Ok(script) => script, }; - // Step 2.b.2. + if script.external { + debug!("loading external script, url = {}", script.url); + } + + // TODO(#12446): beforescriptexecute. if !self.dispatch_before_script_execute_event() { return; } - // Step 2.b.3. + // 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. - // Step 2.b.4. + // Step 4. let document = document_from_node(self); let document = document.r(); let old_script = document.GetCurrentScript(); - // Step 2.b.5. + // Step 5.a.1. document.set_current_script(Some(self)); - // Step 2.b.6. - // TODO: Create a script... + // Step 5.a.2. let window = window_from_node(self); rooted!(in(window.get_cx()) let mut rval = UndefinedValue()); - window.evaluate_script_on_global_with_result(&*source, - url.as_str(), - rval.handle_mut()); + window.evaluate_script_on_global_with_result(&script.text, + script.url.as_str(), + rval.handle_mut()); - // Step 2.b.7. + // Step 6. document.set_current_script(old_script.r()); - // Step 2.b.8. + // Step 7. // TODO: Decrement the ignore-destructive-writes counter of neutralised // doc, if it was incremented in the earlier step. - // Step 2.b.9. + // TODO(#12446): afterscriptexecute. self.dispatch_after_script_execute_event(); - // Step 2.b.10. - if external { + // Step 8. + if script.external { self.dispatch_load_event(); } else { - window.dom_manipulation_task_source().queue_simple_event(self.upcast(), atom!("load")); + window.dom_manipulation_task_source().queue_simple_event(self.upcast(), atom!("load"), window.r()); } } pub fn queue_error_event(&self) { - window_from_node(self).dom_manipulation_task_source().queue_simple_event(self.upcast(), atom!("error")); + let window = window_from_node(self); + window.dom_manipulation_task_source().queue_simple_event(self.upcast(), atom!("error"), window.r()); } pub fn dispatch_before_script_execute_event(&self) -> bool { diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 26e1ad9b0c4..cb42ca2521b 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -48,8 +48,9 @@ impl HTMLSelectElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLSelectElement> { - let element = HTMLSelectElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLSelectElementBinding::Wrap) + Node::reflect_node(box HTMLSelectElement::new_inherited(localName, prefix, document), + document, + HTMLSelectElementBinding::Wrap) } // https://html.spec.whatwg.org/multipage/#ask-for-a-reset diff --git a/components/script/dom/htmlsourceelement.rs b/components/script/dom/htmlsourceelement.rs index 585d7678281..c369ab86aaf 100644 --- a/components/script/dom/htmlsourceelement.rs +++ b/components/script/dom/htmlsourceelement.rs @@ -29,7 +29,8 @@ impl HTMLSourceElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLSourceElement> { - let element = HTMLSourceElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLSourceElementBinding::Wrap) + Node::reflect_node(box HTMLSourceElement::new_inherited(localName, prefix, document), + document, + HTMLSourceElementBinding::Wrap) } } diff --git a/components/script/dom/htmlspanelement.rs b/components/script/dom/htmlspanelement.rs index b66b1602284..d95975c135c 100644 --- a/components/script/dom/htmlspanelement.rs +++ b/components/script/dom/htmlspanelement.rs @@ -26,7 +26,8 @@ impl HTMLSpanElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLSpanElement> { - let element = HTMLSpanElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLSpanElementBinding::Wrap) + Node::reflect_node(box HTMLSpanElement::new_inherited(localName, prefix, document), + document, + HTMLSpanElementBinding::Wrap) } } diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 47409402855..c7cc4cc44a3 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -19,8 +19,7 @@ use std::sync::Arc; use string_cache::Atom; use style::media_queries::parse_media_query_list; use style::parser::ParserContextExtraData; -use style::servo::Stylesheet; -use style::stylesheets::Origin; +use style::stylesheets::{Stylesheet, Origin}; #[dom_struct] pub struct HTMLStyleElement { @@ -42,8 +41,9 @@ impl HTMLStyleElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLStyleElement> { - let element = HTMLStyleElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLStyleElementBinding::Wrap) + Node::reflect_node(box HTMLStyleElement::new_inherited(localName, prefix, document), + document, + HTMLStyleElementBinding::Wrap) } pub fn parse_own_css(&self) { diff --git a/components/script/dom/htmltablecaptionelement.rs b/components/script/dom/htmltablecaptionelement.rs index 108e0b8ea7d..fd01e2ee3fa 100644 --- a/components/script/dom/htmltablecaptionelement.rs +++ b/components/script/dom/htmltablecaptionelement.rs @@ -29,7 +29,8 @@ impl HTMLTableCaptionElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTableCaptionElement> { - let element = HTMLTableCaptionElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTableCaptionElementBinding::Wrap) + Node::reflect_node(box HTMLTableCaptionElement::new_inherited(localName, prefix, document), + document, + HTMLTableCaptionElementBinding::Wrap) } } diff --git a/components/script/dom/htmltablecolelement.rs b/components/script/dom/htmltablecolelement.rs index c995a2f8048..b5e69aaadc1 100644 --- a/components/script/dom/htmltablecolelement.rs +++ b/components/script/dom/htmltablecolelement.rs @@ -29,7 +29,8 @@ impl HTMLTableColElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTableColElement> { - let element = HTMLTableColElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTableColElementBinding::Wrap) + Node::reflect_node(box HTMLTableColElement::new_inherited(localName, prefix, document), + document, + HTMLTableColElementBinding::Wrap) } } diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index ec6e4b59efe..1d189f4a21f 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -34,6 +34,20 @@ pub struct HTMLTableElement { tbodies: MutNullableHeap<JS<HTMLCollection>>, } +#[allow(unrooted_must_root)] +#[derive(JSTraceable, HeapSizeOf)] +struct TableRowFilter { + sections: Vec<JS<Node>>, +} + +impl CollectionFilter for TableRowFilter { + fn filter(&self, elem: &Element, root: &Node) -> bool { + elem.is::<HTMLTableRowElement>() && + (root.is_parent_of(elem.upcast()) + || self.sections.iter().any(|ref section| section.is_parent_of(elem.upcast()))) + } +} + impl HTMLTableElement { fn new_inherited(localName: Atom, prefix: Option<DOMString>, document: &Document) -> HTMLTableElement { @@ -48,8 +62,9 @@ impl HTMLTableElement { #[allow(unrooted_must_root)] pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTableElement> { - let element = HTMLTableElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTableElementBinding::Wrap) + Node::reflect_node(box HTMLTableElement::new_inherited(localName, prefix, document), + document, + HTMLTableElementBinding::Wrap) } pub fn get_border(&self) -> Option<u32> { @@ -119,32 +134,22 @@ impl HTMLTableElement { thead.upcast::<Node>().remove_self(); } } -} - -impl HTMLTableElementMethods for HTMLTableElement { - // https://html.spec.whatwg.org/multipage/#dom-table-rows - fn Rows(&self) -> Root<HTMLCollection> { - #[allow(unrooted_must_root)] - #[derive(JSTraceable, HeapSizeOf)] - struct TableRowFilter { - sections: Vec<JS<Node>> - } - - impl CollectionFilter for TableRowFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - elem.is::<HTMLTableRowElement>() && - (root.is_parent_of(elem.upcast()) - || self.sections.iter().any(|ref section| section.is_parent_of(elem.upcast()))) - } - } - let filter = TableRowFilter { + fn get_rows(&self) -> TableRowFilter { + TableRowFilter { sections: self.upcast::<Node>() .children() .filter_map(|ref node| node.downcast::<HTMLTableSectionElement>().map(|_| JS::from_ref(&**node))) .collect() - }; + } + } +} + +impl HTMLTableElementMethods for HTMLTableElement { + // https://html.spec.whatwg.org/multipage/#dom-table-rows + fn Rows(&self) -> Root<HTMLCollection> { + let filter = self.get_rows(); HTMLCollection::new(window_from_node(self).r(), self.upcast(), box filter) } @@ -337,6 +342,22 @@ impl HTMLTableElementMethods for HTMLTableElement { Ok(new_row) } + // https://html.spec.whatwg.org/multipage/#dom-table-deleterow + fn DeleteRow(&self, mut index: i32) -> Fallible<()> { + let rows = self.Rows(); + // Step 1. + if index == -1 { + index = rows.Length() as i32 - 1; + } + // Step 2. + if index < 0 || index as u32 >= rows.Length() { + return Err(Error::IndexSize); + } + // Step 3. + Root::upcast::<Node>(rows.Item(index as u32).unwrap()).remove_self(); + Ok(()) + } + // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor make_getter!(BgColor, "bgcolor"); diff --git a/components/script/dom/htmltableheadercellelement.rs b/components/script/dom/htmltableheadercellelement.rs index 17ecc472d25..da980e7d840 100644 --- a/components/script/dom/htmltableheadercellelement.rs +++ b/components/script/dom/htmltableheadercellelement.rs @@ -29,7 +29,8 @@ impl HTMLTableHeaderCellElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTableHeaderCellElement> { - let element = HTMLTableHeaderCellElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTableHeaderCellElementBinding::Wrap) + Node::reflect_node(box HTMLTableHeaderCellElement::new_inherited(localName, prefix, document), + document, + HTMLTableHeaderCellElementBinding::Wrap) } } diff --git a/components/script/dom/htmltablesectionelement.rs b/components/script/dom/htmltablesectionelement.rs index 7b047439743..3279e03ff0c 100644 --- a/components/script/dom/htmltablesectionelement.rs +++ b/components/script/dom/htmltablesectionelement.rs @@ -35,8 +35,9 @@ impl HTMLTableSectionElement { #[allow(unrooted_must_root)] pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTableSectionElement> { - let element = HTMLTableSectionElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTableSectionElementBinding::Wrap) + Node::reflect_node(box HTMLTableSectionElement::new_inherited(localName, prefix, document), + document, + HTMLTableSectionElementBinding::Wrap) } } diff --git a/components/script/dom/htmltemplateelement.rs b/components/script/dom/htmltemplateelement.rs index 0459a772273..aa98d849c85 100644 --- a/components/script/dom/htmltemplateelement.rs +++ b/components/script/dom/htmltemplateelement.rs @@ -39,8 +39,9 @@ impl HTMLTemplateElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTemplateElement> { - let element = HTMLTemplateElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTemplateElementBinding::Wrap) + Node::reflect_node(box HTMLTemplateElement::new_inherited(localName, prefix, document), + document, + HTMLTemplateElementBinding::Wrap) } } diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 69fe9046dad..a89df91f99b 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -114,8 +114,9 @@ impl HTMLTextAreaElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTextAreaElement> { - let element = HTMLTextAreaElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTextAreaElementBinding::Wrap) + Node::reflect_node(box HTMLTextAreaElement::new_inherited(localName, prefix, document), + document, + HTMLTextAreaElementBinding::Wrap) } } @@ -260,7 +261,8 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement { &self.upcast(), atom!("select"), EventBubbles::Bubbles, - EventCancelable::NotCancelable); + EventCancelable::NotCancelable, + window.r()); self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } } @@ -383,7 +385,8 @@ impl VirtualMethods for HTMLTextAreaElement { &self.upcast(), atom!("input"), EventBubbles::Bubbles, - EventCancelable::NotCancelable); + EventCancelable::NotCancelable, + window.r()); } self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); diff --git a/components/script/dom/htmltimeelement.rs b/components/script/dom/htmltimeelement.rs index 7c55c2f7e61..bcf214cf5f6 100644 --- a/components/script/dom/htmltimeelement.rs +++ b/components/script/dom/htmltimeelement.rs @@ -26,7 +26,8 @@ impl HTMLTimeElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTimeElement> { - let element = HTMLTimeElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTimeElementBinding::Wrap) + Node::reflect_node(box HTMLTimeElement::new_inherited(localName, prefix, document), + document, + HTMLTimeElementBinding::Wrap) } } diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs index d475f37bc73..077b6d6afdc 100644 --- a/components/script/dom/htmltitleelement.rs +++ b/components/script/dom/htmltitleelement.rs @@ -32,8 +32,9 @@ impl HTMLTitleElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTitleElement> { - let element = HTMLTitleElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTitleElementBinding::Wrap) + Node::reflect_node(box HTMLTitleElement::new_inherited(localName, prefix, document), + document, + HTMLTitleElementBinding::Wrap) } } diff --git a/components/script/dom/htmltrackelement.rs b/components/script/dom/htmltrackelement.rs index df071125b7b..979cbe17079 100644 --- a/components/script/dom/htmltrackelement.rs +++ b/components/script/dom/htmltrackelement.rs @@ -26,7 +26,8 @@ impl HTMLTrackElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLTrackElement> { - let element = HTMLTrackElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLTrackElementBinding::Wrap) + Node::reflect_node(box HTMLTrackElement::new_inherited(localName, prefix, document), + document, + HTMLTrackElementBinding::Wrap) } } diff --git a/components/script/dom/htmlulistelement.rs b/components/script/dom/htmlulistelement.rs index 145d3e6770c..2b38b49f1db 100644 --- a/components/script/dom/htmlulistelement.rs +++ b/components/script/dom/htmlulistelement.rs @@ -26,7 +26,8 @@ impl HTMLUListElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLUListElement> { - let element = HTMLUListElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLUListElementBinding::Wrap) + Node::reflect_node(box HTMLUListElement::new_inherited(localName, prefix, document), + document, + HTMLUListElementBinding::Wrap) } } diff --git a/components/script/dom/htmlunknownelement.rs b/components/script/dom/htmlunknownelement.rs index 5211b5c11e6..1bf321735fc 100644 --- a/components/script/dom/htmlunknownelement.rs +++ b/components/script/dom/htmlunknownelement.rs @@ -29,7 +29,8 @@ impl HTMLUnknownElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLUnknownElement> { - let element = HTMLUnknownElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLUnknownElementBinding::Wrap) + Node::reflect_node(box HTMLUnknownElement::new_inherited(localName, prefix, document), + document, + HTMLUnknownElementBinding::Wrap) } } diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index 6295227cf26..4c6f9663f97 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -27,7 +27,8 @@ impl HTMLVideoElement { pub fn new(localName: Atom, prefix: Option<DOMString>, document: &Document) -> Root<HTMLVideoElement> { - let element = HTMLVideoElement::new_inherited(localName, prefix, document); - Node::reflect_node(box element, document, HTMLVideoElementBinding::Wrap) + Node::reflect_node(box HTMLVideoElement::new_inherited(localName, prefix, document), + document, + HTMLVideoElementBinding::Wrap) } } diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index d76721ed040..effc7f2c761 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -269,6 +269,8 @@ pub mod focusevent; pub mod forcetouchevent; pub mod formdata; pub mod hashchangeevent; +pub mod headers; +pub mod history; pub mod htmlanchorelement; pub mod htmlappletelement; pub mod htmlareaelement; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 811716088b6..2769b7503bc 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -159,7 +159,9 @@ bitflags! { const SEQUENTIALLY_FOCUSABLE = 0x20, /// Whether any ancestor is a fragmentation container - const CAN_BE_FRAGMENTED = 0x40 + const CAN_BE_FRAGMENTED = 0x40, + #[doc = "Specifies whether this node needs to be dirted when viewport size changed."] + const DIRTY_ON_VIEWPORT_SIZE_CHANGE = 0x80 } } @@ -477,19 +479,7 @@ impl Node { return } - // 2. Dirty descendants. - fn dirty_subtree(node: &Node) { - // Stop if this subtree is already dirty. - if node.is_dirty() { return } - - node.set_flag(IS_DIRTY | HAS_DIRTY_DESCENDANTS, true); - - for kid in node.children() { - dirty_subtree(kid.r()); - } - } - - dirty_subtree(self); + self.set_flag(IS_DIRTY, true); // 4. Dirty ancestors. for ancestor in self.ancestors() { @@ -1297,22 +1287,17 @@ impl TreeIterator { depth: 0, } } -} -impl Iterator for TreeIterator { - type Item = Root<Node>; - - // https://dom.spec.whatwg.org/#concept-tree-order - fn next(&mut self) -> Option<Root<Node>> { + pub fn next_skipping_children(&mut self) -> Option<Root<Node>> { let current = match self.current.take() { None => return None, Some(current) => current, }; - if let Some(first_child) = current.GetFirstChild() { - self.current = Some(first_child); - self.depth += 1; - return Some(current); - }; + + self.next_skipping_children_impl(current) + } + + fn next_skipping_children_impl(&mut self, current: Root<Node>) -> Option<Root<Node>> { for ancestor in current.inclusive_ancestors() { if self.depth == 0 { break; @@ -1329,6 +1314,25 @@ impl Iterator for TreeIterator { } } +impl Iterator for TreeIterator { + type Item = Root<Node>; + + // https://dom.spec.whatwg.org/#concept-tree-order + fn next(&mut self) -> Option<Root<Node>> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }; + if let Some(first_child) = current.GetFirstChild() { + self.current = Some(first_child); + self.depth += 1; + return Some(current); + }; + + self.next_skipping_children_impl(current) + } +} + /// Specifies whether children must be recursively cloned or not. #[derive(Copy, Clone, PartialEq, HeapSizeOf)] pub enum CloneChildrenFlag { @@ -1721,7 +1725,8 @@ impl Node { let document = Document::new(window, None, Some((*document.url()).clone()), is_html_doc, None, - None, DocumentSource::NotFromParser, loader); + None, DocumentSource::NotFromParser, loader, + None, None); Root::upcast::<Node>(document) }, NodeTypeId::Element(..) => { diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs index ad303d45915..19af9b09ba4 100644 --- a/components/script/dom/serviceworker.rs +++ b/components/script/dom/serviceworker.rs @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::abstractworker::WorkerScriptMsg; use dom::abstractworker::{SimpleWorkerErrorHandler, WorkerErrorHandler}; -use dom::abstractworker::{WorkerScriptMsg, WorkerScriptLoadOrigin, SharedRt}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap}; @@ -13,19 +13,13 @@ use dom::bindings::js::Root; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::{DOMString, USVString}; -use dom::client::Client; use dom::errorevent::ErrorEvent; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; -use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope; -use dom::workerglobalscope::prepare_workerscope_init; -use ipc_channel::ipc; use js::jsval::UndefinedValue; use script_thread::Runnable; use std::cell::Cell; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc::{Sender, channel}; -use std::sync::{Arc, Mutex}; +use std::sync::mpsc::Sender; use url::Url; pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>; @@ -35,36 +29,27 @@ pub struct ServiceWorker { eventtarget: EventTarget, script_url: DOMRefCell<String>, state: Cell<ServiceWorkerState>, - closing: Arc<AtomicBool>, #[ignore_heap_size_of = "Defined in std"] - sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - #[ignore_heap_size_of = "Defined in rust-mozjs"] - runtime: Arc<Mutex<Option<SharedRt>>>, + sender: Option<Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>>, skip_waiting: Cell<bool> } impl ServiceWorker { - fn new_inherited(sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - closing: Arc<AtomicBool>, - script_url: &str, + fn new_inherited(script_url: &str, skip_waiting: bool) -> ServiceWorker { ServiceWorker { eventtarget: EventTarget::new_inherited(), - closing: closing, - sender: sender, + sender: None, script_url: DOMRefCell::new(String::from(script_url)), state: Cell::new(ServiceWorkerState::Installing), - runtime: Arc::new(Mutex::new(None)), skip_waiting: Cell::new(skip_waiting) } } pub fn new(global: GlobalRef, - closing: Arc<AtomicBool>, - sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, script_url: &str, skip_waiting: bool) -> Root<ServiceWorker> { - reflect_dom_object(box ServiceWorker::new_inherited(sender, closing, script_url, skip_waiting), global, Wrap) + reflect_dom_object(box ServiceWorker::new_inherited(script_url, skip_waiting), global, Wrap) } pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) { @@ -72,23 +57,19 @@ impl ServiceWorker { service_worker.upcast().fire_simple_event("error"); } - pub fn is_closing(&self) -> bool { - self.closing.load(Ordering::SeqCst) - } - pub fn set_transition_state(&self, state: ServiceWorkerState) { self.state.set(state); self.upcast::<EventTarget>().fire_simple_event("statechange"); } + pub fn get_script_url(&self) -> Url { + Url::parse(&self.script_url.borrow().clone()).unwrap() + } + pub fn handle_error_message(address: TrustedServiceWorkerAddress, message: DOMString, filename: DOMString, lineno: u32, colno: u32) { let worker = address.root(); - if worker.is_closing() { - return; - } - let global = worker.r().global(); rooted!(in(global.r().get_cx()) let error = UndefinedValue()); let errorevent = ErrorEvent::new(global.r(), atom!("error"), @@ -97,42 +78,12 @@ impl ServiceWorker { errorevent.upcast::<Event>().fire(worker.upcast()); } - #[allow(unsafe_code)] - pub fn init_service_worker(global: GlobalRef, - script_url: Url, - skip_waiting: bool) -> Root<ServiceWorker> { - let (sender, receiver) = channel(); - let closing = Arc::new(AtomicBool::new(false)); - let worker = ServiceWorker::new(global, - closing.clone(), - sender.clone(), - script_url.as_str(), - skip_waiting); - let worker_ref = Trusted::new(worker.r()); - - let worker_load_origin = WorkerScriptLoadOrigin { - referrer_url: None, - referrer_policy: None, - request_source: global.request_source(), - pipeline_id: Some(global.pipeline()) - }; - - let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); - let init = prepare_workerscope_init(global, - "Service Worker".to_owned(), - script_url.clone(), - devtools_sender.clone(), - closing); - - // represents a service worker client - let sw_client = Client::new(global.as_window()); - let trusted_client = Trusted::new(&*sw_client); - - ServiceWorkerGlobalScope::run_serviceworker_scope( - init, script_url, global.pipeline(), devtools_receiver, worker.runtime.clone(), worker_ref, - global.script_chan(), sender, receiver, trusted_client, worker_load_origin); - - worker + pub fn install_serviceworker(global: GlobalRef, + script_url: Url, + skip_waiting: bool) -> Root<ServiceWorker> { + ServiceWorker::new(global, + script_url.as_str(), + skip_waiting) } } diff --git a/components/script/dom/serviceworkercontainer.rs b/components/script/dom/serviceworkercontainer.rs index 744daba7b91..17fea7100be 100644 --- a/components/script/dom/serviceworkercontainer.rs +++ b/components/script/dom/serviceworkercontainer.rs @@ -98,7 +98,7 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer { script_url, scope_str.clone(), self); - ScriptThread::set_registration(scope, &*worker_registration); + ScriptThread::set_registration(scope, &*worker_registration, self.global().r().pipeline()); Ok(worker_registration) } } diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index cbe195d1b8e..4208754f91d 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -4,8 +4,7 @@ use devtools; use devtools_traits::DevtoolScriptControlMsg; -use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg, SharedRt, SimpleWorkerErrorHandler}; -use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan}; +use dom::abstractworker::WorkerScriptMsg; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding; @@ -13,66 +12,42 @@ use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWo use dom::bindings::global::{GlobalRef, global_root_from_context}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{Root, RootCollection}; -use dom::bindings::refcounted::{Trusted, LiveDOMReferences}; +use dom::bindings::refcounted::LiveDOMReferences; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; -use dom::client::Client; use dom::messageevent::MessageEvent; use dom::serviceworker::TrustedServiceWorkerAddress; use dom::workerglobalscope::WorkerGlobalScope; -use dom::workerglobalscope::WorkerGlobalScopeInit; -use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use ipc_channel::ipc::{self, IpcSender, IpcReceiver}; use ipc_channel::router::ROUTER; use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext}; use js::jsval::UndefinedValue; use js::rust::Runtime; use msg::constellation_msg::PipelineId; -use net_traits::{LoadContext, load_whole_resource, CustomResponse, IpcSend}; -use rand::random; -use script_runtime::ScriptThreadEventCategory::ServiceWorkerEvent; -use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; -use script_traits::{TimerEvent, TimerSource}; -use std::mem::replace; +use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator}; +use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx}; +use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg}; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; -use std::sync::{Arc, Mutex}; -use std::time::Instant; +use std::thread; +use std::time::Duration; use url::Url; use util::prefs::PREFS; use util::thread::spawn_named; use util::thread_state; use util::thread_state::{IN_WORKER, SCRIPT}; -/// Set the `worker` field of a related ServiceWorkerGlobalScope object to a particular -/// value for the duration of this object's lifetime. This ensures that the related Worker -/// object only lives as long as necessary (ie. while events are being executed), while -/// providing a reference that can be cloned freely. -struct AutoWorkerReset<'a> { - workerscope: &'a ServiceWorkerGlobalScope, - old_worker: Option<TrustedServiceWorkerAddress>, +/// Messages used to control service worker event loop +pub enum ServiceWorkerScriptMsg { + /// Message common to all workers + CommonWorker(WorkerScriptMsg), + // Message to request a custom response by the service worker + Response(CustomResponseMediator) } -impl<'a> AutoWorkerReset<'a> { - fn new(workerscope: &'a ServiceWorkerGlobalScope, - worker: TrustedServiceWorkerAddress) - -> AutoWorkerReset<'a> { - AutoWorkerReset { - workerscope: workerscope, - old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)), - } - } -} - -impl<'a> Drop for AutoWorkerReset<'a> { - fn drop(&mut self) { - *self.workerscope.worker.borrow_mut() = self.old_worker.clone(); - } -} - -enum MixedMessage { - FromServiceWorker((TrustedServiceWorkerAddress, WorkerScriptMsg)), - FromScheduler((TrustedServiceWorkerAddress, TimerEvent)), +pub enum MixedMessage { + FromServiceWorker(ServiceWorkerScriptMsg), FromDevtools(DevtoolScriptControlMsg), - FromNetwork(IpcSender<Option<CustomResponse>>), + FromTimeoutThread(()), } #[dom_struct] @@ -80,18 +55,17 @@ pub struct ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, id: PipelineId, #[ignore_heap_size_of = "Defined in std"] - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + receiver: Receiver<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] - timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>, + timer_event_port: Receiver<()>, #[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"] worker: DOMRefCell<Option<TrustedServiceWorkerAddress>>, - #[ignore_heap_size_of = "Can't measure trait objects"] - /// Sender to the parent thread. - parent_sender: Box<ScriptChan + Send>, #[ignore_heap_size_of = "Defined in std"] - service_worker_client: Trusted<Client> + swmanager_sender: IpcSender<ServiceWorkerMsg>, + #[ignore_heap_size_of = "Defined in std"] + scope_url: Url } impl ServiceWorkerGlobalScope { @@ -100,26 +74,27 @@ impl ServiceWorkerGlobalScope { id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, - parent_sender: Box<ScriptChan + Send>, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, timer_event_chan: IpcSender<TimerEvent>, - timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>, - client: Trusted<Client>) + timer_event_port: Receiver<()>, + swmanager_sender: IpcSender<ServiceWorkerMsg>, + scope_url: Url) -> ServiceWorkerGlobalScope { ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited(init, worker_url, runtime, from_devtools_receiver, - timer_event_chan), + timer_event_chan, + None), id: id, receiver: receiver, - own_sender: own_sender, timer_event_port: timer_event_port, - parent_sender: parent_sender, + own_sender: own_sender, worker: DOMRefCell::new(None), - service_worker_client: client + swmanager_sender: swmanager_sender, + scope_url: scope_url } } @@ -128,12 +103,12 @@ impl ServiceWorkerGlobalScope { id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, - parent_sender: Box<ScriptChan + Send>, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, timer_event_chan: IpcSender<TimerEvent>, - timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>, - client: Trusted<Client>) + timer_event_port: Receiver<()>, + swmanager_sender: IpcSender<ServiceWorkerMsg>, + scope_url: Url) -> Root<ServiceWorkerGlobalScope> { let cx = runtime.cx(); let scope = box ServiceWorkerGlobalScope::new_inherited(init, @@ -141,42 +116,39 @@ impl ServiceWorkerGlobalScope { id, from_devtools_receiver, runtime, - parent_sender, own_sender, receiver, timer_event_chan, timer_event_port, - client); + swmanager_sender, + scope_url); ServiceWorkerGlobalScopeBinding::Wrap(cx, scope) } #[allow(unsafe_code)] - pub fn run_serviceworker_scope(init: WorkerGlobalScopeInit, - worker_url: Url, - id: PipelineId, - from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, - main_thread_rt: Arc<Mutex<Option<SharedRt>>>, - worker: TrustedServiceWorkerAddress, - parent_sender: Box<ScriptChan + Send>, - own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>, - client: Trusted<Client>, - worker_load_origin: WorkerScriptLoadOrigin) { - let serialized_worker_url = worker_url.to_string(); + pub fn run_serviceworker_scope(scope_things: ScopeThings, + own_sender: Sender<ServiceWorkerScriptMsg>, + receiver: Receiver<ServiceWorkerScriptMsg>, + devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, + swmanager_sender: IpcSender<ServiceWorkerMsg>, + scope_url: Url) { + let ScopeThings { script_url, + pipeline_id, + init, + worker_load_origin, + .. } = scope_things; + + let serialized_worker_url = script_url.to_string(); spawn_named(format!("ServiceWorker for {}", serialized_worker_url), move || { thread_state::initialize(SCRIPT | IN_WORKER); - let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); - let (url, source) = match load_whole_resource(LoadContext::Script, &init.resource_threads.sender(), - worker_url, + script_url, &worker_load_origin) { Err(_) => { println!("error loading script {}", serialized_worker_url); - parent_sender.send(CommonScriptMsg::RunnableMsg(ServiceWorkerEvent, - box SimpleWorkerErrorHandler::new(worker))).unwrap(); return; } Ok((metadata, bytes)) => { @@ -185,25 +157,18 @@ impl ServiceWorkerGlobalScope { }; let runtime = unsafe { new_rt_and_cx() }; - *main_thread_rt.lock().unwrap() = Some(SharedRt::new(&runtime)); let (devtools_mpsc_chan, devtools_mpsc_port) = channel(); - ROUTER.route_ipc_receiver_to_mpsc_sender(from_devtools_receiver, devtools_mpsc_chan); + ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_receiver, devtools_mpsc_chan); - let (timer_tx, timer_rx) = channel(); - let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap(); - let worker_for_route = worker.clone(); - ROUTER.add_route(timer_ipc_port.to_opaque(), box move |message| { - let event = message.to().unwrap(); - timer_tx.send((worker_for_route.clone(), event)).unwrap(); - }); + // TODO XXXcreativcoder use this timer_ipc_port, when we have a service worker instance here + let (timer_ipc_chan, _timer_ipc_port) = ipc::channel().unwrap(); + let (timer_chan, timer_port) = channel(); let global = ServiceWorkerGlobalScope::new( - init, url, id, devtools_mpsc_port, runtime, - parent_sender.clone(), own_sender, receiver, - timer_ipc_chan, timer_rx, client); - // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter - // registration (#6631), so we instead use a random number and cross our fingers. + init, url, pipeline_id, devtools_mpsc_port, runtime, + own_sender, receiver, + timer_ipc_chan, timer_port, swmanager_sender, scope_url); let scope = global.upcast::<WorkerGlobalScope>(); unsafe { @@ -211,35 +176,25 @@ impl ServiceWorkerGlobalScope { JS_SetInterruptCallback(scope.runtime(), Some(interrupt_callback)); } - if scope.is_closing() { - return; - } - - { - let _ar = AutoWorkerReset::new(global.r(), worker); - scope.execute_script(DOMString::from(source)); - } - + scope.execute_script(DOMString::from(source)); - let reporter_name = format!("service-worker-reporter-{}", random::<u64>()); - scope.mem_profiler_chan().run_with_memory_reporting(|| { - // Service workers are time limited - let sw_lifetime = Instant::now(); + // Service workers are time limited + spawn_named("SWTimeoutThread".to_owned(), move || { let sw_lifetime_timeout = PREFS.get("dom.serviceworker.timeout_seconds").as_u64().unwrap(); - while let Ok(event) = global.receive_event() { - if scope.is_closing() { - break; - } - global.handle_event(event); - if sw_lifetime.elapsed().as_secs() == sw_lifetime_timeout { - break; - } + thread::sleep(Duration::new(sw_lifetime_timeout, 0)); + let _ = timer_chan.send(()); + }); + + // TODO XXXcreativcoder bring back run_with_memory_reporting when things are more concrete here. + while let Ok(event) = global.receive_event() { + if !global.handle_event(event) { + break; } - }, reporter_name, parent_sender, CommonScriptMsg::CollectReports); + } }); } - fn handle_event(&self, event: MixedMessage) { + fn handle_event(&self, event: MixedMessage) -> bool { match event { MixedMessage::FromDevtools(msg) => { let global_ref = GlobalRef::Worker(self.upcast()); @@ -252,33 +207,24 @@ impl ServiceWorkerGlobalScope { devtools::handle_wants_live_notifications(&global_ref, bool_val), _ => debug!("got an unusable devtools control message inside the worker!"), } - }, - MixedMessage::FromScheduler((linked_worker, timer_event)) => { - match timer_event { - TimerEvent(TimerSource::FromWorker, id) => { - let _ar = AutoWorkerReset::new(self, linked_worker); - let scope = self.upcast::<WorkerGlobalScope>(); - scope.handle_fire_timer(id); - }, - TimerEvent(_, _) => { - panic!("The service worker received a TimerEvent from a window.") - } - } + true } - MixedMessage::FromServiceWorker((linked_worker, msg)) => { - let _ar = AutoWorkerReset::new(self, linked_worker); + MixedMessage::FromServiceWorker(msg) => { self.handle_script_event(msg); - }, - MixedMessage::FromNetwork(network_sender) => { - // We send None as of now - let _ = network_sender.send(None); + true + } + MixedMessage::FromTimeoutThread(_) => { + let _ = self.swmanager_sender.send(ServiceWorkerMsg::Timeout(self.scope_url.clone())); + false } } } - fn handle_script_event(&self, msg: WorkerScriptMsg) { + fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) { + use self::ServiceWorkerScriptMsg::*; + match msg { - WorkerScriptMsg::DOMMessage(data) => { + CommonWorker(WorkerScriptMsg::DOMMessage(data)) => { let scope = self.upcast::<WorkerGlobalScope>(); let target = self.upcast(); let _ac = JSAutoCompartment::new(scope.get_cx(), @@ -287,19 +233,22 @@ impl ServiceWorkerGlobalScope { data.read(GlobalRef::Worker(scope), message.handle_mut()); MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle()); }, - WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable))) => { runnable.handler() }, - WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr))) => { LiveDOMReferences::cleanup(addr); }, - WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) => { + CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan))) => { let scope = self.upcast::<WorkerGlobalScope>(); let cx = scope.get_cx(); let path_seg = format!("url({})", scope.get_url()); let reports = get_reports(cx, path_seg); reports_chan.send(reports); }, + Response(mediator) => { + let _ = mediator.response_chan.send(None); + } } } @@ -307,59 +256,39 @@ impl ServiceWorkerGlobalScope { fn receive_event(&self) -> Result<MixedMessage, RecvError> { let scope = self.upcast::<WorkerGlobalScope>(); let worker_port = &self.receiver; - let timer_event_port = &self.timer_event_port; let devtools_port = scope.from_devtools_receiver(); - let msg_port = scope.custom_message_port(); + let timer_event_port = &self.timer_event_port; let sel = Select::new(); let mut worker_handle = sel.handle(worker_port); - let mut timer_event_handle = sel.handle(timer_event_port); let mut devtools_handle = sel.handle(devtools_port); - let mut msg_port_handle = sel.handle(msg_port); + let mut timer_port_handle = sel.handle(timer_event_port); unsafe { worker_handle.add(); - timer_event_handle.add(); if scope.from_devtools_sender().is_some() { devtools_handle.add(); } - msg_port_handle.add(); + timer_port_handle.add(); } + let ret = sel.wait(); if ret == worker_handle.id() { Ok(MixedMessage::FromServiceWorker(try!(worker_port.recv()))) - } else if ret == timer_event_handle.id() { - Ok(MixedMessage::FromScheduler(try!(timer_event_port.recv()))) - } else if ret == devtools_handle.id() { + }else if ret == devtools_handle.id() { Ok(MixedMessage::FromDevtools(try!(devtools_port.recv()))) - } else if ret == msg_port_handle.id() { - Ok(MixedMessage::FromNetwork(try!(msg_port.recv()))) + } else if ret == timer_port_handle.id() { + Ok(MixedMessage::FromTimeoutThread(try!(timer_event_port.recv()))) } else { panic!("unexpected select result!") } } - pub fn script_chan(&self) -> Box<ScriptChan + Send> { - box WorkerThreadWorkerChan { - sender: self.own_sender.clone(), - worker: self.worker.borrow().as_ref().unwrap().clone(), - } - } - pub fn pipeline(&self) -> PipelineId { self.id } pub fn process_event(&self, msg: CommonScriptMsg) { - self.handle_script_event(WorkerScriptMsg::Common(msg)); - } - - pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) { - let (tx, rx) = channel(); - let chan = box SendableWorkerScriptChan { - sender: tx, - worker: self.worker.borrow().as_ref().unwrap().clone(), - }; - (chan, box rx) + self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg))); } } diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs index 358331afffc..e20b7e06c47 100644 --- a/components/script/dom/serviceworkerregistration.rs +++ b/components/script/dom/serviceworkerregistration.rs @@ -11,6 +11,8 @@ use dom::bindings::str::USVString; use dom::eventtarget::EventTarget; use dom::serviceworker::ServiceWorker; use dom::serviceworkercontainer::Controllable; +use dom::workerglobalscope::prepare_workerscope_init; +use script_traits::{WorkerScriptLoadOrigin, ScopeThings}; use url::Url; #[dom_struct] @@ -19,7 +21,7 @@ pub struct ServiceWorkerRegistration { active: Option<JS<ServiceWorker>>, installing: Option<JS<ServiceWorker>>, waiting: Option<JS<ServiceWorker>>, - scope: String, + scope: String } impl ServiceWorkerRegistration { @@ -29,7 +31,7 @@ impl ServiceWorkerRegistration { active: Some(JS::from_ref(active_sw)), installing: None, waiting: None, - scope: scope + scope: scope, } } #[allow(unrooted_must_root)] @@ -37,11 +39,47 @@ impl ServiceWorkerRegistration { script_url: Url, scope: String, container: &Controllable) -> Root<ServiceWorkerRegistration> { - let active_worker = ServiceWorker::init_service_worker(global, script_url, true); + let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), true); active_worker.set_transition_state(ServiceWorkerState::Installed); container.set_controller(&*active_worker.clone()); reflect_dom_object(box ServiceWorkerRegistration::new_inherited(&*active_worker, scope), global, Wrap) } + + pub fn get_installed(&self) -> &ServiceWorker { + self.active.as_ref().unwrap() + } + + pub fn create_scope_things(global: GlobalRef, script_url: Url) -> ScopeThings { + let worker_load_origin = WorkerScriptLoadOrigin { + referrer_url: None, + referrer_policy: None, + pipeline_id: Some(global.pipeline()) + }; + + let worker_id = global.get_next_worker_id(); + let init = prepare_workerscope_init(global, None); + ScopeThings { + script_url: script_url, + pipeline_id: global.pipeline(), + init: init, + worker_load_origin: worker_load_origin, + devtools_chan: global.devtools_chan(), + worker_id: worker_id + } + } +} + +pub fn longest_prefix_match(stored_scope: &Url, potential_match: &Url) -> bool { + if stored_scope.origin() != potential_match.origin() { + return false; + } + let scope_chars = stored_scope.path().chars(); + let matching_chars = potential_match.path().chars(); + if scope_chars.count() > matching_chars.count() { + return false; + } + + stored_scope.path().chars().zip(potential_match.path().chars()).all(|(scope, matched)| scope == matched) } impl ServiceWorkerRegistrationMethods for ServiceWorkerRegistration { diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index 884ac6c8653..a28612416fc 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -171,13 +171,24 @@ impl AsyncResponseListener for ParserContext { Some(parser) => parser.root(), None => return, }; - parser.r().document().finish_load(LoadType::PageSource(self.url.clone())); - if let Err(err) = status { - debug!("Failed to load page URL {}, error: {:?}", self.url, err); + if let Err(NetworkError::Internal(ref reason)) = status { + // Show an error page for network errors, + // certificate errors are handled earlier. + self.is_synthesized_document = true; + let parser = parser.r(); + let page_bytes = read_resource_file("neterror.html").unwrap(); + let page = String::from_utf8(page_bytes).unwrap(); + let page = page.replace("${reason}", reason); + parser.pending_input().borrow_mut().push(page); + parser.parse_sync(); + } else if let Err(err) = status { // TODO(Savago): we should send a notification to callers #5463. + debug!("Failed to load page URL {}, error: {:?}", self.url, err); } + parser.r().document().finish_load(LoadType::PageSource(self.url.clone())); + parser.r().last_chunk_received().set(true); if !parser.r().is_suspended() { parser.r().parse_sync(); diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index d927c5ba213..d6d1e1968f8 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -19,7 +19,6 @@ use net_traits::IpcSend; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use script_thread::{Runnable, ScriptThread}; use task_source::TaskSource; -use task_source::dom_manipulation::DOMManipulationTask; use url::Url; #[dom_struct] @@ -159,10 +158,11 @@ impl Storage { new_value: Option<String>) { let global_root = self.global(); let global_ref = global_root.r(); - let task_source = global_ref.as_window().dom_manipulation_task_source(); + let window = global_ref.as_window(); + let task_source = window.dom_manipulation_task_source(); let trusted_storage = Trusted::new(self); - task_source.queue(DOMManipulationTask::Runnable( - box StorageEventRunnable::new(trusted_storage, key, old_value, new_value))).unwrap(); + task_source.queue(box StorageEventRunnable::new(trusted_storage, key, old_value, new_value), + global_ref).unwrap(); } } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 64fb6fb7578..13579d71330 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -9,8 +9,9 @@ use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::TestBindingBinding; use dom::bindings::codegen::Bindings::TestBindingBinding::{TestBindingMethods, TestDictionary}; use dom::bindings::codegen::Bindings::TestBindingBinding::{TestDictionaryDefaults, TestEnum}; -use dom::bindings::codegen::UnionTypes::{BlobOrBoolean, BlobOrBlobSequence}; +use dom::bindings::codegen::UnionTypes::{BlobOrBoolean, BlobOrBlobSequence, LongOrLongSequenceSequence}; use dom::bindings::codegen::UnionTypes::{BlobOrString, BlobOrUnsignedLong, EventOrString}; +use dom::bindings::codegen::UnionTypes::{ByteStringOrLong, ByteStringSequenceOrLongOrString, ByteStringSequenceOrLong}; use dom::bindings::codegen::UnionTypes::{EventOrUSVString, HTMLElementOrLong}; use dom::bindings::codegen::UnionTypes::{HTMLElementOrUnsignedLongOrStringOrBoolean, LongSequenceOrBoolean}; use dom::bindings::codegen::UnionTypes::{StringOrLongSequence, StringOrStringSequence, StringSequenceOrUnsignedLong}; @@ -132,6 +133,10 @@ impl TestBindingMethods for TestBinding { BlobOrUnsignedLong::UnsignedLong(0u32) } fn SetUnion8Attribute(&self, _: BlobOrUnsignedLong) {} + fn Union9Attribute(&self) -> ByteStringOrLong { + ByteStringOrLong::ByteString(ByteString::new(vec!())) + } + fn SetUnion9Attribute(&self, _: ByteStringOrLong) {} fn ArrayAttribute(&self, _: *mut JSContext) -> *mut JSObject { NullValue().to_object_or_null() } fn AnyAttribute(&self, _: *mut JSContext) -> JSVal { NullValue() } fn SetAnyAttribute(&self, _: *mut JSContext, _: HandleValue) {} @@ -210,6 +215,10 @@ impl TestBindingMethods for TestBinding { Some(StringOrBoolean::Boolean(true)) } fn SetUnion5AttributeNullable(&self, _: Option<StringOrBoolean>) {} + fn GetUnion6AttributeNullable(&self) -> Option<ByteStringOrLong> { + Some(ByteStringOrLong::ByteString(ByteString::new(vec!()))) + } + fn SetUnion6AttributeNullable(&self, _: Option<ByteStringOrLong>) {} fn BinaryRenamedMethod(&self) -> () {} fn ReceiveVoid(&self) -> () {} fn ReceiveBoolean(&self) -> bool { false } @@ -245,6 +254,10 @@ impl TestBindingMethods for TestBinding { fn ReceiveUnion9(&self) -> HTMLElementOrUnsignedLongOrStringOrBoolean { HTMLElementOrUnsignedLongOrStringOrBoolean::Boolean(true) } + fn ReceiveUnion10(&self) -> ByteStringOrLong { ByteStringOrLong::ByteString(ByteString::new(vec!())) } + fn ReceiveUnion11(&self) -> ByteStringSequenceOrLongOrString { + ByteStringSequenceOrLongOrString::ByteStringSequence(vec!(ByteString::new(vec!()))) + } fn ReceiveSequence(&self) -> Vec<i32> { vec![1] } fn ReceiveInterfaceSequence(&self) -> Vec<Root<Blob>> { vec![Blob::new(self.global().r(), BlobImpl::new_from_bytes(vec![]), "".to_owned())] @@ -286,6 +299,9 @@ impl TestBindingMethods for TestBinding { fn ReceiveNullableUnion5(&self) -> Option<UnsignedLongOrBoolean> { Some(UnsignedLongOrBoolean::UnsignedLong(0u32)) } + fn ReceiveNullableUnion6(&self) -> Option<ByteStringOrLong> { + Some(ByteStringOrLong::ByteString(ByteString::new(vec!()))) + } fn ReceiveNullableSequence(&self) -> Option<Vec<i32>> { Some(vec![1]) } fn ReceiveTestDictionaryWithSuccessOnKeyword(&self) -> TestDictionary { TestDictionary { @@ -382,6 +398,7 @@ impl TestBindingMethods for TestBinding { fn PassUnion5(&self, _: StringOrBoolean) {} fn PassUnion6(&self, _: UnsignedLongOrBoolean) {} fn PassUnion7(&self, _: StringSequenceOrUnsignedLong) {} + fn PassUnion8(&self, _: ByteStringSequenceOrLong) {} fn PassAny(&self, _: *mut JSContext, _: HandleValue) {} fn PassObject(&self, _: *mut JSContext, _: *mut JSObject) {} fn PassCallbackFunction(&self, _: Rc<Function>) {} @@ -414,6 +431,7 @@ impl TestBindingMethods for TestBinding { fn PassNullableUnion3(&self, _: Option<StringOrLongSequence>) {} fn PassNullableUnion4(&self, _: Option<LongSequenceOrBoolean>) {} fn PassNullableUnion5(&self, _: Option<UnsignedLongOrBoolean>) {} + fn PassNullableUnion6(&self, _: Option<ByteStringOrLong>) {} fn PassNullableCallbackFunction(&self, _: Option<Rc<Function>>) {} fn PassNullableCallbackInterface(&self, _: Option<Rc<EventListener>>) {} fn PassNullableSequence(&self, _: Option<Vec<i32>>) {} @@ -441,6 +459,7 @@ impl TestBindingMethods for TestBinding { fn PassOptionalUnion3(&self, _: Option<StringOrLongSequence>) {} fn PassOptionalUnion4(&self, _: Option<LongSequenceOrBoolean>) {} fn PassOptionalUnion5(&self, _: Option<UnsignedLongOrBoolean>) {} + fn PassOptionalUnion6(&self, _: Option<ByteStringOrLong>) {} fn PassOptionalAny(&self, _: *mut JSContext, _: HandleValue) {} fn PassOptionalObject(&self, _: *mut JSContext, _: Option<*mut JSObject>) {} fn PassOptionalCallbackFunction(&self, _: Option<Rc<Function>>) {} @@ -471,6 +490,7 @@ impl TestBindingMethods for TestBinding { fn PassOptionalNullableUnion3(&self, _: Option<Option<StringOrLongSequence>>) {} fn PassOptionalNullableUnion4(&self, _: Option<Option<LongSequenceOrBoolean>>) {} fn PassOptionalNullableUnion5(&self, _: Option<Option<UnsignedLongOrBoolean>>) {} + fn PassOptionalNullableUnion6(&self, _: Option<Option<ByteStringOrLong>>) {} fn PassOptionalNullableCallbackFunction(&self, _: Option<Option<Rc<Function>>>) {} fn PassOptionalNullableCallbackInterface(&self, _: Option<Option<Rc<EventListener>>>) {} fn PassOptionalNullableSequence(&self, _: Option<Option<Vec<i32>>>) {} @@ -555,6 +575,7 @@ impl TestBindingMethods for TestBinding { fn PassVariadicUnion4(&self, _: Vec<BlobOrBoolean>) {} fn PassVariadicUnion5(&self, _: Vec<StringOrUnsignedLong>) {} fn PassVariadicUnion6(&self, _: Vec<UnsignedLongOrBoolean>) {} + fn PassVariadicUnion7(&self, _: Vec<ByteStringOrLong>) {} fn PassVariadicAny(&self, _: *mut JSContext, _: Vec<HandleValue>) {} fn PassVariadicObject(&self, _: *mut JSContext, _: Vec<*mut JSObject>) {} fn BooleanMozPreference(&self, pref_name: DOMString) -> bool { @@ -572,6 +593,17 @@ impl TestBindingMethods for TestBinding { fn FuncControlledMethodDisabled(&self) {} fn FuncControlledMethodEnabled(&self) {} + fn PassSequenceSequence(&self, _seq: Vec<Vec<i32>>) {} + fn ReturnSequenceSequence(&self) -> Vec<Vec<i32>> { vec![] } + fn PassUnionSequenceSequence(&self, seq: LongOrLongSequenceSequence) { + match seq { + LongOrLongSequenceSequence::Long(_) => (), + LongOrLongSequenceSequence::LongSequenceSequence(seq) => { + let _seq: Vec<Vec<i32>> = seq; + } + } + } + #[allow(unsafe_code)] fn CrashHard(&self) { static READ_ONLY_VALUE: i32 = 0; @@ -581,6 +613,10 @@ impl TestBindingMethods for TestBinding { } } + fn AdvanceClock(&self, ms: i32) { + self.global().r().as_window().advance_animation_clock(ms); + } + fn Panic(&self) { panic!("explicit panic from script") } } diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs index 961d3c2fd29..81c806de806 100644 --- a/components/script/dom/url.rs +++ b/components/script/dom/url.rs @@ -15,8 +15,8 @@ use dom::urlhelper::UrlHelper; use dom::urlsearchparams::URLSearchParams; use ipc_channel::ipc; use net_traits::IpcSend; -use net_traits::blob_url_store::parse_blob_url; -use net_traits::filemanager_thread::{FileOrigin, SelectedFileId, FileManagerThreadMsg}; +use net_traits::blob_url_store::{get_blob_origin, parse_blob_url}; +use net_traits::filemanager_thread::{SelectedFileId, FileManagerThreadMsg}; use std::borrow::ToOwned; use std::default::Default; use url::quirks::domain_to_unicode; @@ -117,7 +117,7 @@ impl URL { pub fn CreateObjectURL(global: GlobalRef, blob: &Blob) -> DOMString { /// XXX: Second field is an unicode-serialized Origin, it is a temporary workaround /// and should not be trusted. See issue https://github.com/servo/servo/issues/11722 - let origin = URL::get_blob_origin(&global.get_url()); + let origin = get_blob_origin(&global.get_url()); if blob.IsClosed() { // Generate a dummy id @@ -141,10 +141,10 @@ impl URL { NOTE: The first step is unnecessary, since closed blobs do not exist in the store */ - let origin = global.get_url().origin().unicode_serialization(); + let origin = get_blob_origin(&global.get_url()); if let Ok(url) = Url::parse(&url) { - if let Some((id, _)) = parse_blob_url(&url) { + if let Ok((id, _, _)) = parse_blob_url(&url) { let filemanager = global.resource_threads().sender(); let id = SelectedFileId(id.simple().to_string()); let (tx, rx) = ipc::channel().unwrap(); @@ -172,18 +172,6 @@ impl URL { result } - - /* NOTE(izgzhen): WebKit will return things like blob:file:///XXX - while Chrome will return blob:null/XXX - This is not well-specified, and I prefer the WebKit way here - */ - fn get_blob_origin(url: &Url) -> FileOrigin { - if url.scheme() == "file" { - "file://".to_string() - } else { - url.origin().unicode_serialization() - } - } } impl URLMethods for URL { diff --git a/components/script/dom/userscripts.rs b/components/script/dom/userscripts.rs index 25490fb7726..e1c071e83c7 100644 --- a/components/script/dom/userscripts.rs +++ b/components/script/dom/userscripts.rs @@ -24,9 +24,12 @@ pub fn load_script(head: &HTMLHeadElement) { let doc = doc.r(); let path = if &**path_str == "" { - let mut p = resources_dir_path(); - p.push("user-agent-js"); - p + if let Ok(mut p) = resources_dir_path() { + p.push("user-agent-js"); + p + } else { + return + } } else { PathBuf::from(path_str) }; diff --git a/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl b/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl index cd0d393e22e..53996ee3965 100644 --- a/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl +++ b/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl @@ -8,4 +8,6 @@ [Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/); attribute EventHandler onmessage; + + void close(); }; diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index 09b82109ae8..6ea8d3e7e91 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -82,7 +82,7 @@ partial /*sealed*/ interface Document { [/*PutForwards=href, */Unforgeable] readonly attribute Location? location; readonly attribute DOMString domain; - // readonly attribute DOMString referrer; + readonly attribute DOMString referrer; [Throws] attribute DOMString cookie; readonly attribute DOMString lastModified; diff --git a/components/script/dom/webidls/HTMLAnchorElement.webidl b/components/script/dom/webidls/HTMLAnchorElement.webidl index c728744e495..f78d1dae6dd 100644 --- a/components/script/dom/webidls/HTMLAnchorElement.webidl +++ b/components/script/dom/webidls/HTMLAnchorElement.webidl @@ -11,7 +11,6 @@ */ // https://html.spec.whatwg.org/multipage/#htmlanchorelement -[Exposed=(Window,Worker)] interface HTMLAnchorElement : HTMLElement { attribute DOMString target; // attribute DOMString download; diff --git a/components/script/dom/webidls/HTMLAppletElement.webidl b/components/script/dom/webidls/HTMLAppletElement.webidl index efb3d24b2e7..9cfeb4183df 100644 --- a/components/script/dom/webidls/HTMLAppletElement.webidl +++ b/components/script/dom/webidls/HTMLAppletElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlappletelement -[Exposed=(Window,Worker)] interface HTMLAppletElement : HTMLElement { // attribute DOMString align; // attribute DOMString alt; diff --git a/components/script/dom/webidls/HTMLAreaElement.webidl b/components/script/dom/webidls/HTMLAreaElement.webidl index f39db4fa4d2..14883df3613 100644 --- a/components/script/dom/webidls/HTMLAreaElement.webidl +++ b/components/script/dom/webidls/HTMLAreaElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlareaelement -[Exposed=(Window,Worker)] interface HTMLAreaElement : HTMLElement { // attribute DOMString alt; // attribute DOMString coords; diff --git a/components/script/dom/webidls/HTMLAudioElement.webidl b/components/script/dom/webidls/HTMLAudioElement.webidl index df0710b1856..09ad8a7cdb3 100644 --- a/components/script/dom/webidls/HTMLAudioElement.webidl +++ b/components/script/dom/webidls/HTMLAudioElement.webidl @@ -4,5 +4,4 @@ // https://html.spec.whatwg.org/multipage/#htmlaudioelement //[NamedConstructor=Audio(optional DOMString src)] -[Exposed=(Window,Worker)] interface HTMLAudioElement : HTMLMediaElement {}; diff --git a/components/script/dom/webidls/HTMLBRElement.webidl b/components/script/dom/webidls/HTMLBRElement.webidl index 4d811f3e285..ab277396bdd 100644 --- a/components/script/dom/webidls/HTMLBRElement.webidl +++ b/components/script/dom/webidls/HTMLBRElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbrelement -[Exposed=(Window,Worker)] interface HTMLBRElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLBaseElement.webidl b/components/script/dom/webidls/HTMLBaseElement.webidl index dee9895c8ef..a13be544cb9 100644 --- a/components/script/dom/webidls/HTMLBaseElement.webidl +++ b/components/script/dom/webidls/HTMLBaseElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbaseelement -[Exposed=(Window,Worker)] interface HTMLBaseElement : HTMLElement { attribute DOMString href; // attribute DOMString target; diff --git a/components/script/dom/webidls/HTMLBodyElement.webidl b/components/script/dom/webidls/HTMLBodyElement.webidl index 31097e75614..36c6f4d64e3 100644 --- a/components/script/dom/webidls/HTMLBodyElement.webidl +++ b/components/script/dom/webidls/HTMLBodyElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#the-body-element -[Exposed=(Window,Worker)] interface HTMLBodyElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLButtonElement.webidl b/components/script/dom/webidls/HTMLButtonElement.webidl index a5c689cbc46..7f663fd305f 100644 --- a/components/script/dom/webidls/HTMLButtonElement.webidl +++ b/components/script/dom/webidls/HTMLButtonElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlbuttonelement -[Exposed=(Window,Worker)] interface HTMLButtonElement : HTMLElement { // attribute boolean autofocus; attribute boolean disabled; diff --git a/components/script/dom/webidls/HTMLDListElement.webidl b/components/script/dom/webidls/HTMLDListElement.webidl index e0420cf8418..b6275107db5 100644 --- a/components/script/dom/webidls/HTMLDListElement.webidl +++ b/components/script/dom/webidls/HTMLDListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldlistelement -[Exposed=(Window,Worker)] interface HTMLDListElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLDataElement.webidl b/components/script/dom/webidls/HTMLDataElement.webidl index e0b2aa2cafa..be932250678 100644 --- a/components/script/dom/webidls/HTMLDataElement.webidl +++ b/components/script/dom/webidls/HTMLDataElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldataelement -[Exposed=(Window,Worker)] interface HTMLDataElement : HTMLElement { // attribute DOMString value; }; diff --git a/components/script/dom/webidls/HTMLDataListElement.webidl b/components/script/dom/webidls/HTMLDataListElement.webidl index c970ae495fb..b8673b21c77 100644 --- a/components/script/dom/webidls/HTMLDataListElement.webidl +++ b/components/script/dom/webidls/HTMLDataListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldatalistelement -[Exposed=(Window,Worker)] interface HTMLDataListElement : HTMLElement { readonly attribute HTMLCollection options; }; diff --git a/components/script/dom/webidls/HTMLDetailsElement.webidl b/components/script/dom/webidls/HTMLDetailsElement.webidl index 8dbffdea064..811465c1c02 100644 --- a/components/script/dom/webidls/HTMLDetailsElement.webidl +++ b/components/script/dom/webidls/HTMLDetailsElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldetailselement -[Exposed=(Window,Worker)] interface HTMLDetailsElement : HTMLElement { attribute boolean open; }; diff --git a/components/script/dom/webidls/HTMLDialogElement.webidl b/components/script/dom/webidls/HTMLDialogElement.webidl index 82d11ea2cae..78a14e1e2a0 100644 --- a/components/script/dom/webidls/HTMLDialogElement.webidl +++ b/components/script/dom/webidls/HTMLDialogElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldialogelement -[Exposed=(Window,Worker)] interface HTMLDialogElement : HTMLElement { attribute boolean open; attribute DOMString returnValue; diff --git a/components/script/dom/webidls/HTMLDirectoryElement.webidl b/components/script/dom/webidls/HTMLDirectoryElement.webidl index 4a1d8af74ab..5df65cd90c2 100644 --- a/components/script/dom/webidls/HTMLDirectoryElement.webidl +++ b/components/script/dom/webidls/HTMLDirectoryElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldirectoryelement -[Exposed=(Window,Worker)] interface HTMLDirectoryElement : HTMLElement { // attribute boolean compact; }; diff --git a/components/script/dom/webidls/HTMLDivElement.webidl b/components/script/dom/webidls/HTMLDivElement.webidl index 827dfe7ab49..46ee67ee0e5 100644 --- a/components/script/dom/webidls/HTMLDivElement.webidl +++ b/components/script/dom/webidls/HTMLDivElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmldivelement -[Exposed=(Window,Worker)] interface HTMLDivElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLEmbedElement.webidl b/components/script/dom/webidls/HTMLEmbedElement.webidl index 3e4063c9377..26fa4c3ea5a 100644 --- a/components/script/dom/webidls/HTMLEmbedElement.webidl +++ b/components/script/dom/webidls/HTMLEmbedElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlembedelement -[Exposed=(Window,Worker)] interface HTMLEmbedElement : HTMLElement { // attribute DOMString src; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLFieldSetElement.webidl b/components/script/dom/webidls/HTMLFieldSetElement.webidl index 6c05b23f9ae..d041cdd612f 100644 --- a/components/script/dom/webidls/HTMLFieldSetElement.webidl +++ b/components/script/dom/webidls/HTMLFieldSetElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlfieldsetelement -[Exposed=(Window,Worker)] interface HTMLFieldSetElement : HTMLElement { attribute boolean disabled; readonly attribute HTMLFormElement? form; diff --git a/components/script/dom/webidls/HTMLFontElement.webidl b/components/script/dom/webidls/HTMLFontElement.webidl index 7c524eb0a4d..74db3f45057 100644 --- a/components/script/dom/webidls/HTMLFontElement.webidl +++ b/components/script/dom/webidls/HTMLFontElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlfontelement -[Exposed=(Window,Worker)] interface HTMLFontElement : HTMLElement { [TreatNullAs=EmptyString] attribute DOMString color; attribute DOMString face; diff --git a/components/script/dom/webidls/HTMLFrameElement.webidl b/components/script/dom/webidls/HTMLFrameElement.webidl index 0de80f7df1e..ecac61f6860 100644 --- a/components/script/dom/webidls/HTMLFrameElement.webidl +++ b/components/script/dom/webidls/HTMLFrameElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlframeelement -[Exposed=(Window,Worker)] interface HTMLFrameElement : HTMLElement { // attribute DOMString name; // attribute DOMString scrolling; diff --git a/components/script/dom/webidls/HTMLFrameSetElement.webidl b/components/script/dom/webidls/HTMLFrameSetElement.webidl index 34ab7a42289..5addd41d253 100644 --- a/components/script/dom/webidls/HTMLFrameSetElement.webidl +++ b/components/script/dom/webidls/HTMLFrameSetElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlframesetelement -[Exposed=(Window,Worker)] interface HTMLFrameSetElement : HTMLElement { // attribute DOMString cols; // attribute DOMString rows; diff --git a/components/script/dom/webidls/HTMLParagraphElement.webidl b/components/script/dom/webidls/HTMLParagraphElement.webidl index ff2facc455d..a96c6dc6f81 100644 --- a/components/script/dom/webidls/HTMLParagraphElement.webidl +++ b/components/script/dom/webidls/HTMLParagraphElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlparagraphelement -[Exposed=(Window,Worker)] interface HTMLParagraphElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLParamElement.webidl b/components/script/dom/webidls/HTMLParamElement.webidl index 1b0805480a6..9648c9f87ce 100644 --- a/components/script/dom/webidls/HTMLParamElement.webidl +++ b/components/script/dom/webidls/HTMLParamElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlparamelement -[Exposed=(Window,Worker)] interface HTMLParamElement : HTMLElement { // attribute DOMString name; // attribute DOMString value; diff --git a/components/script/dom/webidls/HTMLPreElement.webidl b/components/script/dom/webidls/HTMLPreElement.webidl index 7d65e225d4f..ea0df151020 100644 --- a/components/script/dom/webidls/HTMLPreElement.webidl +++ b/components/script/dom/webidls/HTMLPreElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlpreelement -[Exposed=(Window,Worker)] interface HTMLPreElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLProgressElement.webidl b/components/script/dom/webidls/HTMLProgressElement.webidl index 852e683b1f7..cf69566ecdd 100644 --- a/components/script/dom/webidls/HTMLProgressElement.webidl +++ b/components/script/dom/webidls/HTMLProgressElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlprogresselement -[Exposed=(Window,Worker)] interface HTMLProgressElement : HTMLElement { // attribute double value; // attribute double max; diff --git a/components/script/dom/webidls/HTMLQuoteElement.webidl b/components/script/dom/webidls/HTMLQuoteElement.webidl index 6741d7b4041..e546f151d49 100644 --- a/components/script/dom/webidls/HTMLQuoteElement.webidl +++ b/components/script/dom/webidls/HTMLQuoteElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlquoteelement -[Exposed=(Window,Worker)] interface HTMLQuoteElement : HTMLElement { // attribute DOMString cite; }; diff --git a/components/script/dom/webidls/HTMLSelectElement.webidl b/components/script/dom/webidls/HTMLSelectElement.webidl index 2bcbbf098e4..ba84d183a72 100644 --- a/components/script/dom/webidls/HTMLSelectElement.webidl +++ b/components/script/dom/webidls/HTMLSelectElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlselectelement -[Exposed=(Window,Worker)] interface HTMLSelectElement : HTMLElement { // attribute boolean autofocus; attribute boolean disabled; diff --git a/components/script/dom/webidls/HTMLSourceElement.webidl b/components/script/dom/webidls/HTMLSourceElement.webidl index a631876b42e..738a545713a 100644 --- a/components/script/dom/webidls/HTMLSourceElement.webidl +++ b/components/script/dom/webidls/HTMLSourceElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlsourceelement -[Exposed=(Window,Worker)] interface HTMLSourceElement : HTMLElement { // attribute DOMString src; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLSpanElement.webidl b/components/script/dom/webidls/HTMLSpanElement.webidl index 082ba45cf8b..a74967536a1 100644 --- a/components/script/dom/webidls/HTMLSpanElement.webidl +++ b/components/script/dom/webidls/HTMLSpanElement.webidl @@ -3,5 +3,4 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlspanelement -[Exposed=(Window,Worker)] interface HTMLSpanElement : HTMLElement {}; diff --git a/components/script/dom/webidls/HTMLStyleElement.webidl b/components/script/dom/webidls/HTMLStyleElement.webidl index 4bc4430a38c..dd766f41d22 100644 --- a/components/script/dom/webidls/HTMLStyleElement.webidl +++ b/components/script/dom/webidls/HTMLStyleElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlstyleelement -[Exposed=(Window,Worker)] interface HTMLStyleElement : HTMLElement { // attribute DOMString media; // attribute DOMString type; diff --git a/components/script/dom/webidls/HTMLTableCaptionElement.webidl b/components/script/dom/webidls/HTMLTableCaptionElement.webidl index 0860aa7e796..b405d23ed40 100644 --- a/components/script/dom/webidls/HTMLTableCaptionElement.webidl +++ b/components/script/dom/webidls/HTMLTableCaptionElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecaptionelement -[Exposed=(Window,Worker)] interface HTMLTableCaptionElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableCellElement.webidl b/components/script/dom/webidls/HTMLTableCellElement.webidl index 2264d56b5e2..33863b3dc20 100644 --- a/components/script/dom/webidls/HTMLTableCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableCellElement.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecellelement -[Abstract, Exposed=(Window,Worker)] +[Abstract] interface HTMLTableCellElement : HTMLElement { attribute unsigned long colSpan; // attribute unsigned long rowSpan; diff --git a/components/script/dom/webidls/HTMLTableColElement.webidl b/components/script/dom/webidls/HTMLTableColElement.webidl index 3868de31272..69188251443 100644 --- a/components/script/dom/webidls/HTMLTableColElement.webidl +++ b/components/script/dom/webidls/HTMLTableColElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablecolelement -[Exposed=(Window,Worker)] interface HTMLTableColElement : HTMLElement { // attribute unsigned long span; diff --git a/components/script/dom/webidls/HTMLTableDataCellElement.webidl b/components/script/dom/webidls/HTMLTableDataCellElement.webidl index 7c286df77e4..208ed76d692 100644 --- a/components/script/dom/webidls/HTMLTableDataCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableDataCellElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltabledatacellelement -[Exposed=(Window,Worker)] interface HTMLTableDataCellElement : HTMLTableCellElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableElement.webidl b/components/script/dom/webidls/HTMLTableElement.webidl index c97d24fd57b..f0d8e19d0eb 100644 --- a/components/script/dom/webidls/HTMLTableElement.webidl +++ b/components/script/dom/webidls/HTMLTableElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltableelement -[Exposed=(Window,Worker)] interface HTMLTableElement : HTMLElement { attribute HTMLTableCaptionElement? caption; HTMLTableCaptionElement createCaption(); @@ -20,7 +19,7 @@ interface HTMLTableElement : HTMLElement { HTMLTableSectionElement createTBody(); readonly attribute HTMLCollection rows; [Throws] HTMLTableRowElement insertRow(optional long index = -1); - //void deleteRow(long index); + [Throws] void deleteRow(long index); // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl b/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl index fb3e7126672..9bf8f1fc950 100644 --- a/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl +++ b/components/script/dom/webidls/HTMLTableHeaderCellElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltableheadercellelement -[Exposed=(Window,Worker)] interface HTMLTableHeaderCellElement : HTMLTableCellElement { // attribute DOMString scope; // attribute DOMString abbr; diff --git a/components/script/dom/webidls/HTMLTableRowElement.webidl b/components/script/dom/webidls/HTMLTableRowElement.webidl index 75898c577e1..9d4b0655cad 100644 --- a/components/script/dom/webidls/HTMLTableRowElement.webidl +++ b/components/script/dom/webidls/HTMLTableRowElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablerowelement -[Exposed=(Window,Worker)] interface HTMLTableRowElement : HTMLElement { readonly attribute long rowIndex; readonly attribute long sectionRowIndex; diff --git a/components/script/dom/webidls/HTMLTableSectionElement.webidl b/components/script/dom/webidls/HTMLTableSectionElement.webidl index dd9d1c654f1..979d8030ffd 100644 --- a/components/script/dom/webidls/HTMLTableSectionElement.webidl +++ b/components/script/dom/webidls/HTMLTableSectionElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltablesectionelement -[Exposed=(Window,Worker)] interface HTMLTableSectionElement : HTMLElement { readonly attribute HTMLCollection rows; [Throws] diff --git a/components/script/dom/webidls/HTMLTemplateElement.webidl b/components/script/dom/webidls/HTMLTemplateElement.webidl index 7506f9a28e0..b3383de69d2 100644 --- a/components/script/dom/webidls/HTMLTemplateElement.webidl +++ b/components/script/dom/webidls/HTMLTemplateElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltemplateelement -[Exposed=(Window,Worker)] interface HTMLTemplateElement : HTMLElement { readonly attribute DocumentFragment content; }; diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 32a2ba43ccf..f92e662c354 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltextareaelement -[Exposed=(Window,Worker)] interface HTMLTextAreaElement : HTMLElement { // attribute DOMString autocomplete; // attribute boolean autofocus; diff --git a/components/script/dom/webidls/HTMLTimeElement.webidl b/components/script/dom/webidls/HTMLTimeElement.webidl index dbd80686b0c..21f9dcf090e 100644 --- a/components/script/dom/webidls/HTMLTimeElement.webidl +++ b/components/script/dom/webidls/HTMLTimeElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltimeelement -[Exposed=(Window,Worker)] interface HTMLTimeElement : HTMLElement { // attribute DOMString dateTime; }; diff --git a/components/script/dom/webidls/HTMLTitleElement.webidl b/components/script/dom/webidls/HTMLTitleElement.webidl index 9332cae40a7..10373be7e4b 100644 --- a/components/script/dom/webidls/HTMLTitleElement.webidl +++ b/components/script/dom/webidls/HTMLTitleElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltitleelement -[Exposed=(Window,Worker)] interface HTMLTitleElement : HTMLElement { [Pure] attribute DOMString text; diff --git a/components/script/dom/webidls/HTMLTrackElement.webidl b/components/script/dom/webidls/HTMLTrackElement.webidl index 9828139bee2..55733235321 100644 --- a/components/script/dom/webidls/HTMLTrackElement.webidl +++ b/components/script/dom/webidls/HTMLTrackElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmltrackelement -[Exposed=(Window,Worker)] interface HTMLTrackElement : HTMLElement { // attribute DOMString kind; // attribute DOMString src; diff --git a/components/script/dom/webidls/HTMLUListElement.webidl b/components/script/dom/webidls/HTMLUListElement.webidl index 6abaf544b7f..91a79c7f925 100644 --- a/components/script/dom/webidls/HTMLUListElement.webidl +++ b/components/script/dom/webidls/HTMLUListElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlulistelement -[Exposed=(Window,Worker)] interface HTMLUListElement : HTMLElement { // also has obsolete members }; diff --git a/components/script/dom/webidls/HTMLUnknownElement.webidl b/components/script/dom/webidls/HTMLUnknownElement.webidl index 624d7d8541d..acf5a47a996 100644 --- a/components/script/dom/webidls/HTMLUnknownElement.webidl +++ b/components/script/dom/webidls/HTMLUnknownElement.webidl @@ -11,6 +11,5 @@ * and create derivative works of this document. */ -[Exposed=(Window,Worker)] interface HTMLUnknownElement : HTMLElement { }; diff --git a/components/script/dom/webidls/HTMLVideoElement.webidl b/components/script/dom/webidls/HTMLVideoElement.webidl index 3af425cc06b..5e7c9cb9fce 100644 --- a/components/script/dom/webidls/HTMLVideoElement.webidl +++ b/components/script/dom/webidls/HTMLVideoElement.webidl @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#htmlvideoelement -[Exposed=(Window,Worker)] interface HTMLVideoElement : HTMLMediaElement { // attribute unsigned long width; // attribute unsigned long height; diff --git a/components/script/dom/webidls/Headers.webidl b/components/script/dom/webidls/Headers.webidl new file mode 100644 index 00000000000..038dbe46f74 --- /dev/null +++ b/components/script/dom/webidls/Headers.webidl @@ -0,0 +1,22 @@ +/* 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://fetch.spec.whatwg.org/#headers-class + +/* typedef (Headers or sequence<sequence<ByteString>>) HeadersInit; */ + +/* [Constructor(optional HeadersInit init),*/ + [Exposed=(Window,Worker)] + +interface Headers { + [Throws] + void append(ByteString name, ByteString value); +}; + +/* void delete(ByteString name); + * ByteString? get(ByteString name); + * boolean has(ByteString name); + * void set(ByteString name, ByteString value); + * iterable<ByteString, ByteString>; + * }; */ diff --git a/components/script/dom/webidls/History.webidl b/components/script/dom/webidls/History.webidl new file mode 100644 index 00000000000..04742d52601 --- /dev/null +++ b/components/script/dom/webidls/History.webidl @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// enum ScrollRestoration { "auto", "manual" }; + +// https://html.spec.whatwg.org/multipage/#the-history-interface +[Exposed=(Window,Worker)] +interface History { + // readonly attribute unsigned long length; + // attribute ScrollRestoration scrollRestoration; + // readonly attribute any state; + void go(optional long delta = 0); + void back(); + void forward(); + // void pushState(any data, DOMString title, optional USVString? url = null); + // void replaceState(any data, DOMString title, optional USVString? url = null); +}; diff --git a/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl b/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl index cbe028c129b..35e4b98f9d5 100644 --- a/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl +++ b/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl @@ -4,7 +4,8 @@ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-global-scope -[Global=(Worker,ServiceWorker), Pref="dom.serviceworker.enabled"] +[Global=(Worker,ServiceWorker), Exposed=ServiceWorker, + Pref="dom.serviceworker.enabled"] interface ServiceWorkerGlobalScope : WorkerGlobalScope { // A container for a list of Client objects that correspond to // browsing contexts (or shared workers) that are on the origin of this SW diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index 355141a4d92..9fc8a9e3bb6 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -110,6 +110,7 @@ interface TestBinding { attribute (unsigned long or boolean) union6Attribute; attribute (Blob or boolean) union7Attribute; attribute (Blob or unsigned long) union8Attribute; + attribute (ByteString or long) union9Attribute; readonly attribute Uint8ClampedArray arrayAttribute; attribute any anyAttribute; attribute object objectAttribute; @@ -139,6 +140,7 @@ interface TestBinding { attribute (Blob or boolean)? union3AttributeNullable; attribute (unsigned long or boolean)? union4AttributeNullable; attribute (DOMString or boolean)? union5AttributeNullable; + attribute (ByteString or long)? union6AttributeNullable; [BinaryName="BinaryRenamedAttribute"] attribute DOMString attrToBinaryRename; [BinaryName="BinaryRenamedAttribute2"] attribute DOMString attr-to-binary-rename; attribute DOMString attr-to-automatically-rename; @@ -177,6 +179,8 @@ interface TestBinding { (DOMString or boolean) receiveUnion7(); (unsigned long or boolean) receiveUnion8(); (HTMLElement or unsigned long or DOMString or boolean) receiveUnion9(); + (ByteString or long) receiveUnion10(); + (sequence<ByteString> or long or DOMString) receiveUnion11(); sequence<long> receiveSequence(); sequence<Blob> receiveInterfaceSequence(); @@ -204,6 +208,7 @@ interface TestBinding { (DOMString or sequence<long>)? receiveNullableUnion3(); (sequence<long> or boolean)? receiveNullableUnion4(); (unsigned long or boolean)? receiveNullableUnion5(); + (ByteString or long)? receiveNullableUnion6(); sequence<long>? receiveNullableSequence(); TestDictionary receiveTestDictionaryWithSuccessOnKeyword(); boolean dictMatchesPassedValues(TestDictionary arg); @@ -233,6 +238,7 @@ interface TestBinding { void passUnion5((DOMString or boolean) data); void passUnion6((unsigned long or boolean) bool); void passUnion7((sequence<DOMString> or unsigned long) arg); + void passUnion8((sequence<ByteString> or long) arg); void passAny(any arg); void passObject(object arg); void passCallbackFunction(Function fun); @@ -265,6 +271,7 @@ interface TestBinding { void passNullableUnion3((DOMString or sequence<long>)? data); void passNullableUnion4((sequence<long> or boolean)? bool); void passNullableUnion5((unsigned long or boolean)? arg); + void passNullableUnion6((ByteString or long)? arg); void passNullableCallbackFunction(Function? fun); void passNullableCallbackInterface(EventListener? listener); void passNullableSequence(sequence<long>? seq); @@ -292,6 +299,7 @@ interface TestBinding { void passOptionalUnion3(optional (DOMString or sequence<long>) arg); void passOptionalUnion4(optional (sequence<long> or boolean) data); void passOptionalUnion5(optional (unsigned long or boolean) bool); + void passOptionalUnion6(optional (ByteString or long) arg); void passOptionalAny(optional any arg); void passOptionalObject(optional object arg); void passOptionalCallbackFunction(optional Function fun); @@ -322,6 +330,7 @@ interface TestBinding { void passOptionalNullableUnion3(optional (DOMString or sequence<long>)? arg); void passOptionalNullableUnion4(optional (sequence<long> or boolean)? data); void passOptionalNullableUnion5(optional (unsigned long or boolean)? bool); + void passOptionalNullableUnion6(optional (ByteString or long)? arg); void passOptionalNullableCallbackFunction(optional Function? fun); void passOptionalNullableCallbackInterface(optional EventListener? listener); void passOptionalNullableSequence(optional sequence<long>? seq); @@ -406,9 +415,14 @@ interface TestBinding { void passVariadicUnion4((Blob or boolean)... args); void passVariadicUnion5((DOMString or unsigned long)... args); void passVariadicUnion6((unsigned long or boolean)... args); + void passVariadicUnion7((ByteString or long)... args); void passVariadicAny(any... args); void passVariadicObject(object... args); + void passSequenceSequence(sequence<sequence<long>> seq); + sequence<sequence<long>> returnSequenceSequence(); + void passUnionSequenceSequence((long or sequence<sequence<long>>) seq); + static attribute boolean booleanAttributeStatic; static void receiveVoidStatic(); boolean BooleanMozPreference(DOMString pref_name); @@ -424,6 +438,8 @@ interface TestBinding { static void prefControlledStaticMethodDisabled(); [Pref="dom.testbinding.prefcontrolled.enabled"] const unsigned short prefControlledConstDisabled = 0; + [Pref="layout.animations.test.enabled"] + void advanceClock(long millis); [Pref="dom.testbinding.prefcontrolled2.enabled"] readonly attribute boolean prefControlledAttributeEnabled; diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index bda73c9479a..651c7081305 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -11,7 +11,7 @@ [Unforgeable] readonly attribute Document document; // attribute DOMString name; [/*PutForwards=href, */Unforgeable] readonly attribute Location location; - //readonly attribute History history; + readonly attribute History history; //[Replaceable] readonly attribute BarProp locationbar; //[Replaceable] readonly attribute BarProp menubar; //[Replaceable] readonly attribute BarProp personalbar; diff --git a/components/script/dom/webidls/WorkerGlobalScope.webidl b/components/script/dom/webidls/WorkerGlobalScope.webidl index 0a269068b57..ec65bcb09a6 100644 --- a/components/script/dom/webidls/WorkerGlobalScope.webidl +++ b/components/script/dom/webidls/WorkerGlobalScope.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#workerglobalscope -[Abstract, Exposed=(Window,Worker)] +[Abstract, Exposed=Worker] interface WorkerGlobalScope : EventTarget { [BinaryName="Self_"] readonly attribute WorkerGlobalScope self; readonly attribute WorkerLocation location; @@ -16,7 +16,7 @@ interface WorkerGlobalScope : EventTarget { }; // https://html.spec.whatwg.org/multipage/#WorkerGlobalScope-partial -[Exposed=(Window,Worker)] +[Exposed=Worker] partial interface WorkerGlobalScope { // not obsolete [Throws] void importScripts(DOMString... urls); @@ -26,7 +26,7 @@ WorkerGlobalScope implements WindowTimers; WorkerGlobalScope implements WindowBase64; // Proprietary -[Exposed=(Window,Worker)] +[Exposed=Worker] partial interface WorkerGlobalScope { [Replaceable] readonly attribute Console console; diff --git a/components/script/dom/webidls/WorkerLocation.webidl b/components/script/dom/webidls/WorkerLocation.webidl index 797956aca26..e4c410f720a 100644 --- a/components/script/dom/webidls/WorkerLocation.webidl +++ b/components/script/dom/webidls/WorkerLocation.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#worker-locations -[Exposed=(Window,Worker)] +[Exposed=Worker] interface WorkerLocation { /*stringifier*/ readonly attribute USVString href; // readonly attribute USVString origin; diff --git a/components/script/dom/webidls/WorkerNavigator.webidl b/components/script/dom/webidls/WorkerNavigator.webidl index 04006714a0c..0661325b8be 100644 --- a/components/script/dom/webidls/WorkerNavigator.webidl +++ b/components/script/dom/webidls/WorkerNavigator.webidl @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#workernavigator -[Exposed=(Window,Worker)] +[Exposed=Worker] interface WorkerNavigator {}; WorkerNavigator implements NavigatorID; WorkerNavigator implements NavigatorLanguage; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 1a34096f26b..3b3652040e9 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -461,6 +461,8 @@ struct ConnectionEstablishedTask { } impl Runnable for ConnectionEstablishedTask { + fn name(&self) -> &'static str { "ConnectionEstablishedTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); let global = ws.r().global(); @@ -510,6 +512,8 @@ impl Runnable for BufferedAmountTask { // To be compliant with standards, we need to reset bufferedAmount only when the event loop // reaches step 1. In our implementation, the bytes will already have been sent on a background // thread. + fn name(&self) -> &'static str { "BufferedAmountTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); @@ -526,6 +530,8 @@ struct CloseTask { } impl Runnable for CloseTask { + fn name(&self) -> &'static str { "CloseTask" } + fn handler(self: Box<Self>) { let ws = self.address.root(); let ws = ws.r(); @@ -568,6 +574,8 @@ struct MessageReceivedTask { } impl Runnable for MessageReceivedTask { + fn name(&self) -> &'static str { "MessageReceivedTask" } + #[allow(unsafe_code)] fn handler(self: Box<Self>) { let ws = self.address.root(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 9401eae5a46..ebd9550d117 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -28,7 +28,10 @@ use dom::crypto::Crypto; use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration}; use dom::document::Document; use dom::element::Element; +use dom::event::Event; use dom::eventtarget::EventTarget; +use dom::history::History; +use dom::htmliframeelement::build_mozbrowser_custom_event; use dom::location::Location; use dom::navigator::Navigator; use dom::node::{Node, from_untrusted_node_address, window_from_node}; @@ -43,11 +46,11 @@ use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy}; use js::rust::CompileOptionsWrapper; use js::rust::Runtime; use libc; -use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId, WindowSizeType}; +use msg::constellation_msg::{FrameType, LoadData, PipelineId, SubpageId, WindowSizeType}; +use net_traits::ResourceThreads; use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; use net_traits::storage_thread::StorageType; -use net_traits::{ResourceThreads, CustomResponseSender}; use num_traits::ToPrimitive; use open; use profile_traits::mem; @@ -63,7 +66,7 @@ use script_runtime::{ScriptChan, ScriptPort, maybe_take_panic_result}; use script_thread::SendableMainThreadScriptChan; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper}; use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; -use script_traits::{ConstellationControlMsg, UntrustedNodeAddress}; +use script_traits::{ConstellationControlMsg, MozBrowserEvent, UntrustedNodeAddress}; use script_traits::{DocumentState, MsDuration, TimerEvent, TimerEventId}; use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSource, WindowSizeData}; use std::ascii::AsciiExt; @@ -92,7 +95,7 @@ use task_source::networking::NetworkingTaskSource; use task_source::user_interaction::UserInteractionTaskSource; use time; use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback}; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use tinyfiledialogs::{self, MessageBoxIcon}; use url::Url; use util::geometry::{self, MAX_RECT}; @@ -155,9 +158,8 @@ pub struct Window { image_cache_thread: ImageCacheThread, #[ignore_heap_size_of = "channels are hard"] image_cache_chan: ImageCacheChan, - #[ignore_heap_size_of = "channels are hard"] - custom_message_chan: IpcSender<CustomResponseSender>, browsing_context: MutNullableHeap<JS<BrowsingContext>>, + history: MutNullableHeap<JS<History>>, performance: MutNullableHeap<JS<Performance>>, navigation_start: u64, navigation_start_precise: f64, @@ -266,9 +268,6 @@ pub struct Window { /// A list of scroll offsets for each scrollable element. scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>, - - #[ignore_heap_size_of = "Defined in ipc-channel"] - panic_chan: IpcSender<PanicMsg>, } impl Window { @@ -302,7 +301,7 @@ impl Window { self.history_traversal_task_source.clone() } - pub fn file_reading_task_source(&self) -> Box<ScriptChan + Send> { + pub fn file_reading_task_source(&self) -> FileReadingTaskSource { self.file_reading_task_source.clone() } @@ -314,10 +313,6 @@ impl Window { self.image_cache_chan.clone() } - pub fn custom_message_chan(&self) -> IpcSender<CustomResponseSender> { - self.custom_message_chan.clone() - } - pub fn get_next_worker_id(&self) -> WorkerId { let worker_id = self.next_worker_id.get(); let WorkerId(id_num) = worker_id; @@ -366,14 +361,14 @@ impl Window { } } -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn display_alert_dialog(message: &str) { tinyfiledialogs::message_box_ok("Alert!", message, MessageBoxIcon::Warning); } -#[cfg(not(any(target_os = "macos", target_os = "linux")))] +#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] fn display_alert_dialog(_message: &str) { - // tinyfiledialogs not supported on Windows + // tinyfiledialogs not supported on Android } // https://html.spec.whatwg.org/multipage/#atob @@ -455,13 +450,15 @@ impl WindowMethods for Window { // Right now, just print to the console // Ensure that stderr doesn't trample through the alert() we use to // communicate test results (see executorservo.py in wptrunner). - let stderr = stderr(); - let mut stderr = stderr.lock(); - let stdout = stdout(); - let mut stdout = stdout.lock(); - writeln!(&mut stdout, "ALERT: {}", s).unwrap(); - stdout.flush().unwrap(); - stderr.flush().unwrap(); + { + let stderr = stderr(); + let mut stderr = stderr.lock(); + let stdout = stdout(); + let mut stdout = stdout.lock(); + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); + stdout.flush().unwrap(); + stderr.flush().unwrap(); + } let (sender, receiver) = ipc::channel().unwrap(); self.constellation_chan().send(ConstellationMsg::Alert(self.pipeline(), s.to_string(), sender)).unwrap(); @@ -482,6 +479,11 @@ impl WindowMethods for Window { self.browsing_context().active_document() } + // https://html.spec.whatwg.org/multipage/#dom-history + fn History(&self) -> Root<History> { + self.history.or_init(|| History::new(self)) + } + // https://html.spec.whatwg.org/multipage/#dom-location fn Location(&self) -> Root<Location> { self.Document().GetLocation().unwrap() @@ -1034,6 +1036,12 @@ impl Window { recv.recv().unwrap_or((Size2D::zero(), Point2D::zero())) } + /// Advances the layout animation clock by `delta` milliseconds, and then + /// forces a reflow. + pub fn advance_animation_clock(&self, delta: i32) { + self.layout_chan.send(Msg::AdvanceClockMs(delta)).unwrap(); + } + /// Reflows the page unconditionally if possible and not suppressed. This /// method will wait for the layout thread to complete (but see the `TODO` /// below). If there is no window size yet, the page is presumed invisible @@ -1422,10 +1430,6 @@ impl Window { &self.scheduler_chan } - pub fn panic_chan(&self) -> &IpcSender<PanicMsg> { - &self.panic_chan - } - pub fn schedule_callback(&self, callback: OneshotTimerCallback, duration: MsDuration) -> OneshotTimerHandle { self.timers.schedule_callback(callback, duration, @@ -1594,6 +1598,13 @@ impl Window { _ => false, } } + + #[allow(unsafe_code)] + pub fn dispatch_mozbrowser_event(&self, event: MozBrowserEvent) { + assert!(PREFS.is_mozbrowser_enabled()); + let custom_event = build_mozbrowser_custom_event(&self, event); + custom_event.upcast::<Event>().fire(self.upcast()); + } } impl Window { @@ -1605,7 +1616,6 @@ impl Window { history_task_source: HistoryTraversalTaskSource, file_task_source: FileReadingTaskSource, image_cache_chan: ImageCacheChan, - custom_message_chan: IpcSender<CustomResponseSender>, image_cache_thread: ImageCacheThread, resource_threads: ResourceThreads, bluetooth_thread: IpcSender<BluetoothMethodMsg>, @@ -1615,7 +1625,6 @@ impl Window { constellation_chan: IpcSender<ConstellationMsg>, control_chan: IpcSender<ConstellationControlMsg>, scheduler_chan: IpcSender<TimerEventRequest>, - panic_chan: IpcSender<PanicMsg>, timer_event_chan: IpcSender<TimerEvent>, layout_chan: Sender<Msg>, id: PipelineId, @@ -1641,7 +1650,6 @@ impl Window { history_traversal_task_source: history_task_source, file_reading_task_source: file_task_source, image_cache_chan: image_cache_chan, - custom_message_chan: custom_message_chan, console: Default::default(), crypto: Default::default(), navigator: Default::default(), @@ -1649,6 +1657,7 @@ impl Window { mem_profiler_chan: mem_profiler_chan, time_profiler_chan: time_profiler_chan, devtools_chan: devtools_chan, + history: Default::default(), browsing_context: Default::default(), performance: Default::default(), navigation_start: (current_time.sec * 1000 + current_time.nsec as i64 / 1000000) as u64, @@ -1686,7 +1695,6 @@ impl Window { ignore_further_async_events: Arc::new(AtomicBool::new(false)), error_reporter: error_reporter, scroll_offsets: DOMRefCell::new(HashMap::new()), - panic_chan: panic_chan, }; WindowBinding::Wrap(runtime.cx(), win) diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 2cf1d1c4e46..c1ad7cf5a96 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -2,9 +2,9 @@ * 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 devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolsPageInfo}; +use dom::abstractworker::WorkerScriptMsg; use dom::abstractworker::{SimpleWorkerErrorHandler, SharedRt, WorkerErrorHandler}; -use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg}; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::WorkerBinding; use dom::bindings::codegen::Bindings::WorkerBinding::WorkerMethods; @@ -26,6 +26,8 @@ use ipc_channel::ipc; use js::jsapi::{HandleValue, JSContext, JSAutoCompartment}; use js::jsval::UndefinedValue; use script_thread::Runnable; +use script_traits::WorkerScriptLoadOrigin; +use std::cell::Cell; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Sender, channel}; use std::sync::{Arc, Mutex}; @@ -42,7 +44,8 @@ pub struct Worker { sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, closing: Arc<AtomicBool>, #[ignore_heap_size_of = "Defined in rust-mozjs"] - runtime: Arc<Mutex<Option<SharedRt>>> + runtime: Arc<Mutex<Option<SharedRt>>>, + terminated: Cell<bool>, } impl Worker { @@ -52,7 +55,8 @@ impl Worker { eventtarget: EventTarget::new_inherited(), sender: sender, closing: closing, - runtime: Arc::new(Mutex::new(None)) + runtime: Arc::new(Mutex::new(None)), + terminated: Cell::new(false), } } @@ -81,21 +85,28 @@ impl Worker { let worker_load_origin = WorkerScriptLoadOrigin { referrer_url: None, referrer_policy: None, - request_source: global.request_source(), pipeline_id: Some(global.pipeline()) }; let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); + let worker_id = global.get_next_worker_id(); + if let Some(ref chan) = global.devtools_chan() { + let pipeline_id = global.pipeline(); + let title = format!("Worker for {}", worker_url); + let page_info = DevtoolsPageInfo { + title: title, + url: worker_url.clone(), + }; + let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)), + devtools_sender.clone(), + page_info)); + } - let init = prepare_workerscope_init(global, - "Worker".to_owned(), - worker_url.clone(), - devtools_sender.clone(), - closing); + let init = prepare_workerscope_init(global, Some(devtools_sender)); DedicatedWorkerGlobalScope::run_worker_scope( init, worker_url, global.pipeline(), devtools_receiver, worker.runtime.clone(), worker_ref, - global.script_chan(), sender, receiver, worker_load_origin); + global.script_chan(), sender, receiver, worker_load_origin, closing); Ok(worker) } @@ -104,11 +115,15 @@ impl Worker { self.closing.load(Ordering::SeqCst) } + pub fn is_terminated(&self) -> bool { + self.terminated.get() + } + pub fn handle_message(address: TrustedWorkerAddress, data: StructuredCloneData) { let worker = address.root(); - if worker.is_closing() { + if worker.is_terminated() { return; } @@ -129,7 +144,7 @@ impl Worker { filename: DOMString, lineno: u32, colno: u32) { let worker = address.root(); - if worker.is_closing() { + if worker.is_terminated() { return; } @@ -161,7 +176,10 @@ impl WorkerMethods for Worker { return; } - // Step 4 + // Step 2 + self.terminated.set(true); + + // Step 3 if let Some(runtime) = *self.runtime.lock().unwrap() { runtime.request_interrupt(); } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 2e1c983bfd4..16388d54d73 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -2,7 +2,7 @@ * 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 devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId, DevtoolsPageInfo}; +use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception}; @@ -19,17 +19,18 @@ use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope; use dom::window::{base64_atob, base64_btoa}; use dom::workerlocation::WorkerLocation; use dom::workernavigator::WorkerNavigator; -use ipc_channel::ipc::{self, IpcSender}; -use ipc_channel::router::ROUTER; +use ipc_channel::ipc::IpcSender; use js::jsapi::{HandleValue, JSContext, JSRuntime}; use js::jsval::UndefinedValue; use js::rust::Runtime; -use msg::constellation_msg::{PipelineId, ReferrerPolicy, PanicMsg}; +use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use net_traits::{LoadContext, ResourceThreads, load_whole_resource}; -use net_traits::{RequestSource, LoadOrigin, CustomResponseSender, IpcSend}; +use net_traits::{LoadOrigin, IpcSend}; use profile_traits::{mem, time}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, maybe_take_panic_result}; +use script_thread::RunnableWrapper; use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::WorkerGlobalScopeInit; use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource}; use std::cell::Cell; use std::default::Default; @@ -38,6 +39,7 @@ use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::Receiver; +use task_source::file_reading::FileReadingTaskSource; use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback}; use url::Url; @@ -46,52 +48,18 @@ pub enum WorkerGlobalScopeTypeId { DedicatedWorkerGlobalScope, } -pub struct WorkerGlobalScopeInit { - pub resource_threads: ResourceThreads, - pub mem_profiler_chan: mem::ProfilerChan, - pub time_profiler_chan: time::ProfilerChan, - pub to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, - pub constellation_chan: IpcSender<ConstellationMsg>, - pub scheduler_chan: IpcSender<TimerEventRequest>, - pub panic_chan: IpcSender<PanicMsg>, - pub worker_id: WorkerId, - pub closing: Arc<AtomicBool>, -} - pub fn prepare_workerscope_init(global: GlobalRef, - worker_type: String, - worker_url: Url, - devtools_sender: IpcSender<DevtoolScriptControlMsg>, - closing: Arc<AtomicBool>) -> WorkerGlobalScopeInit { + devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>) -> WorkerGlobalScopeInit { let worker_id = global.get_next_worker_id(); - let optional_sender = match global.devtools_chan() { - Some(ref chan) => { - let pipeline_id = global.pipeline(); - let title = format!("{} for {}", worker_type, worker_url); - let page_info = DevtoolsPageInfo { - title: title, - url: worker_url, - }; - chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)), - devtools_sender.clone(), - page_info)).unwrap(); - Some(devtools_sender) - }, - None => None, - }; - let init = WorkerGlobalScopeInit { resource_threads: global.resource_threads(), mem_profiler_chan: global.mem_profiler_chan().clone(), to_devtools_sender: global.devtools_chan(), time_profiler_chan: global.time_profiler_chan().clone(), - from_devtools_sender: optional_sender, + from_devtools_sender: devtools_sender, constellation_chan: global.constellation_chan().clone(), - panic_chan: global.panic_chan().clone(), scheduler_chan: global.scheduler_chan().clone(), - worker_id: worker_id, - closing: closing, + worker_id: worker_id }; init @@ -103,7 +71,7 @@ pub struct WorkerGlobalScope { eventtarget: EventTarget, worker_id: WorkerId, worker_url: Url, - closing: Arc<AtomicBool>, + closing: Option<Arc<AtomicBool>>, #[ignore_heap_size_of = "Defined in js"] runtime: Runtime, next_worker_id: Cell<WorkerId>, @@ -141,15 +109,6 @@ pub struct WorkerGlobalScope { #[ignore_heap_size_of = "Defined in std"] scheduler_chan: IpcSender<TimerEventRequest>, - - #[ignore_heap_size_of = "Defined in ipc-channel"] - panic_chan: IpcSender<PanicMsg>, - - #[ignore_heap_size_of = "Defined in ipc-channel"] - custom_msg_chan: IpcSender<CustomResponseSender>, - - #[ignore_heap_size_of = "Defined in std"] - custom_msg_port: Receiver<CustomResponseSender>, } impl WorkerGlobalScope { @@ -157,16 +116,15 @@ impl WorkerGlobalScope { worker_url: Url, runtime: Runtime, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, - timer_event_chan: IpcSender<TimerEvent>) + timer_event_chan: IpcSender<TimerEvent>, + closing: Option<Arc<AtomicBool>>) -> WorkerGlobalScope { - let (msg_chan, msg_port) = ipc::channel().unwrap(); - let custom_msg_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(msg_port); WorkerGlobalScope { eventtarget: EventTarget::new_inherited(), next_worker_id: Cell::new(WorkerId(0)), worker_id: init.worker_id, worker_url: worker_url, - closing: init.closing, + closing: closing, runtime: runtime, resource_threads: init.resource_threads, location: Default::default(), @@ -182,9 +140,6 @@ impl WorkerGlobalScope { devtools_wants_updates: Cell::new(false), constellation_chan: init.constellation_chan, scheduler_chan: init.scheduler_chan, - panic_chan: init.panic_chan, - custom_msg_chan: msg_chan, - custom_msg_port: custom_msg_port } } @@ -234,16 +189,12 @@ impl WorkerGlobalScope { self.runtime.cx() } - pub fn custom_message_chan(&self) -> IpcSender<CustomResponseSender> { - self.custom_msg_chan.clone() - } - - pub fn custom_message_port(&self) -> &Receiver<CustomResponseSender> { - &self.custom_msg_port - } - pub fn is_closing(&self) -> bool { - self.closing.load(Ordering::SeqCst) + if let Some(ref closing) = self.closing { + closing.load(Ordering::SeqCst) + } else { + false + } } pub fn resource_threads(&self) -> &ResourceThreads { @@ -265,8 +216,10 @@ impl WorkerGlobalScope { worker_id } - pub fn panic_chan(&self) -> &IpcSender<PanicMsg> { - &self.panic_chan + pub fn get_runnable_wrapper(&self) -> RunnableWrapper { + RunnableWrapper { + cancelled: self.closing.clone().unwrap(), + } } } @@ -277,9 +230,6 @@ impl LoadOrigin for WorkerGlobalScope { fn referrer_policy(&self) -> Option<ReferrerPolicy> { None } - fn request_source(&self) -> RequestSource { - RequestSource::None - } fn pipeline_id(&self) -> Option<PipelineId> { Some(self.pipeline()) } @@ -443,16 +393,17 @@ impl WorkerGlobalScope { pub fn script_chan(&self) -> Box<ScriptChan + Send> { let dedicated = self.downcast::<DedicatedWorkerGlobalScope>(); - let service_worker = self.downcast::<ServiceWorkerGlobalScope>(); if let Some(dedicated) = dedicated { return dedicated.script_chan(); - } else if let Some(service_worker) = service_worker { - return service_worker.script_chan(); } else { - panic!("need to implement a sender for SharedWorker") + panic!("need to implement a sender for SharedWorker/ServiceWorker") } } + pub fn file_reading_task_source(&self) -> FileReadingTaskSource { + FileReadingTaskSource(self.script_chan()) + } + pub fn pipeline(&self) -> PipelineId { let dedicated = self.downcast::<DedicatedWorkerGlobalScope>(); let service_worker = self.downcast::<ServiceWorkerGlobalScope>(); @@ -467,13 +418,10 @@ impl WorkerGlobalScope { pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) { let dedicated = self.downcast::<DedicatedWorkerGlobalScope>(); - let service_worker = self.downcast::<ServiceWorkerGlobalScope>(); if let Some(dedicated) = dedicated { return dedicated.new_script_pair(); - } else if let Some(service_worker) = service_worker { - return service_worker.new_script_pair(); } else { - panic!("need to implement a sender for SharedWorker") + panic!("need to implement a sender for SharedWorker/ServiceWorker") } } @@ -496,4 +444,10 @@ impl WorkerGlobalScope { pub fn set_devtools_wants_updates(&self, value: bool) { self.devtools_wants_updates.set(value); } + + pub fn close(&self) { + if let Some(ref closing) = self.closing { + closing.store(true, Ordering::SeqCst); + } + } } diff --git a/components/script/dom/xmldocument.rs b/components/script/dom/xmldocument.rs index b291c912089..5f6b6e1919c 100644 --- a/components/script/dom/xmldocument.rs +++ b/components/script/dom/xmldocument.rs @@ -41,7 +41,9 @@ impl XMLDocument { content_type, last_modified, source, - doc_loader), + doc_loader, + None, + None), } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 148a51c8c6b..5cef702c01a 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -25,6 +25,7 @@ use dom::document::DocumentSource; use dom::document::{Document, IsHTMLDocument}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; +use dom::headers::is_forbidden_header_name; use dom::progressevent::ProgressEvent; use dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget; use dom::xmlhttprequestupload::XMLHttpRequestUpload; @@ -47,7 +48,7 @@ use net_traits::CoreResourceMsg::Fetch; use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode}; use net_traits::trim_http_whitespace; use net_traits::{CoreResourceThread, LoadOrigin}; -use net_traits::{FetchResponseListener, Metadata, NetworkError, RequestSource}; +use net_traits::{FetchResponseListener, Metadata, NetworkError}; use network_listener::{NetworkListener, PreInvoke}; use parse::html::{ParseContext, parse_html}; use parse::xml::{self, parse_xml}; @@ -274,13 +275,6 @@ impl LoadOrigin for XMLHttpRequest { fn referrer_policy(&self) -> Option<ReferrerPolicy> { return self.referrer_policy; } - fn request_source(&self) -> RequestSource { - if self.sync.get() { - RequestSource::None - } else { - self.global().r().request_source() - } - } fn pipeline_id(&self) -> Option<PipelineId> { let global = self.global(); Some(global.r().pipeline()) @@ -368,6 +362,12 @@ impl XMLHttpRequestMethods for XMLHttpRequest { // Step 11 - abort existing requests self.terminate_ongoing_fetch(); + // TODO(izgzhen): In the WPT test: FileAPI/blob/Blob-XHR-revoke.html, + // the xhr.open(url) is expected to hold a reference to the URL, + // thus renders following revocations invalid. Though we won't + // implement this for now, if ever needed, we should check blob + // scheme and trigger corresponding actions here. + // Step 12 *self.request_method.borrow_mut() = parsed_method; *self.request_url.borrow_mut() = Some(parsed_url); @@ -410,21 +410,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest { // Step 5 // Disallowed headers and header prefixes: // https://fetch.spec.whatwg.org/#forbidden-header-name - let disallowedHeaders = - ["accept-charset", "accept-encoding", - "access-control-request-headers", - "access-control-request-method", - "connection", "content-length", - "cookie", "cookie2", "date", "dnt", - "expect", "host", "keep-alive", "origin", - "referer", "te", "trailer", "transfer-encoding", - "upgrade", "via"]; - - let disallowedHeaderPrefixes = ["sec-", "proxy-"]; - - if disallowedHeaders.iter().any(|header| *header == s) || - disallowedHeaderPrefixes.iter().any(|prefix| s.starts_with(prefix)) { - return Ok(()) + if is_forbidden_header_name(s) { + return Ok(()); } else { s } @@ -1234,7 +1221,10 @@ impl XMLHttpRequest { is_html_document, content_type, None, - DocumentSource::FromParser, docloader) + DocumentSource::FromParser, + docloader, + None, + None) } fn filter_response_headers(&self) -> Headers { |