diff --git a/src/Angular.js b/src/Angular.js index a0117690024a..a6b82c7e9188 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -683,6 +683,10 @@ function isTypedArray(value) { return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value)); } +function isArrayBuffer(obj) { + return toString.call(obj) === '[object ArrayBuffer]'; +} + var trim = function(value) { return isString(value) ? value.trim() : value; @@ -807,7 +811,7 @@ function copy(source, destination) { var stackDest = []; if (destination) { - if (isTypedArray(destination)) { + if (isTypedArray(destination) || isArrayBuffer(destination)) { throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated."); } if (source === destination) { @@ -907,7 +911,16 @@ function copy(source, destination) { case '[object Uint8ClampedArray]': case '[object Uint16Array]': case '[object Uint32Array]': - return new source.constructor(source); + return new source.constructor(copyElement(source.buffer)); + + case '[object ArrayBuffer]': + //Support: IE10 + if (!source.slice) { + var copied = new ArrayBuffer(source.byteLength); + new Uint8Array(copied).set(new Uint8Array(source)); + return copied; + } + return source.slice(0); case '[object Boolean]': case '[object Number]': diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 41b6493a73ed..d397edb8d682 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -86,6 +86,7 @@ describe('angular', function() { expect(copy(src) instanceof Uint8Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -97,6 +98,7 @@ describe('angular', function() { expect(copy(src) instanceof Uint8ClampedArray).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -108,6 +110,7 @@ describe('angular', function() { expect(copy(src) instanceof Uint16Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -119,6 +122,7 @@ describe('angular', function() { expect(copy(src) instanceof Uint32Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -130,6 +134,7 @@ describe('angular', function() { expect(copy(src) instanceof Int8Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -141,6 +146,7 @@ describe('angular', function() { expect(copy(src) instanceof Int16Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -152,6 +158,7 @@ describe('angular', function() { expect(copy(src) instanceof Int32Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -163,6 +170,7 @@ describe('angular', function() { expect(copy(src) instanceof Float32Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); } }); @@ -174,6 +182,49 @@ describe('angular', function() { expect(copy(src) instanceof Float64Array).toBeTruthy(); expect(dst).toEqual(src); expect(dst).not.toBe(src); + expect(dst.buffer).not.toBe(src.buffer); + } + }); + + it('should copy an ArrayBuffer with no destination', function() { + if (typeof ArrayBuffer !== 'undefined') { + var src = new ArrayBuffer(8); + new Int32Array(src).set([1, 2]); + + var dst = copy(src); + expect(dst instanceof ArrayBuffer).toBeTruthy(); + expect(dst).toEqual(src); + expect(dst).not.toBe(src); + } + }); + + it('should handle ArrayBuffer objects with multiple references', function() { + if (typeof ArrayBuffer !== 'undefined') { + var buffer = new ArrayBuffer(8); + var src = [new Int32Array(buffer), new Float32Array(buffer)]; + src[0].set([1, 2]); + + var dst = copy(src); + expect(dst).toEqual(src); + expect(dst[0]).not.toBe(src[0]); + expect(dst[1]).not.toBe(src[1]); + expect(dst[0].buffer).toBe(dst[1].buffer); + expect(dst[0].buffer).not.toBe(buffer); + } + }); + + it('should handle Int32Array objects with multiple references', function() { + if (typeof Int32Array !== 'undefined') { + var arr = new Int32Array(2); + var src = [arr, arr]; + arr.set([1, 2]); + + var dst = copy(src); + expect(dst).toEqual(src); + expect(dst).not.toBe(src); + expect(dst[0]).not.toBe(src[0]); + expect(dst[0]).toBe(dst[1]); + expect(dst[0].buffer).toBe(dst[1].buffer); } }); @@ -258,6 +309,15 @@ describe('angular', function() { } }); + it("should throw an exception if an ArrayBuffer is the destination", function() { + if (typeof ArrayBuffer !== 'undefined') { + var src = new ArrayBuffer(5); + var dst = new ArrayBuffer(5); + expect(function() { copy(src, dst); }) + .toThrowMinErr("ng", "cpta", "Can't copy! TypedArray destination cannot be mutated."); + } + }); + it("should deeply copy an array into an existing array", function() { var src = [1, {name:"value"}]; var dst = [{key:"v"}];