Source/WebCore: Blob constructor accepts a sequence (array-like object) as first arg.

https://bugs.webkit.org/show_bug.cgi?id=124175

Patch by Victor Costan <costan@gmail.com> on 2013-11-13
Reviewed by Christophe Dumez.

Added test cases to fast/files/script-tests/blob-constructor.js.

* bindings/js/JSBlobCustom.cpp: Make the constructor work with sequences.
(WebCore::JSBlobConstructor::constructJSBlob):
* bindings/js/JSDOMBinding.h:
(WebCore::toJSSequence): Slightly better error message when conversion fails.
(WebCore::toJS): Whitespace.
(WebCore::jsArray): Whitespace.

LayoutTests: Blob constructor accepts a sequence (array-like object) as first arg.
https://bugs.webkit.org/show_bug.cgi?id=124175

Patch by Victor Costan <costan@gmail.com> on 2013-11-13
Reviewed by Christophe Dumez.

* crypto/subtle/argument-conversion-expected.txt: Updated sequence error expectations.
* fast/dom/Window/window-postmessage-args-expected.txt: Updated sequence error expectations.
* fast/events/constructors/message-event-constructor-expected.txt: Updated sequence error expectations.
* fast/events/message-port-multi-expected.txt: Updated sequence error expectations.
* fast/files/blob-constructor-expected.txt: Updated error text and added expectations.
* fast/files/script-tests/blob-constructor.js: Added sequence test cases.
* fast/workers/worker-context-multi-port-expected.txt: Updated sequence error expectations.
* fast/workers/worker-multi-port-expected.txt: Updated sequence error expectations.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159275 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3fd04894
2013-11-13 Victor Costan <costan@gmail.com>
Blob constructor accepts a sequence (array-like object) as first arg.
https://bugs.webkit.org/show_bug.cgi?id=124175
Reviewed by Christophe Dumez.
* crypto/subtle/argument-conversion-expected.txt: Updated sequence error expectations.
* fast/dom/Window/window-postmessage-args-expected.txt: Updated sequence error expectations.
* fast/events/constructors/message-event-constructor-expected.txt: Updated sequence error expectations.
* fast/events/message-port-multi-expected.txt: Updated sequence error expectations.
* fast/files/blob-constructor-expected.txt: Updated error text and added expectations.
* fast/files/script-tests/blob-constructor.js: Added sequence test cases.
* fast/workers/worker-context-multi-port-expected.txt: Updated sequence error expectations.
* fast/workers/worker-multi-port-expected.txt: Updated sequence error expectations.
2013-11-13 Sun-woo Nam <sunny.nam@samsung.com>
[EFL] Layout tests with css3 selectors3 properties need to be rebaselined.
......
......@@ -17,8 +17,8 @@ PASS ...succeeded
Passing invalid data to digest()
PASS crypto.subtle.digest({name: 'sha-1'}) threw exception TypeError: Not enough arguments.
PASS crypto.subtle.digest({name: 'sha-1'}, null) threw exception TypeError: Type error.
PASS crypto.subtle.digest({name: 'sha-1'}, 10) threw exception TypeError: Type error.
PASS crypto.subtle.digest({name: 'sha-1'}, null) threw exception TypeError: Value is not a sequence.
PASS crypto.subtle.digest({name: 'sha-1'}, 10) threw exception TypeError: Value is not a sequence.
PASS crypto.subtle.digest({name: 'sha-1'}, [10]) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be part of CryptoOperationData sequence.
PASS crypto.subtle.digest({name: 'sha-1'}, new Uint8Array([0])) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be part of CryptoOperationData sequence.
......
Test that the second argument of window.postMessage is ignored or triggers an error if it is not a message port. You should see PASS message '1' through '7', followed by 'done', with messages 4-7 received below.
PASS: Posting message ('1', 1): threw exception TypeError: Type error
PASS: Posting message ('2', c): threw exception TypeError: Type error
PASS: Posting message ('3', [object Object]): threw exception TypeError: Type error
PASS: Posting message ('1', 1): threw exception TypeError: Value is not a sequence
PASS: Posting message ('2', c): threw exception TypeError: Value is not a sequence
PASS: Posting message ('3', [object Object]): threw exception TypeError: Value is not a sequence
PASS: Posting message ('4', [object Window]) did not throw an exception
PASS: Posting message ('4a', *) did not throw an exception
PASS: Posting message ('5', null) did not throw an exception
......
......@@ -83,18 +83,18 @@ PASS new MessageEvent('eventType', { ports: [] }).ports is []
PASS new MessageEvent('eventType', { ports: undefined }).ports is []
PASS new MessageEvent('eventType', { ports: null }).ports is []
PASS new MessageEvent('eventType', { ports: [1, 2, 3] }).ports[2] threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: test_object }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: document }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: false }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: true }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: '' }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: 'chocolate' }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: 12345 }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: 18446744073709551615 }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: NaN }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { get ports() { return 123; } }).ports threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: test_object }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: document }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: false }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: true }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: '' }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: 'chocolate' }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: 12345 }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: 18446744073709551615 }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { ports: NaN }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { get ports() { return 123; } }).ports threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { get ports() { throw 'MessageEvent Error'; } }) threw exception MessageEvent Error.
PASS new MessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0] threw exception TypeError: Type error.
PASS new MessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0] threw exception TypeError: Value is not a sequence.
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles is true
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable is true
PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).data is test_object
......
......@@ -8,7 +8,7 @@ PASS channel.port1.postMessage("entangled port", [channel.port2]) threw exceptio
PASS channel.port1.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception Error: InvalidStateError: DOM Exception 11.
PASS channel.port1.postMessage("notAPort", [channel3.port1, {}, channel3.port2]) threw exception TypeError: Type error.
PASS channel.port1.postMessage("duplicate port", [channel3.port1, channel3.port1]) threw exception Error: InvalidStateError: DOM Exception 11.
PASS channel.port1.postMessage("notAnArray", channel3.port1) threw exception TypeError: Type error.
PASS channel.port1.postMessage("notAnArray", channel3.port1) threw exception TypeError: Value is not a sequence.
PASS channel.port1.postMessage("notASequence", [{length: 3}]) threw exception TypeError: Type error.
PASS channel.port1.postMessage("largeSequence", largePortArray) threw exception Error: InvalidStateError: DOM Exception 11.
PASS event.ports is non-null and zero length when no port sent
......
......@@ -10,8 +10,8 @@ PASS (new Blob(['hello'], {})) instanceof window.Blob is true
PASS (new Blob(['hello'], {type:'text/html'})) instanceof window.Blob is true
PASS (new Blob(['hello'], {type:'text/html', endings:'native'})) instanceof window.Blob is true
PASS (new Blob(['hello'], {type:'text/html', endings:'transparent'})) instanceof window.Blob is true
PASS new Blob('hello') threw exception TypeError: First argument of the constructor is not of type Array.
PASS new Blob(0) threw exception TypeError: First argument of the constructor is not of type Array.
PASS new Blob('hello') threw exception TypeError: Value is not a sequence.
PASS new Blob(0) threw exception TypeError: Value is not a sequence.
PASS (new Blob([])) instanceof window.Blob is true
PASS (new Blob(['stringPrimitive'])) instanceof window.Blob is true
PASS (new Blob([String('stringObject')])) instanceof window.Blob is true
......@@ -72,6 +72,12 @@ PASS new Blob([(new Float32Array(100)).buffer]).size is 400
PASS new Blob([(new Float64Array(100)).buffer]).size is 800
PASS new Blob([(new Float64Array(100)).buffer, (new Int32Array(100)).buffer, (new Uint8Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size is 1400
PASS new Blob([new Blob([(new Int32Array(100)).buffer]), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size is 1000
PASS new Blob({length: 0}) instanceof window.Blob is true
PASS new Blob({length: 0}).size is 0
PASS new Blob({length: 1, 0: 'string'}).size is 6
PASS new Blob({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}).size is 300
PASS new Blob({length: 1, 0: 'string'}, {type: 'text/html'}).type is 'text/html'
PASS new Blob({length: 0}, {endings:'illegal'}) threw exception TypeError: The endings property must be either "transparent" or "native".
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -10,8 +10,8 @@ shouldBeTrue("(new Blob(['hello'], {type:'text/html', endings:'native'})) instan
shouldBeTrue("(new Blob(['hello'], {type:'text/html', endings:'transparent'})) instanceof window.Blob");
// Test invalid blob parts
shouldThrow("new Blob('hello')", "'TypeError: First argument of the constructor is not of type Array'");
shouldThrow("new Blob(0)", "'TypeError: First argument of the constructor is not of type Array'");
shouldThrow("new Blob('hello')", "'TypeError: Value is not a sequence'");
shouldThrow("new Blob(0)", "'TypeError: Value is not a sequence'");
// Test valid blob parts.
shouldBeTrue("(new Blob([])) instanceof window.Blob");
......@@ -98,3 +98,11 @@ shouldBe("new Blob([(new Float32Array(100)).buffer]).size", "400");
shouldBe("new Blob([(new Float64Array(100)).buffer]).size", "800");
shouldBe("new Blob([(new Float64Array(100)).buffer, (new Int32Array(100)).buffer, (new Uint8Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1400");
shouldBe("new Blob([new Blob([(new Int32Array(100)).buffer]), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1000");
// Test passing blob parts in sequences.
shouldBeTrue("new Blob({length: 0}) instanceof window.Blob");
shouldBe("new Blob({length: 0}).size", "0");
shouldBe("new Blob({length: 1, 0: 'string'}).size", "6");
shouldBe("new Blob({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}).size", "300");
shouldBe("new Blob({length: 1, 0: 'string'}, {type: 'text/html'}).type", "'text/html'");
shouldThrow("new Blob({length: 0}, {endings:'illegal'})", "'TypeError: The endings property must be either \"transparent\" or \"native\"'");
......@@ -9,7 +9,7 @@ PASS event.ports contains two ports when two ports sent
PASS posting a null port did throw: Error: InvalidStateError: DOM Exception 11
PASS posting a non-port did throw: TypeError: Type error
PASS event.ports contains two ports when two ports re-sent after error
PASS posting a non-array did throw: TypeError: Type error
PASS posting a non-array did throw: TypeError: Value is not a sequence
PASS posting a non-sequence did throw: TypeError: Type error
TEST COMPLETE
......
......@@ -5,7 +5,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS worker.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception Error: InvalidStateError: DOM Exception 11.
PASS worker.postMessage("notAPort", [channel3.port1, {}, channel3.port2]) threw exception TypeError: Type error.
PASS worker.postMessage("notAnArray", channel3.port1) threw exception TypeError: Type error.
PASS worker.postMessage("notAnArray", channel3.port1) threw exception TypeError: Value is not a sequence.
PASS worker.postMessage("notASequence", [{length: 3}]) threw exception TypeError: Type error.
PASS event.ports is non-null and zero length when no port sent
PASS event.ports is non-null and zero length when empty array sent
......
2013-11-13 Victor Costan <costan@gmail.com>
Blob constructor accepts a sequence (array-like object) as first arg.
https://bugs.webkit.org/show_bug.cgi?id=124175
Reviewed by Christophe Dumez.
Added test cases to fast/files/script-tests/blob-constructor.js.
* bindings/js/JSBlobCustom.cpp: Make the constructor work with sequences.
(WebCore::JSBlobConstructor::constructJSBlob):
* bindings/js/JSDOMBinding.h:
(WebCore::toJSSequence): Slightly better error message when conversion fails.
(WebCore::toJS): Whitespace.
(WebCore::jsArray): Whitespace.
2013-11-13 Joseph Pecoraro <pecoraro@apple.com>
Web Inspector: InspectorBackendDispatcher improvements
......
......@@ -71,9 +71,11 @@ EncodedJSValue JSC_HOST_CALL JSBlobConstructor::constructJSBlob(ExecState* exec)
return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), Blob, blob.get()));
}
JSValue firstArg = exec->argument(0);
if (!isJSArray(firstArg))
return throwVMError(exec, createTypeError(exec, "First argument of the constructor is not of type Array"));
unsigned blobPartsLength = 0;
JSObject* blobParts = toJSSequence(exec, exec->argument(0), blobPartsLength);
if (exec->hadException())
return JSValue::encode(jsUndefined());
ASSERT(blobParts);
String type;
String endings = ASCIILiteral("transparent");
......@@ -110,11 +112,8 @@ EncodedJSValue JSC_HOST_CALL JSBlobConstructor::constructJSBlob(ExecState* exec)
BlobBuilder blobBuilder;
JSArray* array = asArray(firstArg);
unsigned length = array->length();
for (unsigned i = 0; i < length; ++i) {
JSValue item = array->getIndex(exec, i);
for (unsigned i = 0; i < blobPartsLength; ++i) {
JSValue item = blobParts->get(exec, i);
#if ENABLE(BLOB)
if (item.inherits(JSArrayBuffer::info()))
blobBuilder.append(toArrayBuffer(item));
......
......@@ -119,7 +119,7 @@ inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuff
{
return static_cast<WebCoreTypedArrayController*>(world.vm()->m_typedArrayController.get())->wrapperOwner();
}
inline void* wrapperContext(DOMWrapperWorld& world, JSC::ArrayBuffer*)
{
return &world;
......@@ -197,7 +197,7 @@ template <typename DOMClass, typename WrapperClass> inline void uncacheWrapper(D
return;
weakRemove(world.m_wrappers, (void*)domObject, wrapper);
}
#define CREATE_DOM_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
{
......@@ -251,7 +251,7 @@ inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const AtomicString&
{
return jsStringWithCache(exec, s.string());
}
JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null
......@@ -325,7 +325,7 @@ inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, uns
{
JSC::JSObject* object = value.getObject();
if (!object) {
throwTypeError(exec);
throwVMError(exec, createTypeError(exec, "Value is not a sequence"));
return 0;
}
......@@ -334,7 +334,7 @@ inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, uns
return 0;
if (lengthValue.isUndefinedOrNull()) {
throwTypeError(exec);
throwVMError(exec, createTypeError(exec, "Value is not a sequence"));
return 0;
}
......@@ -374,10 +374,10 @@ template <typename T>
inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Vector<T> vector)
{
JSC::JSArray* array = constructEmptyArray(exec, 0, vector.size());
for (size_t i = 0; i < vector.size(); ++i)
array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i]));
return array;
}
......@@ -385,10 +385,10 @@ template <typename T>
inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Vector<RefPtr<T>> vector)
{
JSC::JSArray* array = constructEmptyArray(exec, 0, vector.size());
for (size_t i = 0; i < vector.size(); ++i)
array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i].get()));
return array;
}
......@@ -428,7 +428,7 @@ template <typename T, size_t inlineCapacity>
JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& iterator)
{
JSC::MarkedArgumentBuffer list;
typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();
typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();
typedef JSValueTraits<T> TraitsType;
for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment