diff --git a/src/core/textures/ImageTexture.test.ts b/src/core/textures/ImageTexture.test.ts new file mode 100644 index 0000000..8517d1a --- /dev/null +++ b/src/core/textures/ImageTexture.test.ts @@ -0,0 +1,91 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { ImageTexture } from './ImageTexture.js'; +import type { CoreTextureManager } from '../CoreTextureManager.js'; + +describe('ImageTexture.createImageBitmap', () => { + beforeEach(() => { + vi.stubGlobal('ImageBitmap', class {}); + }); + + it('passes options to createImageBitmap when no crop is requested and options/full are supported', async () => { + const createImageBitmapMock = vi.fn(() => + Promise.resolve({ close: () => {} }), + ); + const txManager = { + imageBitmapSupported: { + basic: true, + options: true, + full: true, + premultiplyHonored: false, + }, + platform: { + createImageBitmap: createImageBitmapMock, + }, + } as unknown as CoreTextureManager; + + const props = ImageTexture.resolveDefaults({ + src: 'test.png', + premultiplyAlpha: true, + }); + const texture = new ImageTexture(txManager, props); + + const blob = new Blob([], { type: 'image/png' }); + const result = await texture.createImageBitmap( + blob, + true, + null, + null, + null, + null, + ); + + // It should have called createImageBitmap with the options object + expect(createImageBitmapMock).toHaveBeenCalledWith(blob, { + premultiplyAlpha: 'none', + colorSpaceConversion: 'none', + imageOrientation: 'none', + }); + + // Since premultiplyHonored is false, useGlPremultiply should be true + expect(result.premultiplyAlpha).toBe(true); + }); + + it('falls back to basic createImageBitmap when options are not supported', async () => { + const createImageBitmapMock = vi.fn(() => + Promise.resolve({ close: () => {} }), + ); + const txManager = { + imageBitmapSupported: { + basic: true, + options: false, + full: false, + premultiplyHonored: null, + }, + platform: { + createImageBitmap: createImageBitmapMock, + }, + } as unknown as CoreTextureManager; + + const props = ImageTexture.resolveDefaults({ + src: 'test.png', + premultiplyAlpha: true, + }); + const texture = new ImageTexture(txManager, props); + + const blob = new Blob([], { type: 'image/png' }); + const result = await texture.createImageBitmap( + blob, + true, + null, + null, + null, + null, + ); + + // It should have called basic createImageBitmap without options + expect(createImageBitmapMock).toHaveBeenCalledWith(blob); + + // And premultiplyAlpha should be false (browser default is assumed to premultiply) + expect(result.premultiplyAlpha).toBe(false); + }); +}); diff --git a/src/core/textures/ImageTexture.ts b/src/core/textures/ImageTexture.ts index a9651cc..a4e824b 100644 --- a/src/core/textures/ImageTexture.ts +++ b/src/core/textures/ImageTexture.ts @@ -219,7 +219,10 @@ export class ImageTexture extends Texture { }, ); return { data: bitmap, premultiplyAlpha: useGlPremultiply }; - } else if (imageBitmapSupported.basic === true) { + } else if ( + imageBitmapSupported.options === false && + imageBitmapSupported.full === false + ) { // basic createImageBitmap without options or crop // this is supported for Chrome v50 to v52/54 that doesn't support options. // The browser default premultiplies, so WebGL must not premultiply again.