Skip to content

Commit

Permalink
Fix regression of ImageBitmap in Safari (#325)
Browse files Browse the repository at this point in the history
* Fixes #324 - regression of ImageBitmap

* Fixed according to code review changes, cleaned a bit.

* bump version for pre-release to pre.3
  • Loading branch information
HarelM authored Sep 10, 2021
1 parent ce51f14 commit f883001
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 165 deletions.
138 changes: 1 addition & 137 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "maplibre-gl",
"description": "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library",
"version": "2.0.0-pre.2",
"version": "2.0.0-pre.3",
"main": "dist/maplibre-gl.js",
"style": "dist/maplibre-gl.css",
"license": "BSD-3-Clause",
Expand Down
7 changes: 4 additions & 3 deletions src/render/texture.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type Context from '../gl/context';
import type {RGBAImage, AlphaImage} from '../util/image';
import {isImageBitmap} from '../util/util';

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

type DataTextureImage = RGBAImage | AlphaImage | EmptyImage;
export type TextureImage = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageData | ImageBitmap | DataTextureImage;
export type TextureImage = TexImageSource | DataTextureImage;

class Texture {
context: Context;
Expand Down Expand Up @@ -55,15 +56,15 @@ class Texture {
if (resize) {
this.size = [width, height];

if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || (ImageBitmap && image instanceof ImageBitmap)) {
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || isImageBitmap(image)) {
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, gl.UNSIGNED_BYTE, image);
} else {
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, gl.UNSIGNED_BYTE, (image as DataTextureImage).data);
}

} else {
const {x, y} = position || {x: 0, y: 0};
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || (ImageBitmap && image instanceof ImageBitmap)) {
if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || isImageBitmap(image)) {
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, image);
} else {
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, (image as DataTextureImage).data);
Expand Down
4 changes: 2 additions & 2 deletions src/source/raster_dem_tile_source.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {getImage, ResourceType} from '../util/ajax';
import {extend} from '../util/util';
import {extend, isImageBitmap} from '../util/util';
import {Evented} from '../util/evented';
import browser from '../util/browser';
import offscreenCanvasSupported from '../util/offscreen_canvas_supported';
Expand Down Expand Up @@ -53,7 +53,7 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
if (this.map._refreshExpiredTiles) tile.setExpiryData(img);
delete (img as any).cacheControl;
delete (img as any).expires;
const transfer = ImageBitmap && img instanceof ImageBitmap && offscreenCanvasSupported();
const transfer = isImageBitmap(img) && offscreenCanvasSupported();
const rawImageData = transfer ? img : browser.getImageData(img, 1);
const params = {
uid: tile.uid,
Expand Down
3 changes: 2 additions & 1 deletion src/source/raster_dem_tile_worker_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
WorkerDEMTileCallback,
TileParameters
} from './worker_source';
import {isImageBitmap} from '../util/util';

class RasterDEMTileWorkerSource {
actor: Actor;
Expand All @@ -21,7 +22,7 @@ class RasterDEMTileWorkerSource {
loadTile(params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) {
const {uid, encoding, rawImageData} = params;
// Main thread will transfer ImageBitmap if offscreen decode with OffscreenCanvas is supported, else it will transfer an already decoded image.
const imagePixels = (ImageBitmap && rawImageData instanceof ImageBitmap) ? this.getImageData(rawImageData) : rawImageData as RGBAImage;
const imagePixels = isImageBitmap(rawImageData) ? this.getImageData(rawImageData) : rawImageData as RGBAImage;
const dem = new DEMData(uid, imagePixels, encoding);
this.loaded = this.loaded || {};
this.loaded[uid] = dem;
Expand Down
14 changes: 7 additions & 7 deletions src/ui/map.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {extend, bindAll, warnOnce, uniqueId} from '../util/util';
import {extend, bindAll, warnOnce, uniqueId, isImageBitmap} from '../util/util';
import browser from '../util/browser';
import DOM from '../util/dom';
import {getImage, getJSON, ResourceType} from '../util/ajax';
Expand Down Expand Up @@ -1662,8 +1662,8 @@ class Map extends Camera {
this._lazyInitEmptyStyle();
const version = 0;

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

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

const copy = !(image instanceof HTMLImageElement || (ImageBitmap && image instanceof ImageBitmap));
const copy = !(image instanceof HTMLImageElement || isImageBitmap(image));
existingImage.data.replace(data, copy);

this.style.updateImage(id, existingImage);
Expand Down
4 changes: 4 additions & 0 deletions src/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,7 @@ export function b64DecodeUnicode(str: string) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); //eslint-disable-line
}).join(''));
}

export function isImageBitmap(image: any): image is ImageBitmap {
return typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap;
}
24 changes: 10 additions & 14 deletions src/util/web_worker_transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import expressions from '../style-spec/expression/definitions';
import ResolvedImage from '../style-spec/expression/types/resolved_image';

import type {Transferable} from '../types/transferable';
import {isImageBitmap} from './util';

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

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

type Registry = {
[_: string]: {
Expand Down Expand Up @@ -95,14 +96,9 @@ for (const name in expressions) {
register(`Expression_${name}`, expressions[name]);
}

function isArrayBuffer(val: any): boolean {
return val && typeof ArrayBuffer !== 'undefined' &&
(val instanceof ArrayBuffer || (val.constructor && val.constructor.name === 'ArrayBuffer'));
}

function isImageBitmap(val: any): boolean {
return ImageBitmap &&
val instanceof ImageBitmap;
function isArrayBuffer(value: any): value is ArrayBuffer {
return value && typeof ArrayBuffer !== 'undefined' &&
(value instanceof ArrayBuffer || (value.constructor && value.constructor.name === 'ArrayBuffer'));
}

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

if (isArrayBuffer(input)) {
if (transferables) {
transferables.push(((input as any as ArrayBuffer)));
transferables.push(input);
}
return input as Serialized;
return input;
}

if (isImageBitmap(input)) {
if (transferables) {
transferables.push(((input as any as ImageBitmap)));
transferables.push(input);
}
return input as Serialized;
return input;
}

if (ArrayBuffer.isView(input)) {
const view = input;
if (transferables) {
transferables.push(view.buffer);
}
return view as Serialized;
return view;
}

if (input instanceof ImageData) {
Expand Down

0 comments on commit f883001

Please sign in to comment.