Changeset 200619 in webkit


Ignore:
Timestamp:
May 10, 2016 2:47:44 AM (8 years ago)
Author:
youenn.fablet@crf.canon.fr
Message:

NodeList should be iterable
https://bugs.webkit.org/show_bug.cgi?id=131443
<rdar://problem/25731519>

Reviewed by Darin Adler.

Source/WebCore:

Test: fast/dom/nodeListIterator.html

Updating JSKeyValueIterator to support map and set iterators,
depending on the signature of the result type of DOMClass::Iterator::next method.
Symbol.iterator method is made the same as values method for set iterators.

Adding support for NodeList.
Updating FontFaceSet to take benefit of that.

  • bindings/js/JSDOMBinding.h:

(WebCore::jsPair):.

  • bindings/js/JSKeyValueIterator.h:

(WebCore::IteratorInspector::decltype): IteratorInspector detects whether the iterator is a set or map iterator.
(WebCore::IteratorInspector::test):
(WebCore::fillForEachArgumentsWithIteratorValue): Specializing according set/map iterator.
(WebCore::iteratorValueToJS): Ditto.
(WebCore::keyValueIteratorForEach):
(WebCore::JSKeyValueIterator<JSWrapper>::next):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateImplementationIterableFunctions): Removed the line forbidding set iterators.
Making Symbol.iterator function equal to values for set iterators.

  • bindings/scripts/test/JS/JSTestNode.cpp: Rebasing with set iterator functions.
  • bindings/scripts/test/JS/JSTestObj.cpp: Rebasing according updated function names.
  • bindings/scripts/test/TestNode.idl: Making TestNode set iterable.
  • css/FontFaceSet.cpp:

(WebCore::FontFaceSet::Iterator::next): Refactoring to make it a set iterator.

  • css/FontFaceSet.h:
  • css/FontFaceSet.idl:
  • dom/NodeList.h: Making NodeList iterable.

(WebCore::NodeList::Iterator::Iterator):
(WebCore::NodeList::Iterator::next):
(WebCore::NodeList::createIterator):

  • dom/NodeList.idl:

LayoutTests:

  • fast/dom/domListEnumeration-expected.txt:
  • fast/dom/nodeListIterator-expected.txt: Added.
  • fast/dom/nodeListIterator.html: Added.
  • fast/dom/script-tests/domListEnumeration.js:
  • fast/text/font-face-set-javascript-expected.txt:
  • fast/text/font-face-set-javascript.html:
Location:
trunk
Files:
2 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r200618 r200619  
     12016-05-10  Youenn Fablet  <youenn.fablet@crf.canon.fr>
     2
     3        NodeList should be iterable
     4        https://bugs.webkit.org/show_bug.cgi?id=131443
     5        <rdar://problem/25731519>
     6
     7        Reviewed by Darin Adler.
     8
     9        * fast/dom/domListEnumeration-expected.txt:
     10        * fast/dom/nodeListIterator-expected.txt: Added.
     11        * fast/dom/nodeListIterator.html: Added.
     12        * fast/dom/script-tests/domListEnumeration.js:
     13        * fast/text/font-face-set-javascript-expected.txt:
     14        * fast/text/font-face-set-javascript.html:
     15
    1162016-05-09  Sergio Villar Senin  <svillar@igalia.com>
    217
  • trunk/LayoutTests/fast/dom/domListEnumeration-expected.txt

    r188809 r200619  
    66
    77[object NodeList]
    8 PASS resultArray.length is 11
     8PASS resultArray.length is 15
    99PASS resultArray[0].i is '0'
    1010PASS resultArray[0].item is nodeList.item(0)
  • trunk/LayoutTests/fast/dom/script-tests/domListEnumeration.js

    r188809 r200619  
    9898resultArray = iterateList(nodeList);
    9999
    100 shouldBe("resultArray.length", "11");
     100shouldBe("resultArray.length", "15");
    101101shouldBe("resultArray[0].i", "'0'");
    102102shouldBe("resultArray[0].item", "nodeList.item(0)");
  • trunk/LayoutTests/fast/text/font-face-set-javascript-expected.txt

    r200583 r200619  
    44PASS fontFaceSet.status is "loaded"
    55PASS item.done is false
    6 PASS item.value is [fontFace1, fontFace1]
     6PASS item.value.length is 2
     7FAIL item.value[0] should be 0 (of type number). Was [object FontFace] (of type object).
     8PASS item.value[1] is fontFace1
    79PASS item.done is true
     10PASS item.value is undefined
    811PASS item.done is false
    912PASS item.value is fontFace1
  • trunk/LayoutTests/fast/text/font-face-set-javascript.html

    r199216 r200619  
    2424var item = iterator.next();
    2525shouldBeFalse("item.done");
    26 shouldBe("item.value", "[fontFace1, fontFace1]");
     26shouldBe("item.value.length", "2");
     27shouldBe("item.value[0]", "0");
     28shouldBe("item.value[1]", "fontFace1");
    2729item = iterator.next();
    2830shouldBeTrue("item.done");
     31shouldBe("item.value", "undefined");
    2932
    3033iterator = fontFaceSet.keys();
  • trunk/Source/WebCore/ChangeLog

    r200618 r200619  
     12016-05-10  Youenn Fablet  <youenn.fablet@crf.canon.fr>
     2
     3        NodeList should be iterable
     4        https://bugs.webkit.org/show_bug.cgi?id=131443
     5        <rdar://problem/25731519>
     6
     7        Reviewed by Darin Adler.
     8
     9        Test: fast/dom/nodeListIterator.html
     10
     11        Updating JSKeyValueIterator to support map and set iterators,
     12        depending on the signature of the result type of DOMClass::Iterator::next method.
     13        Symbol.iterator method is made the same as values method for set iterators.
     14
     15        Adding support for NodeList.
     16        Updating FontFaceSet to take benefit of that.
     17
     18        * bindings/js/JSDOMBinding.h:
     19        (WebCore::jsPair):.
     20        * bindings/js/JSKeyValueIterator.h:
     21        (WebCore::IteratorInspector::decltype): IteratorInspector detects whether the iterator is a set or map iterator.
     22        (WebCore::IteratorInspector::test):
     23        (WebCore::fillForEachArgumentsWithIteratorValue): Specializing according set/map iterator.
     24        (WebCore::iteratorValueToJS): Ditto.
     25        (WebCore::keyValueIteratorForEach):
     26        (WebCore::JSKeyValueIterator<JSWrapper>::next):
     27        * bindings/scripts/CodeGeneratorJS.pm:
     28        (GenerateImplementationIterableFunctions): Removed the line forbidding set iterators.
     29        Making Symbol.iterator function equal to values for set iterators.
     30        * bindings/scripts/test/JS/JSTestNode.cpp: Rebasing with set iterator functions.
     31        * bindings/scripts/test/JS/JSTestObj.cpp: Rebasing according updated function names.
     32        * bindings/scripts/test/TestNode.idl: Making TestNode set iterable.
     33        * css/FontFaceSet.cpp:
     34        (WebCore::FontFaceSet::Iterator::next): Refactoring to make it a set iterator.
     35        * css/FontFaceSet.h:
     36        * css/FontFaceSet.idl:
     37        * dom/NodeList.h: Making NodeList iterable.
     38        (WebCore::NodeList::Iterator::Iterator):
     39        (WebCore::NodeList::Iterator::next):
     40        (WebCore::NodeList::createIterator):
     41        * dom/NodeList.idl:
     42
    1432016-05-09  Sergio Villar Senin  <svillar@igalia.com>
    244
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.h

    r200583 r200619  
    267267WEBCORE_EXPORT JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>);
    268268
    269 template<typename Value1, typename Value2> JSC::JSValue jsPair(JSC::ExecState&, JSDOMGlobalObject*, const Value1&, const Value2&);
     269JSC::JSValue jsPair(JSC::ExecState&, JSDOMGlobalObject*, JSC::JSValue, JSC::JSValue);
     270template<typename FirstType, typename SecondType> JSC::JSValue jsPair(JSC::ExecState&, JSDOMGlobalObject*, const FirstType&, const SecondType&);
    270271
    271272RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue);
     
    636637}
    637638
    638 template<typename Value1, typename Value2> inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject* globalObject, const Value1& value1, const Value2& value2)
     639inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::JSValue value1, JSC::JSValue value2)
    639640{
    640641    JSC::MarkedArgumentBuffer args;
    641     args.append(toJS(&state, globalObject, value1));
    642     args.append(toJS(&state, globalObject, value2));
     642    args.append(value1);
     643    args.append(value2);
    643644    return constructArray(&state, 0, globalObject, args);
     645}
     646
     647template<typename FirstType, typename SecondType> inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject* globalObject, const FirstType& value1, const SecondType& value2)
     648{
     649    return jsPair(state, globalObject, toJS(&state, globalObject, value1), toJS(&state, globalObject, value2));
    644650}
    645651
  • trunk/Source/WebCore/bindings/js/JSDOMIterator.h

    r200546 r200619  
    6161};
    6262
     63template<typename IteratorValue>
     64class IteratorInspector {
     65private:
     66    template<typename T> static constexpr auto test(int) -> decltype(std::declval<T>()->key, std::declval<T>()->value, bool()) { return true; }
     67    template<typename T> static constexpr bool test(...) { return false; }
     68public:
     69    static constexpr bool isMap = test<IteratorValue>(0);
     70    static constexpr bool isSet = !isMap;
     71};
     72
    6373enum class IterationKind { Key, Value, KeyValue };
    6474
     
    106116
    107117template<typename JSWrapper>
    108 JSC::EncodedJSValue createKeyValueIterator(JSC::ExecState& state, IterationKind kind, const char* propertyName)
     118JSC::EncodedJSValue iteratorCreate(JSC::ExecState&, IterationKind, const char*);
     119template<typename JSWrapper>
     120JSC::EncodedJSValue iteratorForEach(JSC::ExecState&, const char*);
     121
     122template<typename JSWrapper>
     123JSC::EncodedJSValue iteratorCreate(JSC::ExecState& state, IterationKind kind, const char* propertyName)
    109124{
    110125    auto wrapper = JSC::jsDynamicCast<JSWrapper*>(state.thisValue());
     
    115130}
    116131
    117 template<typename JSWrapper>
    118 JSC::EncodedJSValue keyValueIteratorForEach(JSC::ExecState& state, const char* propertyName)
     132template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isMap, JSC::JSValue>::type
     133toJS(JSC::ExecState& state, JSDOMGlobalObject* globalObject, IteratorValue& value, IterationKind kind)
     134{
     135    ASSERT(value);
     136    if (kind != IterationKind::KeyValue)
     137        return toJS(&state, globalObject, (kind == IterationKind::Key) ? value->key : value->value);
     138
     139    return jsPair(state, globalObject, value->key, value->value);
     140}
     141
     142template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isSet, JSC::JSValue>::type
     143toJS(JSC::ExecState& state, JSDOMGlobalObject* globalObject, IteratorValue& value, IterationKind kind)
     144{
     145    ASSERT(value);
     146    JSC::JSValue result = toJS(&state, globalObject, *value);
     147    if (kind != IterationKind::KeyValue)
     148        return result;
     149
     150    // FIXME: first pair value should be the index of result.
     151    return jsPair(state, globalObject, result, result);
     152}
     153
     154template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isMap, void>::type
     155appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
     156{
     157    ASSERT(value);
     158    arguments.append(toJS(&state, globalObject, value->value));
     159    arguments.append(toJS(&state, globalObject, value->key));
     160}
     161
     162template<typename IteratorValue> typename std::enable_if<IteratorInspector<IteratorValue>::isSet, void>::type
     163appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value)
     164{
     165    ASSERT(value);
     166    JSC::JSValue argument = toJS(&state, globalObject, *value);
     167    arguments.append(argument);
     168    arguments.append(argument);
     169}
     170
     171template<typename JSWrapper>
     172JSC::EncodedJSValue iteratorForEach(JSC::ExecState& state, const char* propertyName)
    119173{
    120174    auto wrapper = JSC::jsDynamicCast<JSWrapper*>(state.thisValue());
     
    130184    while (auto value = iterator.next()) {
    131185        JSC::MarkedArgumentBuffer arguments;
    132         arguments.append(toJS(&state, wrapper->globalObject(), value.value().value));
    133         arguments.append(toJS(&state, wrapper->globalObject(), value.value().key));
     186        appendForEachArguments(state, wrapper->globalObject(), arguments, value);
    134187        arguments.append(wrapper);
    135188        JSC::call(&state, state.argument(0), callType, callData, wrapper, arguments);
     
    153206    if (!iteratorValue)
    154207        return createIteratorResultObject(&state, JSC::jsUndefined(), true);
    155 
    156     JSC::JSValue value;
    157     if (m_kind == IterationKind::Value)
    158         value = toJS(&state, globalObject(), iteratorValue.value().value);
    159     else if (m_kind == IterationKind::Key)
    160         value = toJS(&state, globalObject(), iteratorValue.value().key);
    161     else
    162         value = jsPair(state, globalObject(), iteratorValue.value().key, iteratorValue.value().value);
    163 
    164     return createIteratorResultObject(&state, value, false);
     208    return createIteratorResultObject(&state, toJS(state, globalObject(), iteratorValue, m_kind), false);
    165209}
    166210
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r200607 r200619  
    42094209    my $interface = shift;
    42104210
    4211     if (not $interface->iterable->isKeyValue) {
    4212         die "No support yet for set iterators";
    4213     }
    4214 
    42154211    my $interfaceName = $interface->name;
    42164212    my $className = "JS$interfaceName";
     
    42394235            $iterationKind = "Key" if $propertyName eq "keys";
    42404236            $iterationKind = "Value" if $propertyName eq "values";
     4237            $iterationKind = "Value" if $propertyName eq "[Symbol.Iterator]" and not $interface->iterable->isKeyValue;
    42414238            push(@implContent,  <<END);
    42424239JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState* state)
    42434240{
    4244     return createKeyValueIterator<${className}>(*state, IterationKind::${iterationKind}, "${propertyName}");
     4241    return iteratorCreate<${className}>(*state, IterationKind::${iterationKind}, "${propertyName}");
    42454242}
    42464243
     
    42504247JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState* state)
    42514248{
    4252     return keyValueIteratorForEach<${className}>(*state, "${propertyName}");
     4249    return iteratorForEach<${className}>(*state, "${propertyName}");
    42534250}
    42544251
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp

    r200448 r200619  
    2525#include "JSDOMBinding.h"
    2626#include "JSDOMConstructor.h"
     27#include "JSDOMIterator.h"
    2728#include "URL.h"
    2829#include <runtime/Error.h>
     
    3334
    3435namespace WebCore {
     36
     37// Functions
     38
     39JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionSymbolIterator(JSC::ExecState*);
     40JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionEntries(JSC::ExecState*);
     41JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionKeys(JSC::ExecState*);
     42JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionValues(JSC::ExecState*);
     43JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionForEach(JSC::ExecState*);
    3544
    3645// Attributes
     
    95104    { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestNodeConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestNodeConstructor) } },
    96105    { "name", CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestNodeName), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestNodeName) } },
     106    { "entries", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionEntries), (intptr_t) (0) } },
     107    { "keys", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionKeys), (intptr_t) (0) } },
     108    { "values", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionValues), (intptr_t) (0) } },
     109    { "forEach", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestNodePrototypeFunctionForEach), (intptr_t) (1) } },
    97110};
    98111
     
    103116    Base::finishCreation(vm);
    104117    reifyStaticProperties(vm, JSTestNodePrototypeTableValues, *this);
     118    putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject(), 0, ASCIILiteral("[Symbol.Iterator]"), jsTestNodePrototypeFunctionSymbolIterator), ReadOnly | DontEnum);
    105119}
    106120
     
    179193}
    180194
     195using TestNodeIterator = JSDOMIterator<JSTestNode>;
     196using TestNodeIteratorPrototype = JSDOMIteratorPrototype<JSTestNode>;
     197
     198template<>
     199const JSC::ClassInfo TestNodeIterator::s_info = { "TestNode Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(TestNodeIterator) };
     200
     201template<>
     202const JSC::ClassInfo TestNodeIteratorPrototype::s_info = { "TestNode Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(TestNodeIteratorPrototype) };
     203
     204JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionSymbolIterator(JSC::ExecState* state)
     205{
     206    return iteratorCreate<JSTestNode>(*state, IterationKind::Value, "[Symbol.Iterator]");
     207}
     208
     209JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionEntries(JSC::ExecState* state)
     210{
     211    return iteratorCreate<JSTestNode>(*state, IterationKind::KeyValue, "entries");
     212}
     213
     214JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionKeys(JSC::ExecState* state)
     215{
     216    return iteratorCreate<JSTestNode>(*state, IterationKind::Key, "keys");
     217}
     218
     219JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionValues(JSC::ExecState* state)
     220{
     221    return iteratorCreate<JSTestNode>(*state, IterationKind::Value, "values");
     222}
     223
     224JSC::EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionForEach(JSC::ExecState* state)
     225{
     226    return iteratorForEach<JSTestNode>(*state, "forEach");
     227}
     228
    181229void JSTestNode::visitChildren(JSCell* cell, SlotVisitor& visitor)
    182230{
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp

    r200607 r200619  
    61536153JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionSymbolIterator(JSC::ExecState* state)
    61546154{
    6155     return createKeyValueIterator<JSTestObj>(*state, IterationKind::KeyValue, "[Symbol.Iterator]");
     6155    return iteratorCreate<JSTestObj>(*state, IterationKind::KeyValue, "[Symbol.Iterator]");
    61566156}
    61576157
    61586158JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionEntries(JSC::ExecState* state)
    61596159{
    6160     return createKeyValueIterator<JSTestObj>(*state, IterationKind::KeyValue, "entries");
     6160    return iteratorCreate<JSTestObj>(*state, IterationKind::KeyValue, "entries");
    61616161}
    61626162
    61636163JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionKeys(JSC::ExecState* state)
    61646164{
    6165     return createKeyValueIterator<JSTestObj>(*state, IterationKind::Key, "keys");
     6165    return iteratorCreate<JSTestObj>(*state, IterationKind::Key, "keys");
    61666166}
    61676167
    61686168JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionValues(JSC::ExecState* state)
    61696169{
    6170     return createKeyValueIterator<JSTestObj>(*state, IterationKind::Value, "values");
     6170    return iteratorCreate<JSTestObj>(*state, IterationKind::Value, "values");
    61716171}
    61726172
    61736173JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionForEach(JSC::ExecState* state)
    61746174{
    6175     return keyValueIteratorForEach<JSTestObj>(*state, "forEach");
     6175    return iteratorForEach<JSTestObj>(*state, "forEach");
    61766176}
    61776177
  • trunk/Source/WebCore/bindings/scripts/test/TestNode.idl

    r199264 r200619  
    2424] interface TestNode : Node {
    2525    attribute DOMString name;
     26
     27    iterable<TestNode>;
    2628};
    2729
  • trunk/Source/WebCore/css/FontFaceSet.cpp

    r200546 r200619  
    7777}
    7878
    79 Optional<WTF::KeyValuePair<RefPtr<FontFace>, RefPtr<FontFace>>> FontFaceSet::Iterator::next()
     79RefPtr<FontFace> FontFaceSet::Iterator::next()
    8080{
    8181    if (m_index == m_target->size())
    82         return Nullopt;
    83     RefPtr<FontFace> item = m_target->backing()[m_index++].wrapper();
    84     return WTF::KeyValuePair<RefPtr<FontFace>, RefPtr<FontFace>>(item, item);
     82        return nullptr;
     83    return m_target->backing()[m_index++].wrapper();
    8584}
    8685
  • trunk/Source/WebCore/css/FontFaceSet.h

    r200546 r200619  
    6262    public:
    6363        explicit Iterator(FontFaceSet&);
    64         Optional<WTF::KeyValuePair<RefPtr<FontFace>, RefPtr<FontFace>>> next();
     64        RefPtr<FontFace> next();
    6565
    6666    private:
  • trunk/Source/WebCore/css/FontFaceSet.idl

    r200546 r200619  
    3636
    3737    // FIXME: We should add support for the setlike declaration.
    38     // As a first step this map iterable declaration should be changed to a set iterable.
    39     iterable<FontFace, FontFace>;
     38    iterable<FontFace>;
    4039
    4140    readonly attribute long size;
  • trunk/Source/WebCore/dom/NodeList.h

    r188829 r200619  
    4141    virtual Node* item(unsigned index) const = 0;
    4242
     43    class Iterator {
     44    public:
     45        explicit Iterator(NodeList& list) : m_list(list) { }
     46        Node* next() { return m_list->item(m_index++); }
     47
     48    private:
     49        size_t m_index { 0 };
     50        Ref<NodeList> m_list;
     51    };
     52    Iterator createIterator() { return Iterator(*this); }
     53
    4354    // Other methods (not part of DOM)
    4455    virtual bool isLiveNodeList() const { return false; }
  • trunk/Source/WebCore/dom/NodeList.idl

    r188829 r200619  
    2828    getter Node item(unsigned long index);
    2929    readonly attribute unsigned long length;
     30    iterable<Node>;
    3031};
    3132
Note: See TracChangeset for help on using the changeset viewer.