WebIDL bindings

  • Revision slug: Mozilla/WebIDL_bindings
  • Revision title: WebIDL bindings
  • Revision id: 293969
  • Created:
  • Creator: lmorchard
  • Is current revision? No
  • Comment

Revision Content

The WebIDL bindings are generated at build time based on two things: the actual WebIDL file and a configuration file that lists some metadata about how the WebIDL should be reflected into Gecko-internal code.

All WebIDL files should be placed in dom/webidl and added to the list in the WebIDL.mk file in that directory.

The configuration file, dom/bindings/Bindings.conf, is basically a Python dict that maps interface names to information about the interface, called a descriptor.  There are all sorts of possible options here that handle various edge cases, but most descriptors can be very simple.

All the generated code is placed in the mozilla::dom namespace.  For each interface, a namespace whose name is the name of the interface with Binding appended is created, and all the things pertaining to that interface's binding go in that namespace.

There are various helper objects and utility methods in dom/bindings that are also all in the mozilla::dom namespace and whose headers are all exported into mozilla/dom.

Adding WebIDL bindings to a class


To add a WebIDL binding for interface MyInterface to a class MyClass that's supposed to implement that interface, you need to do the following:

  1. Inherit from nsWrapperCache and hook up the class to the cycle collector so it will trace the wrapper cache properly, and call SetIsDOMBinding() in the constructor of the derived class.
  2. Implement a GetParentObject override that, for a given instance of your class, returns the same object every time.  The idea is that walking the GetParentObject chain will eventually get you to a Window, so that every WebIDL object is associated with a particular Window.  For example, nsINode::GetParentObject returns the node's owner document.  The return value of GetParentObject must either singly-inherit from nsISupports or have a corresponding ToSupports() method that can produce an nsISupports from it.  If many instances of MyClass are expected to be created quicky, the return value of GetParentObject should itself inherit from nsWrapperCache for optimal performance.
  3. Add the WebIDL for MyInterface in dom/webidl and to the list in dom/webidl/WebIDL.mk.
  4. Add an entry to dom/bindings/Bindings.conf that sets the 'nativeType' for MyInterface to MyClass.  If MyClass is not in the header file one gets by replacing '::' with '/' and appending '.h', the add a corresponding 'headerFile' annotation.
  5. Implement a WrapObject override on MyClass that just calls through to mozilla::dom::MyInterfaceBinding::Wrap.
  6. Expose whatever methods the interface needs on MyClass.  These can be inline, virtual, have any calling convention, and so forth, as long as they have the right argument types and return types.

See this sample patch that migrates window.performance.* to WebIDL bindings.

Note: If your object can only be reflected into JS by creating it, not by retrieving it from somewhere, you can skip steps 1 and 2 above and instead add 'wrapperCache': False to your descriptor.  If your object already has classinfo, it should be using the nsNewDOMBindingNoWrapperCacheSH scriptable helper in this case.  You will need to flag the functions that return your object as [Creator] in the WebIDL.
Note: If your object needs to be reflected in Workers, you will need to do more work here.  XXXbz need to document.

C++ reflections of WebIDL constructs

 

C++ reflections of WebIDL operations (methods)


A WebIDL operation is turned into a method call on the underlying C++ object.  The return type and argument types are determined as described below.  In addition to those, all fallible (allowed to throw) methods will get an ErrorResult& argument appended to their argument list.  Methods that use certain WebIDL types like any or object will get a JSContext* argument prepended to the argument list.

The name of the C++ method is simply the name of the WebIDL operation with the first letter converted to uppercase.

WebIDL overloads are turned into C++ overloads: they simply call C++ methods with the same name and different signatures.

For example, this webidl:

interface MyInterface 
{
  void doSomething(long number);
  double doSomething(MyInterface? otherInstance);

  MyInterface doSomethingElse(optional long maybeNumber);
  void doSomethingElse(MyInterface otherInstance);

  void doTheOther(any something);
};

will require these method declarations:

class MyClass
{
  void DoSomething(int32_t aNumber, ErrorResult& rv);
  double DoSomething(MyClass* aOtherInstance, ErrorResult& rv);

  already_AddRefed<MyInterface> DoSomethingElse(Optional<int32_t> aMaybeNumber,
                                                ErrorResult& rv);
  void DoSomethingElse(MyClass& aOtherInstance, ErrorResult& rv);
  
  void DoTheOther(JSContext* cx, JS::Value aSomething, ErrorResult& rv);
}

C++ reflections of WebIDL attributes

A WebIDL attribute is turned into a pair of method calls for the getter and setter on the underlying C++ object.  A readonly attribute only has a getter and no setter.

The getter's name is Get followed by the name of the attribute with the first letter converted to uppercase.  The method signature looks just like an operation with no arguments and the attribute's type as the return type.

The setter's name is Set followed by the name of the attribute with the first letter converted to uppercase.  The method signature looks just like an operation with a void return value and a single argument whose type as the attribute's type.

C++ reflections of WebIDL constructors

A WebIDL constructor is turned into a static class method named Constructor.  The arguments of this method will be the arguments of the WebIDL constructor, with an nsISupports* for the global (typically the Window) prepended.  If a JSContext* is also needed due to some of the argument types, it will come before the global.  The return value of the constructor for MyInterface is exactly the same as that of a method returning an instance of MyInterface.

For example, this IDL:

[Constructor,
 Constructor(unsigned long someNumber)]
interface MyInterface 
{
};

will require the following declarations in MyClass:

class MyClass {
  // Various nsISupports stuff or whatnot
  static
  already_AddRefed<MyClass> Constructor(nsISupports* aGlobal,
                                        ErrorResult& rv);
  static
  already_AddRefed<MyClass> Constructor(nsISupports* aGlobal,
                                        uint32_t aSomeNumber,
                                        ErrorResult& rv);  
};

C++ reflections of WebIDL types

The exact C++ representation for WebIDL types can depend on the precise way that they're being used: e.g. return values, arguments, and sequence or dictionary members might all have different representations.

Unless stated otherwise, a type only has one representation.  Also, unless stated otherwise, nullable types are represented by wrapping Nullable<> around the base type.

In all cases, optional arguments which do not have a default value are represented by wrapping const Optional<> around the representation of the argument type.  Optional arguments which do have a default value are just represented by the argument type itself, set to the default value if the argument was not in fact passed in.

any

The any WebIDL type is represented as a JS::Value.  Methods using any always get a JSContext* argument.

For example, this WebIDL:

interface Test {
  attribute any myAttr;
  any myMethod(any arg);
};

will correspond to these C++ function declarations:

JS::Value GetMyAttr(JSContext* cx, ErrorResult& rv);
void SetMyAttr(JSContext* cx, JS::Value value, ErrorResult& rv);
JS::Value MyMethod(JSContext* cx, JS::Value arg, ErrorResult& rv);

boolean

The boolean WebIDL type is represented as a C++ bool.

For example, this WebIDL:

interface Test {
  attribute boolean myAttr;
  boolean myMethod(optional boolean arg);
};

will correspond to these C++ function declarations:

bool GetMyAttr(ErrorResult& rv);
void SetMyAttr(bool value, ErrorResult& rv);
JS::Value MyMethod(const Optional<bool>& arg, ErrorResult& rv);

Integer types

Integer WebIDL types are mapped to the corresponding C99 stdint types.

For example, this WebIDL:

interface Test {
  attribute short myAttr;
  long long myMethod(unsigned long? arg);
};

will correspond to these C++ function declarations:

int16_t GetMyAttr(ErrorResult& rv);
void SetMyAttr(int16_t value, ErrorResult& rv);
int64_t MyMethod(const Nullable<uint32_t>& arg, ErrorResult& rv);

Floating point types

Floating point WebIDL types are mapped to the C++ type of the same name.  So float and unrestricted float become a C++ float, while double and unrestricted double become a C++ double.

For example, this WebIDL:

interface Test {
  float myAttr;
  double myMethod(unrestricted double? arg);
};

will correspond to these C++ function declarations:

float GetMyAttr(ErrorResult& rv);
void SetMyAttr(float value, ErrorResult& rv);
double MyMethod(const Nullable<double>& arg, ErrorResult& rv);

DOMString

Strings are reflected in three different ways, depending on use:

  • String arguments become const nsAString&.
  • String return values become a nsString& out param appended to the argument list.  This comes after all IDL arguments, but before the ErrorResult&, if any, for the method.  Note that this allows callees to declare their methods as taking an nsAString& if desired.
  • Strings in sequences and dictionaries become nsString.

Nullable strings are represented by the same types as non-nullable ones, but the string will return true for DOMStringIsNull().  Returning null as a string value can be done using SetDOMStringToNull on the out param.

For example, this WebIDL:

interface Test {
  DOMString myAttr;
  DOMString myMethod(sequence<DOMString> arg1, DOMString? arg2, optional DOMString arg3);
};

will correspond to these C++ function declarations:

void GetMyAttr(nsString& retval, ErrorResult& rv);
void SetMyAttr(const nsAString& value, ErrorResult& rv);
void MyMethod(const Sequence<nsString>& arg1, const nsAString& arg2,
              const Optional<nsAString>& arg3, nsString& retval, ErrorResult& rv);

ByteString

ByteString is not suported yet.

object

object is represented in two different ways, depending on use:

  • Nullable object arguments and object return values become JSObject*.
  • Non-nullable object arguments become JSObject&.

Methods using object always get a JSContext* argument.

Interface types

There are four kinds of interface types in the WebIDL bindings.  Callback interfaces are used to represent script objects that browser code can call into.  External interfaces are used to represent objects that have not been converted to the WebIDL bindings yet.  WebIDL interfaces are used to represent WebIDL binding objects.  "SpiderMonkey" interfaces are used to represent objects that are implemented natively by the JavaScript engine (e.g. typed arrays).

Callback interfaces

For now, callback interfaces are represented in C++ as objects implementing some XPCOM interface that needs to be declared in XPIDL.  The XPCOM interface should be the nativeType listed for the WebIDL callback interface in the Bindings.conf file.  The exact representation depends on how the type is being used.

  • Nullable arguments become nsIFoo*.
  • Non-nullable arguments become nsIFoo&.
  • Return values become already_AddRefed<nsIFoo> or nsIFoo* depending on whether the method or property involved is flagged as resultNotAddRefed in Bindings.conf.
  • Callback interfaces in sequences and dictionaries are represented by nsRefPtr<nsIFoo> if nullable and OwningNonNull<nsIFoo> otherwise.
External interfaces

External interfaces are represented in C++ as objects that XPConnect knows how to unwrap to.  This can mean XPCOM interfaces (whether declared in XPIDL or not) or it can mean some type that there's a castable native unwrapping function for.  The C++ type to be used should be the nativeType listed for the external interface in the Bindings.conf file.  The exact representation depends on how the type is being used.

  • Arguments become nsIFoo*.
  • Return values become already_AddRefed<nsIFoo> or nsIFoo* depending on whether the method or property involved is flagged as resultNotAddRefed in Bindings.conf.
  • External interfaces in sequences and dictionaries are represented by nsRefPtr<nsIFoo>.
WebIDL interfaces

WebIDL interfaces are represented in C++ as C++ classes.  For non-worker bindings the class involved must inherit from nsISupports.  Furthermore, the canonical nsISupports must be on the primary inheritance chain of the object.  If the interface has a parent interface, the C++ class corresponding to the parent must also be on the primary inheritance chain of the object.  This guarantees that a void* corresponding to the canonical nsISupports can be reinterpret_cast to any of the classes that correspond to interfaces the object implements.  The C++ type to be used should be the nativeType listed for the interface in the Bindings.conf file.  The exact representation depends on how the type is being used.

  • Nullable arguments become Foo*.
  • Non-nullable arguments become Foo&.
  • Return values become already_AddRefed<Foo> or Foo* depending on whether the method or property involved is flagged as resultNotAddRefed in Bindings.conf.
  • WebIDL interfaces in sequences and dictionaries are represented by nsRefPtr<Foo> if nullable and OwningNonNull<Foo> otherwise.

For example, this WebIDL:

interface MyInterface {
  attribute MyInterface myAttr;
  void passNullable(MyInterface? arg);
  MyInterface? doSomething(sequence<MyInterface> arg);
  MyInterface doTheOther(sequence<MyInterface?> arg);
};

Would correspond to these C++ function declarations:

already_AddRefed<MyClass> GetMyAttr(ErrorResult& rv);
void SetMyAttr(MyClass& value, ErrorResult& rv);
void PassNullable(MyClass* arg, ErrorResult& rv);
already_AddRefed<MyClass> doSomething(const Sequence<OwningNonNull<MyClass> >& arg, ErrorResult& rv);
already_AddRefed<MyClass> doTheOther(const Sequence<nsRefPtr<MyClass> >& arg, ErrorResult& rv);
"SpiderMonkey" interfaces

Typed array, array buffer, and array buffer view arguments are represented by the objects in TypedArray.h.  For example, this WebIDL:

interface Test {
  void passTypedArrayBuffer(ArrayBuffer arg);
  void passTypedArray(ArrayBufferView arg);
  void passInt16Array(Int16Array arg);
}

will correspond to these C++ function declarations:

void PassTypedArrayBuffer(ArrayBuffer& arg, ErrorResult& rv);
void PassTypedArray(ArrayBufferView& arg, ErrorResult& rv);
void PassInt16Array(Int16Array& arg, ErrorResult& rv);

There is no support for returning objects of these types yet.

Dictionary types

A dictionary argument is represented by a const reference to a struct whose name is the dictionary name in the mozilla::dom namespace.  The struct has one member for each of the dictionary's members.  The members that have default values have types as described under the corresponding WebIDL type in this document.  The members that don't have default values have those types wrapped in Optional<>.

Dictionary return values are not supported yet.

Note that optional dictionary arguments are always considered to have a default value of null so dictionary arguments are never wrapped in Optional<>.

For example, this WebIDL:

dictionary Dict {
  long foo = 5;
  DOMString bar;
};

interface Test {
  void initSomething(optional Dict arg);
};

will correspond to this C++ function declaration:

void InitSomething(const Dict& arg, ErrorResult& rv);

and the Dict struct will look like this:

struct Dict {
  Optional<nsString> bar;
  int32_t foo;
}

Note that the dictionary members are sorted in the struct in alphabetical order.

Enumeration types

WebIDL enumeration types are represented as C++ enums.  The values of the C++ enum are named by taking the strings in the WebIDL enumeration, replacing dashes with underscores, and uppercasing the first letter, with a special case for the empty string, which becomes the value _empty.

For a WebIDL enum named MyEnum, the C++ enum is named valuelist and placed in the mozilla::dom::MyEnum namespace.

For example, this WebIDL:

enum MyEnum {
  "something",
  "something-else",
  "",
  "another"
};

would lead to this C++ enum declaration:

namespace MyEnum {
  enum valuelist {
    Something,
    Something_else,
    _empty,
    Another
  };
}

Callback function types

Callback functions are represented as JSObject*.  Methods using callback functions always get a JSContext* argument.

Sequences

Sequence arguments are represented by const Sequence<T>, where T depends on the type of elements in the WebIDL sequence.

Sequence return values are represented by an nsTArray<T> out param appended to the argument list, where T is the return type for the elements of the WebIDL sequence.  This comes after all IDL arguments, but before the ErrorResult&, if any, for the method.

Arrays

IDL array objects are not supported yet.

Union types

XXXbz write me

Date

Date is not supported yet.

Throwing exceptions from WebIDL methods, getters, and setters

All WebIDL methods, getters, and setters that are not explicitly marked as infallible have an ErrorResult& argument as their last argument.  To throw an exception, simply call Throw() on the ErrorResult& and return from your C++ back into the binding code.

Note: at the moment Throw() can only be called with an error nsresult, but in the future we expect to add ways to communicate more informative exception strings and other metainformation about the exception.

Custom extended attributes

Our WebIDL parser and code generator recognize several extended attributes that are not present in the WebIDL spec.

[ChromeOnly]

This extended attribute can be specified on any method, attribute, or constant on an interface.  Interface members flagged as [ChromeOnly] are only exposed in chrome Windows (and in particular, are not exposed to webpages).

[Pref=prefname]

This extended attribute can be specified on any method, attribute, or constant on an interface.  It takes a value, which must be the name of a boolean preference.  The interface member involved is then only exposed if that preference is set to true.   An example of how this can be used:

interface MyInterface {
  attribute long alwaysHere;
  [Pref=my.pref.name] attribute long onlyHereIfEnabled;
};

[Creator]

Used to flag methods or attributes as guaranteeing that they create a new object each time the method or attribute getter is called.  Only methods or attribute getters flagged in this way are allowed to return objects that are marked with 'wrapperCache': False.

Helper objects

The C++ side of the bindings uses a number of helper objects.

Nullable<T>

Nullable<> is a struct declared in Nullable.h and exported to mozilla/dom/Nullable.h that is used to represent nullable values of types that don't have a natural way to represent null.

Nullable<T> has an IsNull() getter that returns whether null is represented and a Value() getter that returns a const T& and can be used to get the value when it's not null.

Nullable<T> has a SetNull() setter that sets it as representing null and two setters that can be used to set it to a value: "void SetValue(T)" (for setting it to a given value) and "T& SetValue()" for directly modifying the underlying T&.

Optional<T>

Optional<> is a struct declared in BindingUtils.h and exported to mozilla/dom/BindingUtils.h that is used to represent optional arguments and dictionary members, but only those that have no default value.

Optional<T> has a WasPassed() getter that returns true if a value is available.  In that case, the Value() getter can be used to get a const T& for the value.

NonNull<T>

NonNull<T> is a struct declared in BindingUtils.h and exported to mozilla/dom/BindingUtils.h that is used to represent non-null C++ objects.  It has a conversion operator that produces T&.

OwningNonNull<T>

OwningNonNull<T> is a struct declared in BindingUtils.h and exported to mozilla/dom/BindingUtils.h that is used to represent non-null C++ objects and holds a strong reference to them.  It has a conversion operator that produces T&.

Typed arrays, arraybuffers, array buffer views

TypedArray.h is exported to mozilla/dom/TypedArray.h and exposes structs that correspond to the various typed array types, as well as ArrayBuffer and ArrayBufferView, all in the mozilla::dom namespace.  Each struct has an mData member of the relevant type (uint8_t for ArrayBuffer and ArrayBufferView) and an mLength member.

Sequence<T>

Sequence<> is a type declared in BindingUtils.h and exported to mozilla/dom/BindingUtils.h that used to represent sequence arguments.  It's some kind of typed array, but which exact kind is opaque to consumers.  This allows the binding code to change the exact definition (e.g. to use auto arrays of different sizes and so forth) without having to update all the callees.

Bindings.conf details

XXXbz write me.  In particular, need to describe at least use of concrete, prefable, and addExternalInterface

Revision Source

<p>The <a class="external" href="http://www.w3.org/TR/WebIDL/" title="http://www.w3.org/TR/WebIDL/">WebIDL</a> bindings are generated at build time based on two things: the actual WebIDL file and a configuration file that lists some metadata about how the WebIDL should be reflected into Gecko-internal code.</p>
<p>All WebIDL files should be placed in <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/webidl/" title="http://mxr.mozilla.org/mozilla-central/source/dom/webidl/"><code>dom/webidl</code></a> and added to the list in the <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/webidl/WebIDL.mk" title="http://mxr.mozilla.org/mozilla-central/source/dom/webidl/WebIDL.mk"><code>WebIDL.mk</code></a> file in that directory.</p>
<p>The configuration file, <code><a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/Bindings.conf" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/Bindings.conf">dom/bindings/Bindings.conf</a>,</code> is basically a Python dict that maps interface names to information about the interface, called a <em>descriptor</em>.  There are all sorts of possible options here that handle various edge cases, but most descriptors can be very simple.</p>
<p>All the generated code is placed in the <code>mozilla::dom</code> namespace.  For each interface, a namespace whose name is the name of the interface with <code>Binding</code> appended is created, and all the things pertaining to that interface's binding go in that namespace.</p>
<p>There are various helper objects and utility methods in <code>dom/bindings</code> that are also all in the <code>mozilla::dom</code> namespace and whose headers are all exported into <code>mozilla/dom</code>.</p>
<h2>Adding WebIDL bindings to a class</h2>
<p><br /> To add a WebIDL binding for interface <code>MyInterface</code> to a class <code>MyClass</code> that's supposed to implement that interface, you need to do the following:</p>
<ol> <li>Inherit from <code>nsWrapperCache</code> and hook up the class to the cycle collector so it will trace the wrapper cache properly, and call <code>SetIsDOMBinding()</code> in the constructor of the derived class.</li> <li>Implement a <code>GetParentObject</code> override that, for a given instance of your class, returns the same object every time.  The idea is that walking the <code>GetParentObject</code> chain will eventually get you to a Window, so that every WebIDL object is associated with a particular Window.  For example, <code>nsINode::GetParentObject</code> returns the node's owner document.  The return value of <code>GetParentObject</code> must either singly-inherit from <code>nsISupports</code> or have a corresponding <code>ToSupports()</code> method that can produce an <code>nsISupports</code> from it.  If many instances of <code>MyClass</code> are expected to be created quicky, the return value of <code>GetParentObject</code> should itself inherit from <code>nsWrapperCache</code> for optimal performance.</li> <li>Add the WebIDL for <code>MyInterface</code> in <code>dom/webidl</code> and to the list in <code>dom/webidl/WebIDL.mk</code>.</li> <li>Add an entry to <code>dom/bindings/Bindings.conf</code> that sets the <code>'nativeType'</code> for <code>MyInterface</code> to <code>MyClass</code>.  If <code>MyClass</code> is not in the header file one gets by replacing '::' with '/' and appending '<code>.h</code>', the add a corresponding <code>'headerFile'</code> annotation.</li> <li>Implement a <code>WrapObject</code> override on <code>MyClass</code> that just calls through to <code>mozilla::dom::MyInterfaceBinding::Wrap</code>.</li> <li>Expose whatever methods the interface needs on <code>MyClass</code>.  These can be inline, virtual, have any calling convention, and so forth, as long as they have the right argument types and return types.</li>
</ol>
<p>See this <a href="https://bugzilla.mozilla.org/attachment.cgi?id=640605" title="https://bugzilla.mozilla.org/attachment.cgi?id=640605" class=" link-https">sample patch that migrates window.performance.* to WebIDL bindings</a>.</p>
<div class="note"><strong>Note:</strong> If your object can only be reflected into JS by creating it, not by retrieving it from somewhere, you can skip steps 1 and 2 above and instead add <code>'wrapperCache': False</code> to your descriptor.  If your object already has classinfo, it should be using the <code>nsNewDOMBindingNoWrapperCacheSH</code> scriptable helper in this case.  You will need to flag the functions that return your object as <a href="#Creator" title="#Creator"><code>[Creator]</code></a> in the WebIDL.</div>
<div class="warning"><strong>Note:</strong> If your object needs to be reflected in Workers, you will need to do more work here.  XXXbz need to document.</div>
<h2>C++ reflections of WebIDL constructs</h2>
<p> </p>
<h3>C++ reflections of WebIDL operations (methods)</h3>
<p><br /> A WebIDL operation is turned into a method call on the underlying C++ object.  The return type and argument types are determined <a href="#typemapping" title="#typemapping">as described below</a>.  In addition to those, all fallible (allowed to throw) methods will get an <code>ErrorResult&amp;</code> argument appended to their argument list.  Methods that use certain WebIDL types like <code>any</code> or <code>object</code> will get a <code>JSContext*</code> argument prepended to the argument list.</p>
<p>The name of the C++ method is simply the name of the WebIDL operation with the first letter converted to uppercase.</p>
<p>WebIDL overloads are turned into C++ overloads: they simply call C++ methods with the same name and different signatures.</p>
<p>For example, this webidl:</p>
<pre>
interface MyInterface 
{
  void doSomething(long number);
  double doSomething(MyInterface? otherInstance);

  MyInterface doSomethingElse(optional long maybeNumber);
  void doSomethingElse(MyInterface otherInstance);

  void doTheOther(any something);
};
</pre>
<p>will require these method declarations:</p>
<pre>
class MyClass
{
  void DoSomething(int32_t aNumber, ErrorResult&amp; rv);
  double DoSomething(MyClass* aOtherInstance, ErrorResult&amp; rv);

  already_AddRefed&lt;MyInterface&gt; DoSomethingElse(Optional&lt;int32_t&gt; aMaybeNumber,
                                                ErrorResult&amp; rv);
  void DoSomethingElse(MyClass&amp; aOtherInstance, ErrorResult&amp; rv);
  
  void DoTheOther(JSContext* cx, JS::Value aSomething, ErrorResult&amp; rv);
}
</pre>
<h3>C++ reflections of WebIDL attributes</h3>
<p>A WebIDL attribute is turned into a pair of method calls for the getter and setter on the underlying C++ object.  A readonly attribute only has a getter and no setter.</p>
<p>The getter's name is <code>Get</code> followed by the name of the attribute with the first letter converted to uppercase.  The method signature looks just like an operation with no arguments and the attribute's type as the return type.</p>
<p>The setter's name is <code>Set</code> followed by the name of the attribute with the first letter converted to uppercase.  The method signature looks just like an operation with a void return value and a single argument whose type as the attribute's type.</p>
<h3>C++ reflections of WebIDL constructors</h3>
<p>A WebIDL constructor is turned into a static class method named <code>Constructor</code>.  The arguments of this method will be the arguments of the WebIDL constructor, with an <code>nsISupports*</code> for the global (typically the Window) prepended.  If a <code>JSContext*</code> is also needed due to some of the argument types, it will come before the global.  The return value of the constructor for <code>MyInterface</code> is exactly the same as that of a method returning an instance of <code>MyInterface</code>.</p>
<p>For example, this IDL:</p>
<pre>
[Constructor,
 Constructor(unsigned long someNumber)]
interface MyInterface 
{
};
</pre>
<p>will require the following declarations in <code>MyClass</code>:</p>
<pre>
class MyClass {
  // Various nsISupports stuff or whatnot
  static
  already_AddRefed&lt;MyClass&gt; Constructor(nsISupports* aGlobal,
                                        ErrorResult&amp; rv);
  static
  already_AddRefed&lt;MyClass&gt; Constructor(nsISupports* aGlobal,
                                        uint32_t aSomeNumber,
                                        ErrorResult&amp; rv);  
};
</pre>
<h3><a name="typemapping" />C++ reflections of WebIDL types</h3>
<p>The exact C++ representation for WebIDL types can depend on the precise way that they're being used: e.g. return values, arguments, and sequence or dictionary members might all have different representations.</p>
<p>Unless stated otherwise, a type only has one representation.  Also, unless stated otherwise, nullable types are represented by wrapping <a href="#Nullable" title="#Nullable"><code>Nullable&lt;&gt;</code></a> around the base type.</p>
<p>In all cases, optional arguments which do not have a default value are represented by wrapping <a href="#Optional" title="#Optional"><code>const Optional&lt;&gt;</code></a> around the representation of the argument type.  Optional arguments which do have a default value are just represented by the argument type itself, set to the default value if the argument was not in fact passed in.</p>
<h4><code>any</code></h4>
<p>The <code>any</code> WebIDL type is represented as a <code>JS::Value</code>.  Methods using <code>any</code> always get a <code>JSContext*</code> argument.</p>
<p>For example, this WebIDL:</p>
<pre>
interface Test {
  attribute any myAttr;
  any myMethod(any arg);
};
</pre>
<p>will correspond to these C++ function declarations:</p>
<pre>
JS::Value GetMyAttr(JSContext* cx, ErrorResult&amp; rv);
void SetMyAttr(JSContext* cx, JS::Value value, ErrorResult&amp; rv);
JS::Value MyMethod(JSContext* cx, JS::Value arg, ErrorResult&amp; rv);
</pre>
<h4><code>boolean</code></h4>
<p>The <code>boolean</code> WebIDL type is represented as a C++ <code>bool</code>.</p>
<p>For example, this WebIDL:</p>
<pre>
interface Test {
  attribute boolean myAttr;
  boolean myMethod(optional boolean arg);
};
</pre>
<p>will correspond to these C++ function declarations:</p>
<pre>
bool GetMyAttr(ErrorResult&amp; rv);
void SetMyAttr(bool value, ErrorResult&amp; rv);
JS::Value MyMethod(const Optional&lt;bool&gt;&amp; arg, ErrorResult&amp; rv);
</pre>
<h4>Integer types</h4>
<p>Integer WebIDL types are mapped to the corresponding C99 stdint types.</p>
<p>For example, this WebIDL:</p>
<pre>
interface Test {
  attribute short myAttr;
  long long myMethod(unsigned long? arg);
};
</pre>
<p>will correspond to these C++ function declarations:</p>
<pre>
int16_t GetMyAttr(ErrorResult&amp; rv);
void SetMyAttr(int16_t value, ErrorResult&amp; rv);
int64_t MyMethod(const Nullable&lt;uint32_t&gt;&amp; arg, ErrorResult&amp; rv);
</pre>
<h4>Floating point types</h4>
<p>Floating point WebIDL types are mapped to the C++ type of the same name.  So <code>float</code> and <code>unrestricted float</code> become a C++ <code>float</code>, while <code>double</code> and <code>unrestricted double</code> become a C++ <code>double</code>.</p>
<p>For example, this WebIDL:</p>
<pre>
interface Test {
  float myAttr;
  double myMethod(unrestricted double? arg);
};
</pre>
<p>will correspond to these C++ function declarations:</p>
<pre>
float GetMyAttr(ErrorResult&amp; rv);
void SetMyAttr(float value, ErrorResult&amp; rv);
double MyMethod(const Nullable&lt;double&gt;&amp; arg, ErrorResult&amp; rv);
</pre>
<h4><code>DOMString</code></h4>
<p>Strings are reflected in three different ways, depending on use:</p>
<ul> <li>String arguments become <code>const nsAString&amp;</code>.</li> <li>String return values become a <code>nsString&amp;</code> out param appended to the argument list.  This comes after all IDL arguments, but before the <code>ErrorResult&amp;</code>, if any, for the method.  Note that this allows callees to declare their methods as taking an <code>nsAString&amp;</code> if desired.</li> <li>Strings in sequences and dictionaries become <code>nsString</code>.</li>
</ul>
<p>Nullable strings are represented by the same types as non-nullable ones, but the string will return true for <code>DOMStringIsNull()</code>.  Returning null as a string value can be done using <code>SetDOMStringToNull</code> on the out param.</p>
<p>For example, this WebIDL:</p>
<pre>
interface Test {
  DOMString myAttr;
  DOMString myMethod(sequence&lt;DOMString&gt; arg1, DOMString? arg2, optional DOMString arg3);
};
</pre>
<p>will correspond to these C++ function declarations:</p>
<pre>
void GetMyAttr(nsString&amp; retval, ErrorResult&amp; rv);
void SetMyAttr(const nsAString&amp; value, ErrorResult&amp; rv);
void MyMethod(const Sequence&lt;nsString&gt;&amp; arg1, const nsAString&amp; arg2,
              const Optional&lt;nsAString&gt;&amp; arg3, nsString&amp; retval, ErrorResult&amp; rv);
</pre>
<h4><code>ByteString</code></h4>
<p><code>ByteString</code> is not suported yet.</p>
<h4><code>object</code></h4>
<p><code>object</code> is represented in two different ways, depending on use:</p>
<ul> <li>Nullable <code>object</code> arguments and <code>object</code> return values become <code>JSObject*</code>.</li> <li>Non-nullable <code>object</code> arguments become <code>JSObject&amp;</code>.</li>
</ul>
<p>Methods using <code>object</code> always get a <code>JSContext*</code> argument.</p>
<h4>Interface types</h4>
<p>There are four kinds of interface types in the WebIDL bindings.  Callback interfaces are used to represent script objects that browser code can call into.  External interfaces are used to represent objects that have not been converted to the WebIDL bindings yet.  WebIDL interfaces are used to represent WebIDL binding objects.  &quot;SpiderMonkey&quot; interfaces are used to represent objects that are implemented natively by the JavaScript engine (e.g. typed arrays).</p>
<h5>Callback interfaces</h5>
<p>For now, callback interfaces are represented in C++ as objects implementing some XPCOM interface that needs to be declared in XPIDL.  The XPCOM interface should be the <code>nativeType</code> listed for the WebIDL callback interface in the <a href="#Bindings.conf" title="#Bindings.conf"><code>Bindings.conf</code></a> file.  The exact representation depends on how the type is being used.</p>
<ul> <li>Nullable arguments become <code>nsIFoo*</code>.</li> <li>Non-nullable arguments become <code>nsIFoo&amp;</code>.</li> <li>Return values become <code>already_AddRefed&lt;nsIFoo&gt;</code> or <code>nsIFoo*</code> depending on whether the method or property involved is flagged as <code>resultNotAddRefed</code> in <a href="#Bindings.conf" title="#Bindings.conf"><code>Bindings.conf</code></a>.</li> <li>Callback interfaces in sequences and dictionaries are represented by <code>nsRefPtr&lt;nsIFoo&gt;</code> if nullable and <a href="#OwningNonNull" title="#OwningNonNull"><code>OwningNonNull&lt;nsIFoo&gt;</code></a> otherwise.</li>
</ul>
<h5>External interfaces</h5>
<p>External interfaces are represented in C++ as objects that XPConnect knows how to unwrap to.  This can mean XPCOM interfaces (whether declared in XPIDL or not) or it can mean some type that there's a castable native unwrapping function for.  The C++ type to be used should be the <code>nativeType</code> listed for the external interface in the <a href="#Bindings.conf" title="#Bindings.conf"><code>Bindings.conf</code></a> file.  The exact representation depends on how the type is being used.</p>
<ul> <li>Arguments become <code>nsIFoo*</code>.</li> <li>Return values become <code>already_AddRefed&lt;nsIFoo&gt;</code> or <code>nsIFoo*</code> depending on whether the method or property involved is flagged as <code>resultNotAddRefed</code> in <a href="#Bindings.conf" title="#Bindings.conf"><code>Bindings.conf</code></a>.</li> <li>External interfaces in sequences and dictionaries are represented by <code>nsRefPtr&lt;nsIFoo&gt;.</code></li>
</ul>
<h5>WebIDL interfaces</h5>
<p>WebIDL interfaces are represented in C++ as C++ classes.  For non-worker bindings the class involved must inherit from <code>nsISupports</code>.  Furthermore, the canonical <code>nsISupports</code> must be on the primary inheritance chain of the object.  If the interface has a parent interface, the C++ class corresponding to the parent must also be on the primary inheritance chain of the object.  This guarantees that a <code>void*</code> corresponding to the canonical <code>nsISupports</code> can be <code>reinterpret_cast</code> to any of the classes that correspond to interfaces the object implements.  The C++ type to be used should be the <code>nativeType</code> listed for the interface in the <a href="#Bindings.conf" title="#Bindings.conf"><code>Bindings.conf</code></a> file.  The exact representation depends on how the type is being used.</p>
<ul> <li>Nullable arguments become <code>Foo*</code>.</li> <li>Non-nullable arguments become <code>Foo&amp;</code>.</li> <li>Return values become <code>already_AddRefed&lt;Foo&gt;</code> or <code>Foo*</code> depending on whether the method or property involved is flagged as <code>resultNotAddRefed</code> in <a href="#Bindings.conf" title="#Bindings.conf"><code>Bindings.conf</code></a>.</li> <li>WebIDL interfaces in sequences and dictionaries are represented by <code>nsRefPtr&lt;Foo&gt;</code> if nullable and <a href="#OwningNonNull" title="#OwningNonNull"><code>OwningNonNull&lt;Foo&gt;</code></a> otherwise.</li>
</ul>
<p>For example, this WebIDL:</p>
<pre>interface MyInterface {
  attribute MyInterface myAttr;
  void passNullable(MyInterface? arg);
  MyInterface? doSomething(sequence&lt;MyInterface&gt; arg);
  MyInterface doTheOther(sequence&lt;MyInterface?&gt; arg);
};
</pre>
<p>Would correspond to these C++ function declarations:</p>
<pre>already_AddRefed&lt;MyClass&gt; GetMyAttr(ErrorResult&amp; rv);
void SetMyAttr(MyClass&amp; value, ErrorResult&amp; rv);
void PassNullable(MyClass* arg, ErrorResult&amp; rv);
already_AddRefed&lt;MyClass&gt; doSomething(const Sequence&lt;OwningNonNull&lt;MyClass&gt; &gt;&amp; arg, ErrorResult&amp; rv);
already_AddRefed&lt;MyClass&gt; doTheOther(const Sequence&lt;nsRefPtr&lt;MyClass&gt; &gt;&amp; arg, ErrorResult&amp; rv);
</pre>
<h5>&quot;SpiderMonkey&quot; interfaces</h5>
<p>Typed array, array buffer, and array buffer view arguments are represented by the objects in <a href="#TypedArray" title="#TypedArray"><code>TypedArray.h</code></a>.  For example, this WebIDL:</p>
<pre>interface Test {
  void passTypedArrayBuffer(ArrayBuffer arg);
  void passTypedArray(ArrayBufferView arg);
  void passInt16Array(Int16Array arg);
}
</pre>
<p>will correspond to these C++ function declarations:</p>
<pre>void PassTypedArrayBuffer(ArrayBuffer&amp; arg, ErrorResult&amp; rv);
void PassTypedArray(ArrayBufferView&amp; arg, ErrorResult&amp; rv);
void PassInt16Array(Int16Array&amp; arg, ErrorResult&amp; rv);
</pre>
<p>There is no support for returning objects of these types yet.</p>
<h4>Dictionary types</h4>
<p>A dictionary argument is represented by a const reference to a struct whose name is the dictionary name in the <code>mozilla::dom</code> namespace.  The struct has one member for each of the dictionary's members.  The members that have default values have types as described under the corresponding WebIDL type in this document.  The members that don't have default values have those types wrapped in <a href="#Optional" title="#Optional"><code>Optional&lt;&gt;</code></a>.</p>
<p>Dictionary return values are not supported yet.</p>
<p>Note that optional dictionary arguments are always considered to have a default value of <code>null</code> so dictionary arguments are never wrapped in <code>Optional&lt;&gt;</code>.</p>
<p>For example, this WebIDL:</p>
<pre>dictionary Dict {
  long foo = 5;
  DOMString bar;
};

interface Test {
  void initSomething(optional Dict arg);
};
</pre>
<p>will correspond to this C++ function declaration:</p>
<pre>void InitSomething(const Dict&amp; arg, ErrorResult&amp; rv);
</pre>
<p>and the <code>Dict</code> struct will look like this:</p>
<pre>struct Dict {
  Optional&lt;nsString&gt; bar;
  int32_t foo;
}
</pre>
<p>Note that the dictionary members are sorted in the struct in alphabetical order.</p>
<h4>Enumeration types</h4>
<p>WebIDL enumeration types are represented as C++ enums.  The values of the C++ enum are named by taking the strings in the WebIDL enumeration, replacing dashes with underscores, and uppercasing the first letter, with a special case for the empty string, which becomes the value <code>_empty</code>.</p>
<p>For a WebIDL enum named <code>MyEnum</code>, the C++ enum is named <code>valuelist</code> and placed in the <code>mozilla::dom::MyEnum</code> namespace.</p>
<p>For example, this WebIDL:</p>
<pre>enum MyEnum {
  &quot;something&quot;,
  &quot;something-else&quot;,
  &quot;&quot;,
  &quot;another&quot;
};
</pre>
<p>would lead to this C++ enum declaration:</p>
<pre>namespace MyEnum {
  enum valuelist {
    Something,
    Something_else,
    _empty,
    Another
  };
}
</pre>
<h4>Callback function types</h4>
<p>Callback functions are represented as <code>JSObject*</code>.  Methods using callback functions always get a <code>JSContext*</code> argument.</p>
<h4>Sequences</h4>
<p>Sequence arguments are represented by <a href="#Sequence" title="#Sequence"><code>const Sequence&lt;T&gt;</code></a>, where <code>T</code> depends on the type of elements in the WebIDL sequence.</p>
<p>Sequence return values are represented by an <code>nsTArray&lt;T&gt;</code> out param appended to the argument list, where <code>T</code> is the return type for the elements of the WebIDL sequence.  This comes after all IDL arguments, but before the <code>ErrorResult&amp;</code>, if any, for the method.</p>
<h4>Arrays</h4>
<p>IDL array objects are not supported yet.</p>
<h4>Union types</h4>
<p>XXXbz write me</p>
<h4><code>Date</code></h4>
<p><code>Date</code> is not supported yet.</p>
<h2>Throwing exceptions from WebIDL methods, getters, and setters</h2>
<p>All WebIDL methods, getters, and setters that are not explicitly marked as infallible have an <code>ErrorResult&amp;</code> argument as their last argument.  To throw an exception, simply call <code>Throw()</code> on the <code>ErrorResult&amp;</code> and return from your C++ back into the binding code.</p>
<div class="note"><strong>Note:</strong> at the moment <code>Throw()</code> can only be called with an error <code>nsresult</code>, but in the future we expect to add ways to communicate more informative exception strings and other metainformation about the exception.</div>
<h2 class="note">Custom extended attributes</h2>
<p>Our WebIDL parser and code generator recognize several extended attributes that are not present in the WebIDL spec.</p>
<h3><code>[ChromeOnly]</code></h3>
<p>This extended attribute can be specified on any method, attribute, or constant on an interface.  Interface members flagged as <code>[ChromeOnly]</code> are only exposed in chrome Windows (and in particular, are not exposed to webpages).</p>
<h3><code>[Pref=prefname]</code></h3>
<p>This extended attribute can be specified on any method, attribute, or constant on an interface.  It takes a value, which must be the name of a boolean preference.  The interface member involved is then only exposed if that preference is set to <code>true</code>.   An example of how this can be used:</p>
<pre>interface MyInterface {
  attribute long alwaysHere;
  [Pref=my.pref.name] attribute long onlyHereIfEnabled;
};
</pre>
<h3><a name="Creator" />[Creator]</h3>
<p>Used to flag methods or attributes as guaranteeing that they create a new object each time the method or attribute getter is called.  Only methods or attribute getters flagged in this way are allowed to return objects that are marked with <code>'wrapperCache': False</code>.</p>
<h2 class="note">Helper objects</h2>
<p>The C++ side of the bindings uses a number of helper objects.</p>
<h3><code><a name="Nullable" />Nullable&lt;T&gt;</code></h3>
<p><code>Nullable&lt;&gt;</code> is a struct declared in <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/Nullable.h" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/Nullable.h"><code>Nullable.h</code></a> and exported to <code>mozilla/dom/Nullable.h</code> that is used to represent nullable values of types that don't have a natural way to represent null.</p>
<p><code>Nullable&lt;T&gt;</code> has an <code>IsNull()</code> getter that returns whether null is represented and a <code>Value()</code> getter that returns a <code>const T&amp;</code> and can be used to get the value when it's not null.</p>
<p><code>Nullable&lt;T&gt;</code> has a <code>SetNull()</code> setter that sets it as representing null and two setters that can be used to set it to a value: <code>&quot;void SetValue(T)&quot;</code> (for setting it to a given value) and <code>&quot;T&amp; SetValue()&quot;</code> for directly modifying the underlying <code>T&amp;</code>.</p>
<h3><code><a name="Optional" />Optional&lt;T&gt;</code></h3>
<p><code>Optional&lt;&gt;</code> is a struct declared in <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h"><code>BindingUtils.h</code></a> and exported to <code>mozilla/dom/BindingUtils.h</code> that is used to represent optional arguments and dictionary members, but only those that have no default value.</p>
<p><code>Optional&lt;T&gt;</code> has a <code>WasPassed()</code> getter that returns true if a value is available.  In that case, the <code>Value()</code> getter can be used to get a <code>const T&amp;</code> for the value.</p>
<h3><code><a name="NonNull" />NonNull&lt;T&gt;</code></h3>
<p><code>NonNull&lt;T&gt;</code> is a struct declared in <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h"><code>BindingUtils.h</code></a> and exported to <code>mozilla/dom/BindingUtils.h</code> that is used to represent non-null C++ objects.  It has a conversion operator that produces <code>T&amp;</code>.</p>
<h3><a name="OwningNonNull" /><code>OwningNonNull&lt;T&gt;</code></h3>
<p><code>OwningNonNull&lt;T&gt;</code> is a struct declared in <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h"><code>BindingUtils.h</code></a> and exported to <code>mozilla/dom/BindingUtils.h</code> that is used to represent non-null C++ objects and holds a strong reference to them.  It has a conversion operator that produces <code>T&amp;</code>.</p>
<h3><a name="TypedArrays" />Typed arrays, arraybuffers, array buffer views</h3>
<p><code><a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/TypedArray.h" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/TypedArray.h">TypedArray.h</a></code> is exported to <code>mozilla/dom/TypedArray.h</code> and exposes structs that correspond to the various typed array types, as well as <code>ArrayBuffer</code> and <code>ArrayBufferView</code>, all in the <code>mozilla::dom</code> namespace.  Each struct has an <code>mData</code> member of the relevant type (<code>uint8_t</code> for <code>ArrayBuffer</code> and <code>ArrayBufferView</code>) and an <code>mLength</code> member.</p>
<h3><code><a name="Sequence" />Sequence&lt;T&gt;</code></h3>
<p><code>Sequence&lt;&gt;</code> is a type declared in <a class="external" href="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h" title="http://mxr.mozilla.org/mozilla-central/source/dom/bindings/BindingUtils.h"><code>BindingUtils.h</code></a> and exported to <code>mozilla/dom/BindingUtils.h</code> that used to represent sequence arguments.  It's some kind of typed array, but which exact kind is opaque to consumers.  This allows the binding code to change the exact definition (e.g. to use auto arrays of different sizes and so forth) without having to update all the callees.</p>
<h2><code><a name="Bindings.conf" />Bindings.conf</code> details</h2>
<p>XXXbz write me.  In particular, need to describe at least use of <code>concrete</code>, <code>prefable</code>, and <code>addExternalInterface</code></p>
Revert to this revision