wiki:WebKitIDL

Version 75 (modified by haraken@chromium.org, 12 years ago) ( diff )

--

Table of Contents

Overview
Basics of IDL
IDL attribute checker
run-bindings-tests
Where is the bindings code generated?
Basic naming rules of IDL attributes
IDL attributes

Overview

The Web IDL is a language that defines how WebCore interfaces are bound to external languages such as JavaScriptCore, V8, ObjC, GObject and CPP. You need to write IDL files (e.g. XMLHttpRequest.idl, Element.idl, etc) to expose WebCore interfaces to those external languages. When WebKit is built, the IDL files are parsed, and the code to bind WebCore implementations and JavaScriptCore, V8, ObjC, GObject and CPP interfaces is automatically generated.

This document describes practical information about how the IDL bindings work and how you can write IDL files in WebKit. The syntax of IDL files is fairly well documented in the Web IDL spec, but it is too formal to read:-) and there are several differences between the Web IDL spec and the WebKit IDL due to implementation issues.

Basics of IDL

Here is an example of IDL files:

module core {
    interface [
        JSCustomHeader,
        CustomToJSObject
    ] Node {
        const unsigned short ELEMENT_NODE = 1;
        attribute Node parentNode;
        attribute [TreatReturnedNullStringAs=Null] DOMString nodeName;
        [Custom] Node appendChild(in [CustomReturn] Node newChild);
        void addEventListener(in DOMString type, in EventListener listener, in [Optional] boolean useCapture);
    };
}

Let us introduce some terminologies:

  • The above IDL file describes the Node interface.
  • ELEMENT_NODE is a constant of the Node interface.
  • parentNode and nodeName are attributes of the Node interface.
  • appendChild(...) and addEventListener(...) are methods of the Node interface.
  • type, listener and useCapture are parameters of the Node interface.
  • [JSCustomHeader], [CustomToJSObject], [TreatReturnedNullStringAs=Null], [Custom], [CustomReturn] and [Optional] are IDL attributes.

Note: These terminologies are not aligned with the Web IDL spec. In the Web IDL spec, a 'method' is called an 'operation'. There is no distinction between an 'attribute' and a 'parameter' (a 'parameter' is treated as an 'attribute').

The key points are as follows:

  • An IDL file controls how the bindings code between JavaScript engine (or ObjC, GObject, CPP) and the WebKit implementation is generated.
  • IDL attributes enable you to control the bindings code more in detail.
  • There are 90~ IDL attributes and their roles are explained in the subsequent sections.
  • IDL attributes can be specified on interfaces, methods, attributes and parameters.

Where each IDL attribute can be specified on is defined per each IDL attribute. This is also explained in the subsequent sections.

A template of an IDL file is as follows:

module MODULE_NAME {
    interface [
        IDL_ATTRIBUTE_ON_INTERFACE1,
        IDL_ATTRIBUTE_ON_INTERFACE2,
        ...;
    ] INTERFACE_NAME {
        const unsigned long value = 12345;
        attribute [IDL_ATTRIBUTE_ON_ATTRIBUTE1, IDL_ATTRIBUTE_ON_ATTRIBUTE2, ...] Node node;
        [IDL_ATTRIBUTE_ON_METHOD1, IDL_ATTRIBUTE_ON_METHOD2, ...] void func(in [IDL_ATTRIBUTE_ON_PARAMETER1, IDL_ATTRIBUTE_ON_PARAMETER2, ...] int param, ...);
    };
}

If there is no IDL attributes on interfaces, the IDL file just looks like this:

module MODULE_NAME {
    interface INTERFACE_NAME {
        const unsigned long value = 12345;
        attribute [IDL_ATTRIBUTE_ON_ATTRIBUTE1, IDL_ATTRIBUTE_ON_ATTRIBUTE2, ...] Node node;
        [IDL_ATTRIBUTE_ON_METHOD1, IDL_ATTRIBUTE_ON_METHOD2, ...] void func(in [IDL_ATTRIBUTE_ON_PARAMETER1, IDL_ATTRIBUTE_ON_PARAMETER2, ...] int param, ...);
    };
}

IDL attribute checker

Previously there had been many bugs caused by typos of IDL attributes in IDL files. To avoid such bugs, the IDL attribute checker is introduced to the WebKit build flow to check if all the IDL attributes used in IDL files are implemented in code generators. If you use an IDL attribute not implemented in code generators, the IDL attribute checker fails, and the WebKit build fails.

A list of IDL attributes implemented in code generators is described in WebCore/bindings/scripts/IDLAttributes.txt. If you want to add a new IDL attribute, you need to

  1. add the IDL attribute to WebCore/bindings/scripts/IDLAttributes.txt.
  2. add the explanation to this document.
  3. add test cases to run-bindings-tests (explained below).

run-bindings-tests

Tools/Scripts/run-bindings-tests tests IDL attributes. Specifically, run-bindings-tests reads WebCore/bindings/scripts/test/*.idl, and then generates bindings code to WebCore/bindings/scripts/test/{JS,V8,ObjC,GObject,CPP}/*. For example, run-bindings-tests reads WebCore/bindings/scripts/test/TestObj.idl, and then generates bindings code to WebCore/bindings/scripts/test/JS/JSTestObj.h, WebCore/bindings/scripts/test/JS/JSTestObj.cpp, etc.

If you change the behavior of code generators or add a new IDL attribute, please add test cases to WebCore/bindings/scripts/test/*.idl. You can reset the run-bindings-tests results using the --reset-results option:

    $ ./Tools/Scripts/run-bindings-tests --reset-results

The objective of run-bindings-tests is to show you and reviewers how the code generation is changed by your patch. If you change the behavior of code generators, please update the results of run-bindings-tests.

That being said, run-bindings-tests is just for showing the change to you and reviewers, and the test failure is not critical for the WebKit build. People have been likely to forget to update the run-bindings-tests results in fact. Therefore, build bots do not treat the test failure as a failure. In this way, the run-bindings-tests results in the WebKit repository are sometimes wrong. If you find it, please rebaseline the run-bindings-tests before making your patch. If you make your patch without rebaselining the test results, the run-bindings-tests results will include the changes that had been caused by previous patches, which would be unreadable for you and reviewers.

Anyway, ideally all people should update the run-bindings-tests results if their patch changes the behavior of code generators.

Where is the bindings code generated?

By reading this document you can learn how IDL attributes work. However, the best practice to understand IDL attributes is to try to use some IDL attributes and watch what kind of bindings code is generated.

If you touch any IDL file, all IDL files are rebuilt. The code generation is done at the very early step of the ./webkit-build command, so you can obtain the generated code in 1 minute.

In case of XXX.idl in the Release build, the bindings code is generated in the following files ("Release" becomes "Debug" in the Debug build).

    WebKitBuild/Release/DerivedSources/WebCore/JSXXX.h
    WebKitBuild/Release/DerivedSources/WebCore/JSXXX.cpp
  • V8:
    out/Release/obj/gen/webkit/bindings/V8XXX.h
    out/Release/obj/gen/webcore/bindings/V8XXX.cpp
  • ObjC:
    WebKitBuild/Release/DerivedSources/WebCore/DOMXXX.h
    WebKitBuild/Release/DerivedSources/WebCore/DOMXXX.mm
  • GObject:
    WebKitBuild/Release/DerivedSources/webkit/WebKitDOMXXX.h
    WebKitBuild/Release/DerivedSources/webkit/WebKitDOMXXX.cpp
  • CPP:
    WebKitBuild/Release/DerivedSources/WebCore/WebDOMXXX.h
    WebKitBuild/Release/DerivedSources/WebCore/WebDOMXXX.cpp

Basic naming rules of IDL attributes

There are a few rules in naming IDL attributes:

  • A name should be aligned with the Web IDL spec as much as possible.
  • JavaScriptCore-specific IDL attributes are prefixed by "JS".
  • V8-specific IDL attributes are prefixed by "V8".
  • ObjC-specific IDL attributes are prefixed by "ObjC".
  • GObject-specific IDL attributes are prefixed by "GObject".
  • CPP-specific IDL attributes are prefixed by "CPP".
  • IDL attributes for custom bindings are prefixed by "Custom".

For example, [JSNoStaticTables], [CustomGetter], [V8CustomGetter], etc.

IDL attributes

In the following explanations, (i), (m), (a) or (p) means that a given IDL attribute can be specified on interfaces, methods, attributes and parameters, respectively. For example, (a,p) means that the IDL attribute can be specified on attributes and parameters.

[TreatNullAs](a,p), [TreatUndefinedAs](a,p)

Summary: They control the behavior when a JavaScript null or undefined is passed to a DOMString attribute or parameter.

Usage: The possible usage is [TreatNullAs=NullString] or [TreatUndefinedAs=NullString]. They can be specified on DOMString attributes or DOMString parameters only:

    attribute [TreatNullAs=NullString] DOMString str;
    void func(in [TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString str);

[TreatNullAs=NullString] indicates that if a JavaScript null is passed to the attribute or parameter, then it is converted to a WebKit null string, for which both String::IsEmpty() and String::IsNull() will return true. Without [TreatNullAs=NullString], a JavaScript null is converted to a WebKit string "null".

[TreatNullAs=NullString] in WebKit corresponds to [TreatNullAs=EmptyString] in the Web IDL spec. Unless the spec specifies [TreatNullAs=EmptyString], you should not specify [TreatNullAs=NullString] in WebKit.

[TreatUndefinedAs=NullString] indicates that if a JavaScript undefined is passed to the attribute or parameter, then it is converted to a WebKit null string, for which both String::IsEmpty() and String::IsNull() will return true. Without [TreatUndefinedAs=NullString], a JavaScript undefined is converted to a WebKit string "undefined".

[TreatUndefinedAs=NullString] in WebKit corresponds to [TreatUndefinedAs=EmptyString] in the Web IDL spec. Unless the spec specifies [TreatUndefinedAs=EmptyString], you should not specify [TreatUndefinedAs=NullString] in WebKit.

Note: For now the sole usage of [TreatUndefinedAs=NullString] is not allowed. [TreatUndefinedAs=NullString] must be used with [TreatNullAs=NullString], i.e. [TreatNullAs=NullString, TreatUndefinedAs=NullString].

[TreatReturnedNullStringAs](m,a)

Summary: [TreatReturnedNullStringAs] controls the behavior when a WebKit null string is returned from the WebCore implementation.

Usage: The possible usage is [TreatReturnedNullStringAs=Null], [TreatReturnedNullStringAs=Undefined] or [TreatReturnedNullStringAs=False]. They can be specified on DOMString attributes or methods that return a DOMString value:

    attribute [TreatReturnedNullStringAs=Null] DOMString str;
    [TreatReturnedNullStringAs=Undefined] DOMString func();
  • [TreatReturnedNullStringAs=Null] indicates that if the returned DOMString is a WebKit null string, the returned value is treated as a JavaScript null.
  • [TreatReturnedNullStringAs=Undefined] indicates that if the returned DOMString is a WebKit null string, the returned value is treated as a JavaScript undefined.
  • [TreatReturnedNullStringAs=False] indicates that if the returned DOMString is a WebKit null string, the returned value is treated as a JavaScript false.

Without [TreatReturnedNullStringAs=...], if the returned DOMString is a WebKit null string, then the returned value is treated as a JavaScript empty string .

Note that what should be specified on [TreatReturnedNullStringAs=...] depends on the spec of each attribute or method.

[Optional](p)

Summary: [Optional] allows method overloading for methods whose argument counts are different with each other.

Usage: The possible usage is [Optional], [Optional=DefaultIsUndefined] or [Optional=DefaultIsNullString]. [Optional] and [Optional=DefaultIsUndefined] can be specified on parameters. [Optional=DefaultIsNullString] can be specified on DOMString parameters only:

    interface HTMLFoo {
        void func1(in int a, in int b, in [Optional] int c, in [Optional] int d);
        void func2(in int a, in int b, in [Optional=DefaultIsUndefined] int c);
        void func3(in int a, in int b, in [Optional=DefaultIsUndefined] DOMString c, in [Optional=DefaultIsNullString] DOMString d);
    };

The parameters marked with [Optional=...] are optional, and JavaScript can omit the parameters. Obviously, if parameter X is marked with [Optional=...], then all subsequent parameters of X should be marked with [Optional=...].

The difference between [Optional] and [Optional=DefaultIsUndefined] is whether the WebCore implementation has overloaded methods or not, as explained below.

In case of func1(...), if JavaScript calls func1(100, 200), then HTMLFoo::func1(int a, int b) is called in WebCore. If JavaScript calls func1(100, 200, 300), then HTMLFoo::func1(int a, int b, int c) is called in WebCore. If JavaScript calls func1(100, 200, 300, 400), then HTMLFoo::func1(int a, int b, int c, int d) is called in WebCore. In other words, if the WebCore implementation has overloaded methods, you can use [Optional].

In case of func2(...), if JavaScript calls func2(100, 200), then it behaves as if JavaScript called func2(100, 200, undefined). Consequently, HTMLFoo::func2(int a, int b, int c) is called in WebCore. 100 is passed to a, 200 is passed to b, and 0 is passed to c. (A JavaScript undefined is converted to 0, following the value conversion rule in the Web IDL spec.) In this way, WebCore needs to just implement func2(int a, int b, int c) and needs not to implement both func2(int a, int b) and func2(int a, int b, int c).

The difference between [Optional=DefalutIsUndefined] and [Optional=DefaultIsNullString] appears only when the parameter type is DOMString. In [Optional=DefalutIsUndefined], the "supplemented" JavaScript undefined is converted to a WebKit string "undefined". On the other hand, in [Optional=DefaultIsNullString], the "supplemented" JavaScript undefined is converted to a WebKit null string. For example, if JavaScript calls func3(100, 200), then HTMLFoo::func3(int a, int b, String c, String d) is called in WebCore. At this point, 100 is passed to a, 200 is passed to b, a WebKit string "undefined" is passed to c, and a WebKit null string is passed to d. d.IsEmpty() and d.IsNull() return true.

[Clamp](a,p)

Summary: [Clamp] indicates that when an ECMAScript Number is converted to the IDL type, out of range values will be clamped to the range of valid values, rather than using the operators that use a modulo operation (ToInt32, ToUint32, etc.).

Usage: The [Clamp] extended attribute MUST NOT appear on a read only attribute, or an attribute, operation argument or dictionary member that is not of an integer type.

[Clamp] can be specified on writable attributes:

    interface XXX {
        attribute [Clamp] unsigned short attributeName;
    };

[Clamp] can be specified on extended attributes on methods arguments:

    interface GraphicsContext {
        void setColor(octet red, octet green, octet blue);
        void setColorClamped([Clamp] octet red, [Clamp] octet green, [Clamp] octet blue);
    };

Calling the non-[Clamp] version of setColor() uses ToUint8 to coerce the Numbers to octets. Hence calling context.setColor(-1, 255, 257) is equivalent to calling setColor(255, 255, 1).

Calling the [Clamp] version of setColor() uses clampTo() to coerce the Numbers to octets. Hence calling context.setColor(-1, 255, 257) is equivalent to calling setColorClamped(0, 255, 255).

[Callback](i,p) FIXME

Summary: ADD SUMMARY

Usage: [Callback] can be specified on interfaces and parameters:

    interface [
        Callback
    ] HTMLFoo {
        void func(in int a, in [Callback] int b);
    };

ADD EXPLANATIONS

[Custom](m,a), [JSCustom](m,a), [V8Custom](m,a), [CustomGetter](a), [JSCustomGetter](a), [V8CustomGetter](a), [CustomSetter](a), [JSCustomSetter](a), [V8CustomSetter](a)

Summary: They allow you to write bindings code manually as you like.

Usage: [Custom], [JSCustom] and [V8Custom] can be specified on methods or attributes. [CustomGetter], [JSCustomGetter], [V8CustomGetter], [CustomSetter], [JSCustomSetter], [V8CustomSetter] can be specified on attributes:

    [Custom] void func();
    attribute [CustomGetter, JSCustomSetter] DOMString str;

We should minimize the number of custom bindings as much as possible, since they are likely to be buggy. Before using [Custom], you should doubly consider if you really need custom bindings. You are recommended to modify code generators to avoid using [Custom].

Before explaining the details, let us clarify the relationship of these IDL attributes.

  • [JSCustom] on a method indicates that you can write JavaScriptCore custom bindings for the method.
  • [V8Custom] on a method indicates that you can write V8 custom bindings for the method.
  • [Custom] on a method is equivalent to [JSCustom, V8Custom].
  • [JSCustomGetter] or [JSCustomSetter] on an attribute indicates that you can write JavaScriptCore custom bindings for the attribute getter or setter.
  • [V8CustomGetter] or [V8CustomSetter] on an attribute indicates that you can write V8 custom bindings for the attribute getter or setter.
  • [JSCustom] on an attribute is equivalent to [JSCustomGetter, JSCustomSetter].
  • [V8Custom] on an attribute is equivalent to [V8CustomGetter, V8CustomSetter].
  • [Custom] on an attribute is equivalent to [JSCustom, V8Custom], i.e. [JSCustomGetter, JSCustomSetter, V8CustomGetter, V8CustomSetter].

For example, if you want to write custom bindings only for an attribute getter of JavaScriptCore and V8 and an attribute setter of JavaScriptCore, you can specify [CustomGetter, JSCustomSetter].

How to write custom bindings is different between JavaScriptCore and V8 or between a method and an attribute getter/setter, as follows:

    interface XXX {
        [JSCustom] void func(in int a, in int b);
    };

You can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp:

    JSValue JSXXX::func(ExecState* exec)
    {
        ...;
    }

Refer to WebCore/bindings/js/JSXXXCustom.cpp for more details.

    interface XXX {
        attribute [JSCustomGetter] DOMString str;
    };

You can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp:

    JSValue JSXXX::str(ExecState* exec) const
    {
        ...;
    }

Refer to WebCore/bindings/js/JSXXXCustom.cpp for more details.

    interface XXX {
        attribute [JSCustomSetter] DOMString str;
    };

You can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp:

    void JSXXX::setStr(ExecState*, JSValue value)
    {
        ...;
    }

Refer to WebCore/bindings/js/JSXXXCustom.cpp for more details.

  • Method in V8: Consider the following example:
    interface XXX {
        [V8Custom] void func(in int a, in int b);
    };

You can write custom bindings in WebCore/bindings/v8/custom/V8XXXCustom.cpp:

    v8::Handle<v8::Value> V8XXX::funcCallback(const v8::Arguments& args)
    {
        ...;
    }

Refer to WebCore/bindings/v8/custom/V8XXXCustom.cpp for more details.

  • Attribute getter in V8: Consider the following example:
    interface XXX {
        attribute [V8CustomGetter] DOMString str;
    };

You can write custom bindings in WebCore/bindings/v8/custom/V8XXXCustom.cpp:

    v8::Handle<v8::Value> V8XXX::strAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    {
        ...;
    }

Refer to WebCore/bindings/v8/custom/V8XXXCustom.cpp for more details.

  • Attribute setter in V8: Consider the following example:
    interface XXX {
        attribute [V8CustomSetter] DOMString str;
    };

You can write custom bindings in WebCore/bindings/v8/custom/V8XXXCustom.cpp:

    void V8XXX::strAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
    {
        ...;
    }

Refer to WebCore/bindings/v8/custom/V8XXXCustom.cpp for more details.

Note: ObjC, GObject and CPP bindings do not support custom bindings.

[CallWith](i,m,a)

Summary: [CallWith] indicates that the bindings code calls a WebCore method with additional information.

Usage: The possible usage is [CallWith=X1|X2|X3|...], where X1, X2, X3, ... is "ScriptExecutionContext", "ScriptState", "ScriptArguments" or "CallStack". "ScriptExecutionContext", "ScriptState" and "CallStack" can be specified on methods or attributes, but "ScriptArguments" can be specified on methods only:

    interface HTMLFoo {
        attribute [CallWith=ScriptExecutionContext] DOMString str;
        [CallWith=ScriptExecutionContext] void func1(in int a, in int b);
        [CallWith=ScriptState] void func2(in int a, in int b);
        [CallWith=ScriptArguments|CallStack] void func3(in int a, in int b);
        [CallWith=CallStack|ScriptArguments] void func4(in int a, in int b);
    };

Note: [CallWith] can be also specified on interfaces but it has a different meaning. Refer to the [Constructor section] for [CallWith] on interfaces.

In case of func1(...), HTMLFoo::func1(ScriptExecutionContext* context, int a, int b) is called in WebCore. Thus, in HTMLFoo::func1(...) you can retrieve document or window from context.

In case of func2(...), HTMLFoo::func2(ScriptState* state, int a, int b) is called in WebCore.

In case of func3(...), HTMLFoo::func3(ScriptArguments* arguments, ScriptCallStack* callstack, int a, int b) is called in WebCore.

In this way, the additional information is added at the head of normal arguments. The order of additional information is "ScriptExecutionContext", "ScriptState", "ScriptArguments", and then "CallStack", despite the order specified in [CallWith=X1|X2|X3|...]. For example, in case of func4(...), HTMLFoo::func3(ScriptArguments* arguments, ScriptCallStack* callstack, int a, int b) is called in WebCore.

[StrictTypeChecking](m,a) FIXME

Summary: ADD SUMMARY

Usage: [StrictTypeChecking] can be specified on methods and attributes:

    attribute [StringTypeChecking] float x;
    [StrictTypeChecking] DOMString func();

ADD EXPLANATIONS

[ReturnNewObject](m,a)

Summary: [ReturnNewObject] controls whether WebCore can return a cached wrapped object or WebCore needs to return a newly created wrapped object every time.

Usage: [ReturnNewObject] can be specified on methods or attributes:

    attribute [ReturnNewObject] Node node;
    [ReturnNewObject] Node createTextNode();

Without [ReturnNewObject], JavaScriptCore and V8 cache a wrapped object for performance. For example, consider the case where node.firstChild is accessed:

  1. Node::firstChild() is called in WebCore.
  2. The result of Node::firstChild() is passed to toJS() or toV8().
  3. toJS() or toV8() checks if a wrapped object of the result is already cached on the node.
  4. If cached, the cached wrapped object is returned. That's it.
  5. Otherwise, toJS() or toV8() creates the wrapped object of the result.
  6. The created wrapped object is cached on the node.
  7. The wrapped object is returned.

On the other hand, if you do not want to cache the wrapped object and want to create the wrapped object every time, you can specify [ReturnNewObject].

[ImplementedAs](m,a)

Summary: [ImplementedAs] specifies a method name in WebCore, if the method name in an IDL file and the method name in WebCore are different.

Usage: The possible usage is [ImplementedAs=XXX], where XXX is a method name in WebCore. [ImplementedAs] can be specified on methods:

    [ImplementedAs=deleteFunction] void delete();
    attribute [ImplementedAs=classAttribute] int class;

Basically a method name in WebCore should be the same as the method name in an IDL file. That being said, sometimes you cannot use the same method name; e.g. "delete" is reserved for a C++ keyword. In such cases, you can explicitly specify the method name in WebCore by [ImplementedAs]. You should avoid using [ImplementedAs] as much as possible though.

[Reflect](a)

Summary: [Reflect] indicates that a given attribute should reflect the values of a corresponding content attribute.

Usage: The possible usage is [Reflect] or [Reflect=X], where X is the name of a corresponding content attribute. [Reflect] can be specified on attributes:

    interface Element {
        attribute [Reflect] DOMString id;
        attribute [Reflect=class] DOMString className;
    };

(Informally speaking,) a content attribute means an attribute on an HTML tag:

    <div id="foo" class="fooClass"></div>

Here 'id' and 'class' are content attributes.

If a given attribute in an IDL file is marked as [Reflect], it indicates that the attribute getter returns the value of the corresponding content attribute and that the attribute setter sets the value of the corresponding content attribute. In the above example, 'div.id' returns 'foo', and 'div.id = "bar"' sets "bar" to the 'id' content attribute.

If the name of the corresponding content attribute is different from the attribute name in an IDL file, you can specify the content attribute name by [Reflect=X]. For example, in case of [Reflect=class], if 'div.className="barClass"' is evaluated, then "barClass" is set to the 'class' content attribute.

Whether [Reflect] should be specified or not depends on the spec of each attribute.

[Replaceable](a)

Summary: [Replaceable] controls if a given attribute is "replaceable" or not.

Usage: [Replaceable] can be specified on attributes:

    interface DOMWindow {
        attribute [Replaceable] screenX;
    };

Intuitively, "replaceable" means that you can set a new value to the attribute without overwriting the original value. If you delete the new value, then the original value still remains.

Specifically, without [Replaceable], the attribute behaves as follows:

    window.screenX; // Evaluates to 0
    window.screenX = "foo";
    window.screenX; // Evaluates to "foo"
    delete window.screenX;
    window.screenX; // Evaluates to undefined. 0 is lost.

With [Replaceable], the attribute behaves as follows:

    window.screenX; // Evaluates to 0
    window.screenX = "foo";
    window.screenX; // Evaluates to "foo"
    delete window.screenX;
    window.screenX; // Evaluates to 0. 0 remains.

Whether [Replaceable] should be specified or not depends on the spec of each attribute.

[Deletable](a), [NotEnumerable](a), [V8ReadOnly](a)

Summary: They control Writability, Enumerability and Configurability of attributes.

Usage: They can be specified on attributes:

    attribute [NotEnumerable, Deletable] DOMString str;
    readonly attribute DOMString readonlyStr;
    attribute [V8ReadOnly] DOMString readonlyStrOnV8;

By default, non-"readonly" attributes are enumerable, writable and not deletable. "readonly" attributes are enumerable, not writable and not deletable. You can change the default behavior using [Deletable], [NotEnumerable] or [V8ReadOnly].

  • [Deletable] indicates that the attribute is deletable.
  • [NotEnumerable] indicates that the attribute is not enumerable.
  • [V8ReadOnly] indicates that the attribute is readonly in V8 even if the attribute is not prefixed by "readonly".

[CachedAttribute](a)

Summary: For performance optimization, [CachedAttribute] indicates that a wrapped object should be cached on a DOM object.

Usage: [CachedAttribute] can be specified on attributes:

    interface HTMLFoo {
        attribute [CachedAttribute] DOMString normalValue;
        attribute [CachedAttribute] SerializedScriptValue serializedValue;
    };

Without [CachedAttribute], the normalValue getter works in the following way:

  1. HTMLFoo::normalValue() is called in WebCore.
  2. The result of HTMLFoo::normalValue() is passed to toJS() or toV8(), and is converted to a wrapped object.
  3. The wrapped object is returned.

In case where HTMLFoo::normalValue() or the operation to wrap the result is weight, you can cache the wrapped object onto the DOM object. With [CachedAttribute], the normalValue getter works in the following way:

  1. If the wrapped object is cached, the cached wrapped object is returned. That's it.
  2. Otherwise, HTMLFoo::normalValue() is called in WebCore.
  3. The result of HTMLFoo::normalValue() is passed to toJS() or toV8(), and is converted to a wrapped object.
  4. The wrapped object is cached.
  5. The wrapped object is returned.

In particular, [CachedAttribute] will be useful for serialized values, since deserialization can be weight. Without [CachedAttribute], the serializedValue getter works in the following way:

  1. HTMLFoo::serializedValue() is called in WebCore.
  2. The result of HTMLFoo::serializedValue() is deserialized.
  3. The deserialized result is passed to toJS() or toV8(), and is converted to a wrapped object.
  4. The wrapped object is returned.

In case where HTMLFoo::serializedValue(), the deserialization or the operation to wrap the result is weight, you can cache the wrapped object onto the DOM object. With [CachedAttribute], the serializedValue getter works in the following way:

  1. If the wrapped object is cached, the cached wrapped object is returned. That's it.
  2. Otherwise, HTMLFoo::serializedValue() is called in WebCore.
  3. The result of HTMLFoo::serializedValue() is deserialized.
  4. The deserialized result is passed to toJS() or toV8(), and is converted to a wrapped object.
  5. The wrapped object is cached.
  6. The wrapped object is returned.

Note that you should cache attributes if and only if it is really important for performance. Not only does caching increase the DOM object size, but also it increases the overhead of "cache-miss"ed getters. In addition, setters always need to invalidate the cache.

[V8Unforgeable](m,a), [V8OnProto](m,a)

Summary: They control where a getter/setter of a given attribute is defined.

Usage: They can be specified on methods or attributes:

    [V8Unforgeable] void func();
    attribute [V8OnProto] DOMString str;

By default in JSC and V8, attribute getters/setters are defined on a DOM object, and methods are defined on a prototype chain (although the Web IDL spec requires that both attribute getters/setters and methods should be defined on a prototype chain).

If you want to explicitly control where an attribute getter/setter or a method is defined in V8, you can use [V8Unforgeable] or [V8OnProto].

  • [V8Unforgeable] indicates that an attribute getter/setter or a method should be defined on a DOM object.
  • [V8OnProto] indicates that an attribute getter/setter or a method should be defined on a prototype chain.

Note: As explained above, the current implementation of JSC and V8 is wrong with the Web IDL spec, and [V8Unforgeable] and [V8OnProto] are used for hack. You should not use them unless you have a strong reason to use them.

[URL](a)

Summary: [URL] indicates that a given DOMString represents a URL.

Usage: [URL] can be specified on DOMString attributes only:

    attribute [Reflect, URL] DOMString url;

You need to specify [URL] if a given DOMString represents a URL, since getters of URL attributes need to be realized in a special routine in WebKit, i.e. Element::getURLAttribute(...). If you forgot to specify [URL], then the attribute getter might cause a bug.

[JSWindowEventListener](a) FIXME

Summary: ADD SUMMARY

Usage: [JSWindowEventListener] can be specified on EventListener attributes only:

    attribute [JSWindowEventListener] EventListener onload;

ADD EXPLANATIONS

[Supplemental](i)

Summary: [Supplemental] helps WebKit modularization. [Supplemental] makes it possible to add XXX's APIs (e.g. XXX=WebAudio, WebSocket, Blob, GamePad, ...etc) without modifying code outside of WebCore/Modules/XXX/. This helps make XXX a "self-contained module".

Usage: The possible usage is

    interface [
        Supplemental=YYY
    ] XXX {
    };

where XXX implements YYY. [Supplemental] can be specified on interfaces.

Without [Supplemental], if you want to add XXX's attributes or methods to DOMWindow,

  • you need to modify WebCore/page/DOMWindow.idl to add the XXX's attributes or methods
  • you need to modify WebCore/page/DOMWindow.{h,cpp} to add the WebCore implementation of the attribute getters and setters or the method callbacks.

On the other hand, in the modularized world with [Supplemental], you just need to modify the code under WebCore/Modules/XXX/:

  • WebCore/Modules/XXX/DOMWindowXXX.idl
   interface [
       Conditional=XXX,
       Supplemental=DOMWindow    // The attributes and methods of this interface are exposed as those of DOMWindow.
   ] DOMWindowXXX {
       attribute int foo;
       void bar();
   };
  • WebCore/Modules/XXX/DOMWindowXXX.h
   DOMWindowXXX::foo(...) { ... }   // The WebCore implementation of the foo attribute getter.
   DOMWindowXXX::setFoo(...) { ... }   // The WebCore implementation of the foo attribute setter.
   DOMWindowXXX::bar(...) { ... }   // The WebCore implementation of the bar() method callback.

As shown above, [Supplemental=DOMWindow] indicates that all the attributes and methods of DOMWindowXXX should be exposed on DOMWindow, but should be implemented in DOMWindowXXX. In this way, you can implement the attributes and methods without modifying code of DOMWindow.{h,cpp,idl}.

If you want to add APIs whose implementations are likely to be independent from WebCore, it is strongly recommended to put the APIs and .h/.cpp files into WebCore/Modules/XXX/ using [Supplemental]. On the other hand, if the implementations need to touch WebCore much, the APIs might not be good candidates for [Supplemental].

[Constructor](i), [CallWith](i,m,a), [ConstructorRaisesException](i)

Summary: [Constructor] indicates that the interface should have constructor, i.e. "new XXX()". [CallWith] and [ConstructorRaisesException] adds information when the constructor callback is called in WebCore.

Usage: [Constructor], [CallWith] and [ConstructorRaisesException] can be specified on interfaces:

    interface [
        Constructor(in float x, in float y, in DOMString str),
        ConstructorRaisesException,
        CallWith=ScriptExecutionContext|ScriptState
    ] XXX {
    };

[Constructor(in float x, in float y, in DOMString str)] means that the interface has a constructor and the constructor signature is (in float x, in float y, in DOMString str). Specifically, JavaScript can create a DOM object of XXX by the following code:

    var x = new XXX(1.0, 2.0, "hello");

Then XXX::create(float x, float y, String str) is called in WebCore. That way WebCore needs to implement the following method as a constructor callback:

    PassRefPtr<XXX> XXX::create(float x, float y, String str)
    {
        ...;
    }

[Constructor()] is equivalent to [Constructor].

If XXX::create(...) can throw Exception, you can use [ConstructorRaisesException]. With [ConstructorRaisesException], a placeholder for ExceptionCode is added to the tail argument of XXX::create(...).

    PassRefPtr<XXX> XXX::create(float x, float y, String str, ExceptionCode& ec)
    {
        ...;
        if (...) {
            ec = TYPE_MATCH_ERR;
            return 0;
        }
    }

If XXX::create(...) needs additional information like ScriptExecutionContext and ScriptState, you can specify [CallWith=ScriptExecutionContext|ScriptState]. Then XXX::create(...) can have the following signature:

    PassRefPtr<XXX> XXX::create(ScriptExecutionContext* context, ScriptState* state, float x, float y, String str)
    {
        ...;
    }

You can retrieve document or frame from ScriptExecutionContext. Please see another [CallWith section] for more details.

Note that [CallWith=...] arguments are added at the head of XXX::create(...)'s arguments, and the ExceptionCode argument is added at the tail of XXX::create(...)'s arguments.

Whether you should allow an interface to have constructor depends on the spec of the interface.

Note: Currently [Constructor(...)] does not yet support [Optional] arguments. It just supports [Optional=DefaultIsUndefined] or [Optional=DefaultIsNullString].

[ConstructorTemplate](i), [InitializedByEventConstructor](a)

Summary: They are used for Event constructors.

Usage: The possible usage is [ConstructorTemplate=Event]. [ConstructorTemplate=Event] can be specified on Event interfaces only. [InitializedByEventConstructor] can be specified on attributes in the Event interfaces:

    interface [
        ConstructorTemplate=Event
    ] FooEvent {
        attribute DOMString str1;
        attribute [InitializedByEventConstructor] DOMString str2;
    };

Since constructors for Event interfaces require special bindings, you need to use [ConstructorTemplate=Event] instead of normal [Constructor].

If you specify [ConstructorTemplate=Event] on FooEvent, JavaScript can create a DOM object of FooEvent in the following code:

    var e = new FooEvent("type", { bubbles: true, cancelable: true });

Then FooEvent::create(...) is called in WebCore. Specifically, WebCore needs to implement the following method as a constructor callback:

    PassRefPtr<FooEvent> FooEvent::create(const AtomicString& type, const FooEventInit& initializer)
    {
        ...;
    }

[InitializedByEventConstructor] should be specified on all the attributes that needs to be initialized by the constructor. Which attributes need initialization is defined in the spec of each Event interface. For example, look at the spec of Event. The EventInit dictionary has bubbles and cancelable, and thus bubbles and cancelable are the only attributes that need to be initialized by the Event constructor. In other words, in case of Event, you should specify [InitializedByEventConstructor] on bubbles and cancelable.

[NamedConstructor](i)

Summary: If you want to allow JavaScript to create a DOM object of XXX using a different name constructor (i.e. allow JavaScript to create an XXX object using "new YYY()", where YYY != XXX), you can use [NamedConstructor].

Usage: The possible usage is [NamedConstructor=YYY]. [NamedConstructor] can be specified on interfaces:

    interface [
        NamedConstructor=Audio()
    ] HTMLAudioElement {
    };

The semantics is the same as [Constructor], except that JavaScript can make a DOM object not by "new HTMLAudioElement()" but by "Audio()".

Whether you should allow an interface to have a named constructor or not depends on the spec of each interface.

[CustomConstructor](i), [JSCustomConstructor](i), [V8CustomConstructor](i), [ConstructorParameters](i)

Summary: They allow you to write custom bindings for constructors.

Usage: They can be specified on interfaces. Regarding [ConstructorParameters], the possible usage is [ConstructorParameters=X], where X is the maximum number of arguments of the constructor:

    interface [
        CustomConstructor,
        ConstructorParameters=4
    ] XXX {
    };

We should minimize the number of custom bindings as less as possible. Before using [CustomConstructor], you should doubly consider if you really need custom bindings. You are recommended to modify code generators to avoid using [Custom].

Before explaining the details, let us clarify the relationship of these IDL attributes.

  • [JSCustomConstructor] on an interface indicates that you can write JavaScriptCore custom bindings for the constructor.
  • [V8CustomConstructor] on an interface indicates that you can write V8 custom bindings for the constructor.
  • [CustomConstructor] is equivalent to [JSCustomConstructor, V8CustomConstructor].

For example, if you specify [Constructor, JSCustomConstructor], then the constructor is generated only for V8 and you need to write JavaScriptCore custom bindings for the constructor.

How to write custom bindings is different between JavaScriptCore and V8.

    interface [
        CustomConstructor,
        ConstructorParameters=2
    ] XXX {
    };

Then you can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp:

    EncodedJSValue JSC_HOST_CALL JSXXXConstructor::constructJSXXX(ExecState* exec)
    {
        ...;
    }

Refer to WebCore/bindings/js/JSXXXCustom.cpp for more details.

  • V8: Consider the following example:
    interface [
        CustomConstructor,
        ConstructorParameters=2
    ] XXX {
    };

Then you can write custom bindings in WebCore/bindings/v8/custom/V8XXXConstructorCustom.cpp:

    v8::Handle<v8::Value> V8XXX::constructorCallback(const v8::Arguments& args)
    {
        ...;
    }

Refer to WebCore/bindings/v8/custom/V8XXXConstructorCustom.cpp for more details.

X of [ConstructorParameters=X] is the maximum number of arguments, including optional arguments. For example, if a constructor signature is [Constructor(in int a, in int b, in [Optional=DefaultIsUndefined] int c, in [Optional=DefaultIsUndefined] int d)], then X is 4.

You do not need to specify [ConstructorParameters] if the interface does not have any of [JSCustomConstructor], [V8CustomConstructor] or [CustomConstructor].

[Conditional](i,m,a)

Summary: [Conditional] inserts "#if ENABLE(SOME_FLAG) ... #endif" into the generated code.

Usage: [Conditional] can be specified on interfaces, methods and attributes:

    interface [
        Conditional=INDEXED_DATABASE
    ] XXX {
    };
    interface XXX {
        attribute [Conditional=INDEXED_DATABASE] DOMString str;
        [Conditional=INDEXED_DATABASE] void open();
    };

[Conditional] is used to enable or disable the generated code based on a "flag". If a given flag is enabled, the generated code is compiled. Otherwise, the generated code is not compiled. Whether a flag is enabled or disabled is controlled (mostly) by Tools/Scripts/build-webkit.

If [Conditional] is specified on an interface, it means that [Conditional] is specified on all attributes and methods of the interface.

[V8EnabledAtRuntime](i,m,a)

Summary: In Chromium/V8, you can enable or disable a flag at runtime.

Usage: The possible usage is [V8EnabledAtRuntime] or [V8EnabledAtRuntime=X], where X is an arbitrary string that you want to use for identifying the flag getter. [V8EnabledAtRuntime] can be specified on interfaces, methods or attributes:

    interface [
        V8EnabledAtRuntime
    ] XXX {
    };
    interface XXX {
        attribute [V8EnabledAtRuntime] DOMString str1;
        attribute [V8EnabledAtRuntime=foo] DOMString str2;
        [V8EnabledAtRuntime] void open1();
        [V8EnabledAtRuntime=foo] void open2();
    };

To make interfaces, methods or attributes enabled or disabled through the about:flags page of Chromium/V8, you can specify [V8EnabledAtRuntime].

If you specify [V8EnabledAtRuntime], you need to write "flag-binding" code in WebCore/bindings/generic/RuntimeEnabledFeatures.h, WebCore/bindings/generic/RuntimeEnabledFeatures.cpp and WebKit/chromium/src/WebRuntimeFeatures.cpp.

The method names of a "flag-binding" code in WebCore/bindings/generic/RuntimeEnabledFeatures.h are determined by the name of interfaces, methods or attributes by default. You can change the method names by using [V8EnabledAtRuntime=X], where X becomes the method name base. Refer to WebCore/bindings/generic/RuntimeEnabledFeatures.h, WebCore/bindings/generic/RuntimeEnabledFeatures.cpp and WebKit/chromium/src/WebRuntimeFeatures.cpp for more details.

If [V8EnabledAtRuntime] is specified on an interface, it means that [V8EnabledAtRuntime] is specified on all the attributes and methods of the interface,

[V8EnabledPerContext](i,m,a)

Summary: In Chromium/V8, you can enable or disable a flag per execution context (that is DOMWindow).

If you specify [V8EnabledPerContext], you need to write "flag-binding" code in WebCore/bindings/generic/ContextEnabledFeatures.h, WebCore/bindings/generic/ContextEnabledFeatures.cpp The implementation can choose arbitrary decision logic. A typical approach is to ask FrameLoaderClient about its availability.

Currently, V8EnabledPerContext is only effective for attributes on DOMWindow.

[CustomToJSObject](i), [JSCustomToJSObject](i), [V8CustomToJSObject](i)

Summary: They allow you to write custom toJS() or toV8().

Usage: They can be specified on interfaces:

    interface [
        CustomToJSObject
    ] XXX {
    };
  • [JSCustomToJSObject] on an interface indicates that you can write custom toJS().
  • [V8CustomToJSObject] on an interface indicates that you can write custom toV8().
  • [CustomToJSObject] is equivalent to [JSCustomToJSObject, V8CustomToJSObject].

By default (i.e. without [*CustomToJSObject]), toJS() and toV8() are generated automatically.

  • With [CustomToJSObject] or [JSCustomToJSObject], you can write custom toJS() in WebCore/bindings/js/JSXXXCustom.cpp:
    JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, XXX* impl)
    {
        ...;
    }
  • With [CustomToJSObject] or [V8CustomToJSObject], you can write custom toV8() in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Value> toV8(XXX* impl, bool forceNewObject)
    {
        ...;
    }

[CheckSecurity](i), [DoNotCheckSecurity](m,a), [DoNotCheckSecurityOnGetter](a), [DoNotCheckSecurityOnSetter](a)

Summary: They check whether a given access is allowed or not, in terms of the same-origin security policy.

Usage: [CheckSecurity] can be specified on interfaces. [DoNotCheckSecurity] can be specified on methods or attributes that belong to interfaces that have [CheckSecurity]. [DoNotCheckSecurityOnGetter] and [DoNotCheckSecurityOnSetter] can be specified on attributes that belong to interfaces that have [CheckSecurity]:

    interface [
        CheckSecurity
    ] DOMWindow {
        attribute DOMString str1;
        attribute [DoNotCheckSecurity] DOMString str2:
        attribute [DoNotCheckSecurityOnGetter] DOMString str3:
        attribute [DoNotCheckSecurityOnSetter] DOMString str4:
        void func1();
        [DoNotCheckSecurity] void func2();
    };

Consider the case where you access window.parent from inside an iframe that comes from a different origin. While it is allowed to access window.parent, it is not allowed to access window.parent.document. In such cases, you need to specify [CheckSecurity] in order to check whether a given DOM object is allowed to access the attribute or method, in terms of the same-origin security policy. This is really important for security.

If you specify [CheckSecurity] on an interface, the security check is enabled on all the attributes and methods of the interface. To disable the security check for particular attributes or methods, you can use [DoNotCheckSecurity], [DoNotCheckSecurityOnGetter] or [DoNotCheckSecurityOnSetter].

  • [DoNotCheckSecurity] on a method disables the security check for the method.
  • [DoNotCheckSecurity] on an attribute disables the security check for a getter and setter of the attribute.
  • [DoNotCheckSecurityOnGetter] on an attribute disables the security check for a getter of the attribute.
  • [DoNotCheckSecurityOnSetter] on an attribute disables the security check for a setter of the attribute.
  • [DoNotCheckSecurity] on an attribute is equivalent to [DoNotCheckSecurityOnGetter, DoNotCheckSecurityOnSetter].

[CheckSecurityForNode](m,a)

Summary: [CheckSecurityForNode] checks whether a given access to Node is allowed or not, in terms of the same-origin security policy.

Usage: [CheckSecurityForNode] can be specified on methods or attributes:

    attribute [CheckSecurityForNode] Node contentDocument;
    [CheckSecurityForNode] SVGDocument getSVGDocument();

In terms of the same-origin security policy, node.contentDocument should return undefined if the parent frame and the child frame are from different origins. If the security check is necessary, you should specify [CheckSecurityForNode]. This is really important for security.

[IndexedGetter](i)

Summary: [IndexedGetter] means that a given interface should have a getter of indexed properties.

Usage: [IndexedGetter] can be specified on interfaces:

    interface [
        IndexedGetter
    ] XXX {
    };

Indexed getters define the behavior when XXX[i] is evaluated. For example, if XXX is an array-type interface, it should have indexed getters (and setters). The bindings code for indexed getters is generated automatically so that XXX[i] behaves equivalent to XXX.item(i).

[CustomIndexedSetter](i)

Summary: [CustomIndexedSetter] allows you to write custom bindings for a setter of indexed properties.

Usage: [CustomIndexedSetter] can be specified on interfaces:

    interface [
        CustomIndexedSetter
    ] XXX {
    };

Indexed setters define the behavior when "XXX[i] = ..." is evaluated. For example, if XXX is an array-type interface, it should have indexed (getters and) setters. [CustomIndexedSetter] allows you to write the custom bindings, as follows.

  • JavaScriptCore: You can write custom JSXXX::indexSetter(...) in WebCore/bindings/js/JSXXXCustom.cpp:
    void JSXXX::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value)
    {
        ...;
    }
  • In V8: You can write custom V8XXX::indexedPropertySetter(...) in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Value> V8XXX::indexedPropertySetter(uint32_t index, const v8::AccessorInfo& info)
    {
        ...;
    }

[NamedGetter](i)

Summary: [NamedGetter] means that a given interface should have a getter of named properties.

Usage: [NamedGetter] can be specified on interfaces:

    interface [
        NamedGetter
    ] XXX {
    };

Named getters define the behavior when XXX.foooooooo is evaluated, where foooooooo is not an attribute of XXX. The bindings code for named getters is generated automatically so that XXX.foooooooo behaves equivalent to XXX.namedItem(i).

[CustomNamedGetter](i), [CustomNamedSetter](i)

Summary: [CustomNamedGetter] or [CustomNamedSetter] allows you to write custom bindings for a getter or setter of named properties.

Usage: They can be specified on interfaces:

    interface [
        CustomNamedGetter,
        CustomNamedSetter
    ] XXX {
    };

Named getters define the behavior when XXX.foooooooo is evaluated, where foooooooo is not an attribute of XXX. Named setters define the behavior when "XXX.foooooooo = ..." is evaluated. [CustomNamedGetter] or [CustomNamedSetter] allow you to write the custom bindings, as follows:

  • [CustomNamedGetter] in JavaScriptCore: You can write custom JSXXX::canGetItemsForName(...) and JSXXX::nameGetter(...) in WebCore/bindings/js/JSXXXCustom.cpp:
    bool JSXXX::canGetItemsForName(ExecState* exec, XXX* impl, const Identifier& propertyName)
    {
        ...;
    }

    JSValue JSXXX::nameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
    {
        ...;
    }
  • [CustomNamedGetter] in V8: You can write custom V8XXX::namedPropertyGetter(...) in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Value> V8XXX::namedPropertyGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    {
        ...;
    }
  • [CustomNamedSetter] in JavaScriptCore: You can write custom JSXXX::putDelegate(...) in WebCore/bindings/js/JSXXXCustom.cpp:
    bool JSXXX::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    {
        ...;
    }
  • [CustomNamedSetter] in V8: You can write custom V8XXX::namedPropertySetter(...) in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Value> V8XXX::namedPropertySetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
    {
        ...;
    }

[InterfaceName](i)

Summary: If you want to expose a different interface name to JavaScript, you can specify the name by [InterfaceName].

Usage: The possible usage is [InterfaceName=X], where X is the interface name exposed to JavaScript. [InterfaceName] can be specified on interfaces:

    interface [
        InterfaceName=Window
    ] DOMWindow {
    };

Without [InterfaceName=...], the interface name exposed to JavaScript becomes the same as the interface name in an IDL file. If you want change it based on the spec, you can use [InterfaceName=...]. In the above example, window.toString() will return "[object Window]" in JavaScript.

[EventTarget](i) FIXME

Summary: ADD SUMMARY

Usage: [EventTarget] can be specified on interfaces:

    interface [
        EventTarget
    ] XXX {
    };

ADD EXPLANATIONS

[DoNotCheckConstants](i)

Summary: [DoNotCheckConstants] indicates that constant values in an IDL file can be different from constant values in WebCore implementation.

Usage: [DoNotCheckConstants] can be specified on interfaces:

    interface [
        DoNotCheckConstants
    ] XXX {
        const unsigned short NOT_FOUND_ERR = 12345;
        const unsigned short SYNTAX_ERR = 12346;
    };

By default (i.e. without [DoNotCheckConstants]), compile-time assertions are inserted to check if the constant values defined in IDL files are equal to the constant values in WebCore implementation. In the above example, if NOT_FOUND_ERR were implemented as 100 in WebCore, the build will fail.

Note that basically all constant values are defined in the spec, and thus the values in WebCore implementation should be equal to the values defined in the spec. If you really want to introduce non-speced constant values and allow different values between IDL files and WebCore implementation, you can specify [DoNotCheckConstants] to skip the compile-time assertions.

[ActiveDOMObject](i)

Summary: [ActiveDOMObject] indicates that a given DOM object should be kept alive as long as the DOM object has pending activities.

Usage: [ActiveDOMObject] can be specified on interfaces:

    interface [
        ActiveDOMObject
    ] XMLHttpRequest {
    };

If a given DOM object needs to be kept alive as long as the DOM object has pending activities, you need to specify [ActiveDOMObject]. For example, [ActiveDOMObject] can be used when the DOM object is expecting events to be raised in the future.

If you use [ActiveDOMObject], the corresponding WebCore class needs to inherit ActiveDOMObject. For example, in case of XMLHttpRequest, WebCore/xml/XMLHttpRequest.h would look like this:

    class XMLHttpRequest : public ActiveDOMObject {
        ...;
    };

Then you need to implement the virtual methods of the ActiveDOMObject class, e.g. contextDestroyed(), canSuspend(), suspend(), resume() and stop().

If an interface X has [ActiveDOMObject] and an interface Y inherits the interface X, then the interface Y should also have [ActiveDOMObject].

[V8DependentLifeTime](i) FIXME

Summary: ADD SUMMARY

Usage: [V8DependentLifeTime] can be specified on interfaces:

    interface [
        V8DependentLifeTime
    ] XXX {
    };

ADD EXPLANATIONS

[CustomEnumerateProperty](i), [CustomDeleteProperty](i)

Summary: [CustomEnumerateProperty] allows you to write custom bindings for the case where properties of a given interface are enumerated. [CustomDeleteProperty] allows you to write custom bindings for the case where a property of a given interface is deleted.

Usage: They can be specified on interfaces:

    interface [
        CustomEnumerateProperty,
        CustomDeleteProperty
    ] XXX {
    };
  • [CustomEnumerateProperty] in JavaScriptCore: You can write custom bindings when properties of XXX are enumerated.

Specifically, you can write custom JSXXX::getOwnPropertyNames(...) in WebCore/bindings/js/JSXXXCustom.cpp:

    void JSXXX::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    {
        ...;
    }
  • [CustomEnumerateProperty] in V8: You can write custom bindings as V8XXX::namedPropertyQuery(...) and V8XXX::namedPropertyEnumerator(...) in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Integer> V8XXX::namedPropertyQuery(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    {
        ...;
    }

    v8::Handle<v8::Array> V8XXX::namedPropertyEnumerator(const v8::AccessorInfo& info)
    {
        ...;
    }
  • [CustomDeleteProperty] in JavaScriptCore: You can write custom bindings for the case where a property of XXX is deleted.

Specifically, you can write custom JSXXX::deleteProperty(...) in WebCore/bindings/js/JSXXXCustom.cpp:

    bool JSXXX::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
    {
        ...;
    }
  • [CustomDeleteProperty] in V8: You can write custom bindings as V8XXX::namedPropertyDeleter(...) in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Boolean> V8XXX::namedPropertyDeleter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    {
        ...;
    }

[IsWorkerContext](i)

Summary: [IsWorkerContext] indicates that a given interface is a WorkerContext-related interface.

Usage: [IsWorkerContext] can be specified on WorkerContext-related interfaces only:

    interface [
        IsWorkerContext
    ] SharedWorkerContext {
    };

[TransferList](p)

Summary: [TransferList] allows a SerializedScriptValue parameter used with the structured clone algorithm to specify another parameter used to pass the transfer list.

Usage: The possible usage is [TransferList=XXX] where XXX is another parameter in the same method signature as the SerializedScriptValue parameter on which the modifier is placed. The referenced parameter should be of type "Array" to be compatible with the Web Messaging standard.

When this modifier is used, the code generation automatically creates a MessagePortArray and completes the structured clone algorithm using the input data from the JavaScript caller. The resulting MessagePortArray is then passed to the implementation's method signature in place of the Array parameter referenced.

Example:

    interface Worker {
        void postMessage(in [TransferList=transfer] SerializedScriptValue data, in [Optional=DefaultIsUndefined] Array transfer);
    }

And in the implementation:

    class Worker {
        virtual void postMessage(PassRefPtr<SerializedScriptValue> data, const MessagePortArray& ports);
    }

[CustomCall](i)

Summary: [CustomCall] allows you to write custom bindings for call(...) of a given interface.

Usage: [CustomCall] can be specified on interfaces:

    interface [
        CustomCall
    ] XXX {
    };

If you want to write custom bindings for XXX.call(...), you can use [CustomCall].

  • JavaScriptCore: You can write custom JSXXX::getCallData(...) in WebCore/bindings/js/JSXXXCustom.cpp:
    JSC::CallType JSXXX::getCallData(JSC::JSCell* cell, JSC::CallData& callData)
    {
        ...;
    }
  • V8: You can write custom V8XXX::callAsFunctionCallback(...) in WebCore/bindings/v8/custom/V8XXXCustom.cpp:
    v8::Handle<v8::Value> V8XXX::callAsFunctionCallback(const v8::Arguments& args)
    {
        ...;
    }

[JSCustomToNativeObject](i), [JSCustomFinalize](i), [JSCustomIsReachable](i), [JSCustomMarkFunction](i), [JSCustomNamedGetterOnPrototype](i), [JSCustomPushEventHandlerScope](i), [JSCustomDefineOwnProperty](i), [JSCustomDefineOwnPropertyOnPrototype](i), [JSCustomGetOwnPropertySlotAndDescriptor](i)

Summary: They allow you to write custom bindings for the JavaScriptCore-specific code that would be generated automatically by default.

Usage: They can be specified on interfaces:

    interface [
        JSCustomToNativeObject,
        JSCustomFinalize,
        JSCustomIsReachable,
        JSCustomMarkFunction,
        JSCustomNamedGetterOnPrototype,
        JSCustomPushEventHandlerScope,
        JSCustomDefineOwnProperty,
        JSCustomDefineOwnPropertyOnPrototype,
        JSCustomGetOwnPropertySlotAndDescriptor
    ] XXX {
    };

You can write the following custom bindings in WebCore/bindings/js/JSXXXCustom.cpp. Refer to use cases in WebCore/bindings/js/JSXXXCustom.cpp for more details.

  • [JSCustomToNativeObject]: You can write custom toXXX(...):
    PassRefPtr<XXX> toXXX(JSGlobalData& globalData, JSValue value)
    {
        ...;
    }
  • [JSCustomFinalize]: You can write custom JSXXXOwner::finalize(...):
    void JSXXXOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
    {
        ...;
    }
  • [JSCustomIsReachable]: You can write custom JSXXXOwner::isReachableFromOpaqueRoots(...):
    bool JSXXXOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, SlotVisitor& visitor)
    {
        ...;
    }
  • [JSCustomMarkFunction]: You can write custom JSXXX::visitChildren(...):
    void JSXXX::visitChildren(JSCell* cell, SlotVisitor& visitor)
    {
        ...;
    }
  • [JSCustomNamedGetterOnPrototype]: You can write custom JSXXXPrototype::putDelegate(...):
    bool JSXXXPrototype::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    {
        ...;
    }
  • [JSCustomPushEventHandlerScope]: You can write custom JSXXX::pushEventHandlerScope(...):
    ScopeChainNode* JSXXX::pushEventHandlerScope(ExecState* exec, ScopeChainNode* node) const
    {
        ...;
    }
  • [JSCustomDefineOwnProperty]: You can write custom JSXXX::defineOwnProperty(...):
    bool JSXXX::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
    {
        ...;
    }
  • [JSCustomDefineOwnPropertyOnPrototype]: You can write custom JSXXXPrototype::defineOwnProperty(...):
    bool JSXXXPrototype::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
    {
        ...;
    }
  • [JSCustomGetOwnPropertySlotAndDescriptor]: You can write custom JSXXX::getOwnPropertySlotDelegate(...) and JSXXX::getOwnPropertyDescriptorDelegate(...):
    bool JSXXX::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    {
        ...;
    }

    bool JSXXX::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    {
        ...;
    }

[JSGenerateToJSObject](i), [JSGenerateToNativeObject](i)

Summary: They force JavaScriptCore bindings to generate JavaScriptCore-specific methods, even if a given interface has a parent interface.

Usage: They can be specified on interfaces that do not have a parent interface:

    interface [
        JSGenerateToJSObject,
        JSGenerateToNativeObject
    ] XXX {
    };

toJS(...), isReachableFromOpaqueRoots(...) or toXXX() is not generated if XXX has a parent interface. If you want to generate it even if XXX does not have a parent interface, you can specify [JSGenerateToJSObject] or [JSGenerateToNativeObject], respectively.

[JSGenerateIsReachable](i)

Summary: This generates code that determines if a wrapper is reachable.

Usage: The JSGenerateIsReachable can be specified on the interface. This attribute is ignored if CustomIsReachable is present.

    interface [
        JSGenerateIsReachable=ImplBaseRoot
    ] XXX {
    };

The code generates a function called XXX::isReachableFromOpaqueRoots which returns a boolean if the wrapper is reachable.

The currently valid values are:

  • (no value)
  • Impl
  • ImplContext
  • ImplFrame
  • ImplDocument
  • ImplElementRoot
  • ImplBaseRoot

The value of these represents the functions to call to get the object that determines whether the object is reachable or not KES-400A. See CodeGeneratorJS.pm for more details. The values that end with Root calls WebCore::root to get the root. If the value is left out then WebCore::root is called on impl().

[V8GenerateIsReachable](i), V8CustomIsReachable(i)

Summary: This generates code that allows you to set up implicit references between wrappers which can be used to keep wrappers alive during GC.

Usage: The V8GenerateIsReachable can be specified on the interface. This attribute is ignored if CustomIsReachable is present.

    interface [
        V8GenerateIsReachable=ImplBaseRoot
    ] XXX {
    };

The code generates a function called XXX::visitDOMWrapper which is called by V8GCController before GC. The function adds implicit references to the wrapper which keeps it alive.

The currently valid values are:

|ImplElementRoot|ImplOwnerRoot|ImplOwnerNodeRoot|ImplBaseRoot

  • ImplOwnerRoot
  • ImplOwnerNodeRoot
  • ImplElementRoot
  • ImplBaseRoot

The value of these represents the functions to call to get the object that determines whether the object is reachable or not. See CodeGeneratorV8.pm for more details.

[V8CustomIsReachable(i)

Summary: Allows you to write custom code for visitDOMWrapper.

Usage:

    interface [
        V8CustomIsReachable
    ] XXX {
    };

And then in V8XXXCustom.cpp:

void V8XXX::visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
{
  ...
}

[GenerateIsReachable](i)

Summary: This is the shared version of [JSGenerateIsReachable] and V8GenerateIsReachable. The accepted values are the intersection of those two.

  • ImplElementRoot
  • ImplBaseRoot

[JSCustomHeader](i)

Summary: [JSCustomHeader] allows you to write a custom header for a given interface.

Usage: [JSCustomHeader] can be specified on interfaces:

    interface [
        JSCustomHeader
    ] XXX {
    };

By default, JSXXX.h and JSXXX.cpp are generated automatically. By specifying [Custom*], you can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp. In addition, by specifying [JSCustomHeader], you can write custom header in WebCore/bindings/js/JSXXXCustom.h, which will be included by JSXXX.h.

[JSLegacyParent](i)

Summary: [JSLegacyParent] explicitly controls the parent interface of a given interface.

Usage: [JSLegacyParent] can be specified on interfaces that do not have a parent interface:

    interface [
        JSLegacyParent=JSDOMWindowBase
    ] DOMWindow {
    };

Even if a given interface does not have a parent interface, you can specify a parent interface using [JSLegacyParent].

[JSInlineGetOwnPropertySlot](i)

Summary: For performance, [JSInlineGetOwnPropertySlot] makes getOwnPropertySlot(...) and getOwnPropertyDescriptor(...) an inline method.

Usage: [JSInlineGetOwnPropertySlot] can be specified on interfaces:

    interface [
        JSInlineGetOwnPropertySlot
    ] XXX {
    };

[JSNoStaticTables](i)

Summary: By default, there is only a single static prototype table for the interface. This flag turns off creation of the static table, and each user gets its own table.

Sharing a single static prototype table only works when a class is guaranteed to be accessed from a single heap, because the lookup code expects the key (attribute name) to have the same address across all instances of the object. For interfaces that are exposed to Workers, a single static table won't work because a given string used to look up a property on the object will lie at a different address in each heap.

Usage: [JSNoStaticTables] can be specified on interfaces:

    interface [
        JSNoStaticTables
    ] XXX {
    };

ADD EXPLANATIONS

[ObjCProtocol](i), [ObjCPolymorphic](i), [ObjCLegacyUnnamedParameters](m), [ObjCUseDefaultView](m), [ObjCImplementedAsUnsignedLongLong](a)

Used by ObjC bindings only.

[CPPPureInterface](i)

Used by CPP bindings only.

[CustomReturn](p)

Used by ObjC, GObject and CPP bindings only.

[ArrayClass](i)

Summary: Allows an interface to extend JavaScript arrays.

Usage: [ArrayClass] can be specified on interfaces. An interface may not both have [ArrayClass] and extend another interface.

The bindings for the interface will have the [[Prototype]] of the constructor prototype set to Array.prototype which means that the methods defined on JavaScript arrays work on the instances of this interface.

// IDL
interface [
    ArrayClass,
    IndexedGetter
] NodeList {
    Node item(in unsigned long index);
    readonly attribute unsigned long length;
}

// JS
myNodeList instanceof Array  // true
myNodeList.forEach(function(node) { console.log(node_; });

[OmitConstructor], [Immutable], [MasqueradesAsUndefined], [CustomGetOwnPropertySlot], [ReplaceableConstructor], [ExtendsDOMGlobalObject], [IsIndex], [V8DoNotCheckSignature], [NumericIndexedGetter]

Might be deprecated. Discussion is on-going.

Note: See TracWiki for help on using the wiki.