DOM4: Add support for rest parameters to DOMTokenList
authorarv@chromium.org <arv@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Sep 2012 18:05:28 +0000 (18:05 +0000)
committerarv@chromium.org <arv@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Sep 2012 18:05:28 +0000 (18:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=97335

Reviewed by Ojan Vafai.

This adds support for rest paramaters to DOMTokenList add and remove.
http://dom.spec.whatwg.org/#domtokenlist

The code generator has been updated to understand variadic methods.
When a method has a rest parameter the remaining arguments are collected
into a WTF::Vector.

DOMTokenList, DOMSettableTokenList and ClassList were restructured a bit to
allow code to be shared better.

Source/WebCore:

Updated existing tests and includes new binding tests.

* bindings/js/JSDOMBinding.h:
(WebCore::toNativeArray):
(WebCore):
(WebCore::toNativeArguments): Similar to toNativeArray but extracts the arguments instead.
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateArgumentsCountCheck): Updated to treat rest paramaters as optional.
(GenerateParametersCheck): Generate code for rest params.
* bindings/scripts/CodeGeneratorV8.pm:
(GenerateFunctionParametersCheck): Updated to treat rest paramaters as optional.
(GenerateArgumentsCountCheck): Ditto.
(GenerateParametersCheck):  Generate code for rest params.
* bindings/scripts/IDLParser.pm:
(parseOptionalOrRequiredArgument):
* bindings/scripts/IDLStructure.pm:
* bindings/scripts/test/CPP/WebDOMTestObj.cpp:
(WebDOMTestObj::variadicStringMethod):
(WebDOMTestObj::variadicDoubleMethod):
(WebDOMTestObj::variadicNodeMethod):
* bindings/scripts/test/CPP/WebDOMTestObj.h:
* bindings/scripts/test/GObject/WebKitDOMTestObj.cpp:
(webkit_dom_test_obj_variadic_string_method):
(webkit_dom_test_obj_variadic_double_method):
(webkit_dom_test_obj_variadic_node_method):
* bindings/scripts/test/GObject/WebKitDOMTestObj.h:
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore):
(WebCore::jsTestObjPrototypeFunctionVariadicStringMethod):
(WebCore::jsTestObjPrototypeFunctionVariadicDoubleMethod):
(WebCore::jsTestObjPrototypeFunctionVariadicNodeMethod):
* bindings/scripts/test/JS/JSTestObj.h:
(WebCore):
* bindings/scripts/test/ObjC/DOMTestObj.h:
* bindings/scripts/test/ObjC/DOMTestObj.mm:
(-[DOMTestObj variadicStringMethod:tail:]):
(-[DOMTestObj variadicDoubleMethod:tail:]):
(-[DOMTestObj variadicNodeMethod:tail:]):
* bindings/scripts/test/TestObj.idl:
* bindings/scripts/test/V8/V8TestObj.cpp:
(WebCore::TestObjV8Internal::variadicStringMethodCallback):
(TestObjV8Internal):
(WebCore::TestObjV8Internal::variadicDoubleMethodCallback):
(WebCore::TestObjV8Internal::variadicNodeMethodCallback):
(WebCore):
(WebCore::ConfigureV8TestObjTemplate):
* bindings/v8/V8Binding.h:
(WebCore::toNativeArray):
(WebCore):
(WebCore::toNativeArguments): Similar to toNativeArray but extracts the arguments instead.
* html/ClassList.cpp:
(WebCore::ClassList::ClassList):
* html/ClassList.h:
(WebCore):
(ClassList):
* html/DOMSettableTokenList.cpp:
(WebCore::DOMSettableTokenList::containsInternal):
(WebCore::DOMSettableTokenList::add):
(WebCore::DOMSettableTokenList::addInternal):
(WebCore::DOMSettableTokenList::remove):
(WebCore::DOMSettableTokenList::removeInternal):
(WebCore::DOMSettableTokenList::setValue):
* html/DOMSettableTokenList.h:
(DOMSettableTokenList):
* html/DOMTokenList.cpp:
(WebCore::DOMTokenList::validateTokens):
(WebCore):
(WebCore::DOMTokenList::contains): Moved implementation to base class to allow code sharing.
(WebCore::DOMTokenList::add): Ditto.
(WebCore::DOMTokenList::remove): Ditto.
(WebCore::DOMTokenList::toggle): Ditto.
(WebCore::DOMTokenList::addInternal): Ditto.
(WebCore::DOMTokenList::removeInternal): Ditto.
(WebCore::DOMTokenList::addToken): Ditto.
(WebCore::DOMTokenList::addTokens):
(WebCore::DOMTokenList::removeToken): Ditto.
(WebCore::DOMTokenList::removeTokens):
* html/DOMTokenList.h:
(DOMTokenList):
(WebCore::DOMTokenList::toString):
* html/DOMTokenList.idl:

LayoutTests:

* fast/dom/HTMLElement/class-list-expected.txt:
* fast/dom/HTMLElement/class-list-quirks-expected.txt:
* fast/dom/HTMLElement/script-tests/class-list.js:
(element.classList.add):
(createElement):
(shouldBeEqualToString):
(element.classList.remove):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@129779 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/HTMLElement/class-list-expected.txt
LayoutTests/fast/dom/HTMLElement/class-list-quirks-expected.txt
LayoutTests/fast/dom/HTMLElement/script-tests/class-list.js
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/CodeGeneratorV8.pm
Source/WebCore/bindings/scripts/IDLParser.pm
Source/WebCore/bindings/scripts/IDLStructure.pm
Source/WebCore/bindings/scripts/test/CPP/WebDOMTestObj.cpp
Source/WebCore/bindings/scripts/test/CPP/WebDOMTestObj.h
Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestObj.cpp
Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestObj.h
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.h
Source/WebCore/bindings/scripts/test/ObjC/DOMTestObj.h
Source/WebCore/bindings/scripts/test/ObjC/DOMTestObj.mm
Source/WebCore/bindings/scripts/test/TestObj.idl
Source/WebCore/bindings/scripts/test/V8/V8TestObj.cpp
Source/WebCore/bindings/v8/V8Binding.h
Source/WebCore/html/ClassList.cpp
Source/WebCore/html/ClassList.h
Source/WebCore/html/DOMSettableTokenList.cpp
Source/WebCore/html/DOMSettableTokenList.h
Source/WebCore/html/DOMTokenList.cpp
Source/WebCore/html/DOMTokenList.h
Source/WebCore/html/DOMTokenList.idl

index dc10a86..338e2ff 100644 (file)
@@ -1,3 +1,28 @@
+2012-09-27  Erik Arvidsson  <arv@chromium.org>
+
+        DOM4: Add support for rest parameters to DOMTokenList
+        https://bugs.webkit.org/show_bug.cgi?id=97335
+
+        Reviewed by Ojan Vafai.
+
+        This adds support for rest paramaters to DOMTokenList add and remove.
+        http://dom.spec.whatwg.org/#domtokenlist
+
+        The code generator has been updated to understand variadic methods.
+        When a method has a rest parameter the remaining arguments are collected
+        into a WTF::Vector.
+
+        DOMTokenList, DOMSettableTokenList and ClassList were restructured a bit to
+        allow code to be shared better.
+
+        * fast/dom/HTMLElement/class-list-expected.txt:
+        * fast/dom/HTMLElement/class-list-quirks-expected.txt:
+        * fast/dom/HTMLElement/script-tests/class-list.js:
+        (element.classList.add):
+        (createElement):
+        (shouldBeEqualToString):
+        (element.classList.remove):
+
 2012-09-27  Peter Beverloo  <peter@chromium.org>
 
         [Chromium] Rebaseline more test directories for Android.
index 7164d4b..e41dd88 100644 (file)
@@ -31,10 +31,8 @@ PASS element.classList.contains('') threw expected DOMException with code 12
 PASS element.classList.contains('x y') threw expected DOMException with code 5
 PASS element.classList.add('') threw expected DOMException with code 12
 PASS element.classList.add('x y') threw expected DOMException with code 5
-PASS element.classList.add() threw exception TypeError: Not enough arguments.
 PASS element.classList.remove('') threw expected DOMException with code 12
 PASS element.classList.remove('x y') threw expected DOMException with code 5
-PASS element.classList.remove() threw exception TypeError: Not enough arguments.
 PASS element.classList.toggle('') threw expected DOMException with code 12
 PASS element.classList.toggle('x y') threw expected DOMException with code 5
 PASS element.classList.toggle() threw exception TypeError: Not enough arguments.
@@ -74,6 +72,26 @@ PASS element.classList.constructor is DOMTokenList
 PASS element.classList === element.classList is true
 PASS document.body.classList.contains("FAIL") is true
 PASS document.body.className is ""
+Variadic calls
+PASS element.className is "a b"
+PASS element.className is "a b c"
+PASS element.className is "a b c null d undefined 0 false"
+PASS element.className is "a b a"
+PASS element.classList.add('a', 'b', '') threw expected DOMException with code 12
+PASS element.className is ""
+PASS element.classList.add('a', 'b', 'c d') threw expected DOMException with code 5
+PASS element.className is ""
+PASS element.classList.add() did not throw exception.
+PASS observer.takeRecords().length is 1
+PASS element.className is "b d  "
+PASS element.className is "d  "
+PASS element.className is "a b c"
+PASS element.classList.remove('a', 'b', '') threw expected DOMException with code 12
+PASS element.className is "a b"
+PASS element.classList.remove('a', 'b', 'c d') threw expected DOMException with code 5
+PASS element.className is "a b"
+PASS element.classList.remove() did not throw exception.
+PASS observer.takeRecords().length is 1
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 7164d4b..e41dd88 100644 (file)
@@ -31,10 +31,8 @@ PASS element.classList.contains('') threw expected DOMException with code 12
 PASS element.classList.contains('x y') threw expected DOMException with code 5
 PASS element.classList.add('') threw expected DOMException with code 12
 PASS element.classList.add('x y') threw expected DOMException with code 5
-PASS element.classList.add() threw exception TypeError: Not enough arguments.
 PASS element.classList.remove('') threw expected DOMException with code 12
 PASS element.classList.remove('x y') threw expected DOMException with code 5
-PASS element.classList.remove() threw exception TypeError: Not enough arguments.
 PASS element.classList.toggle('') threw expected DOMException with code 12
 PASS element.classList.toggle('x y') threw expected DOMException with code 5
 PASS element.classList.toggle() threw exception TypeError: Not enough arguments.
@@ -74,6 +72,26 @@ PASS element.classList.constructor is DOMTokenList
 PASS element.classList === element.classList is true
 PASS document.body.classList.contains("FAIL") is true
 PASS document.body.className is ""
+Variadic calls
+PASS element.className is "a b"
+PASS element.className is "a b c"
+PASS element.className is "a b c null d undefined 0 false"
+PASS element.className is "a b a"
+PASS element.classList.add('a', 'b', '') threw expected DOMException with code 12
+PASS element.className is ""
+PASS element.classList.add('a', 'b', 'c d') threw expected DOMException with code 5
+PASS element.className is ""
+PASS element.classList.add() did not throw exception.
+PASS observer.takeRecords().length is 1
+PASS element.className is "b d  "
+PASS element.className is "d  "
+PASS element.className is "a b c"
+PASS element.classList.remove('a', 'b', '') threw expected DOMException with code 12
+PASS element.className is "a b"
+PASS element.classList.remove('a', 'b', 'c d') threw expected DOMException with code 5
+PASS element.className is "a b"
+PASS element.classList.remove() did not throw exception.
+PASS observer.takeRecords().length is 1
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 32190bb..4ef2a5c 100644 (file)
@@ -154,9 +154,6 @@ shouldThrowDOMException(function() {
 }, DOMException.INVALID_CHARACTER_ERR);
 
 createElement('');
-shouldThrow("element.classList.add()");
-
-createElement('');
 shouldThrowDOMException(function() {
     element.classList.remove('');
 }, DOMException.SYNTAX_ERR);
@@ -166,8 +163,7 @@ shouldThrowDOMException(function() {
     element.classList.remove('x y');
 }, DOMException.INVALID_CHARACTER_ERR);
 
-createElement('');
-shouldThrow("element.classList.remove()");
+
 
 createElement('');
 shouldThrowDOMException(function() {
@@ -265,3 +261,72 @@ document.body.classList.add('FAIL');
 shouldBeTrue('document.body.classList.contains("FAIL")');
 document.body.classList.remove('FAIL');
 shouldBeEqualToString('document.body.className', '');
+
+// Variadic
+
+debug('Variadic calls');
+
+createElement('');
+element.classList.add('a', 'b');
+shouldBeEqualToString('element.className', 'a b');
+
+element.classList.add('a', 'b', 'c');
+shouldBeEqualToString('element.className', 'a b c');
+
+element.classList.add(null, {toString: function() { return 'd' }}, undefined, 0, false);
+shouldBeEqualToString('element.className', 'a b c null d undefined 0 false');
+
+createElement('');
+element.classList.add('a', 'b', 'a');
+shouldBeEqualToString('element.className', 'a b a');
+
+createElement('');
+shouldThrowDOMException(function() {
+    element.classList.add('a', 'b', '');
+}, DOMException.SYNTAX_ERR);
+shouldBeEqualToString('element.className', '');
+
+shouldThrowDOMException(function() {
+    element.classList.add('a', 'b', 'c d');
+}, DOMException.INVALID_CHARACTER_ERR);
+shouldBeEqualToString('element.className', '');
+
+createElement('');
+shouldNotThrow('element.classList.add()');
+
+createElement('');
+var observer = new WebKitMutationObserver(function() {});
+observer.observe(element, {attributes: true});
+element.classList.add('a', 'c');
+shouldBe('observer.takeRecords().length', '1');
+
+
+createElement('a b c d  ');
+element.classList.remove('a', 'c');
+shouldBeEqualToString('element.className', 'b d  ');
+
+element.classList.remove('b', 'b');
+shouldBeEqualToString('element.className', 'd  ');
+
+createElement('a b c null d undefined 0 false');
+element.classList.remove(null, {toString: function() { return 'd' }}, undefined, 0, false);
+shouldBeEqualToString('element.className', 'a b c');
+
+createElement('a b');
+shouldThrowDOMException(function() {
+    element.classList.remove('a', 'b', '');
+}, DOMException.SYNTAX_ERR);
+shouldBeEqualToString('element.className', 'a b');
+
+shouldThrowDOMException(function() {
+    element.classList.remove('a', 'b', 'c d');
+}, DOMException.INVALID_CHARACTER_ERR);
+shouldBeEqualToString('element.className', 'a b');
+
+shouldNotThrow('element.classList.remove()');
+
+createElement('a b c');
+observer = new WebKitMutationObserver(function() {});
+observer.observe(element, {attributes: true});
+element.classList.remove('a', 'c');
+shouldBe('observer.takeRecords().length', '1');
index faecebd..612b623 100644 (file)
@@ -1,3 +1,102 @@
+2012-09-27  Erik Arvidsson  <arv@chromium.org>
+
+        DOM4: Add support for rest parameters to DOMTokenList
+        https://bugs.webkit.org/show_bug.cgi?id=97335
+
+        Reviewed by Ojan Vafai.
+
+        This adds support for rest paramaters to DOMTokenList add and remove.
+        http://dom.spec.whatwg.org/#domtokenlist
+
+        The code generator has been updated to understand variadic methods.
+        When a method has a rest parameter the remaining arguments are collected
+        into a WTF::Vector.
+
+        DOMTokenList, DOMSettableTokenList and ClassList were restructured a bit to
+        allow code to be shared better.
+
+        Updated existing tests and includes new binding tests.
+
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::toNativeArray):
+        (WebCore):
+        (WebCore::toNativeArguments): Similar to toNativeArray but extracts the arguments instead.
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateArgumentsCountCheck): Updated to treat rest paramaters as optional.
+        (GenerateParametersCheck): Generate code for rest params.
+        * bindings/scripts/CodeGeneratorV8.pm:
+        (GenerateFunctionParametersCheck): Updated to treat rest paramaters as optional.
+        (GenerateArgumentsCountCheck): Ditto.
+        (GenerateParametersCheck):  Generate code for rest params.
+        * bindings/scripts/IDLParser.pm:
+        (parseOptionalOrRequiredArgument):
+        * bindings/scripts/IDLStructure.pm:
+        * bindings/scripts/test/CPP/WebDOMTestObj.cpp:
+        (WebDOMTestObj::variadicStringMethod):
+        (WebDOMTestObj::variadicDoubleMethod):
+        (WebDOMTestObj::variadicNodeMethod):
+        * bindings/scripts/test/CPP/WebDOMTestObj.h:
+        * bindings/scripts/test/GObject/WebKitDOMTestObj.cpp:
+        (webkit_dom_test_obj_variadic_string_method):
+        (webkit_dom_test_obj_variadic_double_method):
+        (webkit_dom_test_obj_variadic_node_method):
+        * bindings/scripts/test/GObject/WebKitDOMTestObj.h:
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore):
+        (WebCore::jsTestObjPrototypeFunctionVariadicStringMethod):
+        (WebCore::jsTestObjPrototypeFunctionVariadicDoubleMethod):
+        (WebCore::jsTestObjPrototypeFunctionVariadicNodeMethod):
+        * bindings/scripts/test/JS/JSTestObj.h:
+        (WebCore):
+        * bindings/scripts/test/ObjC/DOMTestObj.h:
+        * bindings/scripts/test/ObjC/DOMTestObj.mm:
+        (-[DOMTestObj variadicStringMethod:tail:]):
+        (-[DOMTestObj variadicDoubleMethod:tail:]):
+        (-[DOMTestObj variadicNodeMethod:tail:]):
+        * bindings/scripts/test/TestObj.idl:
+        * bindings/scripts/test/V8/V8TestObj.cpp:
+        (WebCore::TestObjV8Internal::variadicStringMethodCallback):
+        (TestObjV8Internal):
+        (WebCore::TestObjV8Internal::variadicDoubleMethodCallback):
+        (WebCore::TestObjV8Internal::variadicNodeMethodCallback):
+        (WebCore):
+        (WebCore::ConfigureV8TestObjTemplate):
+        * bindings/v8/V8Binding.h:
+        (WebCore::toNativeArray):
+        (WebCore):
+        (WebCore::toNativeArguments): Similar to toNativeArray but extracts the arguments instead.
+        * html/ClassList.cpp:
+        (WebCore::ClassList::ClassList):
+        * html/ClassList.h:
+        (WebCore):
+        (ClassList):
+        * html/DOMSettableTokenList.cpp:
+        (WebCore::DOMSettableTokenList::containsInternal):
+        (WebCore::DOMSettableTokenList::add):
+        (WebCore::DOMSettableTokenList::addInternal):
+        (WebCore::DOMSettableTokenList::remove):
+        (WebCore::DOMSettableTokenList::removeInternal):
+        (WebCore::DOMSettableTokenList::setValue):
+        * html/DOMSettableTokenList.h:
+        (DOMSettableTokenList):
+        * html/DOMTokenList.cpp:
+        (WebCore::DOMTokenList::validateTokens):
+        (WebCore):
+        (WebCore::DOMTokenList::contains): Moved implementation to base class to allow code sharing.
+        (WebCore::DOMTokenList::add): Ditto.
+        (WebCore::DOMTokenList::remove): Ditto.
+        (WebCore::DOMTokenList::toggle): Ditto.
+        (WebCore::DOMTokenList::addInternal): Ditto.
+        (WebCore::DOMTokenList::removeInternal): Ditto.
+        (WebCore::DOMTokenList::addToken): Ditto.
+        (WebCore::DOMTokenList::addTokens):
+        (WebCore::DOMTokenList::removeToken): Ditto.
+        (WebCore::DOMTokenList::removeTokens):
+        * html/DOMTokenList.h:
+        (DOMTokenList):
+        (WebCore::DOMTokenList::toString):
+        * html/DOMTokenList.idl:
+
 2012-09-27  Andreas Kling  <kling@webkit.org>
 
         332kB below DocumentEventQueue::create() on Membuster3.
index 7532b79..1efa4b3 100644 (file)
@@ -353,7 +353,7 @@ enum ParameterDefaultPolicy {
 
     template<>
     struct NativeValueTraits<String> {
-        static inline bool arrayNativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue)
+        static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue)
         {
             indexedValue = jsValue.toString(exec)->value(exec);
             return true;
@@ -362,7 +362,7 @@ enum ParameterDefaultPolicy {
 
     template<>
     struct NativeValueTraits<unsigned long> {
-        static inline bool arrayNativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned long& indexedValue)
+        static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned long& indexedValue)
         {
             if (!jsValue.isNumber())
                 return false;
@@ -377,7 +377,7 @@ enum ParameterDefaultPolicy {
 
     template<>
     struct NativeValueTraits<float> {
-        static inline bool arrayNativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue)
+        static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue)
         {
             indexedValue = jsValue.toFloat(exec);
             return !exec->hadException();
@@ -400,7 +400,25 @@ enum ParameterDefaultPolicy {
 
         for (unsigned i = 0; i < length; ++i) {
             T indexValue;
-            if (!TraitsType::arrayNativeValue(exec, object->get(exec, i), indexValue))
+            if (!TraitsType::nativeValue(exec, object->get(exec, i), indexValue))
+                return Vector<T>();
+            result.append(indexValue);
+        }
+        return result;
+    }
+
+    template <class T>
+    Vector<T> toNativeArguments(JSC::ExecState* exec, size_t startIndex = 0)
+    {
+        size_t length = exec->argumentCount();
+        ASSERT(startIndex <= length);
+
+        Vector<T> result;
+        typedef NativeValueTraits<T> TraitsType;
+
+        for (size_t i = startIndex; i < length; ++i) {
+            T indexValue;
+            if (!TraitsType::nativeValue(exec, exec->argument(i), indexValue))
                 return Vector<T>();
             result.append(indexValue);
         }
index 65914b5..e2e2697 100644 (file)
@@ -1308,6 +1308,7 @@ sub GenerateFunctionParametersCheck
     my @orExpression = ();
     my $numParameters = 0;
     my @neededArguments = ();
+    my $hasVariadic = 0;
     my $numMandatoryParams = @{$function->parameters};
 
     foreach my $parameter (@{$function->parameters}) {
@@ -1317,11 +1318,17 @@ sub GenerateFunctionParametersCheck
             push(@neededArguments, @usedArguments);
             $numMandatoryParams--;
         }
+        if ($parameter->isVariadic) {
+            $hasVariadic = 1;
+            last;
+        }
         $numParameters++;
     }
-    my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
-    push(@orExpression, $expression);
-    push(@neededArguments, @usedArguments);
+    if (!$hasVariadic) {
+        my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
+        push(@orExpression, $expression);
+        push(@neededArguments, @usedArguments);
+    }
     return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments);
 }
 
@@ -2604,7 +2611,7 @@ sub GenerateArgumentsCountCheck
 
     my $numMandatoryParams = @{$function->parameters};
     foreach my $param (reverse(@{$function->parameters})) {
-        if ($param->extendedAttributes->{"Optional"}) {
+        if ($param->extendedAttributes->{"Optional"} or $param->isVariadic) {
             $numMandatoryParams--;
         } else {
             last;
@@ -2707,13 +2714,38 @@ sub GenerateParametersCheck
                 push(@$outputArray, "    RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
             }
         } elsif ($parameter->extendedAttributes->{"Clamp"}) {
-                my $nativeValue = "${name}NativeValue";
-                push(@$outputArray, "    $argType $name = 0;\n");
-                push(@$outputArray, "    double $nativeValue = exec->argument($argsIndex).toNumber(exec);\n");
+            my $nativeValue = "${name}NativeValue";
+            push(@$outputArray, "    $argType $name = 0;\n");
+            push(@$outputArray, "    double $nativeValue = exec->argument($argsIndex).toNumber(exec);\n");
+            push(@$outputArray, "    if (exec->hadException())\n");
+            push(@$outputArray, "        return JSValue::encode(jsUndefined());\n\n");
+            push(@$outputArray, "    if (!isnan($nativeValue))\n");
+            push(@$outputArray, "        $name = clampTo<$argType>($nativeValue);\n\n");
+        } elsif ($parameter->isVariadic) {
+            my $nativeElementType;
+            if ($argType eq "DOMString") {
+                $nativeElementType = "String";
+            } else {
+                $nativeElementType = GetNativeType($argType);
+                if ($nativeElementType =~ />$/) {
+                    $nativeElementType .= " ";
+                }
+            }
+
+            if (!IsNativeType($argType)) {
+                push(@$outputArray, "    Vector<$nativeElementType> $name;\n");
+                push(@$outputArray, "    for (unsigned i = $argsIndex; i < exec->argumentCount(); ++i) {\n");
+                push(@$outputArray, "        if (!exec->argument(i).inherits(&JS${argType}::s_info))\n");
+                push(@$outputArray, "            return throwVMTypeError(exec);\n");
+                push(@$outputArray, "        $name.append(to$argType(exec->argument(i)));\n");
+                push(@$outputArray, "    }\n")
+            } else {
+                push(@$outputArray, "    Vector<$nativeElementType> $name = toNativeArguments<$nativeElementType>(exec, $argsIndex);\n");
+                # Check if the type conversion succeeded.
                 push(@$outputArray, "    if (exec->hadException())\n");
-                push(@$outputArray, "        return JSValue::encode(jsUndefined());\n\n");
-                push(@$outputArray, "    if (!isnan($nativeValue))\n");
-                push(@$outputArray, "        $name = clampTo<$argType>($nativeValue);\n\n");
+                push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
+            }
+
         } else {
             # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
             # interface type, then if the incoming value does not implement that interface, a TypeError
index 86d3eb6..8803444 100644 (file)
@@ -1405,15 +1405,22 @@ sub GenerateFunctionParametersCheck
 
     my @orExpression = ();
     my $numParameters = 0;
+    my $hasVariadic = 0;
     my $numMandatoryParams = @{$function->parameters};
     foreach my $parameter (@{$function->parameters}) {
         if ($parameter->extendedAttributes->{"Optional"}) {
             push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
             $numMandatoryParams--;
         }
+        if ($parameter->isVariadic) {
+            $hasVariadic = 1;
+            last;
+        }
         $numParameters++;
     }
-    push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
+    if (!$hasVariadic) {
+        push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
+    }
     return ($numMandatoryParams, join(" || ", @orExpression));
 }
 
@@ -1624,12 +1631,12 @@ sub GenerateArgumentsCountCheck
     my $dataNode = shift;
 
     my $numMandatoryParams = 0;
-    my $optionalSeen = 0;
+    my $allowNonOptional = 1;
     foreach my $param (@{$function->parameters}) {
-        if ($param->extendedAttributes->{"Optional"}) {
-            $optionalSeen = 1;
+        if ($param->extendedAttributes->{"Optional"} or $param->isVariadic) {
+            $allowNonOptional = 0;
         } else {
-            die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if $optionalSeen;
+            die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if !$allowNonOptional;
             $numMandatoryParams++;
         }
     }
@@ -1760,6 +1767,23 @@ sub GenerateParametersCheck
             $parameterCheckString .= "        ec = TYPE_MISMATCH_ERR;\n";
             $parameterCheckString .= "        goto fail;\n";
             $parameterCheckString .= "    }\n";
+        } elsif ($parameter->isVariadic) {
+            my $nativeElementType = GetNativeType($parameter->type);
+            if ($nativeElementType =~ />$/) {
+                $nativeElementType .= " ";
+            }
+
+            my $argType = GetTypeFromSignature($parameter);
+            if (IsWrapperType($argType)) {
+                $parameterCheckString .= "    Vector<$nativeElementType> $parameterName;\n";
+                $parameterCheckString .= "    for (int i = $paramIndex; i < args.Length(); ++i) {\n";
+                $parameterCheckString .= "        if (!V8${argType}::HasInstance(args[i]))\n";
+                $parameterCheckString .= "            return throwTypeError(0, args.GetIsolate());\n";
+                $parameterCheckString .= "        $parameterName.append(V8${argType}::toNative(v8::Handle<v8::Object>::Cast(args[i])));\n";
+                $parameterCheckString .= "    }\n";
+            } else {
+                $parameterCheckString .= "    EXCEPTION_BLOCK(Vector<$nativeElementType>, $parameterName, toNativeArguments<$nativeElementType>(args, $paramIndex));\n";
+            }
         } elsif ($nativeType =~ /^V8Parameter/) {
             my $value = JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()");
             $parameterCheckString .= "    " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n";
index bb8a0f0..19fb649 100644 (file)
@@ -1246,7 +1246,7 @@ sub parseOptionalOrRequiredArgument
         # Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
         $type =~ s/\?//g;
         $paramDataNode->type($type);
-        $self->parseEllipsis();
+        $paramDataNode->isVariadic($self->parseEllipsis());
         $paramDataNode->name($self->parseArgumentName());
         return $paramDataNode;
     }
index 1eb8a14..ff62872 100644 (file)
@@ -67,7 +67,8 @@ struct( domSignature => {
     name => '$',      # Variable name
     type => '$',      # Variable type
     extendedAttributes => '$', # Extended attributes
-    isNullable => '$' # Is variable type Nullable (T?)
+    isNullable => '$', # Is variable type Nullable (T?)
+    isVariadic => '$' # Is variable variadic (long... numbers)
 });
 
 # Used to represent string constants
index 53181d4..8b185e5 100644 (file)
 #include "HTMLNames.h"
 #include "IDBKey.h"
 #include "KURL.h"
+#include "Node.h"
 #include "SVGPoint.h"
 #include "SerializedScriptValue.h"
 #include "TestObj.h"
 #include "WebDOMDictionary.h"
 #include "WebDOMDocument.h"
 #include "WebDOMIDBKey.h"
+#include "WebDOMNode.h"
 #include "WebDOMSVGPoint.h"
 #include "WebDOMString.h"
 #include "WebDOMa.h"
@@ -965,6 +967,30 @@ WebDOMbool WebDOMTestObj::strictFunction(const WebDOMString& str, float a, int b
     return result;
 }
 
+void WebDOMTestObj::variadicStringMethod(const WebDOMString& head, const WebDOMString& tail)
+{
+    if (!impl())
+        return;
+
+    impl()->variadicStringMethod(head, tail);
+}
+
+void WebDOMTestObj::variadicDoubleMethod(double head, double tail)
+{
+    if (!impl())
+        return;
+
+    impl()->variadicDoubleMethod(head, tail);
+}
+
+void WebDOMTestObj::variadicNodeMethod(const WebDOMNode& head, const WebDOMNode& tail)
+{
+    if (!impl())
+        return;
+
+    impl()->variadicNodeMethod(toWebCore(head), toWebCore(tail));
+}
+
 WebCore::TestObj* toWebCore(const WebDOMTestObj& wrapper)
 {
     return wrapper.impl();
index 5d9a9ac..31c838b 100644 (file)
@@ -34,6 +34,7 @@ class WebDOMDictionary;
 class WebDOMDocument;
 class WebDOMEventListener;
 class WebDOMIDBKey;
+class WebDOMNode;
 class WebDOMSVGPoint;
 class WebDOMString;
 class WebDOMTestObj;
@@ -190,6 +191,9 @@ public:
     WebDOMSVGPoint immutablePointFunction();
     void banana();
     WebDOMbool strictFunction(const WebDOMString& str, float a, int b);
+    void variadicStringMethod(const WebDOMString& head, const WebDOMString& tail);
+    void variadicDoubleMethod(double head, double tail);
+    void variadicNodeMethod(const WebDOMNode& head, const WebDOMNode& tail);
 
     WebCore::TestObj* impl() const;
 
index 2d03dae..c1264bd 100644 (file)
@@ -38,6 +38,8 @@
 #include "webkit/WebKitDOMDocumentPrivate.h"
 #include "webkit/WebKitDOMIDBKey.h"
 #include "webkit/WebKitDOMIDBKeyPrivate.h"
+#include "webkit/WebKitDOMNode.h"
+#include "webkit/WebKitDOMNodePrivate.h"
 #include "webkit/WebKitDOMSVGPoint.h"
 #include "webkit/WebKitDOMSVGPointPrivate.h"
 #include "webkit/WebKitDOMSerializedScriptValue.h"
@@ -1454,6 +1456,49 @@ webkit_dom_test_obj_strict_function(WebKitDOMTestObj* self, const gchar* str, gf
     return result;
 }
 
+void
+webkit_dom_test_obj_variadic_string_method(WebKitDOMTestObj* self, const gchar* head, const gchar* tail)
+{
+    g_return_if_fail(self);
+    WebCore::JSMainThreadNullState state;
+    WebCore::TestObj* item = WebKit::core(self);
+    g_return_if_fail(head);
+    g_return_if_fail(tail);
+    WTF::String convertedHead = WTF::String::fromUTF8(head);
+    WTF::String convertedTail = WTF::String::fromUTF8(tail);
+    item->variadicStringMethod(convertedHead, convertedTail);
+}
+
+void
+webkit_dom_test_obj_variadic_double_method(WebKitDOMTestObj* self, gdouble head, gdouble tail)
+{
+    g_return_if_fail(self);
+    WebCore::JSMainThreadNullState state;
+    WebCore::TestObj* item = WebKit::core(self);
+    item->variadicDoubleMethod(head, tail);
+}
+
+void
+webkit_dom_test_obj_variadic_node_method(WebKitDOMTestObj* self, WebKitDOMNode* head, WebKitDOMNode* tail)
+{
+    g_return_if_fail(self);
+    WebCore::JSMainThreadNullState state;
+    WebCore::TestObj* item = WebKit::core(self);
+    g_return_if_fail(head);
+    g_return_if_fail(tail);
+    WebCore::Node* convertedHead = 0;
+    if (head) {
+        convertedHead = WebKit::core(head);
+        g_return_if_fail(convertedHead);
+    }
+    WebCore::Node* convertedTail = 0;
+    if (tail) {
+        convertedTail = WebKit::core(tail);
+        g_return_if_fail(convertedTail);
+    }
+    item->variadicNodeMethod(convertedHead, convertedTail);
+}
+
 glong
 webkit_dom_test_obj_get_read_only_long_attr(WebKitDOMTestObj* self)
 {
index 9d905ad..176d5b0 100644 (file)
@@ -486,6 +486,42 @@ WEBKIT_API WebKitDOMbool*
 webkit_dom_test_obj_strict_function(WebKitDOMTestObj* self, const gchar* str, gfloat a, glong b, GError** error);
 
 /**
+ * webkit_dom_test_obj_variadic_string_method:
+ * @self: A #WebKitDOMTestObj
+ * @head: A #gchar
+ * @tail: A #gchar
+ *
+ * Returns:
+ *
+**/
+WEBKIT_API void
+webkit_dom_test_obj_variadic_string_method(WebKitDOMTestObj* self, const gchar* head, const gchar* tail);
+
+/**
+ * webkit_dom_test_obj_variadic_double_method:
+ * @self: A #WebKitDOMTestObj
+ * @head: A #gdouble
+ * @tail: A #gdouble
+ *
+ * Returns:
+ *
+**/
+WEBKIT_API void
+webkit_dom_test_obj_variadic_double_method(WebKitDOMTestObj* self, gdouble head, gdouble tail);
+
+/**
+ * webkit_dom_test_obj_variadic_node_method:
+ * @self: A #WebKitDOMTestObj
+ * @head: A #WebKitDOMNode
+ * @tail: A #WebKitDOMNode
+ *
+ * Returns:
+ *
+**/
+WEBKIT_API void
+webkit_dom_test_obj_variadic_node_method(WebKitDOMTestObj* self, WebKitDOMNode* head, WebKitDOMNode* tail);
+
+/**
  * webkit_dom_test_obj_get_read_only_long_attr:
  * @self: A #WebKitDOMTestObj
  *
index 77d4044..adca129 100644 (file)
@@ -33,6 +33,7 @@
 #include "JSDocument.h"
 #include "JSEventListener.h"
 #include "JSFloat32Array.h"
+#include "JSNode.h"
 #include "JSSVGDocument.h"
 #include "JSSVGPoint.h"
 #include "JSScriptProfile.h"
@@ -321,6 +322,9 @@ static const HashTableValue JSTestObjPrototypeTableValues[] =
     { "immutablePointFunction", DontDelete | JSC::Function, (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionImmutablePointFunction), (intptr_t)0, NoIntrinsic },
     { "orange", DontDelete | JSC::Function, (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionOrange), (intptr_t)0, NoIntrinsic },
     { "strictFunction", DontDelete | JSC::Function, (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionStrictFunction), (intptr_t)3, NoIntrinsic },
+    { "variadicStringMethod", DontDelete | JSC::Function, (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionVariadicStringMethod), (intptr_t)2, NoIntrinsic },
+    { "variadicDoubleMethod", DontDelete | JSC::Function, (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionVariadicDoubleMethod), (intptr_t)2, NoIntrinsic },
+    { "variadicNodeMethod", DontDelete | JSC::Function, (intptr_t)static_cast<NativeFunction>(jsTestObjPrototypeFunctionVariadicNodeMethod), (intptr_t)2, NoIntrinsic },
     { 0, 0, 0, 0, NoIntrinsic }
 };
 
@@ -2597,6 +2601,69 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunction(ExecState*
     return JSValue::encode(result);
 }
 
+EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicStringMethod(ExecState* exec)
+{
+    JSValue thisValue = exec->hostThisValue();
+    if (!thisValue.inherits(&JSTestObj::s_info))
+        return throwVMTypeError(exec);
+    JSTestObj* castedThis = jsCast<JSTestObj*>(asObject(thisValue));
+    ASSERT_GC_OBJECT_INHERITS(castedThis, &JSTestObj::s_info);
+    TestObj* impl = static_cast<TestObj*>(castedThis->impl());
+    if (exec->argumentCount() < 1)
+        return throwVMError(exec, createNotEnoughArgumentsError(exec));
+    const String& head(MAYBE_MISSING_PARAMETER(exec, 0, DefaultIsUndefined).isEmpty() ? String() : MAYBE_MISSING_PARAMETER(exec, 0, DefaultIsUndefined).toString(exec)->value(exec));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    Vector<String> tail = toNativeArguments<String>(exec, 1);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    impl->variadicStringMethod(head, tail);
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicDoubleMethod(ExecState* exec)
+{
+    JSValue thisValue = exec->hostThisValue();
+    if (!thisValue.inherits(&JSTestObj::s_info))
+        return throwVMTypeError(exec);
+    JSTestObj* castedThis = jsCast<JSTestObj*>(asObject(thisValue));
+    ASSERT_GC_OBJECT_INHERITS(castedThis, &JSTestObj::s_info);
+    TestObj* impl = static_cast<TestObj*>(castedThis->impl());
+    if (exec->argumentCount() < 1)
+        return throwVMError(exec, createNotEnoughArgumentsError(exec));
+    double head(MAYBE_MISSING_PARAMETER(exec, 0, DefaultIsUndefined).toNumber(exec));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    Vector<double> tail = toNativeArguments<double>(exec, 1);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    impl->variadicDoubleMethod(head, tail);
+    return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicNodeMethod(ExecState* exec)
+{
+    JSValue thisValue = exec->hostThisValue();
+    if (!thisValue.inherits(&JSTestObj::s_info))
+        return throwVMTypeError(exec);
+    JSTestObj* castedThis = jsCast<JSTestObj*>(asObject(thisValue));
+    ASSERT_GC_OBJECT_INHERITS(castedThis, &JSTestObj::s_info);
+    TestObj* impl = static_cast<TestObj*>(castedThis->impl());
+    if (exec->argumentCount() < 1)
+        return throwVMError(exec, createNotEnoughArgumentsError(exec));
+    Node* head(toNode(MAYBE_MISSING_PARAMETER(exec, 0, DefaultIsUndefined)));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    Vector<Node*> tail;
+    for (unsigned i = 1; i < exec->argumentCount(); ++i) {
+        if (!exec->argument(i).inherits(&JSNode::s_info))
+            return throwVMTypeError(exec);
+        tail.append(toNode(exec->argument(i)));
+    }
+    impl->variadicNodeMethod(head, tail);
+    return JSValue::encode(jsUndefined());
+}
+
 void JSTestObj::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
     JSTestObj* thisObject = jsCast<JSTestObj*>(cell);
index f810d80..978d01e 100644 (file)
@@ -215,6 +215,9 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionMutablePointFunction
 JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionImmutablePointFunction(JSC::ExecState*);
 JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionOrange(JSC::ExecState*);
 JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunction(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicStringMethod(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicDoubleMethod(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionVariadicNodeMethod(JSC::ExecState*);
 // Attributes
 
 JSC::JSValue jsTestObjReadOnlyLongAttr(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);
index 9563359..d9066b8 100644 (file)
@@ -31,6 +31,7 @@
 @class DOMDictionary;
 @class DOMDocument;
 @class DOMIDBKey;
+@class DOMNode;
 @class DOMSVGDocument;
 @class DOMSVGPoint;
 @class DOMTestObj;
@@ -173,6 +174,9 @@ enum {
 - (DOMSVGPoint *)immutablePointFunction;
 - (void)orange;
 - (DOMbool *)strictFunction:(NSString *)str a:(float)a b:(int)b;
+- (void)variadicStringMethod:(NSString *)head tail:(NSString *)tail;
+- (void)variadicDoubleMethod:(double)head tail:(double)tail;
+- (void)variadicNodeMethod:(DOMNode *)head tail:(DOMNode *)tail;
 @end
 
 #endif
index 3dd0e7a..4fdc61a 100644 (file)
@@ -58,6 +58,7 @@
 #import "IDBKey.h"
 #import "JSMainThreadExecState.h"
 #import "KURL.h"
+#import "Node.h"
 #import "ObjCEventListener.h"
 #import "SVGDocument.h"
 #import "SVGStaticPropertyTearOff.h"
     return result;
 }
 
+- (void)variadicStringMethod:(NSString *)head tail:(NSString *)tail
+{
+    WebCore::JSMainThreadNullState state;
+    IMPL->variadicStringMethod(head, tail);
+}
+
+- (void)variadicDoubleMethod:(double)head tail:(double)tail
+{
+    WebCore::JSMainThreadNullState state;
+    IMPL->variadicDoubleMethod(head, tail);
+}
+
+- (void)variadicNodeMethod:(DOMNode *)head tail:(DOMNode *)tail
+{
+    WebCore::JSMainThreadNullState state;
+    IMPL->variadicNodeMethod(core(head), core(tail));
+}
+
 @end
 
 WebCore::TestObj* core(DOMTestObj *wrapper)
index 32b4f18..74845a7 100644 (file)
@@ -262,5 +262,9 @@ module test {
         [Reflect=CONST_IMPL] const unsigned short CONST_JAVASCRIPT = 15;
 
         attribute [Replaceable] long replaceableAttribute;
+
+        void variadicStringMethod(in DOMString head, in DOMString... tail);
+        void variadicDoubleMethod(in double head, in double... tail);
+        void variadicNodeMethod(in Node head, in Node... tail);
     };
 }
index 38e6f13..6733b26 100644 (file)
@@ -45,6 +45,7 @@
 #include "V8DOMWrapper.h"
 #include "V8Document.h"
 #include "V8Float32Array.h"
+#include "V8Node.h"
 #include "V8SVGDocument.h"
 #include "V8SVGPoint.h"
 #include "V8ScriptProfile.h"
@@ -1890,6 +1891,47 @@ static v8::Handle<v8::Value> strictFunctionCallback(const v8::Arguments& args)
     return setDOMException(ec, args.GetIsolate());
 }
 
+static v8::Handle<v8::Value> variadicStringMethodCallback(const v8::Arguments& args)
+{
+    INC_STATS("DOM.TestObj.variadicStringMethod");
+    if (args.Length() < 1)
+        return throwNotEnoughArgumentsError(args.GetIsolate());
+    TestObj* imp = V8TestObj::toNative(args.Holder());
+    STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, head, MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined));
+    EXCEPTION_BLOCK(Vector<String>, tail, toNativeArguments<String>(args, 1));
+    imp->variadicStringMethod(head, tail);
+    return v8Undefined();
+}
+
+static v8::Handle<v8::Value> variadicDoubleMethodCallback(const v8::Arguments& args)
+{
+    INC_STATS("DOM.TestObj.variadicDoubleMethod");
+    if (args.Length() < 1)
+        return throwNotEnoughArgumentsError(args.GetIsolate());
+    TestObj* imp = V8TestObj::toNative(args.Holder());
+    EXCEPTION_BLOCK(double, head, static_cast<double>(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)->NumberValue()));
+    EXCEPTION_BLOCK(Vector<double>, tail, toNativeArguments<double>(args, 1));
+    imp->variadicDoubleMethod(head, tail);
+    return v8Undefined();
+}
+
+static v8::Handle<v8::Value> variadicNodeMethodCallback(const v8::Arguments& args)
+{
+    INC_STATS("DOM.TestObj.variadicNodeMethod");
+    if (args.Length() < 1)
+        return throwNotEnoughArgumentsError(args.GetIsolate());
+    TestObj* imp = V8TestObj::toNative(args.Holder());
+    EXCEPTION_BLOCK(Node*, head, V8Node::HasInstance(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)) ? V8Node::toNative(v8::Handle<v8::Object>::Cast(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined))) : 0);
+    Vector<RefPtr<Node> > tail;
+    for (int i = 1; i < args.Length(); ++i) {
+        if (!V8Node::HasInstance(args[i]))
+            return throwTypeError(0, args.GetIsolate());
+        tail.append(V8Node::toNative(v8::Handle<v8::Object>::Cast(args[i])));
+    }
+    imp->variadicNodeMethod(head, tail);
+    return v8Undefined();
+}
+
 } // namespace TestObjV8Internal
 
 static const V8DOMConfiguration::BatchedAttribute V8TestObjAttrs[] = {
@@ -2071,6 +2113,8 @@ static const V8DOMConfiguration::BatchedCallback V8TestObjCallbacks[] = {
     {"immutablePointFunction", TestObjV8Internal::immutablePointFunctionCallback},
     {"orange", TestObjV8Internal::orangeCallback},
     {"strictFunction", TestObjV8Internal::strictFunctionCallback},
+    {"variadicStringMethod", TestObjV8Internal::variadicStringMethodCallback},
+    {"variadicDoubleMethod", TestObjV8Internal::variadicDoubleMethodCallback},
 };
 
 static const V8DOMConfiguration::BatchedConstant V8TestObjConsts[] = {
@@ -2222,6 +2266,12 @@ static v8::Persistent<v8::FunctionTemplate> ConfigureV8TestObjTemplate(v8::Persi
     v8::Handle<v8::FunctionTemplate> convert5Argv[convert5Argc] = { V8e::GetRawTemplate() };
     v8::Handle<v8::Signature> convert5Signature = v8::Signature::New(desc, convert5Argc, convert5Argv);
     proto->Set(v8::String::NewSymbol("convert5"), v8::FunctionTemplate::New(TestObjV8Internal::convert5Callback, v8Undefined(), convert5Signature));
+
+    // Custom Signature 'variadicNodeMethod'
+    const int variadicNodeMethodArgc = 2;
+    v8::Handle<v8::FunctionTemplate> variadicNodeMethodArgv[variadicNodeMethodArgc] = { V8Node::GetRawTemplate(), V8Node::GetRawTemplate() };
+    v8::Handle<v8::Signature> variadicNodeMethodSignature = v8::Signature::New(desc, variadicNodeMethodArgc, variadicNodeMethodArgv);
+    proto->Set(v8::String::NewSymbol("variadicNodeMethod"), v8::FunctionTemplate::New(TestObjV8Internal::variadicNodeMethodCallback, v8Undefined(), variadicNodeMethodSignature));
     V8DOMConfiguration::batchConfigureConstants(desc, proto, V8TestObjConsts, WTF_ARRAY_LENGTH(V8TestObjConsts));
 
     // Custom toString template
index 0c9ee4f..556f686 100644 (file)
@@ -182,28 +182,29 @@ namespace WebCore {
 
     template<>
     struct NativeValueTraits<String> {
-        static inline String arrayNativeValue(const v8::Local<v8::Array>& array, size_t i)
+        static inline String nativeValue(const v8::Handle<v8::Value>& value)
         {
-            return toWebCoreString(array->Get(i));
+            return toWebCoreString(value);
         }
     };
 
     template<>
     struct NativeValueTraits<float> {
-        static inline float arrayNativeValue(const v8::Local<v8::Array>& array, size_t i)
+        static inline float nativeValue(const v8::Handle<v8::Value>& value)
         {
-            return static_cast<float>(array->Get(v8Integer(i))->NumberValue());
+            return static_cast<float>(value->NumberValue());
         }
     };
 
     template<>
     struct NativeValueTraits<double> {
-        static inline double arrayNativeValue(const v8::Local<v8::Array>& array, size_t i)
+        static inline double nativeValue(const v8::Handle<v8::Value>& value)
         {
-            return static_cast<double>(array->Get(v8Integer(i))->NumberValue());
+            return static_cast<double>(value->NumberValue());
         }
     };
 
+
     template <class T>
     Vector<T> toNativeArray(v8::Handle<v8::Value> value)
     {
@@ -215,12 +216,24 @@ namespace WebCore {
         v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(v8Value);
         size_t length = array->Length();
-        for (size_t i = 0; i < length; ++i) {
-            result.append(TraitsType::arrayNativeValue(array, i));
-        }
+        for (size_t i = 0; i < length; ++i)
+            result.append(TraitsType::nativeValue(array->Get(i)));
+        return result;
+    }
+
+    template <class T>
+    Vector<T> toNativeArguments(const v8::Arguments& args, size_t startIndex)
+    {
+        ASSERT(startIndex <= args.Length());
+        Vector<T> result;
+        typedef NativeValueTraits<T> TraitsType;
+        size_t length = args.Length();
+        for (size_t i = startIndex; i < length; ++i)
+            result.append(TraitsType::nativeValue(args[i]));
         return result;
     }
 
+
     // Validates that the passed object is a sequence type per WebIDL spec
     // http://www.w3.org/TR/2012/WD-WebIDL-20120207/#es-sequence
     inline v8::Handle<v8::Value> toV8Sequence(v8::Handle<v8::Value> value, uint32_t& length)
index a325a12..5ff3bda 100644 (file)
 #include "config.h"
 #include "ClassList.h"
 
-#include "Element.h"
-#include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "SpaceSplitString.h"
 #include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
-using namespace HTMLNames;
-
 ClassList::ClassList(Element* element)
     : m_element(element)
 {
     if (m_element->document()->inQuirksMode())
-        m_classNamesForQuirksMode.set(m_element->getAttribute(classAttr), false);
+        m_classNamesForQuirksMode.set(value(), false);
 }
 
 void ClassList::ref()
@@ -64,71 +60,11 @@ const AtomicString ClassList::item(unsigned index) const
     return classNames()[index];
 }
 
-bool ClassList::contains(const AtomicString& token, ExceptionCode& ec) const
-{
-    if (!validateToken(token, ec))
-        return false;
-    return containsInternal(token);
-}
-
 bool ClassList::containsInternal(const AtomicString& token) const
 {
     return m_element->hasClass() && classNames().contains(token);
 }
 
-void ClassList::add(const AtomicString& token, ExceptionCode& ec)
-{
-    if (!validateToken(token, ec))
-        return;
-    addInternal(token);
-}
-
-void ClassList::addInternal(const AtomicString& token)
-{
-    const AtomicString& oldClassName(m_element->getAttribute(classAttr));
-    if (oldClassName.isEmpty())
-        m_element->setAttribute(classAttr, token);
-    else if (!containsInternal(token)) {
-        const AtomicString& newClassName(addToken(oldClassName, token));
-        m_element->setAttribute(classAttr, newClassName);
-    }
-}
-
-void ClassList::remove(const AtomicString& token, ExceptionCode& ec)
-{
-    if (!validateToken(token, ec))
-        return;
-    removeInternal(token);
-}
-
-void ClassList::removeInternal(const AtomicString& token)
-{
-    // Check using contains first since it uses AtomicString comparisons instead
-    // of character by character testing.
-    if (!containsInternal(token))
-        return;
-    const AtomicString& newClassName(removeToken(m_element->getAttribute(classAttr), token));
-    m_element->setAttribute(classAttr, newClassName);
-}
-
-bool ClassList::toggle(const AtomicString& token, ExceptionCode& ec)
-{
-    if (!validateToken(token, ec))
-        return false;
-
-    if (containsInternal(token)) {
-        removeInternal(token);
-        return false;
-    }
-    addInternal(token);
-    return true;
-}
-
-String ClassList::toString() const
-{
-    return m_element->getAttribute(classAttr);
-}
-
 void ClassList::reset(const String& newClassName)
 {
     if (m_element->document()->inQuirksMode())
index 992fad4..764ebf5 100644 (file)
 #define ClassList_h
 
 #include "DOMTokenList.h"
+#include "Element.h"
+#include "HTMLNames.h"
 #include "SpaceSplitString.h"
 #include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
 
 namespace WebCore {
 
+using namespace HTMLNames;
+
 class Element;
 
 typedef int ExceptionCode;
@@ -42,30 +48,26 @@ public:
         return adoptPtr(new ClassList(element));
     }
 
-    virtual void ref();
-    virtual void deref();
+    virtual void ref() OVERRIDE;
+    virtual void deref() OVERRIDE;
 
-    virtual unsigned length() const;
-    virtual const AtomicString item(unsigned index) const;
-    virtual bool contains(const AtomicString&, ExceptionCode&) const;
-    virtual void add(const AtomicString&, ExceptionCode&);
-    virtual void remove(const AtomicString&, ExceptionCode&);
-    virtual bool toggle(const AtomicString&, ExceptionCode&);
-    virtual String toString() const;
+    virtual unsigned length() const OVERRIDE;
+    virtual const AtomicString item(unsigned index) const OVERRIDE;
 
-    virtual Element* element() { return m_element; }
+    virtual Element* element() OVERRIDE { return m_element; }
 
     void reset(const String&);
 
 private:
     ClassList(Element*);
 
-    void addInternal(const AtomicString&);
-    bool containsInternal(const AtomicString&) const;
-    void removeInternal(const AtomicString&);
+    virtual bool containsInternal(const AtomicString&) const OVERRIDE;
 
     const SpaceSplitString& classNames() const;
 
+    virtual AtomicString value() const OVERRIDE { return m_element->fastGetAttribute(classAttr); }
+    virtual void setValue(const AtomicString& value) OVERRIDE { m_element->setAttribute(classAttr, value); }
+
     Element* m_element;
     SpaceSplitString m_classNamesForQuirksMode;
 };
index 3a86e9c..4ef0f7f 100644 (file)
@@ -44,55 +44,46 @@ const AtomicString DOMSettableTokenList::item(unsigned index) const
     return m_tokens[index];
 }
 
-bool DOMSettableTokenList::contains(const AtomicString& token, ExceptionCode& ec) const
+bool DOMSettableTokenList::containsInternal(const AtomicString& token) const
 {
-    if (!validateToken(token, ec))
-        return false;
     return m_tokens.contains(token);
 }
 
-void DOMSettableTokenList::add(const AtomicString& token, ExceptionCode& ec)
+void DOMSettableTokenList::add(const Vector<String>& tokens, ExceptionCode& ec)
 {
-    if (!validateToken(token, ec) || m_tokens.contains(token))
-        return;
-    addInternal(token);
+    DOMTokenList::add(tokens, ec);
+
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (m_tokens.isNull())
+            m_tokens.set(tokens[i], false);
+        else
+            m_tokens.add(tokens[i]);
+    }
 }
 
 void DOMSettableTokenList::addInternal(const AtomicString& token)
 {
-    m_value = addToken(m_value, token);
+    DOMTokenList::addInternal(token);
     if (m_tokens.isNull())
         m_tokens.set(token, false);
     else
         m_tokens.add(token);
 }
 
-void DOMSettableTokenList::remove(const AtomicString& token, ExceptionCode& ec)
+void DOMSettableTokenList::remove(const Vector<String>& tokens, ExceptionCode& ec)
 {
-    if (!validateToken(token, ec) || !m_tokens.contains(token))
-        return;
-    removeInternal(token);
+    DOMTokenList::remove(tokens, ec);
+    for (size_t i = 0; i < tokens.size(); ++i)
+        m_tokens.remove(tokens[i]);
 }
 
 void DOMSettableTokenList::removeInternal(const AtomicString& token)
 {
-    m_value = removeToken(m_value, token);
+    DOMTokenList::removeInternal(token);
     m_tokens.remove(token);
 }
 
-bool DOMSettableTokenList::toggle(const AtomicString& token, ExceptionCode& ec)
-{
-    if (!validateToken(token, ec))
-        return false;
-    if (m_tokens.contains(token)) {
-        removeInternal(token);
-        return false;
-    }
-    addInternal(token);
-    return true;
-}
-
-void DOMSettableTokenList::setValue(const String& value)
+void DOMSettableTokenList::setValue(const AtomicString& value)
 {
     m_value = value;
     m_tokens.set(value, false);
index 0b23c6a..f338dc3 100644 (file)
@@ -44,28 +44,28 @@ public:
     }
     virtual ~DOMSettableTokenList();
 
-    virtual void ref() { RefCounted<DOMSettableTokenList>::ref(); }
-    virtual void deref() { RefCounted<DOMSettableTokenList>::deref(); }
+    virtual void ref() OVERRIDE { RefCounted<DOMSettableTokenList>::ref(); }
+    virtual void deref() OVERRIDE { RefCounted<DOMSettableTokenList>::deref(); }
 
-    virtual unsigned length() const { return m_tokens.size(); }
-    virtual const AtomicString item(unsigned index) const;
-    virtual bool contains(const AtomicString&, ExceptionCode&) const;
-    virtual void add(const AtomicString&, ExceptionCode&);
-    virtual void remove(const AtomicString&, ExceptionCode&);
-    virtual bool toggle(const AtomicString&, ExceptionCode&);
-    virtual String toString() const { return value(); }
+    virtual unsigned length() const OVERRIDE { return m_tokens.size(); }
+    virtual const AtomicString item(unsigned index) const OVERRIDE;
+
+    virtual void add(const Vector<String>&, ExceptionCode&) OVERRIDE;
+    virtual void remove(const Vector<String>&, ExceptionCode&) OVERRIDE;
+
+    virtual AtomicString value() const OVERRIDE { return m_value; }
+    virtual void setValue(const AtomicString&) OVERRIDE;
 
-    String value() const { return m_value; }
     const SpaceSplitString& tokens() const { return m_tokens; }
-    void setValue(const String&);
 
 private:
     DOMSettableTokenList();
 
-    void removeInternal(const AtomicString&);
-    void addInternal(const AtomicString&);
+    virtual void addInternal(const AtomicString&) OVERRIDE;
+    virtual bool containsInternal(const AtomicString&) const OVERRIDE;
+    virtual void removeInternal(const AtomicString&) OVERRIDE;
 
-    String m_value;
+    AtomicString m_value;
     SpaceSplitString m_tokens;
 };
 
index 7132b11..533b1f1 100644 (file)
@@ -49,23 +49,138 @@ bool DOMTokenList::validateToken(const AtomicString& token, ExceptionCode& ec)
     return true;
 }
 
+bool DOMTokenList::validateTokens(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (!validateToken(tokens[i], ec))
+            return false;
+    }
+
+    return true;
+}
+
+bool DOMTokenList::contains(const AtomicString& token, ExceptionCode& ec) const
+{
+    if (!validateToken(token, ec))
+        return false;
+    return containsInternal(token);
+}
+
+void DOMTokenList::add(const AtomicString& token, ExceptionCode& ec)
+{
+    Vector<String> tokens;
+    tokens.append(token.string());
+    add(tokens, ec);
+}
+
+void DOMTokenList::add(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    Vector<String> filteredTokens;
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (!validateToken(tokens[i], ec))
+            return;
+        if (!containsInternal(tokens[i]))
+            filteredTokens.append(tokens[i]);
+    }
+
+    if (filteredTokens.isEmpty())
+        return;
+
+    setValue(addTokens(value(), filteredTokens));
+}
+
+void DOMTokenList::remove(const AtomicString& token, ExceptionCode& ec)
+{
+    Vector<String> tokens;
+    tokens.append(token.string());
+    remove(tokens, ec);
+}
+
+void DOMTokenList::remove(const Vector<String>& tokens, ExceptionCode& ec)
+{
+    if (!validateTokens(tokens, ec))
+        return;
+
+    // Check using containsInternal first since it is a lot faster than going
+    // through the string character by character.
+    bool found = false;
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (containsInternal(tokens[i])) {
+            found = true;
+            break;
+        }
+    }
+
+    if (found)
+        setValue(removeTokens(value(), tokens));
+}
+
+bool DOMTokenList::toggle(const AtomicString& token, ExceptionCode& ec)
+{
+    if (!validateToken(token, ec))
+        return false;
+
+    if (containsInternal(token)) {
+        removeInternal(token);
+        return false;
+    }
+    addInternal(token);
+    return true;
+}
+
+void DOMTokenList::addInternal(const AtomicString& token)
+{
+    if (!containsInternal(token))
+        setValue(addToken(value(), token));
+}
+
+void DOMTokenList::removeInternal(const AtomicString& token)
+{
+    // Check using contains first since it uses AtomicString comparisons instead
+    // of character by character testing.
+    if (!containsInternal(token))
+        return;
+    setValue(removeToken(value(), token));
+}
+
 String DOMTokenList::addToken(const AtomicString& input, const AtomicString& token)
 {
-    if (input.isEmpty())
-        return token;
+    Vector<String> tokens;
+    tokens.append(token.string());
+    return addTokens(input, tokens);
+}
+
+String DOMTokenList::addTokens(const AtomicString& input, const Vector<String>& tokens)
+{
+    bool needsSpace = false;
 
     StringBuilder builder;
-    builder.append(input);
-    if (!isHTMLSpace(input[input.length() - 1]))
-        builder.append(' ');
+    if (!input.isEmpty()) {
+        builder.append(input);
+        needsSpace = !isHTMLSpace(input[input.length() - 1]);
+    }
+
+    for (size_t i = 0; i < tokens.size(); ++i) {
+        if (needsSpace)
+            builder.append(' ');
+        builder.append(tokens[i]);
+        needsSpace = true;
+    }
 
-    builder.append(token);
     return builder.toString();
 }
 
 String DOMTokenList::removeToken(const AtomicString& input, const AtomicString& token)
 {
+    Vector<String> tokens;
+    tokens.append(token.string());
+    return removeTokens(input, tokens);
+}
+
+String DOMTokenList::removeTokens(const AtomicString& input, const Vector<String>& tokens)
+{
     // Algorithm defined at http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#remove-a-token-from-a-string
+    // New spec is at http://dom.spec.whatwg.org/#remove-a-token-from-a-string
 
     unsigned inputLength = input.length();
     StringBuilder output; // 3
@@ -85,7 +200,7 @@ String DOMTokenList::removeToken(const AtomicString& input, const AtomicString&
             s.append(input[position++]);
 
         // Step 8
-        if (s.toStringPreserveCapacity() == token) {
+        if (tokens.contains(s.toStringPreserveCapacity())) {
             // Step 8.1
             while (position < inputLength && isHTMLSpace(input[position]))
                 ++position;
index fd110b7..4b25dce 100644 (file)
@@ -45,18 +45,32 @@ public:
 
     virtual unsigned length() const = 0;
     virtual const AtomicString item(unsigned index) const = 0;
-    virtual bool contains(const AtomicString&, ExceptionCode&) const = 0;
-    virtual void add(const AtomicString&, ExceptionCode&) = 0;
-    virtual void remove(const AtomicString&, ExceptionCode&) = 0;
-    virtual bool toggle(const AtomicString&, ExceptionCode&) = 0;
-    virtual String toString() const = 0;
+
+    bool contains(const AtomicString&, ExceptionCode&) const;
+    virtual void add(const Vector<String>&, ExceptionCode&);
+    void add(const AtomicString&, ExceptionCode&);
+    virtual void remove(const Vector<String>&, ExceptionCode&);
+    void remove(const AtomicString&, ExceptionCode&);
+    bool toggle(const AtomicString&, ExceptionCode&);
+
+    AtomicString toString() const { return value(); }
 
     virtual Element* element() { return 0; }
 
 protected:
+    virtual AtomicString value() const = 0;
+    virtual void setValue(const AtomicString&) = 0;
+
+    virtual void addInternal(const AtomicString&);
+    virtual bool containsInternal(const AtomicString&) const = 0;
+    virtual void removeInternal(const AtomicString&);
+
     static bool validateToken(const AtomicString&, ExceptionCode&);
+    static bool validateTokens(const Vector<String>&, ExceptionCode&);
     static String addToken(const AtomicString&, const AtomicString&);
+    static String addTokens(const AtomicString&, const Vector<String>&);
     static String removeToken(const AtomicString&, const AtomicString&);
+    static String removeTokens(const AtomicString&, const Vector<String>&);
 };
 
 } // namespace WebCore
index cf57e1a..85ef109 100644 (file)
@@ -31,8 +31,8 @@ module core {
         readonly attribute unsigned long length;
         [TreatReturnedNullStringAs=Null] DOMString item(in unsigned long index);
         boolean contains(in DOMString token) raises(DOMException);
-        void add(in DOMString token) raises(DOMException);
-        void remove(in DOMString token) raises(DOMException);
+        void add(in DOMString... tokens) raises(DOMException);
+        void remove(in DOMString... tokens) raises(DOMException);
         boolean toggle(in DOMString token) raises(DOMException);
 
 #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT