diff --git a/CHANGES.md b/CHANGES.md index d9cc6fca297f..9115b1783f55 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,15 @@ Change Log ### 1.56 - 2019-04-01 +##### Breaking Changes :mega: +* `Resource.fetchImage` now returns an `ImageBitmap` instead of `Image` when supported. This allows for decoding images while fetching using `createImageBitmap` to greatly speed up texture upload and decrease frame drops when loading models with large textures. [#7579](https://github.com/AnalyticalGraphicsInc/cesium/pull/7579) + +##### Deprecated :hourglass_flowing_sand: +* `Resource.fetchImage` now takes an options object. Use `resource.fetchImage({ preferBlob: true })` instead of `resource.fetchImage(true)`. The previous function definition will no longer work in 1.57. [#7579](https://github.com/AnalyticalGraphicsInc/cesium/pull/7579) + +##### Additions :tada: +* `Resource.fetchImage` now has a `flipY` option to vertically flip an image during fetch & decode. It is only valid when `ImageBitmapOptions` is supported by the browser. [#7579](https://github.com/AnalyticalGraphicsInc/cesium/pull/7579) + ##### Fixes :wrench: * Fixed the value for `BlendFunction.ONE_MINUS_CONSTANT_COLOR`. [#7624](https://github.com/AnalyticalGraphicsInc/cesium/pull/7624) diff --git a/Source/Core/FeatureDetection.js b/Source/Core/FeatureDetection.js index e124819f342e..620fafa3f8d5 100644 --- a/Source/Core/FeatureDetection.js +++ b/Source/Core/FeatureDetection.js @@ -4,7 +4,6 @@ define([ './defineProperties', './DeveloperError', './Fullscreen', - './RuntimeError', '../ThirdParty/when' ], function( defaultValue, @@ -12,7 +11,6 @@ define([ defineProperties, DeveloperError, Fullscreen, - RuntimeError, when) { 'use strict'; /*global CanvasPixelArray*/ diff --git a/Source/Core/IonResource.js b/Source/Core/IonResource.js index b0800cf4453b..4a629d563b3b 100644 --- a/Source/Core/IonResource.js +++ b/Source/Core/IonResource.js @@ -164,8 +164,18 @@ define([ return result; }; - IonResource.prototype.fetchImage = function (preferBlob, allowCrossOrigin) { - return Resource.prototype.fetchImage.call(this, this._isExternal ? preferBlob : true, allowCrossOrigin); + IonResource.prototype.fetchImage = function (options) { + if (!this._isExternal) { + var userOptions = options; + options = { + preferBlob : true + }; + if (defined(userOptions)) { + options.flipY = userOptions.flipY; + } + } + + return Resource.prototype.fetchImage.call(this, options); }; IonResource.prototype._makeRequest = function(options) { diff --git a/Source/Core/Resource.js b/Source/Core/Resource.js index 28a752a2a5c1..9034d45d0a7b 100644 --- a/Source/Core/Resource.js +++ b/Source/Core/Resource.js @@ -11,6 +11,7 @@ define([ './deprecationWarning', './DeveloperError', './freezeObject', + './FeatureDetection', './getAbsoluteUri', './getBaseUri', './getExtensionFromUri', @@ -39,6 +40,7 @@ define([ deprecationWarning, DeveloperError, freezeObject, + FeatureDetection, getAbsoluteUri, getBaseUri, getExtensionFromUri, @@ -374,6 +376,47 @@ define([ }); }; + var supportsImageBitmapOptionsPromise; + /** + * A helper function to check whether createImageBitmap supports passing ImageBitmapOptions. + * + * @returns {Promise} A promise that resolves to true if this browser supports creating an ImageBitmap with options. + * + * @private + */ + Resource.supportsImageBitmapOptions = function() { + // Until the HTML folks figure out what to do about this, we need to actually try loading an image to + // know if this browser supports passing options to the createImageBitmap function. + // https://github.com/whatwg/html/pull/4248 + if (defined(supportsImageBitmapOptionsPromise)) { + return supportsImageBitmapOptionsPromise; + } + + if (typeof createImageBitmap !== 'function') { + supportsImageBitmapOptionsPromise = when.resolve(false); + return supportsImageBitmapOptionsPromise; + } + + var imageDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg=='; + + supportsImageBitmapOptionsPromise = Resource.fetchBlob({ + url : imageDataUri + }) + .then(function(blob) { + return createImageBitmap(blob, { + imageOrientation: 'flipY' + }); + }) + .then(function(imageBitmap) { + return true; + }) + .otherwise(function() { + return false; + }); + + return supportsImageBitmapOptionsPromise; + }; + defineProperties(Resource, { /** * Returns true if blobs are supported. @@ -827,10 +870,13 @@ define([ /** * Asynchronously loads the given image resource. Returns a promise that will resolve to - * an {@link Image} once loaded, or reject if the image failed to load. + * an {@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap|ImageBitmap} if the browser supports `createImageBitmap` or otherwise an + * {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement|Image} once loaded, or reject if the image failed to load. * - * @param {Boolean} [preferBlob = false] If true, we will load the image via a blob. - * @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle is true and the request does not have high enough priority. + * @param {Object} [options] An object with the following properties. + * @param {Boolean} [options.preferBlob=false] If true, we will load the image via a blob. + * @param {Boolean} [options.flipY=true] If true, image will be vertially flipped during decode. Only applies if the browser supports `createImageBitmap`. + * @returns {Promise.|Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle is true and the request does not have high enough priority. * * * @example @@ -849,8 +895,16 @@ define([ * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing} * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A} */ - Resource.prototype.fetchImage = function (preferBlob) { - preferBlob = defaultValue(preferBlob, false); + Resource.prototype.fetchImage = function (options) { + if (typeof options === 'boolean') { + deprecationWarning('fetchImage-parameter-change', 'fetchImage now takes an options object in CesiumJS 1.56. Use resource.fetchImage({ preferBlob: true }) instead of resource.fetchImage(true).'); + options = { + preferBlob : options + }; + } + options = defaultValue(options, defaultValue.EMPTY_OBJECT); + var preferBlob = defaultValue(options.preferBlob, false); + var flipY = defaultValue(options.flipY, true); checkAndResetRequest(this.request); @@ -860,7 +914,7 @@ define([ // 3. It's a blob URI // 4. It doesn't have request headers and we preferBlob is false if (!xhrBlobSupported || this.isDataUri || this.isBlobUri || (!this.hasHeaders && !preferBlob)) { - return fetchImage(this, true); + return fetchImage(this, flipY); } var blobPromise = this.fetchBlob(); @@ -868,25 +922,36 @@ define([ return; } + var supportsImageBitmap; var generatedBlobResource; var generatedBlob; - return blobPromise + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmap = result; + return blobPromise; + }) .then(function(blob) { if (!defined(blob)) { return; } + if (supportsImageBitmap) { + return Resource._Implementations.createImageBitmapFromBlob(blob, flipY); + } generatedBlob = blob; var blobUrl = window.URL.createObjectURL(blob); generatedBlobResource = new Resource({ url: blobUrl }); - return fetchImage(generatedBlobResource); + return fetchImage(generatedBlobResource, flipY); }) .then(function(image) { if (!defined(image)) { return; } + if (supportsImageBitmap) { + return image; + } window.URL.revokeObjectURL(generatedBlobResource.url); // This is because the blob object is needed for DiscardMissingTileImagePolicy @@ -903,7 +968,7 @@ define([ }); }; - function fetchImage(resource) { + function fetchImage(resource, flipY) { var request = resource.request; request.url = resource.url; request.requestFunction = function() { @@ -917,7 +982,7 @@ define([ var deferred = when.defer(); - Resource._Implementations.createImage(url, crossOrigin, deferred); + Resource._Implementations.createImage(url, crossOrigin, deferred, flipY); return deferred.promise; }; @@ -941,7 +1006,7 @@ define([ request.state = RequestState.UNISSUED; request.deferred = undefined; - return fetchImage(resource); + return fetchImage(resource, flipY); } return when.reject(e); @@ -958,15 +1023,19 @@ define([ * @param {Object} [options.templateValues] Key/Value pairs that are used to replace template values (eg. {x}). * @param {Object} [options.headers={}] Additional HTTP headers that will be sent. * @param {DefaultProxy} [options.proxy] A proxy to be used when loading the resource. + * @param {Boolean} [options.flipY = true] Whether to vertically flip the image during fetch and decode. Only applies when requesting an image and the browser supports createImageBitmap. * @param {Resource~RetryCallback} [options.retryCallback] The Function to call when a request for this resource fails. If it returns true, the request will be retried. * @param {Number} [options.retryAttempts=0] The number of times the retryCallback should be called before giving up. * @param {Request} [options.request] A Request object that will be used. Intended for internal use only. * @param {Boolean} [options.preferBlob = false] If true, we will load the image via a blob. - * @returns {Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle is true and the request does not have high enough priority. + * @returns {Promise.|Promise.|undefined} a promise that will resolve to the requested data when loaded. Returns undefined if request.throttle is true and the request does not have high enough priority. */ Resource.fetchImage = function (options) { var resource = new Resource(options); - return resource.fetchImage(options.preferBlob); + return resource.fetchImage({ + flipY: options.flipY, + preferBlob: options.preferBlob + }); }; /** @@ -1755,7 +1824,7 @@ define([ */ Resource._Implementations = {}; - Resource._Implementations.createImage = function(url, crossOrigin, deferred) { + function loadImageElement(url, crossOrigin, deferred) { var image = new Image(); image.onload = function() { @@ -1775,6 +1844,55 @@ define([ } image.src = url; + } + + Resource._Implementations.createImage = function(url, crossOrigin, deferred, flipY) { + // Passing an Image to createImageBitmap will force it to run on the main thread + // since DOM elements don't exist on workers. We convert it to a blob so it's non-blocking. + // See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1044102#c38 + // https://bugs.chromium.org/p/chromium/issues/detail?id=580202#c10 + Resource.supportsImageBitmapOptions() + .then(function(result) { + // We can only use ImageBitmap if we can flip on decode. + // See: https://github.com/AnalyticalGraphicsInc/cesium/pull/7579#issuecomment-466146898 + if (!result) { + loadImageElement(url, crossOrigin, deferred); + return; + } + + return Resource.fetchBlob({ + url: url + }); + }) + .then(function(blob) { + if (!defined(blob)) { + return; + } + + return Resource._Implementations.createImageBitmapFromBlob(blob, flipY); + }) + .then(function(imageBitmap) { + if (!defined(imageBitmap)) { + return; + } + + deferred.resolve(imageBitmap); + }) + .otherwise(deferred.reject); + }; + + Resource._Implementations.createImageBitmapFromBlob = function(blob, flipY) { + return Resource.supportsImageBitmapOptions() + .then(function(result) { + if (!result) { + return createImageBitmap(blob); + } + + return createImageBitmap(blob, { + imageOrientation: flipY ? 'flipY' : 'none' + }); + }); }; function decodeResponse(loadWithHttpResponse, responseType) { diff --git a/Source/Core/loadImageFromTypedArray.js b/Source/Core/loadImageFromTypedArray.js index fa2df18dc4d7..0ee8cc375c01 100644 --- a/Source/Core/loadImageFromTypedArray.js +++ b/Source/Core/loadImageFromTypedArray.js @@ -1,17 +1,27 @@ define([ '../ThirdParty/when', './Check', + './defined', + './defaultValue', + './FeatureDetection', './Resource' ], function( when, Check, + defined, + defaultValue, + FeatureDetection, Resource) { 'use strict'; /** * @private */ - function loadImageFromTypedArray(uint8Array, format, request) { + function loadImageFromTypedArray(options) { + var uint8Array = options.uint8Array; + var format = options.format; + var request = options.request; + var flipY = defaultValue(options.flipY, true); //>>includeStart('debug', pragmas.debug); Check.typeOf.object('uint8Array', uint8Array); Check.typeOf.string('format', format); @@ -26,11 +36,14 @@ define([ url: blobUrl, request: request }); - return resource.fetchImage() + return resource.fetchImage({ + flipY : flipY + }) .then(function(image) { window.URL.revokeObjectURL(blobUrl); return image; - }, function(error) { + }) + .otherwise(function(error) { window.URL.revokeObjectURL(blobUrl); return when.reject(error); }); diff --git a/Source/Scene/DiscardMissingTileImagePolicy.js b/Source/Scene/DiscardMissingTileImagePolicy.js index ef4c66a18dfb..83c268243026 100644 --- a/Source/Scene/DiscardMissingTileImagePolicy.js +++ b/Source/Scene/DiscardMissingTileImagePolicy.js @@ -89,7 +89,9 @@ define([ that._isReady = true; } - when(resource.fetchImage(true), success, failure); + resource.fetchImage({ + preferBlob : true + }).then(success).otherwise(failure); } /** diff --git a/Source/Scene/GoogleEarthEnterpriseImageryProvider.js b/Source/Scene/GoogleEarthEnterpriseImageryProvider.js index 5e71d409ef50..38e37358383d 100644 --- a/Source/Scene/GoogleEarthEnterpriseImageryProvider.js +++ b/Source/Scene/GoogleEarthEnterpriseImageryProvider.js @@ -488,7 +488,10 @@ define([ return invalidImage; } - return loadImageFromTypedArray(a, type); + return loadImageFromTypedArray({ + uint8Array: a, + format: type + }); }); }; diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js index 61f49b663a56..55d85bb7bfda 100644 --- a/Source/Scene/ImageryProvider.js +++ b/Source/Scene/ImageryProvider.js @@ -344,7 +344,9 @@ define([ } else if (crnRegex.test(resource)) { return loadCRN(resource); } else if (defined(imageryProvider.tileDiscardPolicy)) { - return resource.fetchImage(true); + return resource.fetchImage({ + preferBlob : true + }); } return resource.fetchImage(); diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 096628247372..e35de4ee21f9 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -1723,7 +1723,9 @@ define([ } else if (crnRegex.test(uri)) { promise = loadCRN(imageResource); } else { - promise = imageResource.fetchImage(); + promise = imageResource.fetchImage({ + flipY: false + }); } promise.then(imageLoad(model, id, imageId)).otherwise(ModelUtility.getFailedLoadFunction(model, 'image', imageResource.url)); } @@ -2325,7 +2327,11 @@ define([ ++model._loadResources.pendingTextureLoads; } else { var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture); - loadImageFromTypedArray(loadResources.getBuffer(bufferView), gltfTexture.mimeType) + loadImageFromTypedArray({ + uint8Array: loadResources.getBuffer(bufferView), + format: gltfTexture.mimeType, + flipY: false + }) .then(onload).otherwise(onerror); ++loadResources.pendingBufferViewToImage; } diff --git a/Specs/Core/FeatureDetectionSpec.js b/Specs/Core/FeatureDetectionSpec.js index 630faf531ef6..eb8d4d909d8d 100644 --- a/Specs/Core/FeatureDetectionSpec.js +++ b/Specs/Core/FeatureDetectionSpec.js @@ -134,5 +134,4 @@ defineSuite([ expect(FeatureDetection.supportsWebP()).toEqual(supportsWebP); }); }); - }); diff --git a/Specs/Core/IonResourceSpec.js b/Specs/Core/IonResourceSpec.js index 0baf9e621260..f5f5e2f1d72b 100644 --- a/Specs/Core/IonResourceSpec.js +++ b/Specs/Core/IonResourceSpec.js @@ -225,8 +225,10 @@ defineSuite([ var fetchImage = spyOn(Resource.prototype, 'fetchImage'); var endpointResource = IonResource._createEndpointResource(assetId); var resource = new IonResource(endpoint, endpointResource); - resource.fetchImage(false, true); - expect(fetchImage).toHaveBeenCalledWith(true, true); + resource.fetchImage(); + expect(fetchImage).toHaveBeenCalledWith({ + preferBlob : true + }); }); it('Calls base fetchImage with no changes for external assets', function() { @@ -240,8 +242,12 @@ defineSuite([ var fetchImage = spyOn(Resource.prototype, 'fetchImage'); var endpointResource = IonResource._createEndpointResource(assetId); var resource = new IonResource(externalEndpoint, endpointResource); - resource.fetchImage(false, true); - expect(fetchImage).toHaveBeenCalledWith(false, true); + resource.fetchImage({ + preferBlob : false + }); + expect(fetchImage).toHaveBeenCalledWith({ + preferBlob : false + }); }); describe('retryCallback', function() { diff --git a/Specs/Core/ResourceSpec.js b/Specs/Core/ResourceSpec.js index cc9bad6ded5a..9203cd4e9c93 100644 --- a/Specs/Core/ResourceSpec.js +++ b/Specs/Core/ResourceSpec.js @@ -6,6 +6,8 @@ defineSuite([ 'Core/Request', 'Core/RequestErrorEvent', 'Core/RequestScheduler', + 'Core/TrustedServers', + 'Specs/createCanvas', 'ThirdParty/Uri', 'ThirdParty/when' ], function( @@ -16,10 +18,22 @@ defineSuite([ Request, RequestErrorEvent, RequestScheduler, + TrustedServers, + createCanvas, Uri, when) { 'use strict'; + var dataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Nk+M/wHwAEBgIA5agATwAAAABJRU5ErkJggg=='; + var supportsImageBitmapOptions; + + beforeAll(function() { + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmapOptions = result; + }); + }); + it('Constructor sets correct properties', function() { var proxy = new DefaultProxy('/proxy/'); var request = new Request(); @@ -1122,26 +1136,122 @@ defineSuite([ }); }); - describe('fetchImage', function() { + it('can load an image preferring blob', function() { + return Resource.fetchImage('./Data/Images/Green.png', true).then(function(loadedImage) { + expect(loadedImage.width).toEqual(1); + expect(loadedImage.height).toEqual(1); + }); + }); + + it('can load an image from a data URI', function() { + return Resource.fetchImage(dataUri).then(function(loadedImage) { + expect(loadedImage.width).toEqual(1); + expect(loadedImage.height).toEqual(1); + }); + }); - var dataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Nk+M/wHwAEBgIA5agATwAAAABJRU5ErkJggg=='; + describe('fetchImage with ImageBitmap', function() { + if (!supportsImageBitmapOptions) { + return; + } - it('can load an image', function() { + var canvas; + beforeAll(function() { + canvas = createCanvas(1, 2); + }); + + afterAll(function() { + document.body.removeChild(canvas); + }); + + function getColorAtPixel(image, x, y) { + var context = canvas.getContext('2d'); + context.drawImage(image, 0, 0, image.width, image.height); + var imageData = context.getImageData(0, 0, 1, 1); + return [imageData.data[0], imageData.data[1], imageData.data[2], imageData.data[3]]; + } + + it('can call supportsImageBitmapOptions', function() { + return Resource.supportsImageBitmapOptions() + .then(function(result) { + expect(typeof result).toEqual('boolean'); + }); + }); + + it('can load and decode an image', function() { return Resource.fetchImage('./Data/Images/Green.png').then(function(loadedImage) { expect(loadedImage.width).toEqual(1); expect(loadedImage.height).toEqual(1); + expect(loadedImage instanceof ImageBitmap); }); }); - it('can load an image preferring blob', function() { - return Resource.fetchImage('./Data/Images/Green.png', true).then(function(loadedImage) { - expect(loadedImage.width).toEqual(1); - expect(loadedImage.height).toEqual(1); + it('correctly flips image when ImageBitmapOptions are supported', function() { + var loadedImage; + + return Resource.fetchImage({ + url: './Data/Images/BlueOverRed.png', + flipY: true + }).then(function(image) { + loadedImage = image; + return Resource.supportsImageBitmapOptions(); + }).then(function(supportsImageBitmapOptions) { + if (supportsImageBitmapOptions) { + expect(getColorAtPixel(loadedImage, 0, 0)).toEqual([255, 0, 0, 255]); + } else { + expect(getColorAtPixel(loadedImage, 0, 0)).toEqual([0, 0, 255, 255]); + } + }); + }); + + it('correctly loads image without flip when ImageBitmapOptions are supported', function() { + var loadedImage; + + return Resource.fetchImage({ + url: './Data/Images/BlueOverRed.png', + flipY: false + }).then(function(image) { + loadedImage = image; + return Resource.supportsImageBitmapOptions(); + }).then(function(supportsImageBitmapOptions) { + if (supportsImageBitmapOptions) { + expect(getColorAtPixel(loadedImage, 0, 0)).toEqual([0, 0, 255, 255]); + } else { + expect(getColorAtPixel(loadedImage, 0, 0)).toEqual([0, 0, 255, 255]); + } + }); + }); + + it('does not use ImageBitmap when ImageBitmapOptions are not supported', function() { + spyOn(Resource, 'supportsImageBitmapOptions').and.returnValue(when.resolve(false)); + spyOn(window, 'createImageBitmap').and.callThrough(); + + return Resource.fetchImage('./Data/Images/Green.png').then(function(loadedImage) { + expect(window.createImageBitmap).not.toHaveBeenCalledWith(); }); }); - it('can load an image from a data URI', function() { - return Resource.fetchImage(dataUri).then(function(loadedImage) { + it('rejects the promise when the image errors', function() { + return Resource.fetchImage('http://example.invalid/testuri.png') + .then(function() { + fail('expected promise to reject'); + }) + .otherwise(function(error) { + expect(error).toBeInstanceOf(RequestErrorEvent); + }); + }); + }); + + describe('fetchImage without ImageBitmap', function() { + beforeAll(function() { + // Force it to use the Image constructor since these specs all test + // specific functionality of this code path. For example, the crossOrigin + // restriction does not apply to images loaded with ImageBitmap. + spyOn(Resource, 'supportsImageBitmapOptions').and.returnValue(when.resolve(false)); + }); + + it('can load an image', function() { + return Resource.fetchImage('./Data/Images/Green.png').then(function(loadedImage) { expect(loadedImage.width).toEqual(1); expect(loadedImage.height).toEqual(1); }); diff --git a/Specs/Core/VRTheWorldTerrainProviderSpec.js b/Specs/Core/VRTheWorldTerrainProviderSpec.js index 00b0f4f6b953..f47a1d52b56a 100644 --- a/Specs/Core/VRTheWorldTerrainProviderSpec.js +++ b/Specs/Core/VRTheWorldTerrainProviderSpec.js @@ -24,9 +24,16 @@ defineSuite([ when) { 'use strict'; + var imageUrl = 'Data/Images/Red16x16.png'; + beforeEach(function() { RequestScheduler.clearForSpecs(); Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + if (url === imageUrl) { + Resource._DefaultImplementations.loadWithXhr(url, responseType, method, data, headers, deferred, overrideMimeType); + return; + } + setTimeout(function() { var parser = new DOMParser(); var xmlString = @@ -239,7 +246,7 @@ defineSuite([ expect(url.indexOf('.tif?cesium=true')).toBeGreaterThanOrEqualTo(0); // Just return any old image. - Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred); + Resource._DefaultImplementations.createImage(imageUrl, crossOrigin, deferred); }; var terrainProvider = new VRTheWorldTerrainProvider({ diff --git a/Specs/Core/loadImageFromTypedArraySpec.js b/Specs/Core/loadImageFromTypedArraySpec.js index 43e705f6ee49..05c0f59826d8 100644 --- a/Specs/Core/loadImageFromTypedArraySpec.js +++ b/Specs/Core/loadImageFromTypedArraySpec.js @@ -1,24 +1,85 @@ defineSuite([ 'Core/loadImageFromTypedArray', - 'Core/Resource' + 'Core/Resource', + 'ThirdParty/when' ], function( loadImageFromTypedArray, - Resource) { + Resource, + when) { 'use strict'; it('can load an image', function() { return Resource.fetchArrayBuffer('./Data/Images/Blue10x10.png').then(function(arrayBuffer) { - var arr = new Uint8Array(arrayBuffer); - return loadImageFromTypedArray(arr, 'image/png').then(function(image) { + var options = { + uint8Array: new Uint8Array(arrayBuffer), + format: 'image/png' + }; + + return loadImageFromTypedArray(options).then(function(image) { expect(image.width).toEqual(10); expect(image.height).toEqual(10); }); }); }); + it('flips image only when flipY is true', function() { + var options = { + uint8Array: new Uint8Array([67, 101, 115, 105, 117, 109]), // This is an invalid PNG. + format: 'image/png', + flipY: true + }; + spyOn(window, 'createImageBitmap').and.returnValue(when.resolve({})); + var blob = new Blob([options.uint8Array], { + type : options.format + }); + + return Resource.supportsImageBitmapOptions() + .then(function(result) { + if (!result) { + return; + } + + return loadImageFromTypedArray(options) + .then(function() { + expect(window.createImageBitmap).toHaveBeenCalledWith(blob, { + imageOrientation: 'flipY' + }); + + window.createImageBitmap.calls.reset(); + options.flipY = false; + return loadImageFromTypedArray(options); + }) + .then(function() { + expect(window.createImageBitmap).toHaveBeenCalledWith(blob, { + imageOrientation: 'none' + }); + }); + }); + }); + + it('can load an image when ImageBitmap is not supported', function() { + spyOn(Resource, 'supportsImageBitmapOptions').and.returnValue(when.resolve(false)); + spyOn(window, 'createImageBitmap').and.callThrough(); + return Resource.fetchArrayBuffer('./Data/Images/Blue10x10.png').then(function(arrayBuffer) { + var options = { + uint8Array: new Uint8Array(arrayBuffer), + format: 'image/png' + }; + + return loadImageFromTypedArray(options).then(function(image) { + expect(image.width).toEqual(10); + expect(image.height).toEqual(10); + expect(window.createImageBitmap).not.toHaveBeenCalled(); + }); + }); + }); + it('can not load an invalid image', function() { - var notApng = new Uint8Array([67, 101, 115, 105, 117, 109]); - return loadImageFromTypedArray(notApng, 'image/png').then(function(image) { + var options = { + uint8Array: new Uint8Array([67, 101, 115, 105, 117, 109]), // This is an invalid PNG. + format: 'image/png' + }; + return loadImageFromTypedArray(options).then(function(image) { fail('should not be called'); }).otherwise(function() { }); @@ -26,13 +87,15 @@ defineSuite([ it('Throws without array', function() { expect(function() { - loadImageFromTypedArray(); + loadImageFromTypedArray({}); }).toThrowDeveloperError(); }); it('Throws without format', function() { expect(function() { - loadImageFromTypedArray(new Uint8Array()); + loadImageFromTypedArray({ + uint8Array: new Uint8Array() + }); }).toThrowDeveloperError(); }); }); diff --git a/Specs/Renderer/TextureSpec.js b/Specs/Renderer/TextureSpec.js index ad0bb76976b0..26e31c931cdf 100644 --- a/Specs/Renderer/TextureSpec.js +++ b/Specs/Renderer/TextureSpec.js @@ -2,6 +2,7 @@ defineSuite([ 'Renderer/Texture', 'Core/Cartesian2', 'Core/Color', + 'Core/FeatureDetection', 'Core/loadKTX', 'Core/PixelFormat', 'Core/Resource', @@ -18,6 +19,7 @@ defineSuite([ Texture, Cartesian2, Color, + FeatureDetection, loadKTX, PixelFormat, Resource, @@ -37,6 +39,7 @@ defineSuite([ var blueImage; var blueAlphaImage; var blueOverRedImage; + var blueOverRedUnflippedImage; var red16x16Image; var greenDXTImage; @@ -55,7 +58,6 @@ defineSuite([ beforeAll(function() { context = createContext(); - var promises = []; promises.push(Resource.fetchImage('./Data/Images/Green.png').then(function(image) { greenImage = image; @@ -69,6 +71,13 @@ defineSuite([ promises.push(Resource.fetchImage('./Data/Images/BlueOverRed.png').then(function(image) { blueOverRedImage = image; })); + // Turn off the default flipping. + promises.push(Resource.fetchImage({ + url: './Data/Images/BlueOverRed.png', + flipY: false + }).then(function(image) { + blueOverRedUnflippedImage = image; + })); promises.push(Resource.fetchImage('./Data/Images/Red16x16.png').then(function(image) { red16x16Image = image; })); @@ -187,6 +196,46 @@ defineSuite([ }).contextToRender([0, 0, 255, 255]); }); + it('can flip texture only if ImageBitmapOptions is not supported', function() { + var topColor = new Color(0.0, 0.0, 1.0, 1.0); + var bottomColor = new Color(1.0, 0.0, 0.0, 1.0); + + return Resource.supportsImageBitmapOptions() + .then(function(supportsImageBitmapOptions) { + if (supportsImageBitmapOptions) { + // When imageBitmapOptions is supported, flipY on texture upload is ignored. + bottomColor = topColor; + } + + texture = new Texture({ + context : context, + source : blueOverRedUnflippedImage, + pixelFormat : PixelFormat.RGBA, + flipY : false + }); + + expect({ + context : context, + fragmentShader : fs, + uniformMap : uniformMap + }).contextToRender(topColor.toBytes()); + + // Flip the texture. + texture = new Texture({ + context : context, + source : blueOverRedUnflippedImage, + pixelFormat : PixelFormat.RGBA, + flipY : true + }); + + expect({ + context : context, + fragmentShader : fs, + uniformMap : uniformMap + }).contextToRender(bottomColor.toBytes()); + }); + }); + it('draws the expected floating-point texture color', function() { if (!context.floatingPointTexture) { return; diff --git a/Specs/Scene/ArcGisMapServerImageryProviderSpec.js b/Specs/Scene/ArcGisMapServerImageryProviderSpec.js index e9a237bb2b5e..cc6b5fb372f7 100644 --- a/Specs/Scene/ArcGisMapServerImageryProviderSpec.js +++ b/Specs/Scene/ArcGisMapServerImageryProviderSpec.js @@ -22,6 +22,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/Uri' ], function( ArcGisMapServerImageryProvider, @@ -47,9 +48,20 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, Uri) { 'use strict'; + var supportsImageBitmapOptions; + beforeAll(function() { + // This suite spies on requests. Resource.supportsImageBitmapOptions needs to make a request to a data URI. + // We run it here to avoid interfering with the tests. + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmapOptions = result; + }); + }); + beforeEach(function() { RequestScheduler.clearForSpecs(); }); @@ -207,7 +219,6 @@ defineSuite([ Resource._Implementations.createImage = function(url, crossOrigin, deferred) { if (/^blob:/.test(url)) { - // load blob url normally Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { expect(url).toEqual(getAbsoluteUri(baseUrl + 'tile/0/0/0')); @@ -225,7 +236,7 @@ defineSuite([ }; return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -283,8 +294,8 @@ defineSuite([ expect(provider.usingPrecachedTiles).toEqual(true); Resource._Implementations.createImage = function(url, crossOrigin, deferred) { - if (/^blob:/.test(url)) { - // load blob url normally + if (/^blob:/.test(url) || supportsImageBitmapOptions) { + // If ImageBitmap is supported, we expect a loadWithXhr request to fetch it as a blob. Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { expect(url).toEqual(getAbsoluteUri(baseUrl + 'tile/0/0/0')); @@ -302,7 +313,7 @@ defineSuite([ }; return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -355,7 +366,7 @@ defineSuite([ }; return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -419,7 +430,7 @@ defineSuite([ }; return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -456,8 +467,8 @@ defineSuite([ expect(provider.hasAlphaChannel).toBeDefined(); Resource._Implementations.createImage = function(url, crossOrigin, deferred) { - if (/^blob:/.test(url)) { - // load blob url normally + if (/^blob:/.test(url) || supportsImageBitmapOptions) { + // If ImageBitmap is supported, we expect a loadWithXhr request to fetch it as a blob. Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { expect(url).toEqual(expectedTileUrl); @@ -475,7 +486,7 @@ defineSuite([ }; return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -609,7 +620,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/BillboardCollectionSpec.js b/Specs/Scene/BillboardCollectionSpec.js index dcfc161d223a..5669be5e5666 100644 --- a/Specs/Scene/BillboardCollectionSpec.js +++ b/Specs/Scene/BillboardCollectionSpec.js @@ -6,6 +6,7 @@ defineSuite([ 'Core/Cartesian3', 'Core/CesiumTerrainProvider', 'Core/Color', + 'Core/createGuid', 'Core/DistanceDisplayCondition', 'Core/Math', 'Core/NearFarScalar', @@ -31,6 +32,7 @@ defineSuite([ Cartesian3, CesiumTerrainProvider, Color, + createGuid, DistanceDisplayCondition, CesiumMath, NearFarScalar, @@ -77,7 +79,8 @@ defineSuite([ }), Resource.fetchImage('./Data/Images/Blue10x10.png').then(function(result) { largeBlueImage = result; - })); + }) + ); }); afterAll(function() { @@ -174,7 +177,7 @@ defineSuite([ expect(b.horizontalOrigin).toEqual(HorizontalOrigin.LEFT); expect(b.verticalOrigin).toEqual(VerticalOrigin.BOTTOM); expect(b.scale).toEqual(2.0); - expect(b.image).toEqual(greenImage.src); + expect(b.image).toEqual(b._imageId); expect(b.color.red).toEqual(1.0); expect(b.color.green).toEqual(2.0); expect(b.color.blue).toEqual(3.0); @@ -221,7 +224,7 @@ defineSuite([ expect(b.horizontalOrigin).toEqual(HorizontalOrigin.LEFT); expect(b.verticalOrigin).toEqual(VerticalOrigin.BOTTOM); expect(b.scale).toEqual(2.0); - expect(b.image).toEqual(greenImage.src); + expect(b.image).toEqual(b._imageId); expect(b.color.red).toEqual(1.0); expect(b.color.green).toEqual(2.0); expect(b.color.blue).toEqual(3.0); @@ -822,7 +825,7 @@ defineSuite([ expect(scene).toRender([0, 255, 0, 255]); - b.setImage(largeBlueImage.src, largeBlueImage); + b.setImage(createGuid(), largeBlueImage); expect(scene).toRender([0, 0, 255, 255]); }); @@ -834,8 +837,10 @@ defineSuite([ expect(scene).toRender([0, 255, 0, 255]); - billboards.textureAtlas.addImage(largeBlueImage.src, largeBlueImage); - b.setImageSubRegion(largeBlueImage.src, new BoundingRectangle(5.0, 5.0, 1.0, 1.0)); + var guid = createGuid(); + + billboards.textureAtlas.addImage(guid, largeBlueImage); + b.setImageSubRegion(guid, new BoundingRectangle(5.0, 5.0, 1.0, 1.0)); expect(scene).toRender([0, 0, 255, 255]); }); diff --git a/Specs/Scene/BingMapsImageryProviderSpec.js b/Specs/Scene/BingMapsImageryProviderSpec.js index d6ad4385659b..2d9a06f31184 100644 --- a/Specs/Scene/BingMapsImageryProviderSpec.js +++ b/Specs/Scene/BingMapsImageryProviderSpec.js @@ -14,6 +14,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/Uri' ], function( BingMapsImageryProvider, @@ -31,9 +32,20 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, Uri) { 'use strict'; + var supportsImageBitmapOptions; + beforeAll(function() { + // This suite spies on requests. Resource.supportsImageBitmapOptions needs to make a request to a data URI. + // We run it here to avoid interfering with the tests. + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmapOptions = result; + }); + }); + beforeEach(function() { RequestScheduler.clearForSpecs(); }); @@ -173,8 +185,8 @@ defineSuite([ function installFakeImageRequest(expectedUrl, expectedParams, proxy) { Resource._Implementations.createImage = function(url, crossOrigin, deferred) { - if (/^blob:/.test(url)) { - // load blob url normally + if (/^blob:/.test(url) || supportsImageBitmapOptions) { + // If ImageBitmap is supported, we expect a loadWithXhr request to fetch it as a blob. Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { if (defined(expectedUrl)) { @@ -362,7 +374,7 @@ defineSuite([ }); return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -393,7 +405,7 @@ defineSuite([ }); return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -482,7 +494,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/DiscardMissingTileImagePolicySpec.js b/Specs/Scene/DiscardMissingTileImagePolicySpec.js index 2c5215941a31..0cb9cd5bf040 100644 --- a/Specs/Scene/DiscardMissingTileImagePolicySpec.js +++ b/Specs/Scene/DiscardMissingTileImagePolicySpec.js @@ -12,6 +12,16 @@ defineSuite([ when) { 'use strict'; + var supportsImageBitmapOptions; + beforeAll(function() { + // This suite spies on requests. Resource.supportsImageBitmapOptions needs to make a request to a data URI. + // We run it here to avoid interfering with the tests. + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmapOptions = result; + }); + }); + afterEach(function() { Resource._Implementations.createImage = Resource._DefaultImplementations.createImage; Resource._Implementations.loadWithXhr = Resource._DefaultImplementations.loadWithXhr; @@ -39,9 +49,9 @@ defineSuite([ it('requests the missing image url', function() { var missingImageUrl = 'http://some.host.invalid/missingImage.png'; + spyOn(Resource._Implementations, 'createImageBitmapFromBlob').and.callThrough(); spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) { if (/^blob:/.test(url)) { - // load blob url normally Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { expect(url).toEqual(missingImageUrl); @@ -62,7 +72,11 @@ defineSuite([ return pollToPromise(function() { return policy.isReady(); }).then(function() { - expect(Resource._Implementations.createImage).toHaveBeenCalled(); + if (supportsImageBitmapOptions) { + expect(Resource._Implementations.createImageBitmapFromBlob).toHaveBeenCalled(); + } else { + expect(Resource._Implementations.createImage).toHaveBeenCalled(); + } }); }); }); diff --git a/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js b/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js index 26d201f4baa1..55a0a7a6c070 100644 --- a/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js +++ b/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js @@ -16,6 +16,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/Uri', 'ThirdParty/when' ], function( @@ -36,6 +37,7 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, Uri, when) { 'use strict'; @@ -44,8 +46,15 @@ defineSuite([ RequestScheduler.clearForSpecs(); }); + var supportsImageBitmapOptions; beforeAll(function() { decodeGoogleEarthEnterpriseData.passThroughDataForTesting = true; + // This suite spies on requests. Resource.supportsImageBitmapOptions needs to make a request to a data URI. + // We run it here to avoid interfering with the tests. + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmapOptions = result; + }); }); afterAll(function() { @@ -84,7 +93,7 @@ defineSuite([ function installFakeImageRequest(expectedUrl, proxy) { Resource._Implementations.createImage = function(url, crossOrigin, deferred) { - if (/^blob:/.test(url)) { + if (/^blob:/.test(url) || supportsImageBitmapOptions) { // load blob url normally Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { @@ -101,7 +110,7 @@ defineSuite([ }; Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { - if (defined(expectedUrl)) { + if (defined(expectedUrl) && !/^blob:/.test(url)) { if (proxy) { var uri = new Uri(url); url = decodeURIComponent(uri.query); @@ -224,7 +233,7 @@ defineSuite([ installFakeImageRequest('http://fake.fake.invalid/flatfile?f1-03-i.1'); return imageryProvider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -294,7 +303,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/GoogleEarthEnterpriseMapsProviderSpec.js b/Specs/Scene/GoogleEarthEnterpriseMapsProviderSpec.js index 4915de445d52..32924b25b4ee 100644 --- a/Specs/Scene/GoogleEarthEnterpriseMapsProviderSpec.js +++ b/Specs/Scene/GoogleEarthEnterpriseMapsProviderSpec.js @@ -10,7 +10,8 @@ defineSuite([ 'Scene/ImageryLayer', 'Scene/ImageryProvider', 'Scene/ImageryState', - 'Specs/pollToPromise' + 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap' ], function( GoogleEarthEnterpriseMapsProvider, DefaultProxy, @@ -23,9 +24,20 @@ defineSuite([ ImageryLayer, ImageryProvider, ImageryState, - pollToPromise) { + pollToPromise, + isImageOrImageBitmap) { 'use strict'; + var supportsImageBitmapOptions; + beforeAll(function() { + // This suite spies on requests. Resource.supportsImageBitmapOptions needs to make a request to a data URI. + // We run it here to avoid interfering with the tests. + return Resource.supportsImageBitmapOptions() + .then(function(result) { + supportsImageBitmapOptions = result; + }); + }); + afterEach(function() { Resource._Implementations.createImage = Resource._DefaultImplementations.createImage; Resource._Implementations.loadWithXhr = Resource._DefaultImplementations.loadWithXhr; @@ -172,8 +184,8 @@ defineSuite([ expect(provider.credit).toBeInstanceOf(Object); Resource._Implementations.createImage = function(url, crossOrigin, deferred) { - if (/^blob:/.test(url)) { - // load blob url normally + if (/^blob:/.test(url) || supportsImageBitmapOptions) { + // If ImageBitmap is supported, we expect a loadWithXhr request to fetch it as a blob. Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else { expect(url).toEqual('http://example.invalid/query?request=ImageryMaps&channel=1234&version=1&x=0&y=0&z=1'); @@ -191,7 +203,7 @@ defineSuite([ }; return provider.requestImage(0, 0, 0).then(function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -290,8 +302,8 @@ defineSuite([ }); Resource._Implementations.createImage = function(url, crossOrigin, deferred) { - if (/^blob:/.test(url)) { - // load blob url normally + if (/^blob:/.test(url) || supportsImageBitmapOptions) { + // If ImageBitmap is supported, we expect a loadWithXhr request to fetch it as a blob. Resource._DefaultImplementations.createImage(url, crossOrigin, deferred); } else if (tries === 2) { // Succeed after 2 tries @@ -327,7 +339,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/MapboxImageryProviderSpec.js b/Specs/Scene/MapboxImageryProviderSpec.js index f5800da3d40f..25e854bc4b62 100644 --- a/Specs/Scene/MapboxImageryProviderSpec.js +++ b/Specs/Scene/MapboxImageryProviderSpec.js @@ -10,7 +10,8 @@ defineSuite([ 'Scene/ImageryLayer', 'Scene/ImageryProvider', 'Scene/ImageryState', - 'Specs/pollToPromise' + 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap' ], function( MapboxImageryProvider, DefaultProxy, @@ -23,7 +24,8 @@ defineSuite([ ImageryLayer, ImageryProvider, ImageryState, - pollToPromise) { + pollToPromise, + isImageOrImageBitmap) { 'use strict'; beforeEach(function() { @@ -103,7 +105,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -126,7 +128,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -155,7 +157,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -187,7 +189,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -271,7 +273,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/SingleTileImageryProviderSpec.js b/Specs/Scene/SingleTileImageryProviderSpec.js index bd060548b22a..62fba1eca3a1 100644 --- a/Specs/Scene/SingleTileImageryProviderSpec.js +++ b/Specs/Scene/SingleTileImageryProviderSpec.js @@ -10,6 +10,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/when' ], function( SingleTileImageryProvider, @@ -23,6 +24,7 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, when) { 'use strict'; @@ -150,7 +152,7 @@ defineSuite([ return provider.ready; }).then(function() { return when(provider.requestImage(0, 0, 0), function(image) { - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -216,7 +218,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/TextureAtlasSpec.js b/Specs/Scene/TextureAtlasSpec.js index def26465a7ef..b22948eb0096 100644 --- a/Specs/Scene/TextureAtlasSpec.js +++ b/Specs/Scene/TextureAtlasSpec.js @@ -2,6 +2,7 @@ defineSuite([ 'Scene/TextureAtlas', 'Core/BoundingRectangle', 'Core/Cartesian2', + 'Core/createGuid', 'Core/Math', 'Core/PixelFormat', 'Core/Resource', @@ -11,6 +12,7 @@ defineSuite([ TextureAtlas, BoundingRectangle, Cartesian2, + createGuid, CesiumMath, PixelFormat, Resource, @@ -27,27 +29,40 @@ defineSuite([ var bigBlueImage; var bigGreenImage; + var greenGuid; + var tallGreenGuid; + var blueGuid; + var bigRedGuid; + var bigBlueGuid; + var bigGreenGuid; + beforeAll(function() { scene = createScene(); return when.join( Resource.fetchImage('./Data/Images/Green.png').then(function(image) { greenImage = image; + greenGuid = createGuid(); }), Resource.fetchImage('./Data/Images/Green1x4.png').then(function(image) { tallGreenImage = image; + tallGreenGuid = createGuid(); }), Resource.fetchImage('./Data/Images/Blue.png').then(function(image) { blueImage = image; + blueGuid = createGuid(); }), Resource.fetchImage('./Data/Images/Red16x16.png').then(function(image) { bigRedImage = image; + bigRedGuid = createGuid(); }), Resource.fetchImage('./Data/Images/Blue10x10.png').then(function(image) { bigBlueImage = image; + bigBlueGuid = createGuid(); }), Resource.fetchImage('./Data/Images/Green4x4.png').then(function(image) { bigGreenImage = image; + bigGreenGuid = createGuid(); })); }); @@ -87,7 +102,7 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - return atlas.addImage(greenImage.src, greenImage).then(function(index) { + return atlas.addImage(greenGuid, greenImage).then(function(index) { expect(index).toEqual(0); expect(atlas.numberOfImages).toEqual(1); @@ -115,7 +130,7 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - return atlas.addImage(greenImage.src, greenImage).then(function(index) { + return atlas.addImage(greenGuid, greenImage).then(function(index) { var texture = atlas.texture; var coords = atlas.textureCoordinates[index]; @@ -128,7 +143,7 @@ defineSuite([ context : scene.context }); - return atlas.addImage(greenImage.src, greenImage).then(function(index) { + return atlas.addImage(greenGuid, greenImage).then(function(index) { expect(index).toEqual(0); expect(atlas.numberOfImages).toEqual(1); @@ -155,7 +170,7 @@ defineSuite([ context : scene.context }); - return atlas.addImage(greenImage.src, greenImage).then(function(index) { + return atlas.addImage(greenGuid, greenImage).then(function(index) { var texture = atlas.texture; var coords = atlas.textureCoordinates[index]; @@ -170,7 +185,7 @@ defineSuite([ initialSize : new Cartesian2(1.0, 5.0) }); - return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) { + return atlas.addImage(tallGreenGuid, tallGreenImage).then(function(index) { expect(index).toEqual(0); expect(atlas.numberOfImages).toEqual(1); @@ -197,7 +212,7 @@ defineSuite([ initialSize : new Cartesian2(1.0, 5.0) }); - return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) { + return atlas.addImage(tallGreenGuid, tallGreenImage).then(function(index) { var texture = atlas.texture; var coords = atlas.textureCoordinates[index]; @@ -213,8 +228,8 @@ defineSuite([ }); var promises = []; - promises.push(atlas.addImage(greenImage.src, greenImage)); - promises.push(atlas.addImage(blueImage.src, blueImage)); + promises.push(atlas.addImage(greenGuid, greenImage)); + promises.push(atlas.addImage(blueGuid, blueImage)); return when.all(promises, function(indices) { var greenIndex = indices[0]; @@ -250,8 +265,8 @@ defineSuite([ }); var promises = []; - promises.push(atlas.addImage(greenImage.src, greenImage)); - promises.push(atlas.addImage(blueImage.src, blueImage)); + promises.push(atlas.addImage(greenGuid, greenImage)); + promises.push(atlas.addImage(blueGuid, blueImage)); return when.all(promises, function(indices) { var greenIndex = indices[0]; @@ -274,10 +289,10 @@ defineSuite([ }); var promises = []; - promises.push(atlas.addImage(greenImage.src, greenImage)); - promises.push(atlas.addImage(blueImage.src, blueImage)); - promises.push(atlas.addImage(bigRedImage.src, bigRedImage)); - promises.push(atlas.addImage(bigBlueImage.src, bigBlueImage)); + promises.push(atlas.addImage(greenGuid, greenImage)); + promises.push(atlas.addImage(blueGuid, blueImage)); + promises.push(atlas.addImage(bigRedGuid, bigRedImage)); + promises.push(atlas.addImage(bigBlueGuid, bigBlueImage)); return when.all(promises, function(indices) { var greenIndex = indices.shift(); @@ -307,10 +322,10 @@ defineSuite([ }); var promises = []; - promises.push(atlas.addImage(greenImage.src, greenImage)); - promises.push(atlas.addImage(blueImage.src, blueImage)); - promises.push(atlas.addImage(bigRedImage.src, bigRedImage)); - promises.push(atlas.addImage(bigBlueImage.src, bigBlueImage)); + promises.push(atlas.addImage(greenGuid, greenImage)); + promises.push(atlas.addImage(blueGuid, blueImage)); + promises.push(atlas.addImage(bigRedGuid, bigRedImage)); + promises.push(atlas.addImage(bigBlueGuid, bigBlueImage)); return when.all(promises, function(indices) { var greenIndex = indices.shift(); @@ -361,10 +376,10 @@ defineSuite([ }); var promises = []; - promises.push(atlas.addImage(greenImage.src, greenImage)); - promises.push(atlas.addImage(blueImage.src, blueImage)); - promises.push(atlas.addImage(bigRedImage.src, bigRedImage)); - promises.push(atlas.addImage(bigBlueImage.src, bigBlueImage)); + promises.push(atlas.addImage(greenGuid, greenImage)); + promises.push(atlas.addImage(blueGuid, blueImage)); + promises.push(atlas.addImage(bigRedGuid, bigRedImage)); + promises.push(atlas.addImage(bigBlueGuid, bigBlueImage)); return when.all(promises, function(indices) { var greenIndex = indices.shift(); @@ -394,7 +409,7 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) { + return atlas.addImage(blueGuid, blueImage).then(function(blueIndex) { expect(atlas.numberOfImages).toEqual(1); var texture = atlas.texture; @@ -412,7 +427,7 @@ defineSuite([ expect(coordinates[blueIndex].height).toEqual(1.0 / atlasHeight); //Add the big green image - return atlas.addImage(bigGreenImage.src, bigGreenImage).then(function(greenIndex) { + return atlas.addImage(bigGreenGuid, bigGreenImage).then(function(greenIndex) { expect(atlas.numberOfImages).toEqual(2); var texture = atlas.texture; @@ -445,7 +460,7 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) { + return atlas.addImage(blueGuid, blueImage).then(function(blueIndex) { expect(atlas.numberOfImages).toEqual(1); var texture = atlas.texture; @@ -454,7 +469,7 @@ defineSuite([ var blueCoords = coordinates[blueIndex]; expectToRender(texture, blueCoords, [0, 0, 255, 255]); - return atlas.addImage(bigGreenImage.src, bigGreenImage).then(function(greenIndex) { + return atlas.addImage(bigGreenGuid, bigGreenImage).then(function(greenIndex) { expect(atlas.numberOfImages).toEqual(2); var texture = atlas.texture; @@ -476,7 +491,7 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - return atlas.addImage(bigRedImage.src, bigRedImage).then(function(index) { + return atlas.addImage(bigRedGuid, bigRedImage).then(function(index) { expect(atlas.numberOfImages).toEqual(1); var texture = atlas.texture; @@ -501,7 +516,7 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - return atlas.addImage(bigRedImage.src, bigRedImage).then(function(index) { + return atlas.addImage(bigRedGuid, bigRedImage).then(function(index) { var texture = atlas.texture; var coords = atlas.textureCoordinates[index]; @@ -516,8 +531,8 @@ defineSuite([ initialSize : new Cartesian2(2, 2) }); - var greenPromise = atlas.addImage(greenImage.src, greenImage); - var bluePromise = atlas.addImage(blueImage.src, blueImage); + var greenPromise = atlas.addImage(greenGuid, greenImage); + var bluePromise = atlas.addImage(blueGuid, blueImage); return when.all([greenPromise, bluePromise], function(indices) { var greenIndex = indices.shift(); @@ -552,8 +567,8 @@ defineSuite([ initialSize : new Cartesian2(2, 2) }); - var greenPromise = atlas.addImage(greenImage.src, greenImage); - var bluePromise = atlas.addImage(blueImage.src, blueImage); + var greenPromise = atlas.addImage(greenGuid, greenImage); + var bluePromise = atlas.addImage(blueGuid, blueImage); return when.all([greenPromise, bluePromise], function(indices) { var greenIndex = indices.shift(); @@ -577,7 +592,7 @@ defineSuite([ initialSize : new Cartesian2(1.0, 1.0) }); - return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) { + return atlas.addImage(tallGreenGuid, tallGreenImage).then(function(index) { expect(atlas.numberOfImages).toEqual(1); var texture = atlas.texture; @@ -602,7 +617,7 @@ defineSuite([ initialSize : new Cartesian2(1.0, 1.0) }); - return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) { + return atlas.addImage(tallGreenGuid, tallGreenImage).then(function(index) { var texture = atlas.texture; var coords = atlas.textureCoordinates[index]; @@ -617,9 +632,9 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - var bluePromise = atlas.addImage(blueImage.src, blueImage); - var bigGreenPromise = atlas.addImage(bigGreenImage.src, bigGreenImage); - var bigRedPromise = atlas.addImage(bigRedImage.src, bigRedImage); + var bluePromise = atlas.addImage(blueGuid, blueImage); + var bigGreenPromise = atlas.addImage(bigGreenGuid, bigGreenImage); + var bigRedPromise = atlas.addImage(bigRedGuid, bigRedImage); return when.all([bluePromise, bigGreenPromise, bigRedPromise], function(indices) { var blueIndex = indices.shift(); @@ -644,13 +659,13 @@ defineSuite([ initialSize : new Cartesian2(4, 4) }); - return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) { + return atlas.addImage(blueGuid, blueImage).then(function(blueIndex) { expect(blueIndex).toEqual(0); - return atlas.addImage(greenImage.src, greenImage).then(function(greenIndex) { + return atlas.addImage(greenGuid, greenImage).then(function(greenIndex) { expect(greenIndex).toEqual(1); - return atlas.addImage(blueImage.src, blueImage).then(function(index) { + return atlas.addImage(blueGuid, blueImage).then(function(index) { expect(index).toEqual(blueIndex); expect(atlas.numberOfImages).toEqual(2); @@ -675,12 +690,12 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - atlas.addImage(greenImage.src, greenImage); + atlas.addImage(greenGuid, greenImage); - var promise1 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)); - var promise2 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.5, 0.5, 0.5)); - var promise3 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.0, 0.5, 0.5)); - var promise4 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.5, 0.5, 0.5)); + var promise1 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)); + var promise2 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.0, 0.5, 0.5, 0.5)); + var promise3 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.5, 0.0, 0.5, 0.5)); + var promise4 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.5, 0.5, 0.5, 0.5)); return when.all([promise1, promise2, promise3, promise4], function(indices) { var index1 = indices.shift(); @@ -723,12 +738,12 @@ defineSuite([ initialSize : new Cartesian2(1, 1) }); - atlas.addImage(greenImage.src, greenImage); + atlas.addImage(greenGuid, greenImage); - var promise1 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)); - var promise2 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.5, 0.5, 0.5)); - var promise3 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.0, 0.5, 0.5)); - var promise4 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.5, 0.5, 0.5)); + var promise1 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)); + var promise2 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.0, 0.5, 0.5, 0.5)); + var promise3 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.5, 0.0, 0.5, 0.5)); + var promise4 = atlas.addSubRegion(greenGuid, new BoundingRectangle(0.5, 0.5, 0.5, 0.5)); return when.all([promise1, promise2, promise3, promise4], function(indices) { var index1 = indices.shift(); @@ -738,7 +753,7 @@ defineSuite([ expect(atlas.numberOfImages).toEqual(5); - return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) { + return atlas.addImage(blueGuid, blueImage).then(function(blueIndex) { expect(atlas.numberOfImages).toEqual(6); var coordinates = atlas.textureCoordinates; @@ -819,11 +834,11 @@ defineSuite([ var guid1 = atlas.guid; - return atlas.addImage(greenImage.src, greenImage).then(function(index) { + return atlas.addImage(greenGuid, greenImage).then(function(index) { var guid2 = atlas.guid; expect(guid1).not.toEqual(guid2); - return atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)).then(function(index) { + return atlas.addSubRegion(greenGuid, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)).then(function(index) { var guid3 = atlas.guid; expect(guid2).not.toEqual(guid3); }); diff --git a/Specs/Scene/UrlTemplateImageryProviderSpec.js b/Specs/Scene/UrlTemplateImageryProviderSpec.js index 24070350b008..0c33d8305d47 100644 --- a/Specs/Scene/UrlTemplateImageryProviderSpec.js +++ b/Specs/Scene/UrlTemplateImageryProviderSpec.js @@ -15,6 +15,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/when' ], function( UrlTemplateImageryProvider, @@ -33,6 +34,7 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, when) { 'use strict'; @@ -117,7 +119,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -164,7 +166,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -226,7 +228,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); @@ -252,7 +254,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -281,7 +283,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -310,7 +312,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -339,7 +341,7 @@ defineSuite([ return provider.requestImage(12, 10, 5).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -362,7 +364,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -385,7 +387,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -408,7 +410,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -431,7 +433,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -454,7 +456,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -476,7 +478,7 @@ defineSuite([ return provider.requestImage(3, 0, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -498,7 +500,7 @@ defineSuite([ return provider.requestImage(0, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -520,7 +522,7 @@ defineSuite([ return provider.requestImage(1, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -550,7 +552,7 @@ defineSuite([ return provider.requestImage(1, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -572,7 +574,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -595,7 +597,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -618,7 +620,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -646,7 +648,7 @@ defineSuite([ return provider.requestImage(3, 1, 2).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); diff --git a/Specs/Scene/WebMapServiceImageryProviderSpec.js b/Specs/Scene/WebMapServiceImageryProviderSpec.js index 887388d89fa2..d2b6312d2d8f 100644 --- a/Specs/Scene/WebMapServiceImageryProviderSpec.js +++ b/Specs/Scene/WebMapServiceImageryProviderSpec.js @@ -23,6 +23,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/Uri' ], function( WebMapServiceImageryProvider, @@ -49,6 +50,7 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, Uri) { 'use strict'; @@ -412,7 +414,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -452,7 +454,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -495,7 +497,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -535,7 +537,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -578,7 +580,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -621,7 +623,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -664,7 +666,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -822,7 +824,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/WebMapTileServiceImageryProviderSpec.js b/Specs/Scene/WebMapTileServiceImageryProviderSpec.js index 0eb664879f7b..cdff245bf81d 100644 --- a/Specs/Scene/WebMapTileServiceImageryProviderSpec.js +++ b/Specs/Scene/WebMapTileServiceImageryProviderSpec.js @@ -19,6 +19,7 @@ defineSuite([ 'Scene/ImageryProvider', 'Scene/ImageryState', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/Uri' ], function( WebMapTileServiceImageryProvider, @@ -41,6 +42,7 @@ defineSuite([ ImageryProvider, ImageryState, pollToPromise, + isImageOrImageBitmap, Uri) { 'use strict'; @@ -364,7 +366,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -414,7 +416,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/createOpenStreetMapImageryProviderSpec.js b/Specs/Scene/createOpenStreetMapImageryProviderSpec.js index 86064b000f57..e097ceff92d2 100644 --- a/Specs/Scene/createOpenStreetMapImageryProviderSpec.js +++ b/Specs/Scene/createOpenStreetMapImageryProviderSpec.js @@ -10,7 +10,8 @@ defineSuite([ 'Scene/ImageryLayer', 'Scene/ImageryState', 'Scene/UrlTemplateImageryProvider', - 'Specs/pollToPromise' + 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap' ], function( createOpenStreetMapImageryProvider, DefaultProxy, @@ -23,7 +24,8 @@ defineSuite([ ImageryLayer, ImageryState, UrlTemplateImageryProvider, - pollToPromise) { + pollToPromise, + isImageOrImageBitmap) { 'use strict'; beforeEach(function() { @@ -72,7 +74,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -94,7 +96,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -116,7 +118,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -144,7 +146,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -193,7 +195,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -256,7 +258,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/Scene/createTileMapServiceImageryProviderSpec.js b/Specs/Scene/createTileMapServiceImageryProviderSpec.js index f68f4651d4d2..e813f76e3f2b 100644 --- a/Specs/Scene/createTileMapServiceImageryProviderSpec.js +++ b/Specs/Scene/createTileMapServiceImageryProviderSpec.js @@ -17,6 +17,7 @@ defineSuite([ 'Scene/ImageryState', 'Scene/UrlTemplateImageryProvider', 'Specs/pollToPromise', + 'Specs/isImageOrImageBitmap', 'ThirdParty/when' ], function( createTileMapServiceImageryProvider, @@ -37,6 +38,7 @@ defineSuite([ ImageryState, UrlTemplateImageryProvider, pollToPromise, + isImageOrImageBitmap, when) { 'use strict'; @@ -215,7 +217,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -237,7 +239,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -260,7 +262,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -287,7 +289,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -362,7 +364,7 @@ defineSuite([ return provider.requestImage(0, 0, 0).then(function(image) { expect(Resource._Implementations.createImage).toHaveBeenCalled(); - expect(image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(image)).toBe(true); }); }); }); @@ -422,7 +424,7 @@ defineSuite([ return pollToPromise(function() { return imagery.state === ImageryState.RECEIVED; }).then(function() { - expect(imagery.image).toBeInstanceOf(Image); + expect(isImageOrImageBitmap(imagery.image)).toBe(true); expect(tries).toEqual(2); imagery.releaseReference(); }); diff --git a/Specs/isImageOrImageBitmap.js b/Specs/isImageOrImageBitmap.js new file mode 100644 index 000000000000..bc1cdd86f024 --- /dev/null +++ b/Specs/isImageOrImageBitmap.js @@ -0,0 +1,22 @@ +define([ + 'Core/FeatureDetection', + 'Core/Resource' + ], function( + FeatureDetection, + Resource) { + 'use strict'; + + function isImageOrImageBitmap(image) { + // Many ImageryProvider specs will test if the requested image + // succeeded by checking its instance. Since this may be an Image + // or ImageBitmap, we abstract this check here. + var isImageBitmap = false; + if (typeof createImageBitmap === 'function') { + isImageBitmap = image instanceof ImageBitmap; + } + + return isImageBitmap || image instanceof Image; + } + + return isImageOrImageBitmap; +});