= Table of Contents =
[#Overview Overview][[br]]
[#Basics Basics of IDL][[br]]
[#IDLAttributeChecker IDL attribute checker][[br]]
[#RunBindingsTests run-bindings-tests][[br]]
[#BindingsCode Where is the bindings code generated?][[br]]
[#NamingRules Basic naming rules of IDL attributes][[br]]
[#IDLAttributes IDL attributes]
- [#TreatNullAs TreatNullAs(a,p)][[br]]
- [#Clamp Clamp(a,p)][[br]]
- [#Custom Custom(m,a), CustomGetter(a), CustomSetter(a)][[br]]
- [#CustomBinding CustomBinding][[br]]
- [#CallWith CallWith(m,a), SetterCallWith(a)][[br]]
- [#NewObject NewObject(m,a)][[br]]
- [#ImplementedAs ImplementedAs(m,a)][[br]]
- [#Reflect Reflect(a)][[br]]
- [#Replaceable Replaceable(a)][[br]]
- [#Deletable Deletable(a), NotEnumerable(a)][[br]]
- [#CachedAttribute CachedAttribute(a)][[br]]
- [#JSWindowEventListener JSWindowEventListener(a)][[br]]
- [#Constructor Constructor(i), ConstructorCallWith(i), ConstructorRaisesException(i)][[br]]
- [#ConstructorTemplate ConstructorTemplate(i), InitializedByEventConstructor(a)][[br]]
- [#NamedConstructor NamedConstructor(i)][[br]]
- [#CustomConstructor CustomConstructor(i)][[br]]
- [#Conditional Conditional(i,m,a)][[br]]
- [#CheckSecurity CheckSecurity(i), DoNotCheckSecurity(m,a), DoNotCheckSecurityOnGetter(a), DoNotCheckSecurityOnSetter(a)][[br]]
- [#CheckSecurityForNode CheckSecurityForNode(m,a)][[br]]
- [#CustomIndexedSetter CustomIndexedSetter(i)][[br]]
- [#CustomNamedGetter CustomNamedGetter(i), CustomNamedSetter(i)][[br]]
- [#InterfaceName InterfaceName(i)][[br]]
- [#DoNotCheckConstants DoNotCheckConstants(i)][[br]]
- [#ActiveDOMObject ActiveDOMObject(i)][[br]]
- [#CustomEnumerateProperty CustomEnumerateProperty(i), CustomDeleteProperty(i)][[br]]
- [#TypedArray TypedArray(i), ConstructorTemplate=TypedArray(i)][[br]]
- [#CustomCall CustomCall(i)][[br]]
- [#JSCustomToNativeObject JSCustomToNativeObject(i), JSCustomFinalize(i), CustomIsReachable(i), JSCustomMarkFunction(i), JSCustomNamedGetterOnPrototype(i), JSCustomPushEventHandlerScope(i), JSCustomDefineOwnProperty(i), JSCustomDefineOwnPropertyOnPrototype(i), JSCustomGetOwnPropertySlotAndDescriptor(i)][[br]]
- [#JSGenerateToJSObject JSGenerateToJSObject(i), JSGenerateToNativeObject(i)][[br]]
- [#GenerateIsReachable GenerateIsReachable(i)]
- [#JSLegacyParent JSLegacyParent(i)][[br]]
- [#JSInlineGetOwnPropertySlot JSInlineGetOwnPropertySlot(i)][[br]]
- [#JSNoStaticTables JSNoStaticTables(i)][[br]]
- [#ObjCProtocol ObjCProtocol(i), ObjCPolymorphic(i), ObjCLegacyUnnamedParameters(m), ObjCUseDefaultView(m), ObjCImplementedAsUnsignedLongLong(a)][[br]]
- [#CPPPureInterface CPPPureInterface(i)][[br]]
- [#CustomReturn CustomReturn(p)][[br]]
- [#ArrayClass ArrayClass(i)][[br]]
- [#Immutable Immutable, MasqueradesAsUndefined, CustomGetOwnPropertySlot, ReplaceableConstructor][[br]]
- [#ImplementationNamespace ImplementationNamespace(i)][[br]]
- [#SkipVTableValidation SkipVTableValidation(i), ImplementationLacksVTable(i),][[br]]
- [#NoInterfaceObject NoInterfaceObject(i), GlobalContext(i)][[br]]
- [#EnabledAtRuntime EnabledAtRuntime(i)][[br]]
- [#RaisesException RaisesException(m) GetterRaisesException(a), SetterRaisesException(a)][[br]]
- [#OverrideBuiltins OverrideBuiltins(i)][[br]]
- [#Unforgeable Unforgeable(i)][[br]]
- [#JSBuiltin JSBuiltin(i,m,a), Private][[br]]
- [#ExportMacro ExportMacro(i)][[br]]
= Overview = #Overview
The [http://www.w3.org/TR/WebIDL/ Web IDL] is a language that defines how WebCore interfaces are bound to external languages such as JavaScriptCore, 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, 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 [http://www.w3.org/TR/WebIDL/ 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 = #Basics
Here is an example of IDL files:
{{{
module core {
[
CustomToJSObject
] interface Node {
const unsigned short ELEMENT_NODE = 1;
attribute Node parentNode;
attribute DOMString? nodeName;
[Custom] Node appendChild([CustomReturn] Node newChild);
void addEventListener(DOMString type, EventListener listener, 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 '''attribute'''s of the Node interface.
* appendChild(...) and addEventListener(...) are '''method'''s of the Node interface.
* type, listener and useCapture are '''parameter'''s of the Node interface.
* `[CustomToJSObject]`, `[Custom]` and `[CustomReturn]` are '''IDL attribute'''s.
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 {
[
IDL_ATTRIBUTE_ON_INTERFACE1,
IDL_ATTRIBUTE_ON_INTERFACE2,
...
] interface INTERFACE_NAME {
const unsigned long value = 12345;
[IDL_ATTRIBUTE_ON_ATTRIBUTE1, IDL_ATTRIBUTE_ON_ATTRIBUTE2, ...] attribute Node node;
[IDL_ATTRIBUTE_ON_METHOD1, IDL_ATTRIBUTE_ON_METHOD2, ...] void func([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;
[IDL_ATTRIBUTE_ON_ATTRIBUTE1, IDL_ATTRIBUTE_ON_ATTRIBUTE2, ...] attribute Node node;
[IDL_ATTRIBUTE_ON_METHOD1, IDL_ATTRIBUTE_ON_METHOD2, ...] void func([IDL_ATTRIBUTE_ON_PARAMETER1, IDL_ATTRIBUTE_ON_PARAMETER2, ...] int param, ...);
};
}
}}}
= IDL attribute checker = #IDLAttributeChecker
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.
1. add the explanation to this document.
1. add test cases to run-bindings-tests (explained below).
= run-bindings-tests = #RunBindingsTests
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,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? = #BindingsCode
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).
* JavaScriptCore:
{{{
WebKitBuild/Release/DerivedSources/WebCore/JSXXX.h
WebKitBuild/Release/DerivedSources/WebCore/JSXXX.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 = #NamingRules
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".
* 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]`, etc.
= IDL attributes = #IDLAttributes
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) == #TreatNullAs
* [http://heycam.github.io/webidl/#TreatNullAs The spec of TreatNullAs]
Summary: When a JavaScript null is passed to a DOMString attribute or parameter, its gets converted to the empty string "" internally instead of being stringified as the string "null".
Usage: The possible usage is `[TreatNullAs=EmptyString]`.
They can be specified on DOMString attributes or DOMString parameters only:
{{{
[TreatNullAs=EmptyString] attribute DOMString str;
void func([TreatNullAs=EmptyString] DOMString str);
}}}
== `[Clamp]`(a,p) == #Clamp
* [http://www.w3.org/TR/2012/CR-WebIDL-20120419/#Clamp The spec of Clamp]
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 {
[Clamp] attribute 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)`.
== `[Custom]`(m,a), `[CustomGetter]`(a), `[CustomSetter]`(a) == #Custom
Summary: They allow you to write bindings code manually as you like.
Usage: `[Custom]` can be specified on methods or attributes. `[CustomGetter]`, `[CustomSetter]` can be specified on attributes:
{{{
[Custom] void func();
[CustomGetter, JSCustomSetter] attribute 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.
* `[Custom]` on a method indicates that you can write JavaScriptCore custom bindings for the method.
* `[CustomGetter]` or `[CustomSetter]` on an attribute indicates that you can write JavaScriptCore custom bindings for the attribute getter or setter.
You can write custom bindings with JavaScriptCore for a method or an attribute getter/setter, as follows:
* Method: Consider the following example:
{{{
interface XXX {
[Custom] void func(int a, 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.
* Attribute getter: Consider the following example:
{{{
interface XXX {
[CustomGetter] attribute 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.
* Attribute setter: Consider the following example:
{{{
interface XXX {
[CustomSetter] attribute DOMString str;
};
}}}
You can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp:
{{{
void JSXXX::setStr(ExecState*, JSValue value)
{
...;
}
}}}
Note: ObjC, GObject and CPP bindings do not support custom bindings.
== `[CustomBinding]` == #CustomBinding
Summary: They allow you to write bindings code even more manually than `[Custom]`.
Usage: `[CustomBinding]` can be specified only on methods:
{{{
[CustomBinding] void myMethod();
}}}
We should minimize the number of custom bindings as much as possible, since they are likely to be buggy.
Before using `[CustomBinding]`, you should doubly consider if you really need custom bindings.
You are recommended to modify code generators to avoid using `[CustomBinding]`.
Before explaining the details, let us clarify the relationship of these IDL attributes.
* `[CustomBinding]` on a method indicates that you can write JavaScriptCore custom bindings for the method at a higher level than `[Custom]`.
You can write custom bindings with JavaScriptCore for a method as follows:
{{{
interface XXX {
[CustomBinding] void myMethod(int a, int b);
};
}}}
You can write custom bindings in WebCore/bindings/js/JSXXXCustom.cpp:
{{{
EncodedJSValue JSC_HOST_CALL jsXXXPrototypeFunctionMyMethod(ExecState*)
{
// Read parameters manually if any.
// Get the called object from the ExecState if needed and wanted.
// Call the object and implementation if needed and wanted.
// Return a value.
return JSValue::encode(...);
}
}}}
Refer to WebCore/bindings/js/JSXXXCustom.cpp for more details.
The main difference between `[Custom]` and `[CustomBinding]` is that `[Custom]` generates a `jsXXXPrototypeFunctionMyMethod` where it performs the parameters management, casting to the object and calls the `JSXXX::myMethod` with the parameters and the instance. With `[CustomBinding]`, the implementation of `jsXXXPrototypeFunctionMyMethod` is not done automatically and it is up to the developer to do all the parameter, casting and call operations.
Note: ObjC, GObject and CPP bindings do not support `[CustomBinding]` bindings.
== `[CallWith]`(m,a), `[SetterCallWith]`(a) == #CallWith
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 "Document", "ScriptExecutionContext", "ScriptState", "ScriptArguments", "CallStack", "ActiveWindow" or "FirstWindow".
"ScriptExecutionContext", "ScriptState" and "CallStack" can be specified on methods or attributes,
but "ScriptArguments" can be specified on methods only:
{{{
interface HTMLFoo {
[CallWith=ScriptExecutionContext] attribute DOMString str;
[SetterCallWith=ScriptExecutionContext] attribute DOMString str2;
[CallWith=ScriptExecutionContext] void func1(int a, int b);
[CallWith=ScriptState] void func2(int a, int b);
[CallWith=ScriptArguments|CallStack] void func3(int a, int b);
[CallWith=CallStack|ScriptArguments] void func4(int a, int b);
};
}}}
Note: See `[ConstructorCallWith]` in the [#Constructor [Constructor] section] for similar functionality on constructors.
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.
== `[NewObject]`(m,a) == #NewObject
* [https://heycam.github.io/webidl/#NewObject The spec of NewObject]
Summary: `[NewObject]` controls whether WebCore can return a cached wrapped object or WebCore needs to return a newly created wrapped object every time.
Usage: `[NewObject]` can be specified on methods or attributes:
{{{
[NewObject] attribute Node node;
[NewObject] Node createTextNode();
}}}
Without `[NewObject]`, JavaScriptCore cache a wrapped object for performance.
For example, consider the case where `node.firstChild` is accessed:
1. `Node::firstChild()` is called in WebCore.
1. The result of `Node::firstChild()` is passed to `toJS()`.
1. `toJS()` checks if a wrapped object of the result is already cached on the node.
1. If cached, the cached wrapped object is returned. That's it.
1. Otherwise, `toJS()` creates the wrapped object of the result.
1. The created wrapped object is cached on the node.
1. 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 `[NewObject]`.
== `[ImplementedAs]`(m,a) == #ImplementedAs
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();
[ImplementedAs=classAttribute] attribute 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) == #Reflect
* [http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#reflect The spec of Reflect]
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 {
[Reflect] attribute DOMString id;
[Reflect=class] attribute DOMString className;
};
}}}
(Informally speaking,) a content attribute means an attribute on an HTML tag:
{{{
}}}
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) == #Replaceable
* [http://dev.w3.org/2006/webapi/WebIDL/#Replaceable The spec of Replaceable]
Summary: `[Replaceable]` controls if a given attribute is "replaceable" or not.
Usage: `[Replaceable]` can be specified on attributes:
{{{
interface DOMWindow {
[Replaceable] attribute 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)`(a) == #Deletable
* [http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf The spec of Writable, Enumerable and Configurable (Section 8.6.1)]
Summary: They control `Writability`, `Enumerability` attributes (`readonly` keyword controls the `Configurability` attributes).
Usage: They can be specified on attributes:
{{{
[NotEnumerable, Deletable] attribute DOMString str;
readonly attribute DOMString readonlyStr;
}}}
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 `readonly`.
* `[Deletable]` indicates that the attribute is deletable.
* `[NotEnumerable]` indicates that the attribute is not enumerable.
* `readonly` indicates that the attribute is read only.
== `[CachedAttribute]`(a) == #CachedAttribute
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 {
[CachedAttribute] attribute DOMString normalValue;
[CachedAttribute] attribute SerializedScriptValue serializedValue;
};
}}}
Without `[CachedAttribute]`, the normalValue getter works in the following way:
1. `HTMLFoo::normalValue()` is called in WebCore.
1. The result of `HTMLFoo::normalValue()` is passed to `toJS()`, and is converted to a wrapped object.
1. 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.
1. Otherwise, `HTMLFoo::normalValue()` is called in WebCore.
1. The result of `HTMLFoo::normalValue()` is passed to `toJS()`, and is converted to a wrapped object.
1. The wrapped object is cached.
1. 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.
1. The result of `HTMLFoo::serializedValue()` is deserialized.
1. The deserialized result is passed to `toJS()`, and is converted to a wrapped object.
1. 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.
1. Otherwise, `HTMLFoo::serializedValue()` is called in WebCore.
1. The result of `HTMLFoo::serializedValue()` is deserialized.
1. The deserialized result is passed to `toJS()`, and is converted to a wrapped object.
1. The wrapped object is cached.
1. 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.
== `[JSWindowEventListener]`(a) FIXME == #JSWindowEventListener
Summary: ADD SUMMARY
Usage: `[JSWindowEventListener]` can be specified on `EventListener` attributes only:
{{{
[JSWindowEventListener] attribute EventListener onload;
}}}
ADD EXPLANATIONS
== `[Constructor]`(i), `[ConstructorCallWith]`(i), `[ConstructorRaisesException](i)` == #Constructor
* [http://dev.w3.org/2006/webapi/WebIDL/#Constructor The spec of Constructor]
Summary: `[Constructor]` indicates that the interface should have constructor, i.e. "new XXX()".
`[ConstructorCallWith]` and `[ConstructorRaisesException]` add information when the constructor callback is called in WebCore.
Usage: `[Constructor]`, `[ConstructorCallWith]` and `[ConstructorRaisesException]` can be specified on interfaces:
{{{
[
Constructor(float x, float y, DOMString str),
ConstructorRaisesException,
ConstructorCallWith=ScriptExecutionContext
] interface XXX {
};
}}}
`[Constructor(float x, float y, DOMString str)]` means that the interface has a constructor
and the constructor signature is `(float x, float y, 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::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::create(float x, float y, String str, ExceptionCode& ec)
{
...;
if (...) {
ec = TYPE_MATCH_ERR;
return 0;
}
}
}}}
If `XXX::create(...)` needs additional information like ScriptExecutionContext,
you can specify `[ConstructorCallWith=ScriptExecutionContext]`.
Then `XXX::create(...)` can have the following signature:
{{{
PassRefPtr XXX::create(ScriptExecutionContext* context, float x, float y, String str)
{
...;
}
}}}
You can retrieve document or frame from ScriptExecutionContext.
Note that `[ConstructorCallWith=...]` 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 w/o defaults.
== `[ConstructorTemplate]`(i), `[InitializedByEventConstructor]`(a) == #ConstructorTemplate
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:
{{{
[
ConstructorTemplate=Event
] interface FooEvent {
attribute DOMString str1;
[InitializedByEventConstructor] attribute 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::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 [http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#event 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) == #NamedConstructor
* [http://dev.w3.org/2006/webapi/WebIDL/#NamedConstructor The spec of NamedConstructor]
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:
{{{
[
NamedConstructor=Audio()
] interface 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) == #CustomConstructor
Summary: It allows you to write custom bindings for constructors.
Usage: It can be specified on interfaces.
{{{
[
CustomConstructor,
] interface XXX {
};
[
CustomConstructor(DOMString str, optional boolean flag),
] interface YYY {
};
}}}
The constructor arguments should be specified so that the bindings generator can properly compute the value for the "length" property of the constructor object.
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.
* `[CustomConstructor]` on an interface indicates that you can write JavaScriptCore custom bindings for the constructor.
You can write custom bindings for JavaScriptCore as follows.
* Consider the following example:
{{{
[
CustomConstructor,
] interface 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.
== `[Conditional]`(i,m,a) == #Conditional
Summary: `[Conditional]` inserts "#if ENABLE(SOME_FLAG) ... #endif" into the generated code.
Usage: `[Conditional]` can be specified on interfaces, methods and attributes:
{{{
[
Conditional=INDEXED_DATABASE
] interface XXX {
};
}}}
{{{
interface XXX {
[Conditional=INDEXED_DATABASE] attribute 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.
== `[CheckSecurity]`(i), `[DoNotCheckSecurity]`(m,a), `[DoNotCheckSecurityOnGetter]`(a), `[DoNotCheckSecurityOnSetter]`(a) == #CheckSecurity
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]`:
{{{
[
CheckSecurity
] interface DOMWindow {
attribute DOMString str1;
[DoNotCheckSecurity] attribute DOMString str2:
[DoNotCheckSecurityOnGetter] attribute DOMString str3:
[DoNotCheckSecurityOnSetter] attribute 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) == #CheckSecurityForNode
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:
{{{
[CheckSecurityForNode] attribute 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.
== `[CustomIndexedSetter]`(i) == #CustomIndexedSetter
* [http://dev.w3.org/2006/webapi/WebIDL/#idl-indexed-properties The spec of indexed properties] (Note: The WebKit behavior explained below is different from the spec)
Summary: `[CustomIndexedSetter]` allows you to write custom bindings for a setter of indexed properties.
Usage: [CustomIndexedSetter] can be specified on interfaces:
{{{
[
CustomIndexedSetter
] interface 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)
{
...;
}
}}}
== `[CustomNamedGetter]`(i), `[CustomNamedSetter]`(i) == #CustomNamedGetter
* [http://dev.w3.org/2006/webapi/WebIDL/#idl-named-properties The spec of named properties] (Note: The WebKit behavior explained below is different from the spec)
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:
{{{
[
CustomNamedGetter,
CustomNamedSetter
] interface 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)
{
...;
}
}}}
* `[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)
{
...;
}
}}}
== `[InterfaceName]`(i) == #InterfaceName
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.
== `[DoNotCheckConstants]`(i) == #DoNotCheckConstants
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:
{{{
[
DoNotCheckConstants
] interface 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) == #ActiveDOMObject
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:
{{{
[
ActiveDOMObject
] interface 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]`.
== `[CustomEnumerateProperty]`(i), `[CustomDeleteProperty]`(i) == #CustomEnumerateProperty
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:
{{{
[
CustomEnumerateProperty,
CustomDeleteProperty
] interface 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)
{
...;
}
}}}
* `[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)
{
...;
}
}}}
== `[TypedArray]`(i), [ConstructorTemplate=TypedArray](i) == #TypedArray
* [http://www.khronos.org/registry/typedarray/specs/latest/#7 The spec of TypedArray]
Summary: The typed array view types represent a view of an ArrayBuffer that allows for indexing and manipulation.
TypedArray implements ArrayBufferView. Each of the typed array types has the following constructors, properties, constants and methods.
Usage: `[TypedArray]` must be specified on interfaces in conjunction with `[ConstructorTemplate=TypedArray]`:
Example:
{{{
[
ConstructorTemplate=TypedArray,
TypedArray=int
] interface XXX : ArrayBufferView {
void set(TypedArray array, optional unsigned long offset);
}
}}}
`TypedArray=*` Allows us to specify any valid typed array view type.
TypedArray interfaces require special bindings code, you need to use `[ConstructorTemplate=TypedArray]` instead of normal `[Constructor]`.
== `[CustomCall]`(i) == #CustomCall
Summary: `[CustomCall]` allows you to write custom bindings for `call(...)` of a given interface.
Usage: `[CustomCall]` can be specified on interfaces:
{{{
[
CustomCall
] interface 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)
{
...;
}
}}}
== `[JSCustomToNativeObject]`(i), `[JSCustomFinalize]`(i), `[CustomIsReachable]`(i), `[JSCustomMarkFunction]`(i), `[JSCustomNamedGetterOnPrototype]`(i), `[JSCustomPushEventHandlerScope]`(i), `[JSCustomDefineOwnProperty]`(i), `[JSCustomDefineOwnPropertyOnPrototype]`(i), `[JSCustomGetOwnPropertySlotAndDescriptor]`(i) == #JSCustomToNativeObject
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:
{{{
[
JSCustomToNativeObject,
JSCustomFinalize,
CustomIsReachable,
JSCustomMarkFunction,
JSCustomNamedGetterOnPrototype,
JSCustomPushEventHandlerScope,
JSCustomDefineOwnProperty,
JSCustomDefineOwnPropertyOnPrototype,
JSCustomGetOwnPropertySlotAndDescriptor
] interface 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 toXXX(JSGlobalData& globalData, JSValue value)
{
...;
}
}}}
* `[JSCustomFinalize]`: You can write custom `JSXXXOwner::finalize(...)`:
{{{
void JSXXXOwner::finalize(JSC::Handle handle, void* context)
{
...;
}
}}}
* `[CustomIsReachable]`: You can write custom `JSXXXOwner::isReachableFromOpaqueRoots(...)`:
{{{
bool JSXXXOwner::isReachableFromOpaqueRoots(JSC::Handle 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) == #JSGenerateToJSObject
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:
{{{
[
JSGenerateToJSObject,
JSGenerateToNativeObject
] interface 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.
== `[GenerateIsReachable]`(i) == #GenerateIsReachable
Summary: This generates code that determines if a wrapper is reachable.
Usage: The `GenerateIsReachable` can be specified on the interface. This attribute is ignored if `CustomIsReachable` is present.
{{{
[
GenerateIsReachable=ImplBaseRoot
] interface 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. 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().
== `[JSLegacyParent]`(i) == #JSLegacyParent
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:
{{{
[
JSLegacyParent=JSDOMWindowBase
] interface DOMWindow {
};
}}}
Even if a given interface does not have a parent interface, you can specify a parent interface using `[JSLegacyParent]`.
== `[JSInlineGetOwnPropertySlot]`(i) == #JSInlineGetOwnPropertySlot
Summary: For performance, `[JSInlineGetOwnPropertySlot]` makes `getOwnPropertySlot(...)` and `getOwnPropertyDescriptor(...)` an inline method.
Usage: `[JSInlineGetOwnPropertySlot]` can be specified on interfaces:
{{{
[
JSInlineGetOwnPropertySlot
] interface XXX {
};
}}}
== `[JSNoStaticTables]`(i) == #JSNoStaticTables
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:
{{{
[
JSNoStaticTables
] interface XXX {
};
}}}
ADD EXPLANATIONS
== `[ObjCProtocol]`(i), `[ObjCPolymorphic]`(i), `[ObjCLegacyUnnamedParameters]`(m), `[ObjCUseDefaultView]`(m), `[ObjCImplementedAsUnsignedLongLong]`(a) == #ObjCProtocol
Used by ObjC bindings only.
== `[CPPPureInterface]`(i) == #CPPPureInterface
Used by CPP bindings only.
== `[CustomReturn]`(p) == #CustomReturn
Used by ObjC, GObject and CPP bindings only.
== `[ArrayClass]`(i) == #ArrayClass
* [http://dev.w3.org/2006/webapi/WebIDL/#ArrayClass The spec of ArrayClass]
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
[
ArrayClass
] interface NodeList {
getter Node item(unsigned long index);
readonly attribute unsigned long length;
};
// JS
myNodeList instanceof Array // true
myNodeList.forEach(function(node) { console.log(node_; });
}}}
== `[Immutable]`, `[MasqueradesAsUndefined]`, `[CustomGetOwnPropertySlot]`, `[ReplaceableConstructor]` == #Immutable
Might be deprecated. Discussion is on-going.
== `[ImplementationNameSpace]` == #ImplementationNamespace
Summary: Specifies the namespace for the corresponding native type.
By default, the namespace is WebCore. This is presently used to mark WTF types.
Usage: `[ImplementationNamespace]` can be specified on interfaces:
{{{
[
ImplementationNamespace=WTF
] interface ArrayBuffer {
};
}}}
== `[SkipVTableValidation]`, `[ImplementationLacksVTable]` == #SkipVTableValidation
Summary: Specifies that a type can not be checked as part of the Bindings Integrity option.
Bindings Integrity tries to ensure that free/corrupted objects are not wrapped by JSC, thereby reducing their exploitability. In order for that to be the case, the implementation must have a distinct VTable pointer in its first word.
Usage: `[SkipVTableValidation]` and `[ImplementationLacksVTable]` can be specified on interfaces.
{{{
[
SkipVTableValidation
] interface XXX {
};
}}}
{{{
[
ImplementationLacksVTable
] interface XXX {
};
}}}
== `[NoInterfaceObject]`(i), `[GlobalContext]`(i) == #NoInterfaceObject
Standard: [http://dev.w3.org/2006/webapi/WebIDL/#NoInterfaceObject The spec of NoInterfaceObject]
Summary: If the `[NoInterfaceObject]` extended attribute is specified on an interface, it indicates that an interface object will not exist for the interface in the ECMAScript binding.
Note that for every interface that:
* is a callback interface that has constants declared on it, or
* is a non-callback interface that is not declared with the `[NoInterfaceObject]` extended attribute,
a corresponding property is automatically added on the ECMAScript global object by the bindings generator.
`[GlobalContext=*]` is a WebKit-specific extended attribute that may only be used on interfaces that do not have the `[NoInterfaceObject]` attribute. The following values are allowed for this attribute:
* `DOMWindow`: A corresponding attribute (global constructor) will be automatically added on the `DOMWindow` interface (default if the extended attribute is omitted).
* `WorkerGlobalScope`: A corresponding attribute (global constructor) will be automatically added on the `WorkerGlobalScope` interface.
* `SharedWorkerGlobalScope`: A corresponding attribute (global constructor) will be automatically added on the `SharedWorkerGlobalScope` interface.
* `DedicatedWorkerGlobalScope`: A corresponding attribute (global constructor) will be automatically added on the `DedicatedWorkerGlobalScope` interface.
It is possible to have the global constructor generated on several interfaces by specifying several interface names and separating them with a '&', for e.g. `[GlobalContext=DOMWindow&WorkerGlobalScope]`.
Usage: `[NoInterfaceObject]` and `[GlobalContext]` can be specified on interfaces, but not at the same time.
{{{
[
NoInterfaceObject
] interface XXX {
...
};
// A 'YYY' constructor property will be generated on the global DedicatedWorkerGlobalScope object.
[
GlobalContext=DedicatedWorkerGlobalScope
] interface YYY {
...
};
// A 'ZZZ' constructor property will be generated on both the global Window object and the global WorkerGlobalScope object.
[
GlobalContext=DOMWindow&WorkerGlobalScope
] interface ZZZ {
...
};
}}}
== `[EnabledAtRuntime]`(i) == #EnabledAtRuntime
Standard: this is a non-standard attribute
Summary: If the `[EnabledAtRuntime]` extended attribute is specified on non-callback interface that is not declared with the `[NoInterfaceObject]` extended attribute, it indicates that the corresponding attribute(s) generated on the global Window object can be enabled / disabled at runtime.
The [https://trac.webkit.org/browser/trunk/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.h RuntimeEnabledFeatures class] is used to determine if the global constructor should be enabled, at runtime. By default, the name of the interface is used as feature name but it is possible to specify the feature name explicitly as well via `[EnabledAtRuntime=FeatureName]`.
Usage: `[EnabledAtRuntime]` can be specified on interfaces.
{{{
// window.XXX will only be enabled if RuntimeEnabledFeatures::xXXEnabled() returns true.
[
EnabledAtRuntime
] interface XXX {
...
};
// window.YYY will only be enabled if RuntimeEnabledFeatures::featureNameEnabled() returns true.
[
EnabledAtRuntime=FeatureName
] interface YYY {
...
};
}}}
== `[RaisesException]`(m), `[GetterRaisesException]`(a), `[SetterRaisesException]`(a) == #RaisesException
Standard: This is a non-standard attribute.
Summary: Tells the code generator to append an ExceptionCode& argument when calling the WebCore implementation.
Implementations may assign a DOMException code to this reference parameter, and the generated binding code will create and throw the appropriate exception type.
Usage: [RaisesException] can be specified on methods, and [GetterRaisesException] and [SetterRaisesException] can be specified on attributes. On methods and attributes, the IDL looks like:
{{{
interface XXX {
[GetterRaisesException, SetterRaisesException] attribute long count;
[RaisesException] void foo();
};
}}}
And the WebCore implementations would look like:
{{{
long XXX::count(ExceptionCode& ec) {
if (...) {
ec = TYPE_MISMATCH_ERROR;
return;
}
...;
}
void XXX::setCount(long value, ExceptionCode& ec) {
if (...) {
ec = TYPE_MISMATCH_ERROR;
return;
}
...;
}
void XXX::foo(ExceptionCode& ec) {
if (...) {
ec = TYPE_MISMATCH_ERROR;
return;
}
...;
};
}}}
See [ConstructorRaisesException] to specify that a constructor throws exceptions.
== `[OverrideBuiltins]`(i) == #OverrideBuiltins
Standard: [https://heycam.github.io/webidl/#OverrideBuiltins The spec of OverrideBuiltins]
Summary: Controls if named properties should override own properties or not.
Usage: [OverrideBuiltins] can be specified on interfaces that have a named property getter. The IDL looks like:
{{{
[OverrideBuiltins]
interface XXX {
readonly attribute unsigned long length;
getter DOMString lookup(DOMString key);
};
}}}
== `[Unforgeable]`(i) == #Unforgeable
Standard: [https://heycam.github.io/webidl/#Unforgeable The spec of Unforgeable]
Summary: Indicates that the attribute or operation will be reflected as an ECMAScript property in a way that means its behavior cannot be modified and that performing a property lookup on the object will always result in the attribute’s property value being returned. In particular, the property will be non-configurable and will exist as an own property on the object itself rather than on its prototype.
Usage: [Unforgeable] can be specified on interfaces, on non-static attributes and on non-static operations. The IDL looks like:
{{{
[Unforgeable]
interface XXX {
readonly attribute unsigned long length;
DOMString getString(DOMString key);
};
interface YYY {
[Unforgeable] readonly attribute unsigned long length;
[Unforgeable] DOMString getString(DOMString key);
};
}}}
== `[JSBuiltin]`(m,a, i) `[Private]`(m) == #JSBuiltin
Standard: These are non-standard attributes.
Summary: If JSBuiltin is set on a method, it tells the code generator to implement the corresponding method as a JS builtin.
Usage: given a IDL file called XX.idl, a corresponding XX.js file should be created containing a JS function with the same method name in the case of JSBuiltin. JSBuiltin can also be set for read-only attributes (JS Builtin setter not yet supported), in which case the attribute getter should be implemented as JS builtin in the corresponding XX.js file.
JSBuiltin may also be set at the interface level. In that case, all methods and attributes are considered as JS builtins, except if the method or attribute is set as Custom, CustomGetter or CustomSetter. Such an interface does not need any corresponding DOM class.
An interface setting both JSBuiltin and Constructor will need to implement a 'initializeXX' JS builtin function.
Private attribute is used to add C++ implemented functions to the JS prototype as private slots. These functions can then be called from JS builtin functions.
{{{
interface YYY {
// Implemented as JS builtin
[JSBuiltin] readonly attribute unsigned long length;
// Implemented as JS builtin
[JSBuiltin] DOMString getString(DOMString key);
// Implemented as C++ YYY::setString(...)
void setString(DOMString key, DOMString value);
// Implemented as C++ YYY::doSomething. Can be used within JS Builtin code as this.@doSomething
[Private] void doSomething(DOMString action);
};
[JSBuiltin]
interface XXX {
// Implemented as JS builtin
readonly attribute unsigned long length;
// Implemented as JS builtin
DOMString getString(DOMString key);
// Implemented as C++ JSXXX::setString(...)
[Custom] void setString(DOMString key, DOMString value);
};
}}}
== `[ExportMacro]`(i) == #ExportMacro
Standard: This is a non-standard IDL extended attribute.
Summary: If [ExportMacro=XXX] is set on an interface ABC, it tells the code generator that the corresponding JSABC class should be exported using the provided XXX macro.
Usage: [ExportMacro=XXX] can be specified on interfaces. Its currently supported values are: WEBCORE_EXPORT and WEBCORE_TESTSUPPORT_EXPORT.
{{{
[
ExportMacro=WEBCORE_EXPORT
] interface X {
...
};
[
ExportMacro=WEBCORE_TESTSUPPORT_EXPORT
] interface Y {
...
};
}}}