WebIDL bindings

  • Revision slug: Mozilla/WebIDL_bindings
  • Revision title: WebIDL bindings
  • Revision id: 293928
  • Created:
  • Creator: Bzbarsky
  • Is current revision? No
  • Comment 9 words added, 1 words removed

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.

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.
  2. Implement a GetParentObject override that, for any 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.
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.

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 is determined as described below.  The argument types are likewise described below.

C++ reflections of WebIDL attributes

 

C++ reflections of WebIDL constructors

 

C++ reflections of WebIDL argument types

 

C++ reflections of WebIDL return types

 

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.

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>
<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.</li> <li>Implement a <code>GetParentObject</code> override that, for any 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>
</ol>
<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 <code>[Creator]</code> in the WebIDL.</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 is determined <a href="/#returntypes" title="#returntypes">as described below</a>.  The argument types are likewise described below.</p>
<h3>C++ reflections of WebIDL attributes</h3>
<p> </p>
<h3>C++ reflections of WebIDL constructors</h3>
<p> </p>
<h3><a name="argumenttypes">C++ reflections of WebIDL argument types</a></h3><a name="argumenttypes">
<p> </p>
</a><h3><a name="argumenttypes"></a><a name="returntypes">C++ reflections of WebIDL return types</a></h3><a name="returntypes">
<p> </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></a>
Revert to this revision