wiki:WebKitIDL

Version 22 (modified by haraken@chromium.org, 10 years ago) (diff)

--

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. We 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/CPP interfaces is automatically generated.

This page describes practical information about how the IDL binding works and how we 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 the IDL

How the IDL bindings work

JavaScriptCore

V8

ObjC

GObject

CPP

IDL attributes

Basic naming rules

IDL attributes around methods, attributes and parameters

In the following explanations, (i), (m), (a) and (p) means that the 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 DOMString attributes/parameters.

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

    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/parameter, then it is converted to a WebKit null string, for which String::IsEmpty() and String::IsNull() will return true. Without [TreatNullAs=NullString], a JavaScript null is converted to a WebKit string "null".

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

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

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

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

* [TreatReturnedNullStringAs](m,a)

Summary: It controls the behavior when a WebKit null string is returned.

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

    attribute [TreatReturnedNullStringAs=Null] DOMString str;
    [TreatReturnedNullStringAs=Undefined] DOMString func();

[TreatReturnedNullStringAs=Null] indicates that if the returned string is a WebKit null string, the returned value is converted to a JavaScript null.

[TreatReturnedNullStringAs=Undefined] indicates that if the returned string is a WebKit null string, the returned value is converted to a JavaScript undefined.

[TreatReturnedNullStringAs=False] indicates that if the returned string is a WebKit null string, the returned value is converted to a JavaScript false.

Without [TreatReturnedNullStringAs=...], if the returned string is a WebKit null string, the returned value becomes a JavaScript empty string . Note that what should be specified depends on the spec of each attribute or method.

* [Optional](p)

Summary: It allows method overloading for methods whose argument count 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, like this:

    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 must be marked with [Optional=...]. The difference between [Optional] and [Optional=DefaultIsUndefined] is whether your 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 your 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, undefined). Consequently, HTMLFoo::func1(int a, int b, int c, int d) is called in WebCore. 100 is passed to a, 200 is passed to b, 0 is passed to c, and 0 is passed to d. (A JavaScript undefined is converted to 0, following the value conversion rule in the Web IDL spec.) In this way, WebCore needs to implement func2(int a, int b, int c, int d) only, and needs not to implement overloaded methods like func2(int a, int b) or func2(int a, int b, int c).

The difference between [Optional=DefalutIsUndefined] and [Optional=DefaultIsNullString] appears only when the parameter type is DOMString. While in [Optional=DefalutIsUndefined] the "supplemented" JavaScript undefined is converted to a WebKit string "undefined", in [Optional=DefaultIsNullString] the "supplemented" JavaScript undefined is converted to a WebKit null string. Specifically, if JavaScript calls func3(100, 200), then HTMLFoo::func3(int a, int b, String c, String d) is called in WebCore. Here 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.

* [Callback](i,p) FIXME

Summary: ADD SUMMARY

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

    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)

* [CallWith](m,a)

* [CheckAccessToNode](m,a)

* [StrictTypeChecking](m,a) FIXME

Summary: ADD SUMMARY

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

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

ADD EXPLANATIONS

* [ReturnNewObject](m,a)

* [ImplementedAs](m)

Summary: It specifies a method name in WebCore implementation, if the IDL method name and the WebCore method name are different.

Usage: The possible usage is [ImplementedAs=XXX], where XXX is a method name of the WebCore implementation. It can be specified on methods, like this:

    void [ImplementedAs=deleteFunction] delete();

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

* [Reflect](a) FIXME

Summary: ADD SUMMARY

Usage: [Reflect] can be specified on attributes.

    attribute [Reflect] DOMString str;

ADD EXPLANATIONS

* [Replaceable](a)

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

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

Usage: They can be specified on attributes, like this:

    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, it indicates to cache a wrapped object in a DOM object.

Usage: It can be specified on attributes, like this:

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

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

  • HTMLFoo::normalValue() is called.
  • The result is passed to toJS() or toV8(), and is converted to a wrapper object.
  • The wrapper object is returned.

In case where HTMLFoo::normalValue() and wrapping the result is weight, you can cache the wrapped object in the DOM object by using [CachedAttribute]. With [CachedAttribute], the normalValue getter works in the following way:

  • If the wrapper object is cached, the cached wrapper object is returned.
  • Otherwise, HTMLFoo::normalValue() is called.
  • The result is passed to toJS() or toV8(), and is converted to a wrapped object.
  • The wrapped object is cached.
  • The wrapped object is returned.

In particular, [CachedAttribute] will be helpful for serialized values. Without [CachedAttribute], the serializedValue getter works in the following way:

  • HTMLFoo::serializedValue() is called.
  • The result is deserialized.
  • The deserialized result is passed to toJS() or toV8(), and is converted to a wrapped object.
  • The wrapped object is returned.

In case where HTMLFoo::serializedValue(), deserializing and wrapping the result is weight, you can cache the wrapped object to the DOM object by specifying [CachedAttribute]. With [CachedAttribute], the serializedValue getter works in the following way:

  • If the wrapper object is cached, the cached wrapper object is returned.
  • Otherwise, HTMLFoo::serializedValue() is called.
  • The result is deserialized.
  • The deserialized result is passed to toJS() or toV8(), and is converted to a wrapped object.
  • The wrapped object is cached.
  • 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 and setters (Setters always need to invalidate the caches).

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

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

Usage: They can be specified on attributes, like this:

    attribute [V8Unforgeable] DOMString str1;
    attribute [V8OnProto] DOMString str2;

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 the attribute getter/setter or the method should be defined on a DOM object. On the other hand, [V8OnProto] indicates that the attribute getter/setter or the method should be defined on a chain.

Note: As explained above, the current implementation of JSC and V8 is wrong to 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: It indicates that a given DOMString is a URL.

Usage: It can be specified on DOMString attributes, like this:

    attribute [Reflect, V8URL] DOMString url;

You must specify [URL] if the DOMString represents URL, since URL attribute getters are 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)

IDL attributes around interfaces

* [Supplemental](i)

Summary: [Supplemental] helps WebKit modularization. The [Supplemental] IDL 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.

Here is an example. Without [Supplemental], if we want to add XXX's attributes or methods to DOMWindow,

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

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

  • 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 foo;
           void bar();
       };
    
  • WebCore/Modules/XXX/DOMWindowXXX.h
       DOMWindowXXX::foo(...) { ... }   // The C++ implementation of the foo attribute getter.
       DOMWindowXXX::setFoo(...) { ... }   // The C++ implementation of the foo attribute setter.
       DOMWindowXXX::bar(...) { ... }   // The C++ 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, we 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].

* [Constructor](i), [ConstructorCallWith](i), [ConstructorRaisesException](i)

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

* [NamedConstructor](i)

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

* [Conditional](i,m,a)

* [V8EnabledAtRuntime](i,m,a)

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

* [CheckDomainSecurity](i), [DoNotCheckDomainSecurity](m,a), [DoNotCheckDomainSecurityOnGetter](a), [DoNotCheckDomainSecurityOnSetter](a)

* [IndexedGetter](i), [CustomIndexedGetter](i)

* [NamedGetter](i), [NamedCustomGetter](i), [NamedCustomSetter](i)

* [EventTarget](i)

* [DoNotCheckConstants](i)

* [ActiveDOMObject](i), [V8DependentLifeTime](i)

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

* [IsWorkerContext](i)

* [CustomCall](i)

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

* [JSCustomHeader](i)

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

* [JSLegacyParent](i)

* [JSInlineGetOwnPropertySlot](i)

* [JSNoStaticTables](i)

IDL attributes used by ObjC, GObject and CPP bindings only

* [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.

IDL attributes which might be deprecated

* [OmitConstructor], [Immutable], [MasqueradesAsUndefined]

Might be deprecated. Discussion is on-going.

* [CustomGetOwnPropertySlot], [ConstructorParameters], [ReplaceableConstructor], [ExtendsDOMGlobalObject], [IsIndex], [V8DoNotCheckSignature], [NumericIndexedGetter]

Will be deprecated. Discussion is on-going.