Skip to content

Commit f883001

Browse files
authored
Fix regression of ImageBitmap in Safari (#325)
* Fixes #324 - regression of ImageBitmap * Fixed according to code review changes, cleaned a bit. * bump version for pre-release to pre.3
1 parent ce51f14 commit f883001

File tree

8 files changed

+31
-165
lines changed

8 files changed

+31
-165
lines changed

package-lock.json

Lines changed: 1 addition & 137 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "maplibre-gl",
33
"description": "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library",
4-
"version": "2.0.0-pre.2",
4+
"version": "2.0.0-pre.3",
55
"main": "dist/maplibre-gl.js",
66
"style": "dist/maplibre-gl.css",
77
"license": "BSD-3-Clause",

src/render/texture.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type Context from '../gl/context';
22
import type {RGBAImage, AlphaImage} from '../util/image';
3+
import {isImageBitmap} from '../util/util';
34

45
export type TextureFormat = WebGLRenderingContext['RGBA'] | WebGLRenderingContext['ALPHA'];
56
export type TextureFilter = WebGLRenderingContext['LINEAR'] | WebGLRenderingContext['LINEAR_MIPMAP_NEAREST'] | WebGLRenderingContext['NEAREST'];
@@ -12,7 +13,7 @@ type EmptyImage = {
1213
};
1314

1415
type DataTextureImage = RGBAImage | AlphaImage | EmptyImage;
15-
export type TextureImage = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageData | ImageBitmap | DataTextureImage;
16+
export type TextureImage = TexImageSource | DataTextureImage;
1617

1718
class Texture {
1819
context: Context;
@@ -55,15 +56,15 @@ class Texture {
5556
if (resize) {
5657
this.size = [width, height];
5758

58-
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || (ImageBitmap && image instanceof ImageBitmap)) {
59+
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || isImageBitmap(image)) {
5960
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, gl.UNSIGNED_BYTE, image);
6061
} else {
6162
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, gl.UNSIGNED_BYTE, (image as DataTextureImage).data);
6263
}
6364

6465
} else {
6566
const {x, y} = position || {x: 0, y: 0};
66-
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || (ImageBitmap && image instanceof ImageBitmap)) {
67+
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || isImageBitmap(image)) {
6768
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, image);
6869
} else {
6970
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, (image as DataTextureImage).data);

src/source/raster_dem_tile_source.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {getImage, ResourceType} from '../util/ajax';
2-
import {extend} from '../util/util';
2+
import {extend, isImageBitmap} from '../util/util';
33
import {Evented} from '../util/evented';
44
import browser from '../util/browser';
55
import offscreenCanvasSupported from '../util/offscreen_canvas_supported';
@@ -53,7 +53,7 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
5353
if (this.map._refreshExpiredTiles) tile.setExpiryData(img);
5454
delete (img as any).cacheControl;
5555
delete (img as any).expires;
56-
const transfer = ImageBitmap && img instanceof ImageBitmap && offscreenCanvasSupported();
56+
const transfer = isImageBitmap(img) && offscreenCanvasSupported();
5757
const rawImageData = transfer ? img : browser.getImageData(img, 1);
5858
const params = {
5959
uid: tile.uid,

src/source/raster_dem_tile_worker_source.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
WorkerDEMTileCallback,
88
TileParameters
99
} from './worker_source';
10+
import {isImageBitmap} from '../util/util';
1011

1112
class RasterDEMTileWorkerSource {
1213
actor: Actor;
@@ -21,7 +22,7 @@ class RasterDEMTileWorkerSource {
2122
loadTile(params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) {
2223
const {uid, encoding, rawImageData} = params;
2324
// Main thread will transfer ImageBitmap if offscreen decode with OffscreenCanvas is supported, else it will transfer an already decoded image.
24-
const imagePixels = (ImageBitmap && rawImageData instanceof ImageBitmap) ? this.getImageData(rawImageData) : rawImageData as RGBAImage;
25+
const imagePixels = isImageBitmap(rawImageData) ? this.getImageData(rawImageData) : rawImageData as RGBAImage;
2526
const dem = new DEMData(uid, imagePixels, encoding);
2627
this.loaded = this.loaded || {};
2728
this.loaded[uid] = dem;

src/ui/map.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {extend, bindAll, warnOnce, uniqueId} from '../util/util';
1+
import {extend, bindAll, warnOnce, uniqueId, isImageBitmap} from '../util/util';
22
import browser from '../util/browser';
33
import DOM from '../util/dom';
44
import {getImage, getJSON, ResourceType} from '../util/ajax';
@@ -1662,8 +1662,8 @@ class Map extends Camera {
16621662
this._lazyInitEmptyStyle();
16631663
const version = 0;
16641664

1665-
if (image instanceof HTMLImageElement || (ImageBitmap && image instanceof ImageBitmap)) {
1666-
const {width, height, data} = browser.getImageData(image as HTMLImageElement | ImageBitmap);
1665+
if (image instanceof HTMLImageElement || isImageBitmap(image)) {
1666+
const {width, height, data} = browser.getImageData(image);
16671667
this.style.addImage(id, {data: new RGBAImage({width, height}, data), pixelRatio, stretchX, stretchY, content, sdf, version});
16681668
} else if (image.width === undefined || image.height === undefined) {
16691669
return this.fire(new ErrorEvent(new Error(
@@ -1720,9 +1720,9 @@ class Map extends Camera {
17201720
return this.fire(new ErrorEvent(new Error(
17211721
'The map has no image with that id. If you are adding a new image use `map.addImage(...)` instead.')));
17221722
}
1723-
const imageData = (image instanceof HTMLImageElement || (ImageBitmap && image instanceof ImageBitmap)) ?
1724-
browser.getImageData(image as HTMLImageElement | ImageBitmap) :
1725-
image as ImageData;
1723+
const imageData = (image instanceof HTMLImageElement || isImageBitmap(image)) ?
1724+
browser.getImageData(image) :
1725+
image;
17261726
const {width, height, data} = imageData;
17271727

17281728
if (width === undefined || height === undefined) {
@@ -1736,7 +1736,7 @@ class Map extends Camera {
17361736
'The width and height of the updated image must be that same as the previous version of the image')));
17371737
}
17381738

1739-
const copy = !(image instanceof HTMLImageElement || (ImageBitmap && image instanceof ImageBitmap));
1739+
const copy = !(image instanceof HTMLImageElement || isImageBitmap(image));
17401740
existingImage.data.replace(data, copy);
17411741

17421742
this.style.updateImage(id, existingImage);

src/util/util.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,7 @@ export function b64DecodeUnicode(str: string) {
500500
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); //eslint-disable-line
501501
}).join(''));
502502
}
503+
504+
export function isImageBitmap(image: any): image is ImageBitmap {
505+
return typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap;
506+
}

src/util/web_worker_transfer.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import expressions from '../style-spec/expression/definitions';
88
import ResolvedImage from '../style-spec/expression/types/resolved_image';
99

1010
import type {Transferable} from '../types/transferable';
11+
import {isImageBitmap} from './util';
1112

1213
type SerializedObject = {
1314
[_: string]: Serialized;
1415
}; // eslint-disable-line
1516

16-
export type Serialized = null | void | boolean | number | string | Boolean | Number | String | Date | RegExp | ArrayBuffer | ArrayBufferView | ImageData | Array<Serialized> | SerializedObject;
17+
export type Serialized = null | void | boolean | number | string | Boolean | Number | String | Date | RegExp | ArrayBuffer | ArrayBufferView | ImageData | ImageBitmap | Array<Serialized> | SerializedObject;
1718

1819
type Registry = {
1920
[_: string]: {
@@ -95,14 +96,9 @@ for (const name in expressions) {
9596
register(`Expression_${name}`, expressions[name]);
9697
}
9798

98-
function isArrayBuffer(val: any): boolean {
99-
return val && typeof ArrayBuffer !== 'undefined' &&
100-
(val instanceof ArrayBuffer || (val.constructor && val.constructor.name === 'ArrayBuffer'));
101-
}
102-
103-
function isImageBitmap(val: any): boolean {
104-
return ImageBitmap &&
105-
val instanceof ImageBitmap;
99+
function isArrayBuffer(value: any): value is ArrayBuffer {
100+
return value && typeof ArrayBuffer !== 'undefined' &&
101+
(value instanceof ArrayBuffer || (value.constructor && value.constructor.name === 'ArrayBuffer'));
106102
}
107103

108104
/**
@@ -135,24 +131,24 @@ export function serialize(input: unknown, transferables?: Array<Transferable> |
135131

136132
if (isArrayBuffer(input)) {
137133
if (transferables) {
138-
transferables.push(((input as any as ArrayBuffer)));
134+
transferables.push(input);
139135
}
140-
return input as Serialized;
136+
return input;
141137
}
142138

143139
if (isImageBitmap(input)) {
144140
if (transferables) {
145-
transferables.push(((input as any as ImageBitmap)));
141+
transferables.push(input);
146142
}
147-
return input as Serialized;
143+
return input;
148144
}
149145

150146
if (ArrayBuffer.isView(input)) {
151147
const view = input;
152148
if (transferables) {
153149
transferables.push(view.buffer);
154150
}
155-
return view as Serialized;
151+
return view;
156152
}
157153

158154
if (input instanceof ImageData) {

0 commit comments

Comments
 (0)