aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-09-10 07:33:25 -0500
committerGitHub <noreply@github.com>2016-09-10 07:33:25 -0500
commit84f3cf22bfa3a8897a687e9282b1a9df1cbcb8cc (patch)
tree256a1d5e82056965040213b43c4ed7deeacf9bbf /components/script
parent5e7d91829782828e1020652e7bc9d16aa7456499 (diff)
parent2bc0862f47a937eaf96aec929e884bddd23c6447 (diff)
downloadservo-84f3cf22bfa3a8897a687e9282b1a9df1cbcb8cc.tar.gz
servo-84f3cf22bfa3a8897a687e9282b1a9df1cbcb8cc.zip
Auto merge of #13185 - nox:namespaces, r=jdm,Ms2ger
Make console a namespace (fixes #13010) <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13185) <!-- Reviewable:end -->
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py85
-rw-r--r--components/script/dom/bindings/codegen/Configuration.py22
-rw-r--r--components/script/dom/bindings/global.rs9
-rw-r--r--components/script/dom/bindings/interface.rs7
-rw-r--r--components/script/dom/bindings/mod.rs1
-rw-r--r--components/script/dom/bindings/namespace.rs42
-rw-r--r--components/script/dom/bindings/str.rs9
-rw-r--r--components/script/dom/console.rs111
-rw-r--r--components/script/dom/webidls/Console.webidl6
-rw-r--r--components/script/dom/webidls/Window.webidl1
-rw-r--r--components/script/dom/webidls/WorkerGlobalScope.webidl7
-rw-r--r--components/script/dom/window.rs20
-rw-r--r--components/script/dom/workerglobalscope.rs17
13 files changed, 220 insertions, 117 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 717fc4a4cf2..486758182d2 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -26,6 +26,7 @@ from WebIDL import (
)
from Configuration import (
+ MakeNativeName,
MemberIsUnforgeable,
getModuleFromObject,
getTypesFromCallback,
@@ -80,7 +81,7 @@ def toStringBool(arg):
def toBindingNamespace(arg):
- return re.sub("((_workers)?$)", "Binding\\1", arg)
+ return re.sub("((_workers)?$)", "Binding\\1", MakeNativeName(arg))
def stripTrailingWhitespace(text):
@@ -96,9 +97,6 @@ def innerSequenceType(type):
return type.inner.inner if type.nullable() else type.inner
-def MakeNativeName(name):
- return name[0].upper() + name[1:]
-
builtinNames = {
IDLType.Tags.bool: 'bool',
IDLType.Tags.int8: 'i8',
@@ -1811,7 +1809,8 @@ class CGImports(CGWrapper):
def isImportable(type):
if not type.isType():
- assert type.isInterface() or type.isDictionary() or type.isEnum()
+ assert (type.isInterface() or type.isDictionary() or
+ type.isEnum() or type.isNamespace())
return True
return not (type.builtin or type.isSequence() or type.isUnion())
@@ -1830,7 +1829,7 @@ class CGImports(CGWrapper):
if t.isCallback():
return t.callback.identifier
return t.identifier
- assert t.isInterface() or t.isDictionary() or t.isEnum()
+ assert t.isInterface() or t.isDictionary() or t.isEnum() or t.isNamespace()
return t.identifier
def removeWrapperAndNullableTypes(types):
@@ -1881,7 +1880,7 @@ class CGImports(CGWrapper):
# Importing these types in the same module that defines them is an error.
if t in dictionaries or t in enums:
continue
- if t.isInterface():
+ if t.isInterface() or t.isNamespace():
descriptor = descriptorProvider.getDescriptor(getIdentifier(t).name)
extras += [descriptor.path]
if descriptor.interface.parent:
@@ -2060,6 +2059,17 @@ class CGInterfaceObjectJSClass(CGThing):
self.descriptor = descriptor
def define(self):
+ if self.descriptor.interface.isNamespace():
+ classString = self.descriptor.interface.getExtendedAttribute("ClassString")
+ if classString:
+ classString = classString[0]
+ else:
+ classString = "Object"
+ return """\
+static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {
+ NamespaceObjectClass::new(%s)
+};
+""" % str_to_const_array(classString)
if self.descriptor.interface.ctor():
constructorBehavior = "InterfaceConstructorBehavior::call(%s)" % CONSTRUCT_HOOK_NAME
else:
@@ -2659,6 +2669,28 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
def definition_body(self):
name = self.descriptor.interface.identifier.name
+ if self.descriptor.interface.isNamespace():
+ if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"):
+ proto = "JS_GetObjectPrototype(cx, global)"
+ else:
+ proto = "JS_NewPlainObject(cx)"
+ if self.properties.static_methods.length():
+ methods = self.properties.static_methods.variableName()
+ else:
+ methods = "&[]"
+ return CGGeneric("""\
+rooted!(in(cx) let proto = %(proto)s);
+assert!(!proto.is_null());
+rooted!(in(cx) let mut namespace = ptr::null_mut());
+create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS,
+ %(methods)s, %(name)s, namespace.handle_mut());
+assert!(!namespace.is_null());
+assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
+(*cache)[PrototypeList::Constructor::%(id)s as usize] = namespace.get();
+<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize),
+ ptr::null_mut(),
+ namespace.get());
+""" % {"id": MakeNativeName(name), "methods": methods, "name": str_to_const_array(name), "proto": proto})
if self.descriptor.interface.isCallback():
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
return CGGeneric("""\
@@ -2873,7 +2905,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
Argument('MutableHandleObject', 'rval')]
CGAbstractMethod.__init__(self, descriptor, name,
'void', args, pub=pub, unsafe=True)
- self.id = idPrefix + "::" + self.descriptor.name
+ self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name)
def definition_body(self):
return CGGeneric("""
@@ -3016,7 +3048,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
return CGAbstractMethod.define(self)
def definition_body(self):
- if self.descriptor.interface.isCallback():
+ if self.descriptor.interface.isCallback() or self.descriptor.interface.isNamespace():
function = "GetConstructorObject"
else:
function = "GetProtoObject"
@@ -3047,7 +3079,7 @@ class CGCallGenerator(CGThing):
exception from the native code, or None if no error reporting is needed.
"""
def __init__(self, errorResult, arguments, argsPre, returnType,
- extendedAttributes, descriptorProvider, nativeMethodName,
+ extendedAttributes, descriptor, nativeMethodName,
static, object="this"):
CGThing.__init__(self)
@@ -3055,7 +3087,7 @@ class CGCallGenerator(CGThing):
isFallible = errorResult is not None
- result = getRetvalDeclarationForType(returnType, descriptorProvider)
+ result = getRetvalDeclarationForType(returnType, descriptor)
if isFallible:
result = CGWrapper(result, pre="Result<", post=", Error>")
@@ -3076,7 +3108,7 @@ class CGCallGenerator(CGThing):
call = CGGeneric(nativeMethodName)
if static:
- call = CGWrapper(call, pre="%s::" % descriptorProvider.interface.identifier.name)
+ call = CGWrapper(call, pre="%s::" % MakeNativeName(descriptor.interface.identifier.name))
else:
call = CGWrapper(call, pre="%s." % object)
call = CGList([call, CGWrapper(args, pre="(", post=")")])
@@ -5454,6 +5486,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'dom::bindings::js::OptionalRootedReference',
'dom::bindings::js::Root',
'dom::bindings::js::RootedReference',
+ 'dom::bindings::namespace::NamespaceObjectClass',
+ 'dom::bindings::namespace::create_namespace_object',
'dom::bindings::reflector::MutReflectable',
'dom::bindings::reflector::Reflectable',
'dom::bindings::utils::DOMClass',
@@ -5561,7 +5595,7 @@ class CGDescriptor(CGThing):
return name
cgThings = []
- if not descriptor.interface.isCallback():
+ if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
cgThings.append(CGGetProtoObjectMethod(descriptor))
reexports.append('GetProtoObject')
if (descriptor.interface.hasInterfaceObject() and
@@ -5622,7 +5656,7 @@ class CGDescriptor(CGThing):
if not descriptor.interface.isCallback():
cgThings.append(CGInterfaceObjectJSClass(descriptor))
- if not descriptor.interface.isCallback():
+ if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
cgThings.append(CGPrototypeJSClass(descriptor))
# If there are no constant members, don't make a module for constants
@@ -5679,7 +5713,7 @@ class CGDescriptor(CGThing):
reexports.append('Wrap')
haveUnscopables = False
- if not descriptor.interface.isCallback():
+ if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
if unscopableNames:
haveUnscopables = True
cgThings.append(
@@ -5706,7 +5740,7 @@ class CGDescriptor(CGThing):
cgThings, public=True),
post='\n')
reexports = ', '.join(map(lambda name: reexportedName(name), reexports))
- self.cgRoot = CGList([CGGeneric('pub use self::%sBinding::{%s};' % (descriptor.name, reexports)),
+ self.cgRoot = CGList([CGGeneric('pub use self::%s::{%s};' % (toBindingNamespace(descriptor.name), reexports)),
cgThings], '\n')
def define(self):
@@ -6760,10 +6794,12 @@ class GlobalGenRoots():
@staticmethod
def PrototypeList(config):
# Prototype ID enum.
- interfaces = config.getDescriptors(isCallback=False)
+ interfaces = config.getDescriptors(isCallback=False, isNamespace=False)
protos = [d.name for d in interfaces]
- constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)
- if d.shouldHaveGetConstructorObjectMethod()]
+ constructors = sorted([MakeNativeName(d.name)
+ for d in config.getDescriptors(hasInterfaceObject=True)
+ if d.shouldHaveGetConstructorObjectMethod()])
+
proxies = [d.name for d in config.getDescriptors(proxy=True)]
return CGList([
@@ -6800,10 +6836,13 @@ class GlobalGenRoots():
@staticmethod
def InterfaceTypes(config):
- descriptors = [d.name for d in config.getDescriptors(register=True,
+ descriptors = sorted([MakeNativeName(d.name)
+ for d in config.getDescriptors(register=True,
isCallback=False,
- isIteratorInterface=False)]
- curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
+ isIteratorInterface=False)])
+ curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(),
+ MakeNativeName(name)))
+ for name in descriptors])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr
@@ -6814,7 +6853,7 @@ class GlobalGenRoots():
return getModuleFromObject(d).split('::')[-1]
descriptors = config.getDescriptors(register=True, isIteratorInterface=False)
- descriptors = (set(d.name + "Binding" for d in descriptors) |
+ descriptors = (set(toBindingNamespace(d.name) for d in descriptors) |
set(leafModule(d) for d in config.callbacks) |
set(leafModule(d) for d in config.getDictionaries()))
curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py
index c8f92472618..6e71bd4bd00 100644
--- a/components/script/dom/bindings/codegen/Configuration.py
+++ b/components/script/dom/bindings/codegen/Configuration.py
@@ -4,7 +4,7 @@
import os
-from WebIDL import IDLExternalInterface, IDLInterface, IDLWrapperType, WebIDLError
+from WebIDL import IDLExternalInterface, IDLWrapperType, WebIDLError
class Configuration:
@@ -30,10 +30,9 @@ class Configuration:
raise WebIDLError("Servo does not support external interfaces.",
[thing.location])
- # Some toplevel things are sadly types, and those have an
- # isInterface that doesn't mean the same thing as IDLObject's
- # isInterface()...
- if not isinstance(thing, IDLInterface):
+ assert not thing.isType()
+
+ if not thing.isInterface() and not thing.isNamespace():
continue
iface = thing
@@ -83,6 +82,8 @@ class Configuration:
getter = lambda x: x.interface.hasInterfaceObject()
elif key == 'isCallback':
getter = lambda x: x.interface.isCallback()
+ elif key == 'isNamespace':
+ getter = lambda x: x.interface.isNamespace()
elif key == 'isJSImplemented':
getter = lambda x: x.interface.isJSImplemented()
elif key == 'isGlobal':
@@ -210,7 +211,7 @@ class Descriptor(DescriptorProvider):
if self.interface.isIteratorInterface():
pathDefault = 'dom::bindings::iterable::IterableIterator'
else:
- pathDefault = 'dom::types::%s' % typeName
+ pathDefault = 'dom::types::%s' % MakeNativeName(typeName)
self.concreteType = typeName
self.register = desc.get('register', True)
@@ -223,6 +224,7 @@ class Descriptor(DescriptorProvider):
# If we're concrete, we need to crawl our ancestor interfaces and mark
# them as having a concrete descendant.
self.concrete = (not self.interface.isCallback() and
+ not self.interface.isNamespace() and
not self.interface.getExtendedAttribute("Abstract"))
self.hasUnforgeableMembers = (self.concrete and
any(MemberIsUnforgeable(m, self) for m in
@@ -381,7 +383,7 @@ class Descriptor(DescriptorProvider):
def shouldHaveGetConstructorObjectMethod(self):
assert self.interface.hasInterfaceObject()
- return self.interface.isCallback() or self.hasDescendants()
+ return self.interface.isCallback() or self.interface.isNamespace() or self.hasDescendants()
def isExposedConditionally(self):
return self.interface.isExposedConditionally()
@@ -396,6 +398,12 @@ class Descriptor(DescriptorProvider):
# Some utility methods
+
+
+def MakeNativeName(name):
+ return name[0].upper() + name[1:]
+
+
def getModuleFromObject(object):
return ('dom::bindings::codegen::Bindings::' +
os.path.basename(object.location.filename()).split('.webidl')[0] + 'Binding')
diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs
index dd03554217d..a5c9d1a3d79 100644
--- a/components/script/dom/bindings/global.rs
+++ b/components/script/dom/bindings/global.rs
@@ -13,6 +13,7 @@ use dom::bindings::conversions::root_from_object;
use dom::bindings::error::ErrorInfo;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflectable, Reflector};
+use dom::console::TimerSet;
use dom::window::{self, ScriptHelpers};
use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::IpcSender;
@@ -271,6 +272,14 @@ impl<'a> GlobalRef<'a> {
}
}
+ /// Returns the global's timers for the Console API.
+ pub fn console_timers(&self) -> &TimerSet {
+ match *self {
+ GlobalRef::Window(ref window) => window.console_timers(),
+ GlobalRef::Worker(ref worker) => worker.console_timers(),
+ }
+ }
+
/// Returns a wrapper for runnables to ensure they are cancelled if the global
/// is being destroyed.
pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs
index f7786163cc5..cae5da97887 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script/dom/bindings/interface.rs
@@ -257,7 +257,8 @@ pub unsafe fn create_named_constructors(
}
}
-unsafe fn create_object(
+/// Create a new object with a unique type.
+pub unsafe fn create_object(
cx: *mut JSContext,
proto: HandleObject,
class: &'static JSClass,
@@ -316,7 +317,9 @@ pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
globals.contains(dom_class.global)
}
-unsafe fn define_on_global_object(
+/// Define a property with a given name on the global object. Should be called
+/// through the resolve hook.
+pub unsafe fn define_on_global_object(
cx: *mut JSContext,
global: HandleObject,
name: &[u8],
diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs
index 8aefc71d577..16607c9045f 100644
--- a/components/script/dom/bindings/mod.rs
+++ b/components/script/dom/bindings/mod.rs
@@ -140,6 +140,7 @@ pub mod inheritance;
pub mod interface;
pub mod iterable;
pub mod js;
+pub mod namespace;
pub mod num;
pub mod proxyhandler;
pub mod refcounted;
diff --git a/components/script/dom/bindings/namespace.rs b/components/script/dom/bindings/namespace.rs
new file mode 100644
index 00000000000..38055dea180
--- /dev/null
+++ b/components/script/dom/bindings/namespace.rs
@@ -0,0 +1,42 @@
+/* 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/. */
+
+//! Machinery to initialise namespace objects.
+
+use dom::bindings::guard::Guard;
+use dom::bindings::interface::{create_object, define_on_global_object};
+use js::jsapi::{HandleObject, JSClass, JSContext, JSFunctionSpec, MutableHandleObject};
+use libc;
+use std::ptr;
+
+/// The class of a namespace object.
+#[derive(Copy, Clone)]
+pub struct NamespaceObjectClass(JSClass);
+
+unsafe impl Sync for NamespaceObjectClass {}
+
+impl NamespaceObjectClass {
+ /// Create a new `NamespaceObjectClass` structure.
+ pub const unsafe fn new(name: &'static [u8]) -> Self {
+ NamespaceObjectClass(JSClass {
+ name: name as *const _ as *const libc::c_char,
+ flags: 0,
+ cOps: ptr::null_mut(),
+ reserved: [ptr::null_mut(); 3],
+ })
+ }
+}
+
+/// Create a new namespace object.
+pub unsafe fn create_namespace_object(
+ cx: *mut JSContext,
+ global: HandleObject,
+ proto: HandleObject,
+ class: &'static NamespaceObjectClass,
+ methods: &[Guard<&'static [JSFunctionSpec]>],
+ name: &[u8],
+ rval: MutableHandleObject) {
+ create_object(cx, proto, &class.0, methods, &[], &[], rval);
+ define_on_global_object(cx, global, name, rval.handle());
+}
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index c73a08d182b..2e28a1b314e 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -5,7 +5,7 @@
//! The `ByteString` struct.
use std::ascii::AsciiExt;
-use std::borrow::{ToOwned, Cow};
+use std::borrow::{Borrow, Cow, ToOwned};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
@@ -180,6 +180,13 @@ impl DOMString {
}
}
+impl Borrow<str> for DOMString {
+ #[inline]
+ fn borrow(&self) -> &str {
+ &self.0
+ }
+}
+
impl Default for DOMString {
fn default() -> Self {
DOMString(String::new())
diff --git a/components/script/dom/console.rs b/components/script/dom/console.rs
index 9382bf936a8..37d549befd9 100644
--- a/components/script/dom/console.rs
+++ b/components/script/dom/console.rs
@@ -4,39 +4,17 @@
use devtools_traits::{ConsoleMessage, LogLevel, ScriptToDevtoolsControlMsg};
use dom::bindings::cell::DOMRefCell;
-use dom::bindings::codegen::Bindings::ConsoleBinding;
-use dom::bindings::codegen::Bindings::ConsoleBinding::ConsoleMethods;
use dom::bindings::global::GlobalRef;
-use dom::bindings::js::Root;
-use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use std::collections::HashMap;
+use std::collections::hash_map::Entry;
use time::{Timespec, get_time};
// https://developer.mozilla.org/en-US/docs/Web/API/Console
-#[dom_struct]
-pub struct Console {
- reflector_: Reflector,
- timers: DOMRefCell<HashMap<DOMString, u64>>,
-}
+pub struct Console(());
impl Console {
- fn new_inherited() -> Console {
- Console {
- reflector_: Reflector::new(),
- timers: DOMRefCell::new(HashMap::new()),
- }
- }
-
- pub fn new(global: GlobalRef) -> Root<Console> {
- reflect_dom_object(box Console::new_inherited(),
- global,
- ConsoleBinding::Wrap)
- }
-
- fn send_to_devtools(&self, level: LogLevel, message: DOMString) {
- let global = self.global();
- let global = global.r();
+ fn send_to_devtools(global: GlobalRef, level: LogLevel, message: DOMString) {
if let Some(chan) = global.devtools_chan() {
let console_message = prepare_message(level, message);
let devtools_message = ScriptToDevtoolsControlMsg::ConsoleAPI(
@@ -48,83 +26,73 @@ impl Console {
}
}
-impl ConsoleMethods for Console {
+impl Console {
// https://developer.mozilla.org/en-US/docs/Web/API/Console/log
- fn Log(&self, messages: Vec<DOMString>) {
+ pub fn Log(global: GlobalRef, messages: Vec<DOMString>) {
for message in messages {
println!("{}", message);
- self.send_to_devtools(LogLevel::Log, message);
+ Self::send_to_devtools(global, LogLevel::Log, message);
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console
- fn Debug(&self, messages: Vec<DOMString>) {
+ pub fn Debug(global: GlobalRef, messages: Vec<DOMString>) {
for message in messages {
println!("{}", message);
- self.send_to_devtools(LogLevel::Debug, message);
+ Self::send_to_devtools(global, LogLevel::Debug, message);
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console/info
- fn Info(&self, messages: Vec<DOMString>) {
+ pub fn Info(global: GlobalRef, messages: Vec<DOMString>) {
for message in messages {
println!("{}", message);
- self.send_to_devtools(LogLevel::Info, message);
+ Self::send_to_devtools(global, LogLevel::Info, message);
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console/warn
- fn Warn(&self, messages: Vec<DOMString>) {
+ pub fn Warn(global: GlobalRef, messages: Vec<DOMString>) {
for message in messages {
println!("{}", message);
- self.send_to_devtools(LogLevel::Warn, message);
+ Self::send_to_devtools(global, LogLevel::Warn, message);
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console/error
- fn Error(&self, messages: Vec<DOMString>) {
+ pub fn Error(global: GlobalRef, messages: Vec<DOMString>) {
for message in messages {
println!("{}", message);
- self.send_to_devtools(LogLevel::Error, message);
+ Self::send_to_devtools(global, LogLevel::Error, message);
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console/assert
- fn Assert(&self, condition: bool, message: Option<DOMString>) {
+ pub fn Assert(global: GlobalRef, condition: bool, message: Option<DOMString>) {
if !condition {
let message = message.unwrap_or_else(|| DOMString::from("no message"));
println!("Assertion failed: {}", message);
- self.send_to_devtools(LogLevel::Error, message);
+ Self::send_to_devtools(global, LogLevel::Error, message);
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console/time
- fn Time(&self, label: DOMString) {
- let mut timers = self.timers.borrow_mut();
- if timers.contains_key(&label) {
- // Timer already started
- return;
- }
- if timers.len() >= 10000 {
- // Too many timers on page
- return;
+ pub fn Time(global: GlobalRef, label: DOMString) {
+ if let Ok(()) = global.console_timers().time(label.clone()) {
+ let message = DOMString::from(format!("{}: timer started", label));
+ println!("{}", message);
+ Self::send_to_devtools(global, LogLevel::Log, message);
}
-
- timers.insert(label.clone(), timestamp_in_ms(get_time()));
- let message = DOMString::from(format!("{}: timer started", label));
- println!("{}", message);
- self.send_to_devtools(LogLevel::Log, message);
}
// https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd
- fn TimeEnd(&self, label: DOMString) {
- let mut timers = self.timers.borrow_mut();
- if let Some(start) = timers.remove(&label) {
+ pub fn TimeEnd(global: GlobalRef, label: DOMString) {
+ if let Ok(delta) = global.console_timers().time_end(&label) {
let message = DOMString::from(
- format!("{}: {}ms", label, timestamp_in_ms(get_time()) - start)
+ format!("{}: {}ms", label, delta)
);
println!("{}", message);
- self.send_to_devtools(LogLevel::Log, message);
+ Self::send_to_devtools(global, LogLevel::Log, message);
};
}
}
@@ -143,3 +111,32 @@ fn prepare_message(logLevel: LogLevel, message: DOMString) -> ConsoleMessage {
columnNumber: 1,
}
}
+
+#[derive(HeapSizeOf, JSTraceable)]
+pub struct TimerSet(DOMRefCell<HashMap<DOMString, u64>>);
+
+impl TimerSet {
+ pub fn new() -> Self {
+ TimerSet(DOMRefCell::new(Default::default()))
+ }
+
+ fn time(&self, label: DOMString) -> Result<(), ()> {
+ let mut timers = self.0.borrow_mut();
+ if timers.len() >= 10000 {
+ return Err(());
+ }
+ match timers.entry(label) {
+ Entry::Vacant(entry) => {
+ entry.insert(timestamp_in_ms(get_time()));
+ Ok(())
+ },
+ Entry::Occupied(_) => Err(()),
+ }
+ }
+
+ fn time_end(&self, label: &str) -> Result<u64, ()> {
+ self.0.borrow_mut().remove(label).ok_or(()).map(|start| {
+ timestamp_in_ms(get_time()) - start
+ })
+ }
+}
diff --git a/components/script/dom/webidls/Console.webidl b/components/script/dom/webidls/Console.webidl
index 09273db78b8..90f9bb9f58e 100644
--- a/components/script/dom/webidls/Console.webidl
+++ b/components/script/dom/webidls/Console.webidl
@@ -9,8 +9,10 @@
* © Copyright 2014 Mozilla Foundation.
*/
-[Exposed=(Window,Worker)]
-interface Console {
+[ClassString="Console",
+ Exposed=(Window,Worker),
+ ProtoObjectHack]
+namespace console {
// These should be DOMString message, DOMString message2, ...
void log(DOMString... messages);
void debug(DOMString... messages);
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index dcf79a61c7e..dbe73ca4831 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -161,7 +161,6 @@ partial interface Window {
// Proprietary extensions.
partial interface Window {
- readonly attribute Console console;
void debug(DOMString arg);
void gc();
void trap();
diff --git a/components/script/dom/webidls/WorkerGlobalScope.webidl b/components/script/dom/webidls/WorkerGlobalScope.webidl
index cc9fb292cd3..186e5cd7fee 100644
--- a/components/script/dom/webidls/WorkerGlobalScope.webidl
+++ b/components/script/dom/webidls/WorkerGlobalScope.webidl
@@ -24,10 +24,3 @@ partial interface WorkerGlobalScope { // not obsolete
};
WorkerGlobalScope implements WindowTimers;
WorkerGlobalScope implements WindowBase64;
-
-// Proprietary
-[Exposed=Worker]
-partial interface WorkerGlobalScope {
- [Replaceable]
- readonly attribute Console console;
-};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 4954f7cccd0..e8006123360 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -25,7 +25,7 @@ use dom::bindings::str::DOMString;
use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::utils::{GlobalStaticData, WindowProxyHandler};
use dom::browsingcontext::BrowsingContext;
-use dom::console::Console;
+use dom::console::TimerSet;
use dom::crypto::Crypto;
use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration};
use dom::document::Document;
@@ -157,7 +157,6 @@ pub struct Window {
history_traversal_task_source: HistoryTraversalTaskSource,
#[ignore_heap_size_of = "task sources are hard"]
file_reading_task_source: FileReadingTaskSource,
- console: MutNullableHeap<JS<Console>>,
crypto: MutNullableHeap<JS<Crypto>>,
navigator: MutNullableHeap<JS<Navigator>>,
#[ignore_heap_size_of = "channels are hard"]
@@ -276,7 +275,10 @@ pub struct Window {
scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>,
/// https://html.spec.whatwg.org/multipage/#in-error-reporting-mode
- in_error_reporting_mode: Cell<bool>
+ in_error_reporting_mode: Cell<bool>,
+
+ /// Timers used by the Console API.
+ console_timers: TimerSet,
}
impl Window {
@@ -508,11 +510,6 @@ impl WindowMethods for Window {
self.local_storage.or_init(|| Storage::new(&GlobalRef::Window(self), StorageType::Local))
}
- // https://developer.mozilla.org/en-US/docs/Web/API/Console
- fn Console(&self) -> Root<Console> {
- self.console.or_init(|| Console::new(GlobalRef::Window(self)))
- }
-
// https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-GlobalCrypto
fn Crypto(&self) -> Root<Crypto> {
self.crypto.or_init(|| Crypto::new(GlobalRef::Window(self)))
@@ -1701,7 +1698,6 @@ impl Window {
history_traversal_task_source: history_task_source,
file_reading_task_source: file_task_source,
image_cache_chan: image_cache_chan,
- console: Default::default(),
crypto: Default::default(),
navigator: Default::default(),
image_cache_thread: image_cache_thread,
@@ -1747,10 +1743,16 @@ impl Window {
error_reporter: error_reporter,
scroll_offsets: DOMRefCell::new(HashMap::new()),
in_error_reporting_mode: Cell::new(false),
+ console_timers: TimerSet::new(),
};
WindowBinding::Wrap(runtime.cx(), win)
}
+
+ pub fn console_timers(&self) -> &TimerSet {
+ &self.console_timers
+ }
+
pub fn live_devtools_updates(&self) -> bool {
return self.devtools_wants_updates.get();
}
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index d60ddb84f88..1c2c46fb52d 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -12,7 +12,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
-use dom::console::Console;
+use dom::console::TimerSet;
use dom::crypto::Crypto;
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::eventtarget::EventTarget;
@@ -80,7 +80,6 @@ pub struct WorkerGlobalScope {
resource_threads: ResourceThreads,
location: MutNullableHeap<JS<WorkerLocation>>,
navigator: MutNullableHeap<JS<WorkerNavigator>>,
- console: MutNullableHeap<JS<Console>>,
crypto: MutNullableHeap<JS<Crypto>>,
timers: OneshotTimers,
@@ -110,6 +109,9 @@ pub struct WorkerGlobalScope {
#[ignore_heap_size_of = "Defined in std"]
scheduler_chan: IpcSender<TimerEventRequest>,
+
+ /// Timers used by the Console API.
+ console_timers: TimerSet,
}
impl WorkerGlobalScope {
@@ -130,7 +132,6 @@ impl WorkerGlobalScope {
resource_threads: init.resource_threads,
location: Default::default(),
navigator: Default::default(),
- console: Default::default(),
crypto: Default::default(),
timers: OneshotTimers::new(timer_event_chan, init.scheduler_chan.clone()),
mem_profiler_chan: init.mem_profiler_chan,
@@ -141,9 +142,14 @@ impl WorkerGlobalScope {
devtools_wants_updates: Cell::new(false),
constellation_chan: init.constellation_chan,
scheduler_chan: init.scheduler_chan,
+ console_timers: TimerSet::new(),
}
}
+ pub fn console_timers(&self) -> &TimerSet {
+ &self.console_timers
+ }
+
pub fn mem_profiler_chan(&self) -> &mem::ProfilerChan {
&self.mem_profiler_chan
}
@@ -299,11 +305,6 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
self.navigator.or_init(|| WorkerNavigator::new(self))
}
- // https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/console
- fn Console(&self) -> Root<Console> {
- self.console.or_init(|| Console::new(GlobalRef::Worker(self)))
- }
-
// https://html.spec.whatwg.org/multipage/#dfn-Crypto
fn Crypto(&self) -> Root<Crypto> {
self.crypto.or_init(|| Crypto::new(GlobalRef::Worker(self)))