From e88ecae897dbe766a68d89fe8e98d30cba449daf Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 11 Dec 2018 13:48:46 -0500 Subject: [PATCH 1/5] fix #7671 by avoiding incomplete webp support in Edge 18 --- src/util/browser.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/util/browser.js b/src/util/browser.js index 2ea3570a851..4d7ae90b2c8 100755 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -58,9 +58,31 @@ const exported = { export default exported; if (window.document) { + testWebp(); +} + +function testWebp() { const webpImgTest = window.document.createElement('img'); webpImgTest.onload = function() { - exported.supportsWebp = true; + + // Edge 18 supports WebP but not uploading a WebP image to a gl texture + // Test support for this before allowing WebP images. + // https://github.com/mapbox/mapbox-gl-js/issues/7671 + const canvas = window.document.createElement('canvas'); + const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + + try { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, webpImgTest); + exported.supportsWebp = true; + } catch (e) { + // Catch "Unspecified Error." in Edge 18. + } + + gl.deleteTexture(texture); + const extension = gl.getExtension('WEBGL_lose_context'); + if (extension) extension.loseContext(); }; webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; } From ecb64911f43a11adaf6caed7d1bb1c31673ae0aa Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 11 Dec 2018 15:52:31 -0500 Subject: [PATCH 2/5] version 2 --- src/ui/map.js | 3 +++ src/util/browser.js | 30 ------------------------- src/util/test_webp.js | 52 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 30 deletions(-) create mode 100755 src/util/test_webp.js diff --git a/src/ui/map.js b/src/ui/map.js index 277df72dc83..178cdbe3932 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -25,6 +25,7 @@ import { RGBAImage } from '../util/image'; import { Event, ErrorEvent } from '../util/evented'; import { MapMouseEvent } from './events'; import TaskQueue from '../util/task_queue'; +import testWebp from '../util/test_webp'; import type {PointLike} from '@mapbox/point-geometry'; import type {LngLatLike} from '../geo/lng_lat'; @@ -1539,6 +1540,8 @@ class Map extends Camera { } this.painter = new Painter(gl, this.transform); + + testWebp(gl); } _contextLost(event: *) { diff --git a/src/util/browser.js b/src/util/browser.js index 4d7ae90b2c8..f4ad917e3a5 100755 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -56,33 +56,3 @@ const exported = { }; export default exported; - -if (window.document) { - testWebp(); -} - -function testWebp() { - const webpImgTest = window.document.createElement('img'); - webpImgTest.onload = function() { - - // Edge 18 supports WebP but not uploading a WebP image to a gl texture - // Test support for this before allowing WebP images. - // https://github.com/mapbox/mapbox-gl-js/issues/7671 - const canvas = window.document.createElement('canvas'); - const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - const texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - - try { - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, webpImgTest); - exported.supportsWebp = true; - } catch (e) { - // Catch "Unspecified Error." in Edge 18. - } - - gl.deleteTexture(texture); - const extension = gl.getExtension('WEBGL_lose_context'); - if (extension) extension.loseContext(); - }; - webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; -} diff --git a/src/util/test_webp.js b/src/util/test_webp.js new file mode 100755 index 00000000000..6a899ab1e34 --- /dev/null +++ b/src/util/test_webp.js @@ -0,0 +1,52 @@ +// @flow + +import browser from './browser'; + +let glForTesting; +let webpCheckComplete = false; +let webpImgTest; + +if (window.document) { + webpImgTest = window.document.createElement('img'); + webpImgTest.onload = function() { + if (glForTesting) testWebpTextureUpload(glForTesting); + glForTesting = null; + } + webpImgTest.onerror = function() { + webpCheckComplete = true; + glForTesting = null; + } + webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; +} + +export default testWebp; + +function testWebp(gl: WebGLRenderingContext) { + if (webpCheckComplete || !webpImgTest) return; + + if (!webpImgTest.complete) { + glForTesting = gl; + return; + } + + testWebpTextureUpload(gl); +} + +function testWebpTextureUpload(gl: WebGLRenderingContext) { + // Edge 18 supports WebP but not uploading a WebP image to a gl texture + // Test support for this before allowing WebP images. + // https://github.com/mapbox/mapbox-gl-js/issues/7671 + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + + try { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, webpImgTest); + browser.supportsWebp = true; + } catch (e) { + // Catch "Unspecified Error." in Edge 18. + } + + gl.deleteTexture(texture); + + webpCheckComplete = true; +} From 9c79313804c42a9e7da2db0253d87670acdcbd96 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 11 Dec 2018 16:01:43 -0500 Subject: [PATCH 3/5] fixup --- src/util/test_webp.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/test_webp.js b/src/util/test_webp.js index 6a899ab1e34..177a20c772d 100755 --- a/src/util/test_webp.js +++ b/src/util/test_webp.js @@ -1,5 +1,6 @@ // @flow +import window from './window'; import browser from './browser'; let glForTesting; @@ -11,11 +12,11 @@ if (window.document) { webpImgTest.onload = function() { if (glForTesting) testWebpTextureUpload(glForTesting); glForTesting = null; - } + }; webpImgTest.onerror = function() { webpCheckComplete = true; glForTesting = null; - } + }; webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; } From 9f83861e0dcc3fed2882985b3d6c0060415c83b1 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Wed, 12 Dec 2018 14:50:16 -0500 Subject: [PATCH 4/5] move webp support out of `browser` --- src/ui/map.js | 4 ++-- src/util/browser.js | 3 +-- src/util/mapbox.js | 3 ++- src/util/{test_webp.js => webp_supported.js} | 18 +++++++++++++----- test/unit/util/browser.test.js | 5 ----- test/unit/util/mapbox.test.js | 9 +++++---- 6 files changed, 23 insertions(+), 19 deletions(-) rename src/util/{test_webp.js => webp_supported.js} (81%) diff --git a/src/ui/map.js b/src/ui/map.js index 178cdbe3932..76008dd7369 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -25,7 +25,7 @@ import { RGBAImage } from '../util/image'; import { Event, ErrorEvent } from '../util/evented'; import { MapMouseEvent } from './events'; import TaskQueue from '../util/task_queue'; -import testWebp from '../util/test_webp'; +import webpSupported from '../util/webp_supported'; import type {PointLike} from '@mapbox/point-geometry'; import type {LngLatLike} from '../geo/lng_lat'; @@ -1541,7 +1541,7 @@ class Map extends Camera { this.painter = new Painter(gl, this.transform); - testWebp(gl); + webpSupported.testSupport(gl); } _contextLost(event: *) { diff --git a/src/util/browser.js b/src/util/browser.js index f4ad917e3a5..70036884a76 100755 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -51,8 +51,7 @@ const exported = { }, hardwareConcurrency: window.navigator.hardwareConcurrency || 4, - get devicePixelRatio() { return window.devicePixelRatio; }, - supportsWebp: false + get devicePixelRatio() { return window.devicePixelRatio; } }; export default exported; diff --git a/src/util/mapbox.js b/src/util/mapbox.js index 5c5dccea7c3..14b75347a4a 100644 --- a/src/util/mapbox.js +++ b/src/util/mapbox.js @@ -3,6 +3,7 @@ import config from './config'; import browser from './browser'; +import webpSupported from './webp_supported'; import window from './window'; import { version } from '../../package.json'; import { uuid, validateUuid, storageAvailable, warnOnce, extend } from './util'; @@ -101,7 +102,7 @@ export const normalizeTileURL = function(tileURL: string, sourceURL?: ?string, t // is appended to the tile URL. If `tileSize: 512` is specified for // a Mapbox raster source force the @2x suffix even if a non hidpi device. const suffix = browser.devicePixelRatio >= 2 || tileSize === 512 ? '@2x' : ''; - const extension = browser.supportsWebp ? '.webp' : '$1'; + const extension = webpSupported.supported ? '.webp' : '$1'; urlObject.path = urlObject.path.replace(imageExtensionRe, `${suffix}${extension}`); urlObject.path = `/v4${urlObject.path}`; diff --git a/src/util/test_webp.js b/src/util/webp_supported.js similarity index 81% rename from src/util/test_webp.js rename to src/util/webp_supported.js index 177a20c772d..452bb10a5f9 100755 --- a/src/util/test_webp.js +++ b/src/util/webp_supported.js @@ -1,7 +1,13 @@ // @flow import window from './window'; -import browser from './browser'; + +const exported = { + supported: false, + testSupport +}; + +export default exported; let glForTesting; let webpCheckComplete = false; @@ -20,9 +26,7 @@ if (window.document) { webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA='; } -export default testWebp; - -function testWebp(gl: WebGLRenderingContext) { +function testSupport(gl: WebGLRenderingContext) { if (webpCheckComplete || !webpImgTest) return; if (!webpImgTest.complete) { @@ -42,7 +46,11 @@ function testWebpTextureUpload(gl: WebGLRenderingContext) { try { gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, webpImgTest); - browser.supportsWebp = true; + + // The error does not get triggered in Edge if the context is lost + if (gl.isContextLost()) return; + + exported.supported = true; } catch (e) { // Catch "Unspecified Error." in Edge 18. } diff --git a/test/unit/util/browser.test.js b/test/unit/util/browser.test.js index e520f0d9016..4a65646f225 100644 --- a/test/unit/util/browser.test.js +++ b/test/unit/util/browser.test.js @@ -33,10 +33,5 @@ test('browser', (t) => { t.end(); }); - t.test('supportsWebp', (t) => { - t.equal(typeof browser.supportsWebp, 'boolean'); - t.end(); - }); - t.end(); }); diff --git a/test/unit/util/mapbox.test.js b/test/unit/util/mapbox.test.js index c3b6fc50f88..1b1e382c3dd 100644 --- a/test/unit/util/mapbox.test.js +++ b/test/unit/util/mapbox.test.js @@ -2,6 +2,7 @@ import { test } from 'mapbox-gl-js-test'; import * as mapbox from '../../../src/util/mapbox'; import config from '../../../src/util/config'; import browser from '../../../src/util/browser'; +import webpSupported from '../../../src/util/webp_supported'; import window from '../../../src/util/window'; import { uuid } from '../../../src/util/util'; import { version } from '../../../package.json'; @@ -287,7 +288,7 @@ test("mapbox", (t) => { }); t.test('.normalizeTileURL', (t) => { - browser.supportsWebp = false; + webpSupported.supported = false; t.test('does nothing on 1x devices', (t) => { config.API_URL = 'http://path.png'; @@ -321,14 +322,14 @@ test("mapbox", (t) => { }); t.test('replaces img extension with webp on supporting devices', (t) => { - browser.supportsWebp = true; + webpSupported.supported = true; config.API_URL = 'http://path.png'; config.REQUIRE_ACCESS_TOKEN = false; t.equal(mapbox.normalizeTileURL('http://path.png/tile.png', mapboxSource), 'http://path.png/v4/tile.webp'); t.equal(mapbox.normalizeTileURL('http://path.png/tile.png32', mapboxSource), 'http://path.png/v4/tile.webp'); t.equal(mapbox.normalizeTileURL('http://path.png/tile.jpg70', mapboxSource), 'http://path.png/v4/tile.webp'); t.equal(mapbox.normalizeTileURL('http://path.png/tile.png?access_token=foo', mapboxSource), 'http://path.png/v4/tile.webp?access_token=foo'); - browser.supportsWebp = false; + webpSupported.supported = false; t.end(); }); @@ -372,7 +373,7 @@ test("mapbox", (t) => { t.end(); }); - browser.supportsWebp = true; + webpSupported.supported = true; t.end(); }); From 307d1ef62f9aba9c50f5b4603249e2a198fc814e Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Wed, 12 Dec 2018 14:57:47 -0500 Subject: [PATCH 5/5] lint --- test/unit/util/mapbox.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/util/mapbox.test.js b/test/unit/util/mapbox.test.js index 1b1e382c3dd..25480485395 100644 --- a/test/unit/util/mapbox.test.js +++ b/test/unit/util/mapbox.test.js @@ -1,7 +1,6 @@ import { test } from 'mapbox-gl-js-test'; import * as mapbox from '../../../src/util/mapbox'; import config from '../../../src/util/config'; -import browser from '../../../src/util/browser'; import webpSupported from '../../../src/util/webp_supported'; import window from '../../../src/util/window'; import { uuid } from '../../../src/util/util';