From 859b1a7c1d88a111031f3938f1c329604120f1e0 Mon Sep 17 00:00:00 2001 From: Harel M Date: Thu, 23 Nov 2023 11:12:45 +0200 Subject: [PATCH] Async `Actor` and version 4.x first breaking changes (#3233) * Initial concept * More improvements * Fix lint * Main commit to move most of the actor code to use promises and register. There are still things to do. * Fix actor tests * Remove more any when it comes to worker self typings. * Improve more types, add more tests * Improve more types, add more tests * Fix lint * Fix more tests * Fix tests * Fix some sytle tests * Add comment for todo. * Fix test related to message parameters change * Fix remaining tests * Added todo to accomodate for code review. * Fix build test * Fix geojson types * Rename some events, remove clutter a bit * Fix issue with multiple maps found in integration tests * Fix tests and improve types and docs a bit more * Final fixes to make the tests pass * Fix build test * a couple of tweaks (#3267) * Add changelog item * More improvement to async `Actor` and replace more callbacks with promises (#3269) * Improve vector tile source * Fix unit tests * Fix render tests for the case of 404 * Fix lint * Remove unused method * More improvements to remove callbacks and move to promises * Fixed some tests, more fixes are needed. * Fix remaining tests. * Fix lint * Fix tile parser code to pass render tests * Fix lint * Fix lint * More fixes and tests in the infrasturcure when it comes to cancelling * forgot to inclue this... * Fix lint and build * Convert parse to be a proper async method. * Add more test coverate to actor, allow more testing in mock web worker. * Replace getJson call with async code and remove more callbacks (#3273) * Add abort between actors of main thread and worker thread with tests * Fix lint * Fix lint * Fix node from lts to nvmrc * Improve the code of vector tile and geojson workers * Fix lint * Add debug when tests are failing * Do not throw in case of empty geojson tile * Fix lint * Move geojson worker source to be more async like. * Change getJSON to be async extenally * Update src/ui/map.test.ts Co-authored-by: Bart Louwers --------- Co-authored-by: Bart Louwers * Move image queue to use promises, move getArrayBuffer to use promises (#3280) * Migrate getArrayBuffer to be promise based * Remove dead code in ajax.ts file * Code review changes (#3278) Co-authored-by: neodescis * Make image request return promises. * Move process queue to the right location * Increase build size * Last fixes * fix lint warning * Fix lint * update docs Co-authored-by: neodescis * Update docs Co-authored-by: neodescis * Fix docs * Code review comments. * Update src/util/image_request.ts * Update src/util/util.ts --------- Co-authored-by: neodescis Co-authored-by: neodescis * Remove TODOs, tidy up last things (#3301) * Remove some TODOs * Remove some todos, make ajax API fully promise based * Move tileJson to be async * fix lint * Remove another TODO * Move makexmlhttprequest to return a promise * Make load_sprite async * Added relevant tests * Final fixes * Update src/source/vector_tile_source.test.ts Co-authored-by: neodescis --------- Co-authored-by: neodescis * Async actor docs additions (#3305) * Fix missing classes in the docs * Fixed the relevant docs in the places where API calls were changed. * Fix lint * Remove some "then" from tests * remove todos, remove "then"s, simplify the ajax code a bit * Remove as any from where it's not needed * Fix code review expect stuff... * explicit promises instead of array. * Improve ajax further * Improve docs for RTL plugin status and reduce code in geojson worker test * Last simplification to actor, simplify a style test. * Add missing docs comments * Fix lint... * Fix Actor XSS, introduce subscribe (#3329) * Fix XSS, intorduce subscribe * Update changelog * Fix developer diagram with updated flow * Async actor no log warnings and errors in unit tests (#3368) * Upgrade jest, fix tests, remove console log messages. * Fix incorrect additions, lint * Async actor remove cancelables (#3371) * Remove more places that use cancelable * Remove more places with canceable * Async actor callback and promise (#3374) * Remove more places that use cancelable * Remove more places with canceable * callback and promise * Improve sources code when it is related to callback * Use callback failback when needed * Update build size test * Removed callbacks from various places, adding docs, simplifying tests * Improve type * Update src/util/actor.test.ts Co-authored-by: neodescis * Make load async for all sources --------- Co-authored-by: neodescis * Update changelog with most of the changes --------- Co-authored-by: Michael Barry Co-authored-by: Bart Louwers Co-authored-by: neodescis Co-authored-by: neodescis --- CHANGELOG.md | 8 + build/generate-doc-images.ts | 7 +- developer-guides/life-of-a-tile.md | 24 +- src/data/dem_data.ts | 39 +- src/data/feature_index.ts | 1 - src/index.test.ts | 68 +- src/render/glyph_atlas.ts | 9 +- src/render/glyph_manager.test.ts | 166 ++--- src/render/glyph_manager.ts | 167 ++--- src/render/image_atlas.ts | 4 +- src/render/image_manager.ts | 83 +-- src/source/canvas_source.ts | 12 +- src/source/geojson_source.test.ts | 113 ++-- src/source/geojson_source.ts | 119 ++-- src/source/geojson_worker_source.test.ts | 256 +++----- src/source/geojson_worker_source.ts | 263 +++----- src/source/image_source.test.ts | 26 +- src/source/image_source.ts | 46 +- src/source/load_tilejson.ts | 46 +- src/source/query_features.test.ts | 9 +- src/source/raster_dem_tile_source.test.ts | 137 ++-- src/source/raster_dem_tile_source.ts | 80 +-- .../raster_dem_tile_worker_source.test.ts | 16 +- src/source/raster_dem_tile_worker_source.ts | 7 +- src/source/raster_tile_source.test.ts | 10 +- src/source/raster_tile_source.ts | 76 ++- src/source/rtl_text_plugin.ts | 88 +-- src/source/source.ts | 69 +- src/source/source_cache.test.ts | 593 ++++++++---------- src/source/source_cache.ts | 39 +- src/source/tile.ts | 6 +- src/source/vector_tile_source.test.ts | 289 +++++---- src/source/vector_tile_source.ts | 102 +-- src/source/vector_tile_worker_source.test.ts | 254 ++++---- src/source/vector_tile_worker_source.ts | 209 +++--- src/source/video_source.ts | 53 +- src/source/worker.test.ts | 98 ++- src/source/worker.ts | 281 +++++---- src/source/worker_source.ts | 67 +- src/source/worker_tile.test.ts | 119 ++-- src/source/worker_tile.ts | 156 ++--- src/style/load_glyph_range.test.ts | 39 +- src/style/load_glyph_range.ts | 28 +- src/style/load_sprite.test.ts | 151 ++--- src/style/load_sprite.ts | 75 +-- src/style/style.test.ts | 76 ++- src/style/style.ts | 140 ++--- src/style/style_glyph.ts | 4 +- src/style/style_image.ts | 7 + src/types/tilejson.ts | 2 + src/ui/control/geolocate_control.test.ts | 240 ++++--- src/ui/control/geolocate_control.ts | 5 +- src/ui/events.ts | 2 +- src/ui/handler/dblclick_zoom.test.ts | 80 +-- src/ui/map.test.ts | 70 ++- src/ui/map.ts | 58 +- src/util/abort_error.ts | 21 + src/util/actor.test.ts | 229 ++++--- src/util/actor.ts | 309 +++++---- src/util/actor_messages.ts | 124 ++++ src/util/ajax.test.ts | 102 ++- src/util/ajax.ts | 304 +++++---- src/util/browser.ts | 11 + src/util/dispatcher.test.ts | 8 +- src/util/dispatcher.ts | 25 +- src/util/geolocation_support.test.ts | 46 +- src/util/geolocation_support.ts | 35 +- src/util/image.ts | 1 - src/util/image_request.test.ts | 275 ++++---- src/util/image_request.ts | 225 +++---- src/util/task_queue.ts | 2 +- src/util/test/mock_fetch.ts | 51 -- src/util/test/util.ts | 31 +- src/util/throttled_invoker.ts | 35 +- src/util/util.test.ts | 60 +- src/util/util.ts | 110 ++-- src/util/web_worker.ts | 12 +- src/util/web_worker_transfer.ts | 8 +- test/bench/lib/create_map.ts | 6 +- test/bench/lib/tile_parser.ts | 56 +- test/build/min.test.ts | 2 +- test/build/sourcemaps.test.ts | 2 +- test/integration/browser/browser.test.ts | 7 +- .../tests/debug/raster/expected-macos-m2.png | Bin 0 -> 286983 bytes .../debug/tile-raster/expected-macos-m2.png | Bin 0 -> 622078 bytes .../tests/debug/tile/expected-macos-m2.png | Bin 0 -> 48092 bytes .../overlapping-zoom/expected_macos-m2.png | Bin 0 -> 136256 bytes test/unit/lib/web_worker_mock.ts | 27 +- typedoc.json | 2 + 89 files changed, 3550 insertions(+), 3768 deletions(-) create mode 100644 src/util/abort_error.ts create mode 100644 src/util/actor_messages.ts delete mode 100644 src/util/test/mock_fetch.ts create mode 100644 test/integration/render/tests/debug/raster/expected-macos-m2.png create mode 100644 test/integration/render/tests/debug/tile-raster/expected-macos-m2.png create mode 100644 test/integration/render/tests/debug/tile/expected-macos-m2.png create mode 100644 test/integration/render/tests/raster-masking/overlapping-zoom/expected_macos-m2.png diff --git a/CHANGELOG.md b/CHANGELOG.md index d753ae06c4..22bd3e628a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,17 @@ ## main ### ✨ Features and improvements + +- Changed `ImageRequest` to be `Promise` based ([#3233](https://github.com/maplibre/maplibre-gl-js/pull/3233)) +- ⚠️ Changed the undeling worker communication from callbacks to promises. This has a breaking effect on the implementation of custom `WorkerSource` and how it behaves ([#3233](https://github.com/maplibre/maplibre-gl-js/pull/3233)) +- ⚠️ Changed the `Source` interface to return promises instead of callbacks ([#3233](https://github.com/maplibre/maplibre-gl-js/pull/3233)) +- ⚠️ Changed all the sources to be promises based. ([#3233](https://github.com/maplibre/maplibre-gl-js/pull/3233)) +- ⚠️ Changed the `map.loadImage` method to return a `Promise` ([#3233](https://github.com/maplibre/maplibre-gl-js/pull/3233)) - _...Add new stuff here..._ ### 🐞 Bug fixes + +- Fixes a security issue in `Actor` against XSS attacks in postMessage / onmessage ([#3239](https://github.com/maplibre/maplibre-gl-js/pull/3239)) - _...Add new stuff here..._ ## 3.6.2 diff --git a/build/generate-doc-images.ts b/build/generate-doc-images.ts index 50ce85bb19..cf44d80269 100644 --- a/build/generate-doc-images.ts +++ b/build/generate-doc-images.ts @@ -2,6 +2,7 @@ import path from 'path'; import fs from 'fs'; import puppeteer from 'puppeteer'; import packageJson from '../package.json' assert { type: 'json' }; +import {sleep} from '../src/util/test/util'; const exampleName = process.argv[2]; const examplePath = path.resolve('test', 'examples'); @@ -28,10 +29,8 @@ async function createImage(exampleName) { .then(async () => { // Wait for 5 seconds on 3d model examples, since this takes longer to load. const waitTime = exampleName.includes('3d-model') ? 5000 : 1500; - await new Promise((resolve) => { - console.log(`waiting for ${waitTime} ms`); - setTimeout(resolve, waitTime); - }); + console.log(`waiting for ${waitTime} ms`); + await sleep(waitTime); }) // map.loaded() does not evaluate to true within 3 seconds, it's probably an animated example. // In this case we take the screenshot immediately. diff --git a/developer-guides/life-of-a-tile.md b/developer-guides/life-of-a-tile.md index 4ebe28631e..8e980c4d04 100644 --- a/developer-guides/life-of-a-tile.md +++ b/developer-guides/life-of-a-tile.md @@ -93,7 +93,7 @@ sequenceDiagram worker_tile->glyph manager: getImages glyph manager->>ajax: Fetch icon
images glyph manager-->>worker_tile: glyph/Image dependencies - worker_tile->>worker_tile: maybePrepare() + worker_tile->>worker_tile: wait for all requests to finish worker_tile->>worker_tile: create GlyphAtlas worker_tile->>worker_tile: create ImageAtlas worker_tile->>bucket: addFeatures @@ -169,19 +169,19 @@ sequenceDiagram map->>painter: render(style) painter->>source_cache: prepare(context) loop for each tile - source_cache->>GPU: upload vertices - source_cache->>GPU: upload image textures + source_cache->>GPU: upload vertices + source_cache->>GPU: upload image textures end loop for each layer - painter->>layer: renderLayer(pass=offscreen) - painter->>layer: renderLayer(pass=opaque) - painter->>layer: renderLayer(pass=translucent) - painter->>layer: renderLayer(pass=debug) - loop renderLayer() call for each tile - layer->>GPU: load program - layer->>GPU: drawElements() - GPU->>user: display pixels - end + painter->>layer: renderLayer(pass=offscreen) + painter->>layer: renderLayer(pass=opaque) + painter->>layer: renderLayer(pass=translucent) + painter->>layer: renderLayer(pass=debug) + loop renderLayer() call for each tile + layer->>GPU: load program + layer->>GPU: drawElements() + GPU->>user: display pixels + end end map->>map: triggerRepaint() ``` diff --git a/src/data/dem_data.ts b/src/data/dem_data.ts index b95be92b7a..90ae832c2a 100644 --- a/src/data/dem_data.ts +++ b/src/data/dem_data.ts @@ -3,20 +3,24 @@ import {RGBAImage} from '../util/image'; import {warnOnce} from '../util/util'; import {register} from '../util/web_worker_transfer'; -// DEMData is a data structure for decoding, backfilling, and storing elevation data for processing in the hillshade shaders -// data can be populated either from a pngraw image tile or from serliazed data sent back from a worker. When data is initially -// loaded from a image tile, we decode the pixel values using the appropriate decoding formula, but we store the -// elevation data as an Int32 value. we add 65536 (2^16) to eliminate negative values and enable the use of -// integer overflow when creating the texture used in the hillshadePrepare step. - -// DEMData also handles the backfilling of data from a tile's neighboring tiles. This is necessary because we use a pixel's 8 -// surrounding pixel values to compute the slope at that pixel, and we cannot accurately calculate the slope at pixels on a -// tile's edge without backfilling from neighboring tiles. - +/** + * The possible DEM encoding types + */ export type DEMEncoding = 'mapbox' | 'terrarium' | 'custom' +/** + * DEMData is a data structure for decoding, backfilling, and storing elevation data for processing in the hillshade shaders + * data can be populated either from a pngraw image tile or from serliazed data sent back from a worker. When data is initially + * loaded from a image tile, we decode the pixel values using the appropriate decoding formula, but we store the + * elevation data as an Int32 value. we add 65536 (2^16) to eliminate negative values and enable the use of + * integer overflow when creating the texture used in the hillshadePrepare step. + * + * DEMData also handles the backfilling of data from a tile's neighboring tiles. This is necessary because we use a pixel's 8 + * surrounding pixel values to compute the slope at that pixel, and we cannot accurately calculate the slope at pixels on a + * tile's edge without backfilling from neighboring tiles. + */ export class DEMData { - uid: string; + uid: string | number; data: Uint32Array; stride: number; dim: number; @@ -27,9 +31,18 @@ export class DEMData { blueFactor: number; baseShift: number; - // RGBAImage data has uniform 1px padding on all sides: square tile edge size defines stride + /** + * Constructs a `DEMData` object + * @param uid - the tile's unique id + * @param data - RGBAImage data has uniform 1px padding on all sides: square tile edge size defines stride // and dim is calculated as stride - 2. - constructor(uid: string, data: RGBAImage, encoding: DEMEncoding, redFactor = 1.0, greenFactor = 1.0, blueFactor = 1.0, baseShift = 0.0) { + * @param encoding - the encoding type of the data + * @param redFactor - the red channel factor used to unpack the data, used for `custom` encoding only + * @param greenFactor - the green channel factor used to unpack the data, used for `custom` encoding only + * @param blueFactor - the blue channel factor used to unpack the data, used for `custom` encoding only + * @param baseShift - the base shift used to unpack the data, used for `custom` encoding only + */ + constructor(uid: string | number, data: RGBAImage | ImageData, encoding: DEMEncoding, redFactor = 1.0, greenFactor = 1.0, blueFactor = 1.0, baseShift = 0.0) { this.uid = uid; if (data.height !== data.width) throw new RangeError('DEM tiles must be square'); if (encoding && !['mapbox', 'terrarium', 'custom'].includes(encoding)) { diff --git a/src/data/feature_index.ts b/src/data/feature_index.ts index 1d8ea9df41..4869eca60c 100644 --- a/src/data/feature_index.ts +++ b/src/data/feature_index.ts @@ -40,7 +40,6 @@ type QueryParameters = { }; /** - * @internal * An in memory index class to allow fast interaction with features */ export class FeatureIndex { diff --git a/src/index.test.ts b/src/index.test.ts index 628bbe2d86..16536806b4 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -2,6 +2,7 @@ import {config} from './util/config'; import maplibre from './index'; import {getJSON, getArrayBuffer} from './util/ajax'; import {ImageRequest} from './util/image_request'; +import {isAbortError} from './util/abort_error'; describe('maplibre', () => { beforeEach(() => { @@ -34,65 +35,55 @@ describe('maplibre', () => { expect(Object.keys(config.REGISTERED_PROTOCOLS)).toHaveLength(0); }); - test('#addProtocol - getJSON', done => { + test('#addProtocol - getJSON', async () => { let protocolCallbackCalled = false; maplibre.addProtocol('custom', (reqParam, callback) => { protocolCallbackCalled = true; callback(null, {'foo': 'bar'}); return {cancel: () => {}}; }); - getJSON({url: 'custom://test/url/json'}, (error, data) => { - expect(error).toBeFalsy(); - expect(data).toEqual({foo: 'bar'}); - expect(protocolCallbackCalled).toBeTruthy(); - done(); - }); + const response = await getJSON({url: 'custom://test/url/json'}, new AbortController()); + expect(response.data).toEqual({foo: 'bar'}); + expect(protocolCallbackCalled).toBeTruthy(); }); - test('#addProtocol - getArrayBuffer', done => { + test('#addProtocol - getArrayBuffer', async () => { let protocolCallbackCalled = false; - maplibre.addProtocol('custom', (reqParam, callback) => { + maplibre.addProtocol('custom', (_reqParam, callback) => { protocolCallbackCalled = true; - callback(null, new ArrayBuffer(1)); + callback(null, new ArrayBuffer(1), 'cache-control', 'expires'); return {cancel: () => {}}; }); - getArrayBuffer({url: 'custom://test/url/getArrayBuffer'}, async (error, data) => { - expect(error).toBeFalsy(); - expect(data).toBeInstanceOf(ArrayBuffer); - expect(protocolCallbackCalled).toBeTruthy(); - done(); - }); + const response = await getArrayBuffer({url: 'custom://test/url/getArrayBuffer'}, new AbortController()); + expect(response.data).toBeInstanceOf(ArrayBuffer); + expect(response.cacheControl).toBe('cache-control'); + expect(response.expires).toBe('expires'); + expect(protocolCallbackCalled).toBeTruthy(); }); - test('#addProtocol - returning ImageBitmap for getImage', done => { + test('#addProtocol - returning ImageBitmap for getImage', async () => { let protocolCallbackCalled = false; - maplibre.addProtocol('custom', (reqParam, callback) => { + maplibre.addProtocol('custom', (_reqParam, callback) => { protocolCallbackCalled = true; callback(null, new ImageBitmap()); return {cancel: () => {}}; }); - ImageRequest.getImage({url: 'custom://test/url/getImage'}, async (error, img) => { - expect(error).toBeFalsy(); - expect(img).toBeInstanceOf(ImageBitmap); - expect(protocolCallbackCalled).toBeTruthy(); - done(); - }); + const img = await ImageRequest.getImage({url: 'custom://test/url/getImage'}, new AbortController()); + expect(img.data).toBeInstanceOf(ImageBitmap); + expect(protocolCallbackCalled).toBeTruthy(); }); - test('#addProtocol - returning HTMLImageElement for getImage', done => { + test('#addProtocol - returning HTMLImageElement for getImage', async () => { let protocolCallbackCalled = false; maplibre.addProtocol('custom', (reqParam, callback) => { protocolCallbackCalled = true; callback(null, new Image()); return {cancel: () => {}}; }); - ImageRequest.getImage({url: 'custom://test/url/getImage'}, async (error, img) => { - expect(error).toBeFalsy(); - expect(img).toBeInstanceOf(HTMLImageElement); - expect(protocolCallbackCalled).toBeTruthy(); - done(); - }); + const img = await ImageRequest.getImage({url: 'custom://test/url/getImage'}, new AbortController()); + expect(img.data).toBeInstanceOf(HTMLImageElement); + expect(protocolCallbackCalled).toBeTruthy(); }); test('#addProtocol - error', () => { @@ -101,20 +92,27 @@ describe('maplibre', () => { return {cancel: () => { }}; }); - getJSON({url: 'custom://test/url/json'}, (error) => { + getJSON({url: 'custom://test/url/json'}, new AbortController()).catch((error) => { expect(error).toBeTruthy(); }); }); - test('#addProtocol - Cancel request', () => { + test('#addProtocol - Cancel request', async () => { let cancelCalled = false; maplibre.addProtocol('custom', () => { return {cancel: () => { cancelCalled = true; }}; }); - const request = getJSON({url: 'custom://test/url/json'}, () => { }); - request.cancel(); + const abortController = new AbortController(); + const promise = getJSON({url: 'custom://test/url/json'}, abortController); + abortController.abort(); + try { + await promise; + } catch (err) { + expect(isAbortError(err)).toBeTruthy(); + } + expect(cancelCalled).toBeTruthy(); }); diff --git a/src/render/glyph_atlas.ts b/src/render/glyph_atlas.ts index 0f80b336e8..6ce83f7e4c 100644 --- a/src/render/glyph_atlas.ts +++ b/src/render/glyph_atlas.ts @@ -2,7 +2,8 @@ import {AlphaImage} from '../util/image'; import {register} from '../util/web_worker_transfer'; import potpack from 'potpack'; -import type {GlyphMetrics, StyleGlyph} from '../style/style_glyph'; +import type {GlyphMetrics} from '../style/style_glyph'; +import type {GetGlyphsResponse} from '../util/actor_messages'; const padding = 1; @@ -37,11 +38,7 @@ export class GlyphAtlas { image: AlphaImage; positions: GlyphPositions; - constructor(stacks: { - [_: string]: { - [_: number]: StyleGlyph; - }; - }) { + constructor(stacks: GetGlyphsResponse) { const positions = {}; const bins = []; diff --git a/src/render/glyph_manager.test.ts b/src/render/glyph_manager.test.ts index 65c0ff72ff..60eb97f61e 100644 --- a/src/render/glyph_manager.test.ts +++ b/src/render/glyph_manager.test.ts @@ -3,144 +3,118 @@ import {GlyphManager} from './glyph_manager'; import fs from 'fs'; import {RequestManager} from '../util/request_manager'; -const glyphs = {}; -for (const glyph of parseGlyphPbf(fs.readFileSync('./test/unit/assets/0-255.pbf'))) { - glyphs[glyph.id] = glyph; -} - -const identityTransform = ((url) => ({url})) as any as RequestManager; - -const createLoadGlyphRangeStub = () => { - return jest.spyOn(GlyphManager, 'loadGlyphRange').mockImplementation((stack, range, urlTemplate, transform, callback) => { - expect(stack).toBe('Arial Unicode MS'); - expect(range).toBe(0); - expect(urlTemplate).toBe('https://localhost/fonts/v1/{fontstack}/{range}.pbf'); - expect(transform).toBe(identityTransform); - setTimeout(() => callback(null, glyphs), 0); - }); -}; - -const createGlyphManager = (font?) => { - const manager = new GlyphManager(identityTransform, font); - manager.setURL('https://localhost/fonts/v1/{fontstack}/{range}.pbf'); - return manager; -}; +describe('GlyphManager', () => { + const GLYPHS = {}; + for (const glyph of parseGlyphPbf(fs.readFileSync('./test/unit/assets/0-255.pbf'))) { + GLYPHS[glyph.id] = glyph; + } + + const identityTransform = ((url) => ({url})) as any as RequestManager; + + const createLoadGlyphRangeStub = () => { + return jest.spyOn(GlyphManager, 'loadGlyphRange').mockImplementation((stack, range, urlTemplate, transform) => { + expect(stack).toBe('Arial Unicode MS'); + expect(range).toBe(0); + expect(urlTemplate).toBe('https://localhost/fonts/v1/{fontstack}/{range}.pbf'); + expect(transform).toBe(identityTransform); + return Promise.resolve(GLYPHS); + }); + }; -afterEach(() => { - jest.clearAllMocks(); -}); + const createGlyphManager = (font?) => { + const manager = new GlyphManager(identityTransform, font); + manager.setURL('https://localhost/fonts/v1/{fontstack}/{range}.pbf'); + return manager; + }; -describe('GlyphManager', () => { + afterEach(() => { + jest.clearAllMocks(); + }); - test('GlyphManager requests 0-255 PBF', done => { + test('GlyphManager requests 0-255 PBF', async () => { createLoadGlyphRangeStub(); const manager = createGlyphManager(); - manager.getGlyphs({'Arial Unicode MS': [55]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS']['55'].metrics.advance).toBe(12); - done(); - }); + const returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [55]}); + expect(returnedGlyphs['Arial Unicode MS']['55'].metrics.advance).toBe(12); }); - test('GlyphManager doesn\'t request twice 0-255 PBF if a glyph is missing', done => { + test('GlyphManager doesn\'t request twice 0-255 PBF if a glyph is missing', async () => { const stub = createLoadGlyphRangeStub(); const manager = createGlyphManager(); - manager.getGlyphs({'Arial Unicode MS': [0.5]}, (err) => { - expect(err).toBeFalsy(); - expect(manager.entries['Arial Unicode MS'].ranges[0]).toBe(true); - expect(stub).toHaveBeenCalledTimes(1); + await manager.getGlyphs({'Arial Unicode MS': [0.5]}); + expect(manager.entries['Arial Unicode MS'].ranges[0]).toBe(true); + expect(stub).toHaveBeenCalledTimes(1); - // We remove all requests as in getGlyphs code. - delete manager.entries['Arial Unicode MS'].requests[0]; + // We remove all requests as in getGlyphs code. + delete manager.entries['Arial Unicode MS'].requests[0]; - manager.getGlyphs({'Arial Unicode MS': [0.5]}, (err) => { - expect(err).toBeFalsy(); - expect(manager.entries['Arial Unicode MS'].ranges[0]).toBe(true); - expect(stub).toHaveBeenCalledTimes(1); - done(); - }); - }); + await manager.getGlyphs({'Arial Unicode MS': [0.5]}); + expect(manager.entries['Arial Unicode MS'].ranges[0]).toBe(true); + expect(stub).toHaveBeenCalledTimes(1); }); - test('GlyphManager requests remote CJK PBF', done => { - jest.spyOn(GlyphManager, 'loadGlyphRange').mockImplementation((stack, range, urlTemplate, transform, callback) => { - setTimeout(() => callback(null, glyphs), 0); + test('GlyphManager requests remote CJK PBF', async () => { + jest.spyOn(GlyphManager, 'loadGlyphRange').mockImplementation((_stack, _range, _urlTemplate, _transform) => { + return Promise.resolve(GLYPHS); }); const manager = createGlyphManager(); - manager.getGlyphs({'Arial Unicode MS': [0x5e73]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS'][0x5e73]).toBeNull(); // The fixture returns a PBF without the glyph we requested - done(); - }); + const returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x5e73]}); + expect(returnedGlyphs['Arial Unicode MS'][0x5e73]).toBeNull(); // The fixture returns a PBF without the glyph we requested }); - test('GlyphManager does not cache CJK chars that should be rendered locally', done => { - jest.spyOn(GlyphManager, 'loadGlyphRange').mockImplementation((stack, range, urlTemplate, transform, callback) => { + test('GlyphManager does not cache CJK chars that should be rendered locally', async () => { + jest.spyOn(GlyphManager, 'loadGlyphRange').mockImplementation((_stack, range, _urlTemplate, _transform) => { const overlappingGlyphs = {}; const start = range * 256; const end = start + 256; for (let i = start, j = 0; i < end; i++, j++) { - overlappingGlyphs[i] = glyphs[j]; + overlappingGlyphs[i] = GLYPHS[j]; } - setTimeout(() => callback(null, overlappingGlyphs), 0); + return Promise.resolve(overlappingGlyphs); }); const manager = createGlyphManager('sans-serif'); //Request char that overlaps Katakana range - manager.getGlyphs({'Arial Unicode MS': [0x3005]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS'][0x3005]).not.toBeNull(); - //Request char from Katakana range (te テ) - manager.getGlyphs({'Arial Unicode MS': [0x30C6]}, (err, glyphs) => { - expect(err).toBeFalsy(); - const glyph = glyphs['Arial Unicode MS'][0x30c6]; - //Ensure that te is locally generated. - expect(glyph.bitmap.height).toBe(12); - expect(glyph.bitmap.width).toBe(12); - done(); - }); - }); + let returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x3005]}); + expect(returnedGlyphs['Arial Unicode MS'][0x3005]).not.toBeNull(); + //Request char from Katakana range (te テ) + returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x30C6]}); + const glyph = returnedGlyphs['Arial Unicode MS'][0x30c6]; + //Ensure that te is locally generated. + expect(glyph.bitmap.height).toBe(12); + expect(glyph.bitmap.width).toBe(12); }); - test('GlyphManager generates CJK PBF locally', done => { + test('GlyphManager generates CJK PBF locally', async () => { const manager = createGlyphManager('sans-serif'); // character 平 - manager.getGlyphs({'Arial Unicode MS': [0x5e73]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS'][0x5e73].metrics.advance).toBe(0.5); - done(); - }); + const returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x5e73]}); + expect(returnedGlyphs['Arial Unicode MS'][0x5e73].metrics.advance).toBe(0.5); }); - test('GlyphManager generates Katakana PBF locally', done => { + test('GlyphManager generates Katakana PBF locally', async () => { const manager = createGlyphManager('sans-serif'); // Katakana letter te テ - manager.getGlyphs({'Arial Unicode MS': [0x30c6]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS'][0x30c6].metrics.advance).toBe(0.5); - done(); - }); + const returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x30c6]}); + expect(returnedGlyphs['Arial Unicode MS'][0x30c6].metrics.advance).toBe(0.5); }); - test('GlyphManager generates Hiragana PBF locally', done => { + test('GlyphManager generates Hiragana PBF locally', async () => { const manager = createGlyphManager('sans-serif'); //Hiragana letter te て - manager.getGlyphs({'Arial Unicode MS': [0x3066]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS'][0x3066].metrics.advance).toBe(0.5); - done(); - }); + const returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x3066]}); + expect(returnedGlyphs['Arial Unicode MS'][0x3066].metrics.advance).toBe(0.5); }); - test('GlyphManager caches locally generated glyphs', done => { + test('GlyphManager caches locally generated glyphs', async () => { const manager = createGlyphManager('sans-serif'); const drawSpy = GlyphManager.TinySDF.prototype.draw = jest.fn().mockImplementation(() => { @@ -148,13 +122,9 @@ describe('GlyphManager', () => { }); // Katakana letter te - manager.getGlyphs({'Arial Unicode MS': [0x30c6]}, (err, glyphs) => { - expect(err).toBeFalsy(); - expect(glyphs['Arial Unicode MS'][0x30c6].metrics.advance).toBe(24); - manager.getGlyphs({'Arial Unicode MS': [0x30c6]}, () => { - expect(drawSpy).toHaveBeenCalledTimes(1); - done(); - }); - }); + const returnedGlyphs = await manager.getGlyphs({'Arial Unicode MS': [0x30c6]}); + expect(returnedGlyphs['Arial Unicode MS'][0x30c6].metrics.advance).toBe(24); + await manager.getGlyphs({'Arial Unicode MS': [0x30c6]}); + expect(drawSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/render/glyph_manager.ts b/src/render/glyph_manager.ts index acffee4d2d..e4ffda9406 100644 --- a/src/render/glyph_manager.ts +++ b/src/render/glyph_manager.ts @@ -2,12 +2,11 @@ import {loadGlyphRange} from '../style/load_glyph_range'; import TinySDF from '@mapbox/tiny-sdf'; import {unicodeBlockLookup} from '../util/is_char_in_unicode_block'; -import {asyncAll} from '../util/util'; import {AlphaImage} from '../util/image'; import type {StyleGlyph} from '../style/style_glyph'; import type {RequestManager} from '../util/request_manager'; -import type {Callback} from '../types/callback'; +import type {GetGlyphsResponse} from '../util/actor_messages'; type Entry = { // null means we've requested the range, but the glyph wasn't included in the result. @@ -15,9 +14,7 @@ type Entry = { [id: number]: StyleGlyph | null; }; requests: { - [range: number]: Array>; + [range: number]: Promise<{[_: number]: StyleGlyph | null}>; }; ranges: { [range: number]: boolean | null; @@ -28,9 +25,7 @@ type Entry = { export class GlyphManager { requestManager: RequestManager; localIdeographFontFamily: string; - entries: { - [_: string]: Entry; - }; + entries: {[stack: string]: Entry}; url: string; // exposed as statics to enable stubbing in unit tests @@ -47,117 +42,81 @@ export class GlyphManager { this.url = url; } - getGlyphs(glyphs: { - [stack: string]: Array; - }, callback: Callback<{ - [stack: string]: { - [id: number]: StyleGlyph; - }; - }>) { - const all = []; + async getGlyphs(glyphs: {[stack: string]: Array}): Promise { + const glyphsPromises: Promise<{stack: string; id: number; glyph: StyleGlyph}>[] = []; for (const stack in glyphs) { for (const id of glyphs[stack]) { - all.push({stack, id}); + glyphsPromises.push(this._getAndCacheGlyphsPromise(stack, id)); } } - asyncAll(all, ({stack, id}, callback: Callback<{ - stack: string; - id: number; - glyph: StyleGlyph; - }>) => { - let entry = this.entries[stack]; - if (!entry) { - entry = this.entries[stack] = { - glyphs: {}, - requests: {}, - ranges: {} - }; - } + const updatedGlyphs = await Promise.all(glyphsPromises); - let glyph = entry.glyphs[id]; - if (glyph !== undefined) { - callback(null, {stack, id, glyph}); - return; - } + const result: GetGlyphsResponse = {}; - glyph = this._tinySDF(entry, stack, id); - if (glyph) { - entry.glyphs[id] = glyph; - callback(null, {stack, id, glyph}); - return; + for (const {stack, id, glyph} of updatedGlyphs) { + if (!result[stack]) { + result[stack] = {}; } + // Clone the glyph so that our own copy of its ArrayBuffer doesn't get transferred. + result[stack][id] = glyph && { + id: glyph.id, + bitmap: glyph.bitmap.clone(), + metrics: glyph.metrics + }; + } - const range = Math.floor(id / 256); - if (range * 256 > 65535) { - callback(new Error('glyphs > 65535 not supported')); - return; - } + return result; + } - if (entry.ranges[range]) { - callback(null, {stack, id, glyph}); - return; - } + async _getAndCacheGlyphsPromise(stack: string, id: number): Promise<{stack: string; id: number; glyph: StyleGlyph}> { + let entry = this.entries[stack]; + if (!entry) { + entry = this.entries[stack] = { + glyphs: {}, + requests: {}, + ranges: {} + }; + } - if (!this.url) { - callback(new Error('glyphsUrl is not set')); - return; - } + let glyph = entry.glyphs[id]; + if (glyph !== undefined) { + return {stack, id, glyph}; + } - let requests = entry.requests[range]; - if (!requests) { - requests = entry.requests[range] = []; - GlyphManager.loadGlyphRange(stack, range, this.url, this.requestManager, - (err, response?: { - [_: number]: StyleGlyph | null; - } | null) => { - if (response) { - for (const id in response) { - if (!this._doesCharSupportLocalGlyph(+id)) { - entry.glyphs[+id] = response[+id]; - } - } - entry.ranges[range] = true; - } - for (const cb of requests) { - cb(err, response); - } - delete entry.requests[range]; - }); - } + glyph = this._tinySDF(entry, stack, id); + if (glyph) { + entry.glyphs[id] = glyph; + return {stack, id, glyph}; + } - requests.push((err, result?: { - [_: number]: StyleGlyph | null; - } | null) => { - if (err) { - callback(err); - } else if (result) { - callback(null, {stack, id, glyph: result[id] || null}); - } - }); - }, (err, glyphs?: Array<{ - stack: string; - id: number; - glyph: StyleGlyph; - }> | null) => { - if (err) { - callback(err); - } else if (glyphs) { - const result = {}; - - for (const {stack, id, glyph} of glyphs) { - // Clone the glyph so that our own copy of its ArrayBuffer doesn't get transferred. - (result[stack] || (result[stack] = {}))[id] = glyph && { - id: glyph.id, - bitmap: glyph.bitmap.clone(), - metrics: glyph.metrics - }; - } - - callback(null, result); + const range = Math.floor(id / 256); + if (range * 256 > 65535) { + throw new Error('glyphs > 65535 not supported'); + } + + if (entry.ranges[range]) { + return {stack, id, glyph}; + } + + if (!this.url) { + throw new Error('glyphsUrl is not set'); + } + + if (!entry.requests[range]) { + const promise = GlyphManager.loadGlyphRange(stack, range, this.url, this.requestManager); + entry.requests[range] = promise; + } + + const response = await entry.requests[range]; + for (const id in response) { + if (!this._doesCharSupportLocalGlyph(+id)) { + entry.glyphs[+id] = response[+id]; } - }); + } + entry.ranges[range] = true; + return {stack, id, glyph: response[id] || null}; } _doesCharSupportLocalGlyph(id: number): boolean { diff --git a/src/render/image_atlas.ts b/src/render/image_atlas.ts index a86d2e69ff..492dab944d 100644 --- a/src/render/image_atlas.ts +++ b/src/render/image_atlas.ts @@ -7,6 +7,7 @@ import type {StyleImage} from '../style/style_image'; import type {ImageManager} from './image_manager'; import type {Texture} from './texture'; import type {Rect} from './glyph_atlas'; +import type {GetImagesResponse} from '../util/actor_messages'; const IMAGE_PADDING: number = 1; export {IMAGE_PADDING}; @@ -61,7 +62,6 @@ export class ImagePosition { } /** - * @internal * A class holding all the images */ export class ImageAtlas { @@ -71,7 +71,7 @@ export class ImageAtlas { haveRenderCallbacks: Array; uploaded: boolean; - constructor(icons: {[_: string]: StyleImage}, patterns: {[_: string]: StyleImage}) { + constructor(icons: GetImagesResponse, patterns: GetImagesResponse) { const iconPositions = {}, patternPositions = {}; this.haveRenderCallbacks = []; diff --git a/src/render/image_manager.ts b/src/render/image_manager.ts index 33a0d1aaf1..0e50eef309 100644 --- a/src/render/image_manager.ts +++ b/src/render/image_manager.ts @@ -11,38 +11,44 @@ import {warnOnce} from '../util/util'; import type {StyleImage} from '../style/style_image'; import type {Context} from '../gl/context'; import type {PotpackBox} from 'potpack'; -import type {Callback} from '../types/callback'; +import type {GetImagesResponse} from '../util/actor_messages'; type Pattern = { bin: PotpackBox; position: ImagePosition; }; -// When copied into the atlas texture, image data is padded by one pixel on each side. Icon -// images are padded with fully transparent pixels, while pattern images are padded with a -// copy of the image data wrapped from the opposite side. In both cases, this ensures the -// correct behavior of GL_LINEAR texture sampling mode. +/** + * When copied into the atlas texture, image data is padded by one pixel on each side. Icon + * images are padded with fully transparent pixels, while pattern images are padded with a + * copy of the image data wrapped from the opposite side. In both cases, this ensures the + * correct behavior of GL_LINEAR texture sampling mode. + */ const padding = 1; -/* - ImageManager does three things: - - 1. Tracks requests for icon images from tile workers and sends responses when the requests are fulfilled. - 2. Builds a texture atlas for pattern images. - 3. Rerenders renderable images once per frame - - These are disparate responsibilities and should eventually be handled by different classes. When we implement - data-driven support for `*-pattern`, we'll likely use per-bucket pattern atlases, and that would be a good time - to refactor this. +/** + * ImageManager does three things: + * + * 1. Tracks requests for icon images from tile workers and sends responses when the requests are fulfilled. + * 2. Builds a texture atlas for pattern images. + * 3. Rerenders renderable images once per frame + * + * These are disparate responsibilities and should eventually be handled by different classes. When we implement + * data-driven support for `*-pattern`, we'll likely use per-bucket pattern atlases, and that would be a good time + * to refactor this. */ export class ImageManager extends Evented { images: {[_: string]: StyleImage}; updatedImages: {[_: string]: boolean}; callbackDispatchedThisFrame: {[_: string]: boolean}; loaded: boolean; + /** + * This is used to track requests for images that are not yet available. When the image is loaded, + * the requestors will be notified. + */ requestors: Array<{ ids: Array; - callback: Callback<{[_: string]: StyleImage}>; + promiseResolve: (value: GetImagesResponse) => void; }>; patterns: {[_: string]: Pattern}; @@ -75,8 +81,8 @@ export class ImageManager extends Evented { this.loaded = loaded; if (loaded) { - for (const {ids, callback} of this.requestors) { - this._notify(ids, callback); + for (const {ids, promiseResolve} of this.requestors) { + promiseResolve(this._getImagesForIds(ids)); } this.requestors = []; } @@ -176,28 +182,30 @@ export class ImageManager extends Evented { return Object.keys(this.images); } - getImages(ids: Array, callback: Callback<{[_: string]: StyleImage}>) { - // If the sprite has been loaded, or if all the icon dependencies are already present - // (i.e. if they've been added via runtime styling), then notify the requestor immediately. - // Otherwise, delay notification until the sprite is loaded. At that point, if any of the - // dependencies are still unavailable, we'll just assume they are permanently missing. - let hasAllDependencies = true; - if (!this.isLoaded()) { - for (const id of ids) { - if (!this.images[id]) { - hasAllDependencies = false; + getImages(ids: Array): Promise { + return new Promise((resolve, _reject) => { + // If the sprite has been loaded, or if all the icon dependencies are already present + // (i.e. if they've been added via runtime styling), then notify the requestor immediately. + // Otherwise, delay notification until the sprite is loaded. At that point, if any of the + // dependencies are still unavailable, we'll just assume they are permanently missing. + let hasAllDependencies = true; + if (!this.isLoaded()) { + for (const id of ids) { + if (!this.images[id]) { + hasAllDependencies = false; + } } } - } - if (this.isLoaded() || hasAllDependencies) { - this._notify(ids, callback); - } else { - this.requestors.push({ids, callback}); - } + if (this.isLoaded() || hasAllDependencies) { + resolve(this._getImagesForIds(ids)); + } else { + this.requestors.push({ids, promiseResolve: resolve}); + } + }); } - _notify(ids: Array, callback: Callback<{[_: string]: StyleImage}>) { - const response = {}; + _getImagesForIds(ids: Array): GetImagesResponse { + const response: GetImagesResponse = {}; for (const id of ids) { let image = this.getImage(id); @@ -224,8 +232,7 @@ export class ImageManager extends Evented { warnOnce(`Image "${id}" could not be loaded. Please make sure you have added the image with map.addImage() or a "sprite" property in your style. You can provide missing images by listening for the "styleimagemissing" map event.`); } } - - callback(null, response); + return response; } // Pattern stuff diff --git a/src/source/canvas_source.ts b/src/source/canvas_source.ts index 72994df239..911c87416c 100644 --- a/src/source/canvas_source.ts +++ b/src/source/canvas_source.ts @@ -107,7 +107,7 @@ export class CanvasSource extends ImageSource { this.animate = options.animate !== undefined ? options.animate : true; } - load = () => { + async load() { this._loaded = true; if (!this.canvas) { this.canvas = (this.options.canvas instanceof HTMLCanvasElement) ? @@ -137,7 +137,7 @@ export class CanvasSource extends ImageSource { }; this._finishLoading(); - }; + } /** * Returns the HTML `canvas` element. @@ -160,7 +160,7 @@ export class CanvasSource extends ImageSource { this.pause(); } - prepare = () => { + prepare() { let resize = false; if (this.canvas.width !== this.width) { this.width = this.canvas.width; @@ -205,14 +205,14 @@ export class CanvasSource extends ImageSource { if (newTilesLoaded) { this.fire(new Event('data', {dataType: 'source', sourceDataType: 'idle', sourceId: this.id})); } - }; + } - serialize = (): CanvasSourceSpecification => { + serialize(): CanvasSourceSpecification { return { type: 'canvas', coordinates: this.coordinates }; - }; + } hasTransition() { return this._playing; diff --git a/src/source/geojson_source.test.ts b/src/source/geojson_source.test.ts index a5eeebbf9b..19e2718951 100644 --- a/src/source/geojson_source.test.ts +++ b/src/source/geojson_source.test.ts @@ -16,7 +16,7 @@ const wrapDispatcher = (dispatcher) => { }; const mockDispatcher = wrapDispatcher({ - send() {} + sendAsync() { return Promise.resolve({}); } }); const hawkHill = { @@ -58,10 +58,10 @@ describe('GeoJSONSource#setData', () => { opts = opts || {}; opts = extend(opts, {data: {}}); return new GeoJSONSource('id', opts, wrapDispatcher({ - send (type, data, callback) { - if (callback) { - return setTimeout(callback, 0); - } + sendAsync(_message) { + return new Promise((resolve) => { + setTimeout(() => resolve({}), 0); + }); } }), undefined); } @@ -91,8 +91,10 @@ describe('GeoJSONSource#setData', () => { test('fires "dataabort" event', done => { const source = new GeoJSONSource('id', {} as any, wrapDispatcher({ - send(type, data, callback) { - setTimeout(() => callback(null, {abandoned: true})); + sendAsync(_message) { + return new Promise((resolve) => { + setTimeout(() => resolve({abandoned: true}), 0); + }); } }), undefined); source.on('dataabort', () => { @@ -108,13 +110,15 @@ describe('GeoJSONSource#setData', () => { transformRequest: (url) => { return {url}; } } as any as RequestManager } as any; - source.actor.send = function(type, params: any, cb) { - if (type === 'geojson.loadData') { - expect(params.request.collectResourceTiming).toBeTruthy(); - setTimeout(cb, 0); - done(); - } - } as any; + source.actor.sendAsync = (message) => { + return new Promise((resolve) => { + if (message.type === 'loadData') { + expect((message.data as any).request.collectResourceTiming).toBeTruthy(); + setTimeout(() => resolve({} as any), 0); + done(); + } + }); + }; source.setData('http://localhost/nonexistent'); }); @@ -148,8 +152,10 @@ describe('GeoJSONSource#setData', () => { test('marks source as loaded before firing "dataabort" event', done => { const source = new GeoJSONSource('id', {} as any, wrapDispatcher({ - send(type, data, callback) { - setTimeout(() => callback(null, {abandoned: true})); + sendAsync(_message) { + return new Promise((resolve) => { + setTimeout(() => resolve({abandoned: true}), 0); + }); } }), undefined); source.on('dataabort', () => { @@ -163,11 +169,11 @@ describe('GeoJSONSource#setData', () => { describe('GeoJSONSource#onRemove', () => { test('broadcasts "removeSource" event', done => { const source = new GeoJSONSource('id', {data: {}} as GeoJSONSourceOptions, wrapDispatcher({ - send(type, data, callback) { - expect(callback).toBeFalsy(); - expect(type).toBe('removeSource'); - expect(data).toEqual({type: 'geojson', source: 'id'}); + sendAsync(message) { + expect(message.type).toBe('removeSource'); + expect(message.data).toEqual({type: 'geojson', source: 'id'}); done(); + return Promise.resolve({}); }, broadcast() { // Ignore @@ -187,9 +193,10 @@ describe('GeoJSONSource#update', () => { test('sends initial loadData request to dispatcher', done => { const mockDispatcher = wrapDispatcher({ - send(message) { - expect(message).toBe('geojson.loadData'); + sendAsync(message) { + expect(message.type).toBe('loadData'); done(); + return Promise.resolve({}); } }); @@ -198,9 +205,9 @@ describe('GeoJSONSource#update', () => { test('forwards geojson-vt options with worker request', done => { const mockDispatcher = wrapDispatcher({ - send(message, params) { - expect(message).toBe('geojson.loadData'); - expect(params.geojsonVtOptions).toEqual({ + sendAsync(message) { + expect(message.type).toBe('loadData'); + expect(message.data.geojsonVtOptions).toEqual({ extent: 8192, maxZoom: 10, tolerance: 4, @@ -209,6 +216,7 @@ describe('GeoJSONSource#update', () => { generateId: true }); done(); + return Promise.resolve({}); } }); @@ -223,9 +231,9 @@ describe('GeoJSONSource#update', () => { test('forwards Supercluster options with worker request', done => { const mockDispatcher = wrapDispatcher({ - send(message, params) { - expect(message).toBe('geojson.loadData'); - expect(params.superclusterOptions).toEqual({ + sendAsync(message) { + expect(message.type).toBe('loadData'); + expect(message.data.superclusterOptions).toEqual({ maxZoom: 12, minPoints: 3, extent: 8192, @@ -234,6 +242,7 @@ describe('GeoJSONSource#update', () => { generateId: true }); done(); + return Promise.resolve({}); } }); @@ -250,12 +259,13 @@ describe('GeoJSONSource#update', () => { test('modifying cluster properties after adding a source', done => { // test setCluster function on GeoJSONSource const mockDispatcher = wrapDispatcher({ - send(message, params) { - expect(message).toBe('geojson.loadData'); - expect(params.cluster).toBe(true); - expect(params.superclusterOptions.radius).toBe(80); - expect(params.superclusterOptions.maxZoom).toBe(16); + sendAsync(message) { + expect(message.type).toBe('loadData'); + expect(message.data.cluster).toBe(true); + expect(message.data.superclusterOptions.radius).toBe(80); + expect(message.data.superclusterOptions.maxZoom).toBe(16); done(); + return Promise.resolve({}); } }); new GeoJSONSource('id', { @@ -270,9 +280,9 @@ describe('GeoJSONSource#update', () => { test('forwards Supercluster options with worker request, ignore max zoom of source', done => { const mockDispatcher = wrapDispatcher({ - send(message, params) { - expect(message).toBe('geojson.loadData'); - expect(params.superclusterOptions).toEqual({ + sendAsync(message) { + expect(message.type).toBe('loadData'); + expect(message.data.superclusterOptions).toEqual({ maxZoom: 12, minPoints: 3, extent: 8192, @@ -281,6 +291,7 @@ describe('GeoJSONSource#update', () => { generateId: true }); done(); + return Promise.resolve({}); } }); @@ -309,10 +320,10 @@ describe('GeoJSONSource#update', () => { }); test('fires event when metadata loads', done => { const mockDispatcher = wrapDispatcher({ - send(message, args, callback) { - if (callback) { - setTimeout(callback, 0); - } + sendAsync(_message) { + return new Promise((resolve) => { + setTimeout(() => resolve({}), 0); + }); } }); @@ -328,8 +339,10 @@ describe('GeoJSONSource#update', () => { test('fires metadata data event even when initial request is aborted', done => { let requestCount = 0; const mockDispatcher = wrapDispatcher({ - send(message, args, callback) { - setTimeout(() => callback(null, {abandoned: requestCount++ === 0})); + sendAsync(_message) { + return new Promise((resolve) => { + setTimeout(() => resolve({abandoned: requestCount++ === 0})); + }); } }); @@ -345,10 +358,8 @@ describe('GeoJSONSource#update', () => { test('fires "error"', done => { const mockDispatcher = wrapDispatcher({ - send(message, args, callback) { - if (callback) { - setTimeout(callback.bind(null, 'error'), 0); - } + sendAsync(_message) { + return Promise.reject('error'); // eslint-disable-line prefer-promise-reject-errors } }); @@ -365,13 +376,11 @@ describe('GeoJSONSource#update', () => { test('sends loadData request to dispatcher after data update', done => { let expectedLoadDataCalls = 2; const mockDispatcher = wrapDispatcher({ - send(message, args, callback) { - if (message === 'geojson.loadData' && --expectedLoadDataCalls <= 0) { + sendAsync(message) { + if (message.type === 'loadData' && --expectedLoadDataCalls <= 0) { done(); } - if (callback) { - setTimeout(callback, 0); - } + return new Promise((resolve) => setTimeout(() => resolve({}), 0)); } }); @@ -384,7 +393,7 @@ describe('GeoJSONSource#update', () => { source.on('data', (e) => { if (e.sourceDataType === 'metadata') { source.setData({} as GeoJSON.GeoJSON); - source.loadTile(new Tile(new OverscaledTileID(0, 0, 0, 0, 0), 512), () => {}); + source.loadTile(new Tile(new OverscaledTileID(0, 0, 0, 0, 0), 512)); } }); diff --git a/src/source/geojson_source.ts b/src/source/geojson_source.ts index ada698d39d..4799e1891d 100644 --- a/src/source/geojson_source.ts +++ b/src/source/geojson_source.ts @@ -13,10 +13,10 @@ import type {Actor} from '../util/actor'; import type {Callback} from '../types/callback'; import type {GeoJSONSourceSpecification, PromoteIdSpecification} from '@maplibre/maplibre-gl-style-spec'; import type {GeoJSONSourceDiff} from './geojson_source_diff'; -import type {Options, ClusterProperties} from 'supercluster'; +import type {GeoJSONWorkerOptions, LoadGeoJSONParameters} from './geojson_worker_source'; export type GeoJSONSourceOptions = GeoJSONSourceSpecification & { - workerOptions?: WorkerOptions; + workerOptions?: GeoJSONWorkerOptions; collectResourceTiming?: boolean; } @@ -28,23 +28,6 @@ export type GeoJsonSourceOptions = { clusterMinPoints?: number; generateId?: boolean; } -export type WorkerOptions = { - source?: string; - cluster?: boolean; - geojsonVtOptions?: { - buffer?: number; - tolerance?: number; - extent?: number; - maxZoom?: number; - linemetrics?: boolean; - generateId?: boolean; - }; - superclusterOptions?: Options; - clusterProperties?: ClusterProperties; - fliter?: any; - promoteId?: any; - collectResourceTiming?: boolean; -} /** * The cluster options to set @@ -131,7 +114,7 @@ export class GeoJSONSource extends Evented implements Source { reparseOverscaled: boolean; _data: GeoJSON.GeoJSON | string | undefined; _options: GeoJsonSourceOptions; - workerOptions: WorkerOptions; + workerOptions: GeoJSONWorkerOptions; map: Map; actor: Actor; _pendingLoads: number; @@ -204,9 +187,9 @@ export class GeoJSONSource extends Evented implements Source { } } - load = () => { - this._updateWorkerData(); - }; + async load() { + await this._updateWorkerData(); + } onAdd(map: Map) { this.map = map; @@ -275,7 +258,9 @@ export class GeoJSONSource extends Evented implements Source { * @returns `this` */ getClusterExpansionZoom(clusterId: number, callback: Callback): this { - this.actor.send('geojson.getClusterExpansionZoom', {clusterId, source: this.id}, callback); + this.actor.sendAsync({type: 'getClusterExpansionZoom', data: {type: this.type, clusterId, source: this.id}}) + .then((v) => callback(null, v)) + .catch((e) => callback(e)); return this; } @@ -287,7 +272,9 @@ export class GeoJSONSource extends Evented implements Source { * @returns `this` */ getClusterChildren(clusterId: number, callback: Callback>): this { - this.actor.send('geojson.getClusterChildren', {clusterId, source: this.id}, callback); + this.actor.sendAsync({type: 'getClusterChildren', data: {type: this.type, clusterId, source: this.id}}) + .then((v) => callback(null, v)) + .catch((e) => callback(e)); return this; } @@ -319,12 +306,14 @@ export class GeoJSONSource extends Evented implements Source { * ``` */ getClusterLeaves(clusterId: number, limit: number, offset: number, callback: Callback>): this { - this.actor.send('geojson.getClusterLeaves', { + this.actor.sendAsync({type: 'getClusterLeaves', data: { + type: this.type, source: this.id, clusterId, limit, offset - }, callback); + }}).then((l) => callback(null, l)) + .catch((e) => callback(e)); return this; } @@ -334,8 +323,8 @@ export class GeoJSONSource extends Evented implements Source { * using geojson-vt or supercluster as appropriate. * @param diff - the diff object */ - _updateWorkerData(diff?: GeoJSONSourceDiff) { - const options = extend({}, this.workerOptions); + async _updateWorkerData(diff?: GeoJSONSourceDiff) { + const options: LoadGeoJSONParameters = extend({}, this.workerOptions); if (diff) { options.dataDiff = diff; } else if (typeof this._data === 'string') { @@ -344,46 +333,46 @@ export class GeoJSONSource extends Evented implements Source { } else { options.data = JSON.stringify(this._data); } - + options.type = this.type; this._pendingLoads++; this.fire(new Event('dataloading', {dataType: 'source'})); - - // target {this.type}.loadData rather than literally geojson.loadData, - // so that other geojson-like source types can easily reuse this - // implementation - this.actor.send(`${this.type}.loadData`, options, (err, result) => { + try { + const result = await this.actor.sendAsync({type: 'loadData', data: options}); this._pendingLoads--; - - if (this._removed || (result && result.abandoned)) { + if (this._removed || result.abandoned) { this.fire(new Event('dataabort', {dataType: 'source'})); return; } - let resourceTiming = null; - if (result && result.resourceTiming && result.resourceTiming[this.id]) + let resourceTiming: PerformanceResourceTiming[] = null; + if (result.resourceTiming && result.resourceTiming[this.id]) { resourceTiming = result.resourceTiming[this.id].slice(0); - - if (err) { - this.fire(new ErrorEvent(err)); - return; } const data: any = {dataType: 'source'}; - if (this._collectResourceTiming && resourceTiming && resourceTiming.length > 0) + if (this._collectResourceTiming && resourceTiming && resourceTiming.length > 0) { extend(data, {resourceTiming}); + } // although GeoJSON sources contain no metadata, we fire this event to let the SourceCache // know its ok to start requesting tiles. this.fire(new Event('data', {...data, sourceDataType: 'metadata'})); this.fire(new Event('data', {...data, sourceDataType: 'content'})); - }); + } catch (err) { + this._pendingLoads--; + if (this._removed) { + this.fire(new Event('dataabort', {dataType: 'source'})); + return; + } + this.fire(new ErrorEvent(err)); + } } loaded(): boolean { return this._pendingLoads === 0; } - loadTile(tile: Tile, callback: Callback) { + async loadTile(tile: Tile): Promise { const message = !tile.actor ? 'loadTile' : 'reloadTile'; tile.actor = this.actor; const params = { @@ -399,48 +388,40 @@ export class GeoJSONSource extends Evented implements Source { promoteId: this.promoteId }; - tile.request = this.actor.send(message, params, (err, data) => { - delete tile.request; - tile.unloadVectorData(); - - if (tile.aborted) { - return callback(null); - } - - if (err) { - return callback(err); - } + tile.abortController = new AbortController(); + const data = await this.actor.sendAsync({type: message, data: params}, tile.abortController); + delete tile.abortController; + tile.unloadVectorData(); + if (!tile.aborted) { tile.loadVectorData(data, this.map.painter, message === 'reloadTile'); - - return callback(null); - }); + } } - abortTile(tile: Tile) { - if (tile.request) { - tile.request.cancel(); - delete tile.request; + async abortTile(tile: Tile) { + if (tile.abortController) { + tile.abortController.abort(); + delete tile.abortController; } tile.aborted = true; } - unloadTile(tile: Tile) { + async unloadTile(tile: Tile) { tile.unloadVectorData(); - this.actor.send('removeTile', {uid: tile.uid, type: this.type, source: this.id}); + await this.actor.sendAsync({type: 'removeTile', data: {uid: tile.uid, type: this.type, source: this.id}}); } onRemove() { this._removed = true; - this.actor.send('removeSource', {type: this.type, source: this.id}); + this.actor.sendAsync({type: 'removeSource', data: {type: this.type, source: this.id}}); } - serialize = (): GeoJSONSourceSpecification => { + serialize(): GeoJSONSourceSpecification { return extend({}, this._options, { type: this.type, data: this._data }); - }; + } hasTransition() { return false; diff --git a/src/source/geojson_worker_source.test.ts b/src/source/geojson_worker_source.test.ts index c4e1643973..c540aaa4de 100644 --- a/src/source/geojson_worker_source.test.ts +++ b/src/source/geojson_worker_source.test.ts @@ -5,7 +5,7 @@ import perf from '../util/performance'; import {LayerSpecification} from '@maplibre/maplibre-gl-style-spec'; import {Actor} from '../util/actor'; import {WorkerTileParameters} from './worker_source'; -import {setPerformance} from '../util/test/util'; +import {setPerformance, sleep} from '../util/test/util'; import {type FakeServer, fakeServer} from 'nise'; const actor = {send: () => {}} as any as Actor; @@ -15,7 +15,7 @@ beforeEach(() => { }); describe('reloadTile', () => { - test('does not rebuild vector data unless data has changed', done => { + test('does not rebuild vector data unless data has changed', async () => { const layers = [ { id: 'mylayer', @@ -25,12 +25,7 @@ describe('reloadTile', () => { ] as LayerSpecification[]; const layerIndex = new StyleLayerIndex(layers); const source = new GeoJSONWorkerSource(actor, layerIndex, []); - const originalLoadVectorData = source.loadVectorData; - let loadVectorCallCount = 0; - source.loadVectorData = function(params, callback) { - loadVectorCallCount++; - return originalLoadVectorData.call(this, params, callback); - }; + const spy = jest.spyOn(source, 'loadVectorTile'); const geoJson = { 'type': 'Feature', 'geometry': { @@ -45,49 +40,29 @@ describe('reloadTile', () => { maxZoom: 10 }; - function addData(callback) { - source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err) => { - expect(err).toBeNull(); - callback(); - }); - } + await source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters); - function reloadTile(callback) { - source.reloadTile(tileParams as any as WorkerTileParameters, (err, data) => { - expect(err).toBeNull(); - return callback(data); - }); - } + // first call should load vector data from geojson + const firstData = await source.reloadTile(tileParams as any as WorkerTileParameters); + expect(spy).toHaveBeenCalledTimes(1); - addData(() => { - // first call should load vector data from geojson - let firstData; - reloadTile(data => { - firstData = data; - }); - expect(loadVectorCallCount).toBe(1); + // second call won't give us new rawTileData + let data = await source.reloadTile(tileParams as any as WorkerTileParameters); + expect('rawTileData' in data).toBeFalsy(); + data.rawTileData = firstData.rawTileData; + expect(data).toEqual(firstData); - // second call won't give us new rawTileData - reloadTile(data => { - expect('rawTileData' in data).toBeFalsy(); - data.rawTileData = firstData.rawTileData; - expect(data).toEqual(firstData); - }); + // also shouldn't call loadVectorData again + expect(spy).toHaveBeenCalledTimes(1); - // also shouldn't call loadVectorData again - expect(loadVectorCallCount).toBe(1); - - // replace geojson data - addData(() => { - // should call loadVectorData again after changing geojson data - reloadTile(data => { - expect('rawTileData' in data).toBeTruthy(); - expect(data).toEqual(firstData); - }); - expect(loadVectorCallCount).toBe(2); - done(); - }); - }); + // replace geojson data + await source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters); + + // should call loadVectorData again after changing geojson data + data = await source.reloadTile(tileParams as any as WorkerTileParameters); + expect('rawTileData' in data).toBeTruthy(); + expect(data).toEqual(firstData); + expect(spy).toHaveBeenCalledTimes(2); }); }); @@ -109,7 +84,7 @@ describe('resourceTiming', () => { } } as GeoJSON.GeoJSON; - test('loadData - url', done => { + test('loadData - url', async () => { const exampleResourceTiming = { connectEnd: 473, connectStart: 473, @@ -134,19 +109,15 @@ describe('resourceTiming', () => { window.performance.getEntriesByName = jest.fn().mockReturnValue([exampleResourceTiming]); const layerIndex = new StyleLayerIndex(layers); - const source = new GeoJSONWorkerSource(actor, layerIndex, [], (params, callback) => { - callback(null, geoJson); - return {cancel: () => {}}; - }); + const source = new GeoJSONWorkerSource(actor, layerIndex, []); + source.loadGeoJSON = () => Promise.resolve(geoJson); - source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters, (err, result) => { - expect(err).toBeNull(); - expect(result.resourceTiming.testSource).toEqual([exampleResourceTiming]); - done(); - }); + const result = await source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters); + + expect(result.resourceTiming.testSource).toEqual([exampleResourceTiming]); }); - test('loadData - url (resourceTiming fallback method)', done => { + test('loadData - url (resourceTiming fallback method)', async () => { const sampleMarks = [100, 350]; const marks = {}; const measures = {}; @@ -169,29 +140,22 @@ describe('resourceTiming', () => { jest.spyOn(perf, 'clearMeasures').mockImplementation(() => { return null; }); const layerIndex = new StyleLayerIndex(layers); - const source = new GeoJSONWorkerSource(actor, layerIndex, [], (params, callback) => { - callback(null, geoJson); - return {cancel: () => {}}; - }); + const source = new GeoJSONWorkerSource(actor, layerIndex, []); + source.loadGeoJSON = () => Promise.resolve(geoJson); - source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters, (err, result) => { - expect(err).toBeNull(); - expect(result.resourceTiming.testSource).toEqual( - [{'duration': 250, 'entryType': 'measure', 'name': 'http://localhost/nonexistent', 'startTime': 100}] - ); - done(); - }); + const result = await source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters); + + expect(result.resourceTiming.testSource).toEqual( + [{'duration': 250, 'entryType': 'measure', 'name': 'http://localhost/nonexistent', 'startTime': 100}] + ); }); - test('loadData - data', done => { + test('loadData - data', async () => { const layerIndex = new StyleLayerIndex(layers); const source = new GeoJSONWorkerSource(actor, layerIndex, []); - source.loadData({source: 'testSource', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => { - expect(err).toBeNull(); - expect(result.resourceTiming).toBeUndefined(); - done(); - }); + const result = await source.loadData({source: 'testSource', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters); + expect(result.resourceTiming).toBeUndefined(); }); }); @@ -239,131 +203,105 @@ describe('loadData', () => { const layerIndex = new StyleLayerIndex(layers); function createWorker() { - const worker = new GeoJSONWorkerSource(actor, layerIndex, []); - - // Making the call to loadGeoJSON asynchronous - // allows these tests to mimic a message queue building up - // (regardless of timing) - const originalLoadGeoJSON = worker.loadGeoJSON; - worker.loadGeoJSON = function(params, callback) { - const timeout = setTimeout(() => { - originalLoadGeoJSON(params, callback); - }, 0); - - return {cancel: () => clearTimeout(timeout)}; - }; - return worker; + return new GeoJSONWorkerSource(actor, layerIndex, []); } - test('abandons previous callbacks', done => { + test('abandons previous requests', async () => { const worker = createWorker(); - let firstCallbackHasRun = false; - worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => { - expect(err).toBeNull(); - expect(result && result.abandoned).toBeTruthy(); - firstCallbackHasRun = true; + server.respondWith(request => { + request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(geoJson)); }); - worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => { - expect(err).toBeNull(); - expect(result && result.abandoned).toBeFalsy(); - expect(firstCallbackHasRun).toBeTruthy(); - done(); - }); + const p1 = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters); + await sleep(0); + + const p2 = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters); + + await sleep(0); + + server.respond(); + + const firstCallResult = await p1; + expect(firstCallResult && firstCallResult.abandoned).toBeTruthy(); + const result = await p2; + expect(result && result.abandoned).toBeFalsy(); }); - test('removeSource aborts callbacks', done => { + test('removeSource aborts requests', async () => { const worker = createWorker(); - let loadDataCallbackHasRun = false; - worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => { - expect(err).toBeNull(); - expect(result && result.abandoned).toBeTruthy(); - loadDataCallbackHasRun = true; - }); - worker.removeSource({source: 'source1'}, (err) => { - expect(err).toBeFalsy(); - expect(loadDataCallbackHasRun).toBeTruthy(); - done(); + server.respondWith(request => { + request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(geoJson)); }); + + const loadPromise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters); + await sleep(0); + const removePromise = worker.removeSource({source: 'source1', type: 'type'}); + await sleep(0); + + server.respond(); + + const result = await loadPromise; + expect(result && result.abandoned).toBeTruthy(); + await removePromise; }); - test('loadData with geojson creates an non-updateable source', done => { + test('loadData with geojson creates an non-updateable source', async () => { const worker = new GeoJSONWorkerSource(actor, layerIndex, []); - worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeDefined(); - done(); - }); - }); + await worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters); + await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).rejects.toBeDefined(); }); - test('loadData with geojson creates an updateable source', done => { + test('loadData with geojson creates an updateable source', async () => { const worker = new GeoJSONWorkerSource(actor, layerIndex, []); - worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - done(); - }); - }); + await worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters); + await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).resolves.toBeDefined(); }); - test('loadData with geojson network call creates an updateable source', done => { + test('loadData with geojson network call creates an updateable source', async () => { const worker = new GeoJSONWorkerSource(actor, layerIndex, []); server.respondWith(request => { request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(updateableGeoJson)); }); - worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - done(); - }); - }); - + const load1Promise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters); server.respond(); + + await load1Promise; + await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).resolves.toBeDefined(); }); - test('loadData with geojson network call creates a non-updateable source', done => { + test('loadData with geojson network call creates a non-updateable source', async () => { const worker = new GeoJSONWorkerSource(actor, layerIndex, []); server.respondWith(request => { request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(geoJson)); }); - worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeDefined(); - done(); - }); - }); + const promise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters); server.respond(); + + await promise; + + await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).rejects.toBeDefined(); }); - test('loadData with diff updates', done => { + test('loadData with diff updates', async () => { const worker = new GeoJSONWorkerSource(actor, layerIndex, []); - worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - worker.loadData({source: 'source1', dataDiff: { - add: [{ - type: 'Feature', - id: 'update_point', - geometry: {type: 'Point', coordinates: [0, 0]}, - properties: {} - }]}} as LoadGeoJSONParameters, (err, _result) => { - expect(err).toBeNull(); - done(); - }); - }); + await worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters); + await expect(worker.loadData({source: 'source1', dataDiff: { + add: [{ + type: 'Feature', + id: 'update_point', + geometry: {type: 'Point', coordinates: [0, 0]}, + properties: {} + }] + }} as LoadGeoJSONParameters)).resolves.toBeDefined(); }); }); diff --git a/src/source/geojson_worker_source.ts b/src/source/geojson_worker_source.ts index a0fc131c70..1634d81522 100644 --- a/src/source/geojson_worker_source.ts +++ b/src/source/geojson_worker_source.ts @@ -1,5 +1,4 @@ import {getJSON} from '../util/ajax'; - import {RequestPerformance} from '../util/performance'; import rewind from '@mapbox/geojson-rewind'; import {GeoJSONWrapper} from './geojson_wrapper'; @@ -8,38 +7,46 @@ import Supercluster, {type Options as SuperclusterOptions, type ClusterPropertie import geojsonvt, {type Options as GeoJSONVTOptions} from 'geojson-vt'; import {VectorTileWorkerSource} from './vector_tile_worker_source'; import {createExpression} from '@maplibre/maplibre-gl-style-spec'; +import {isAbortError} from '../util/abort_error'; import type { WorkerTileParameters, - WorkerTileCallback, + WorkerTileResult, } from '../source/worker_source'; -import type {Actor} from '../util/actor'; -import type {StyleLayerIndex} from '../style/style_layer_index'; - -import type {LoadVectorDataCallback} from './vector_tile_worker_source'; -import type {RequestParameters, ResponseCallback} from '../util/ajax'; -import type {Callback} from '../types/callback'; -import type {Cancelable} from '../types/cancelable'; +import type {LoadVectorTileResult} from './vector_tile_worker_source'; +import type {RequestParameters} from '../util/ajax'; import {isUpdateableGeoJSON, type GeoJSONSourceDiff, applySourceDiff, toUpdateable, GeoJSONFeatureId} from './geojson_source_diff'; +import type {ClusterIDAndSource, GeoJSONWorkerSourceLoadDataResult, RemoveSourceParams} from '../util/actor_messages'; -export type LoadGeoJSONParameters = { +/** + * The geojson worker options that can be passed to the worker + */ +export type GeoJSONWorkerOptions = { + source?: string; + cluster?: boolean; + geojsonVtOptions?: GeoJSONVTOptions; + superclusterOptions?: SuperclusterOptions; + clusterProperties?: ClusterProperties; + filter?: Array; + promoteId?: string; + collectResourceTiming?: boolean; +} + +/** + * Parameters needed to load a geojson to the wokrer + */ +export type LoadGeoJSONParameters = GeoJSONWorkerOptions & { + type: 'geojson'; request?: RequestParameters; /** * Literal GeoJSON data. Must be provided if `request.url` is not. */ data?: string; dataDiff?: GeoJSONSourceDiff; - source: string; - cluster: boolean; - superclusterOptions?: SuperclusterOptions; - geojsonVtOptions?: GeoJSONVTOptions; - clusterProperties?: ClusterProperties; - filter?: Array; - promoteId?: string; }; -export type LoadGeoJSON = (params: LoadGeoJSONParameters, callback: ResponseCallback) => Cancelable; +export type LoadGeoJSON = (params: LoadGeoJSONParameters, abortController: AbortController) => Promise; type GeoJSONIndex = ReturnType | Supercluster; @@ -52,37 +59,20 @@ type GeoJSONIndex = ReturnType | Supercluster; * For a full example, see [mapbox-gl-topojson](https://github.com/developmentseed/mapbox-gl-topojson). */ export class GeoJSONWorkerSource extends VectorTileWorkerSource { - _pendingCallback: Callback<{ - resourceTiming?: {[_: string]: Array}; - abandoned?: boolean; - }>; - _pendingRequest: Cancelable; + _pendingRequest: AbortController; _geoJSONIndex: GeoJSONIndex; _dataUpdateable = new Map(); - /** - * @param loadGeoJSON - Optional method for custom loading/parsing of - * GeoJSON based on parameters passed from the main-thread Source. - * See {@link GeoJSONWorkerSource#loadGeoJSON}. - */ - constructor(actor: Actor, layerIndex: StyleLayerIndex, availableImages: Array, loadGeoJSON?: LoadGeoJSON | null) { - super(actor, layerIndex, availableImages); - this.loadVectorData = this.loadGeoJSONTile; - if (loadGeoJSON) { - this.loadGeoJSON = loadGeoJSON; - } - } - - loadGeoJSONTile(params: WorkerTileParameters, callback: LoadVectorDataCallback): (() => void) | void { + override async loadVectorTile(params: WorkerTileParameters, _abortController: AbortController): Promise { const canonical = params.tileID.canonical; if (!this._geoJSONIndex) { - return callback(null, null); // we couldn't load the file + throw new Error('Unable to parse the data into a cluster or geojson'); } const geoJSONTile = this._geoJSONIndex.getTile(canonical.z, canonical.x, canonical.y); if (!geoJSONTile) { - return callback(null, null); // nothing in the given tile + return null; } const geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features); @@ -95,10 +85,10 @@ export class GeoJSONWorkerSource extends VectorTileWorkerSource { pbf = new Uint8Array(pbf); } - callback(null, { + return { vectorTile: geojsonWrapper, rawData: pbf.buffer - }); + }; } /** @@ -107,72 +97,60 @@ export class GeoJSONWorkerSource extends VectorTileWorkerSource { * can correctly serve up tiles. * * Defers to {@link GeoJSONWorkerSource#loadGeoJSON} for the fetching/parsing, - * expecting `callback(error, data)` to be called with either an error or a - * parsed GeoJSON object. * * When a `loadData` request comes in while a previous one is being processed, * the previous one is aborted. * * @param params - the parameters - * @param callback - the callback for completion or error + * @returns a promise that resolves when the data is loaded and parsed into a GeoJSON object */ - loadData(params: LoadGeoJSONParameters, callback: Callback<{ - resourceTiming?: {[_: string]: Array}; - abandoned?: boolean; - }>) { - this._pendingRequest?.cancel(); - if (this._pendingCallback) { - // Tell the foreground the previous call has been abandoned - this._pendingCallback(null, {abandoned: true}); - } - + async loadData(params: LoadGeoJSONParameters): Promise { + this._pendingRequest?.abort(); const perf = (params && params.request && params.request.collectResourceTiming) ? new RequestPerformance(params.request) : false; - this._pendingCallback = callback; - this._pendingRequest = this.loadGeoJSON(params, (err?: Error | null, data?: any | null) => { - delete this._pendingCallback; + this._pendingRequest = new AbortController(); + try { + let data = await this.loadGeoJSON(params, this._pendingRequest); delete this._pendingRequest; + if (typeof data !== 'object') { + throw new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`); + } + rewind(data, true); - if (err || !data) { - return callback(err); - } else if (typeof data !== 'object') { - return callback(new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`)); - } else { - rewind(data, true); - - try { - if (params.filter) { - const compiled = createExpression(params.filter, {type: 'boolean', 'property-type': 'data-driven', overridable: false, transition: false} as any); - if (compiled.result === 'error') - throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', ')); - - const features = data.features.filter(feature => compiled.value.evaluate({zoom: 0}, feature)); - data = {type: 'FeatureCollection', features}; - } - - this._geoJSONIndex = params.cluster ? - new Supercluster(getSuperclusterOptions(params)).load(data.features) : - geojsonvt(data, params.geojsonVtOptions); - } catch (err) { - return callback(err); - } + if (params.filter) { + const compiled = createExpression(params.filter, {type: 'boolean', 'property-type': 'data-driven', overridable: false, transition: false} as any); + if (compiled.result === 'error') + throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', ')); + + const features = (data as any).features.filter(feature => compiled.value.evaluate({zoom: 0}, feature)); + data = {type: 'FeatureCollection', features}; + } - this.loaded = {}; - - const result = {} as { resourceTiming: any }; - if (perf) { - const resourceTimingData = perf.finish(); - // it's necessary to eval the result of getEntriesByName() here via parse/stringify - // late evaluation in the main thread causes TypeError: illegal invocation - if (resourceTimingData) { - result.resourceTiming = {}; - result.resourceTiming[params.source] = JSON.parse(JSON.stringify(resourceTimingData)); - } + this._geoJSONIndex = params.cluster ? + new Supercluster(getSuperclusterOptions(params)).load((data as any).features) : + geojsonvt(data, params.geojsonVtOptions); + + this.loaded = {}; + + const result = {} as GeoJSONWorkerSourceLoadDataResult; + if (perf) { + const resourceTimingData = perf.finish(); + // it's necessary to eval the result of getEntriesByName() here via parse/stringify + // late evaluation in the main thread causes TypeError: illegal invocation + if (resourceTimingData) { + result.resourceTiming = {}; + result.resourceTiming[params.source] = JSON.parse(JSON.stringify(resourceTimingData)); } - callback(null, result); } - }); + return result; + } catch (err) { + delete this._pendingRequest; + if (isAbortError(err)) { + return {abandoned: true}; + } + throw err; + } } /** @@ -182,108 +160,75 @@ export class GeoJSONWorkerSource extends VectorTileWorkerSource { * Otherwise, such as after a setData() call, we load the tile fresh. * * @param params - the parameters - * @param callback - the callback for completion or error + * @returns A promise that resolves when the tile is reloaded */ - reloadTile(params: WorkerTileParameters, callback: WorkerTileCallback) { + reloadTile(params: WorkerTileParameters): Promise { const loaded = this.loaded, uid = params.uid; if (loaded && loaded[uid]) { - return super.reloadTile(params, callback); + return super.reloadTile(params); } else { - return this.loadTile(params, callback); + return this.loadTile(params); } } /** - * Fetch and parse GeoJSON according to the given params. Calls `callback` - * with `(err, data)`, where `data` is a parsed GeoJSON object. + * Fetch and parse GeoJSON according to the given params. * * GeoJSON is loaded and parsed from `params.url` if it exists, or else * expected as a literal (string or object) `params.data`. * * @param params - the parameters - * @param callback - the callback for completion or error - * @returns A Cancelable object. + * @param abortController - the abort controller that allows aborting this operation + * @returns a promise that resolves when the data is loaded */ - loadGeoJSON = (params: LoadGeoJSONParameters, callback: ResponseCallback): Cancelable => { + async loadGeoJSON(params: LoadGeoJSONParameters, abortController: AbortController): Promise { const {promoteId} = params; - // Because of same origin issues, urls must either include an explicit - // origin or absolute path. - // ie: /foo/bar.json or http://example.com/bar.json - // but not ../foo/bar.json if (params.request) { - return getJSON(params.request, ( - error?: Error, - data?: any, - cacheControl?: string, - expires?: string - ) => { - this._dataUpdateable = isUpdateableGeoJSON(data, promoteId) ? toUpdateable(data, promoteId) : undefined; - callback(error, data, cacheControl, expires); - }); - } else if (typeof params.data === 'string') { + const response = await getJSON(params.request, abortController); + this._dataUpdateable = isUpdateableGeoJSON(response.data, promoteId) ? toUpdateable(response.data, promoteId) : undefined; + return response.data; + } + if (typeof params.data === 'string') { try { const parsed = JSON.parse(params.data); this._dataUpdateable = isUpdateableGeoJSON(parsed, promoteId) ? toUpdateable(parsed, promoteId) : undefined; - callback(null, parsed); + return parsed; } catch (e) { - callback(new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`)); + throw new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`); } - } else if (params.dataDiff) { - if (this._dataUpdateable) { - applySourceDiff(this._dataUpdateable, params.dataDiff, promoteId); - callback(null, {type: 'FeatureCollection', features: Array.from(this._dataUpdateable.values())}); - } else { - callback(new Error(`Cannot update existing geojson data in ${params.source}`)); - } - } else { - callback(new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`)); } - - return {cancel: () => {}}; - }; - - removeSource(params: { - source: string; - }, callback: WorkerTileCallback) { - if (this._pendingCallback) { - // Don't leak callbacks - this._pendingCallback(null, {abandoned: true}); + if (!params.dataDiff) { + throw new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`); + } + if (!this._dataUpdateable) { + throw new Error(`Cannot update existing geojson data in ${params.source}`); } - callback(); + applySourceDiff(this._dataUpdateable, params.dataDiff, promoteId); + return {type: 'FeatureCollection', features: Array.from(this._dataUpdateable.values())}; } - getClusterExpansionZoom(params: { - clusterId: number; - }, callback: Callback) { - try { - callback(null, (this._geoJSONIndex as Supercluster).getClusterExpansionZoom(params.clusterId)); - } catch (e) { - callback(e); + async removeSource(_params: RemoveSourceParams): Promise { + if (this._pendingRequest) { + this._pendingRequest.abort(); } } - getClusterChildren(params: { - clusterId: number; - }, callback: Callback>) { - try { - callback(null, (this._geoJSONIndex as Supercluster).getChildren(params.clusterId)); - } catch (e) { - callback(e); - } + getClusterExpansionZoom(params: ClusterIDAndSource): number { + return (this._geoJSONIndex as Supercluster).getClusterExpansionZoom(params.clusterId); + } + + getClusterChildren(params: ClusterIDAndSource): Array { + return (this._geoJSONIndex as Supercluster).getChildren(params.clusterId); } getClusterLeaves(params: { clusterId: number; limit: number; offset: number; - }, callback: Callback>) { - try { - callback(null, (this._geoJSONIndex as Supercluster).getLeaves(params.clusterId, params.limit, params.offset)); - } catch (e) { - callback(e); - } + }): Array { + return (this._geoJSONIndex as Supercluster).getLeaves(params.clusterId, params.limit, params.offset); } } diff --git a/src/source/image_source.test.ts b/src/source/image_source.test.ts index 124b2a86cf..cbb9fab461 100644 --- a/src/source/image_source.test.ts +++ b/src/source/image_source.test.ts @@ -4,8 +4,7 @@ import {Transform} from '../geo/transform'; import {extend} from '../util/util'; import {type FakeServer, fakeServer} from 'nise'; import {RequestManager} from '../util/request_manager'; -import {Dispatcher} from '../util/dispatcher'; -import {stubAjaxGetImage} from '../util/test/util'; +import {sleep, stubAjaxGetImage} from '../util/test/util'; import {Tile} from './tile'; import {OverscaledTileID} from './tile_id'; import {VertexBuffer} from '../gl/vertex_buffer'; @@ -18,7 +17,7 @@ function createSource(options) { coordinates: [[0, 0], [1, 0], [1, 1], [0, 1]] }, options); - const source = new ImageSource('id', options, {send() {}} as any as Dispatcher, options.eventedParent); + const source = new ImageSource('id', options, {} as any, options.eventedParent); return source; } @@ -61,13 +60,14 @@ describe('ImageSource', () => { expect(source.tileSize).toBe(512); }); - test('fires dataloading event', () => { + test('fires dataloading event', async () => { const source = createSource({url: '/image.png'}); source.on('dataloading', (e) => { expect(e.dataType).toBe('source'); }); source.onAdd(new StubMap() as any); server.respond(); + await sleep(0); expect(source.image).toBeTruthy(); }); @@ -110,7 +110,7 @@ describe('ImageSource', () => { expect(afterSerialized.coordinates).toEqual([[0, 0], [-1, 0], [-1, -1], [0, -1]]); }); - test('sets coordinates via updateImage', () => { + test('sets coordinates via updateImage', async () => { const source = createSource({url: '/image.png'}); const map = new StubMap() as any; source.onAdd(map); @@ -122,6 +122,7 @@ describe('ImageSource', () => { coordinates: [[0, 0], [-1, 0], [-1, -1], [0, -1]] }); server.respond(); + await sleep(0); const afterSerialized = source.serialize(); expect(afterSerialized.coordinates).toEqual([[0, 0], [-1, 0], [-1, -1], [0, -1]]); }); @@ -164,7 +165,7 @@ describe('ImageSource', () => { source.tiles[String(tile.tileID.wrap)] = tile; source.image = new ImageBitmap(); // assign dummies directly so we don't need to stub the gl things - source.boundsBuffer = {} as VertexBuffer; + source.boundsBuffer = {destroy: () => {}} as VertexBuffer; source.boundsSegments = {} as SegmentVector; source.texture = {} as Texture; source.prepare(); @@ -179,22 +180,27 @@ describe('ImageSource', () => { expect(serialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]); }); - test('allows using updateImage before initial image is loaded', () => { - const source = createSource({url: '/image.png'}); + test('allows using updateImage before initial image is loaded', async () => { const map = new StubMap() as any; + const source = createSource({url: '/image.png', eventedParent: map}); + // Suppress errors because we're aborting when updating. + map.on('error', () => {}); source.onAdd(map); - expect(source.image).toBeUndefined(); source.updateImage({url: '/image2.png'}); server.respond(); + await sleep(10); + expect(source.image).toBeTruthy(); }); test('cancels request if updateImage is used', () => { - const source = createSource({url: '/image.png'}); const map = new StubMap() as any; + const source = createSource({url: '/image.png', eventedParent: map}); + // Suppress errors because we're aborting. + map.on('error', () => {}); source.onAdd(map); const spy = jest.spyOn(server.requests[0] as any, 'abort'); diff --git a/src/source/image_source.ts b/src/source/image_source.ts index 8be422aa54..a27fdbd322 100644 --- a/src/source/image_source.ts +++ b/src/source/image_source.ts @@ -20,7 +20,6 @@ import type { ImageSourceSpecification, VideoSourceSpecification } from '@maplibre/maplibre-gl-style-spec'; -import {Cancelable} from '../types/cancelable'; /** * Four geographical coordinates, @@ -107,7 +106,7 @@ export class ImageSource extends Evented implements Source { boundsBuffer: VertexBuffer; boundsSegments: SegmentVector; _loaded: boolean; - _request: Cancelable; + _request: AbortController; /** @internal */ constructor(id: string, options: ImageSourceSpecification | VideoSourceSpecification | CanvasSourceSpecification, dispatcher: Dispatcher, eventedParent: Evented) { @@ -128,30 +127,30 @@ export class ImageSource extends Evented implements Source { this.options = options; } - load = (newCoordinates?: Coordinates, successCallback?: () => void) => { + async load(newCoordinates?: Coordinates): Promise { this._loaded = false; this.fire(new Event('dataloading', {dataType: 'source'})); this.url = this.options.url; - this._request = ImageRequest.getImage(this.map._requestManager.transformRequest(this.url, ResourceType.Image), (err, image) => { + this._request = new AbortController(); + try { + const image = await ImageRequest.getImage(this.map._requestManager.transformRequest(this.url, ResourceType.Image), this._request); this._request = null; this._loaded = true; - if (err) { - this.fire(new ErrorEvent(err)); - } else if (image) { - this.image = image; + if (image && image.data) { + this.image = image.data; if (newCoordinates) { this.coordinates = newCoordinates; } - if (successCallback) { - successCallback(); - } this._finishLoading(); } - }); - }; + } catch (err) { + this._request = null; + this.fire(new ErrorEvent(err)); + } + } loaded(): boolean { return this._loaded; @@ -170,12 +169,12 @@ export class ImageSource extends Evented implements Source { } if (this._request) { - this._request.cancel(); + this._request.abort(); this._request = null; } this.options.url = options.url; - this.load(options.coordinates, () => { this.texture = null; }); + this.load(options.coordinates).finally(() => { this.texture = null; }); return this; } @@ -193,7 +192,7 @@ export class ImageSource extends Evented implements Source { onRemove() { if (this._request) { - this._request.cancel(); + this._request.abort(); this._request = null; } } @@ -245,7 +244,7 @@ export class ImageSource extends Evented implements Source { return this; } - prepare = () => { + prepare() { if (Object.keys(this.tiles).length === 0 || !this.image) { return; } @@ -279,9 +278,9 @@ export class ImageSource extends Evented implements Source { if (newTilesLoaded) { this.fire(new Event('data', {dataType: 'source', sourceDataType: 'idle', sourceId: this.id})); } - }; + } - loadTile(tile: Tile, callback: Callback) { + async loadTile(tile: Tile, callback?: Callback): Promise { // We have a single tile -- whose coordinates are this.tileID -- that // covers the image we want to render. If that's the one being // requested, set it up with the image; otherwise, mark the tile as @@ -291,20 +290,21 @@ export class ImageSource extends Evented implements Source { if (this.tileID && this.tileID.equals(tile.tileID.canonical)) { this.tiles[String(tile.tileID.wrap)] = tile; tile.buckets = {}; - callback(null); } else { tile.state = 'errored'; - callback(null); + } + if (callback) { + callback(); } } - serialize = (): ImageSourceSpecification | VideoSourceSpecification | CanvasSourceSpecification => { + serialize(): ImageSourceSpecification | VideoSourceSpecification | CanvasSourceSpecification { return { type: 'image', url: this.options.url, coordinates: this.coordinates }; - }; + } hasTransition() { return false; diff --git a/src/source/load_tilejson.ts b/src/source/load_tilejson.ts index 9fc6e61fc8..af38b6afc7 100644 --- a/src/source/load_tilejson.ts +++ b/src/source/load_tilejson.ts @@ -1,42 +1,36 @@ import {pick, extend} from '../util/util'; - import {getJSON} from '../util/ajax'; import {ResourceType} from '../util/request_manager'; import {browser} from '../util/browser'; import type {RequestManager} from '../util/request_manager'; -import type {Callback} from '../types/callback'; import type {TileJSON} from '../types/tilejson'; -import type {Cancelable} from '../types/cancelable'; import type {RasterDEMSourceSpecification, RasterSourceSpecification, VectorSourceSpecification} from '@maplibre/maplibre-gl-style-spec'; -export function loadTileJson( +export async function loadTileJson( options: RasterSourceSpecification | RasterDEMSourceSpecification | VectorSourceSpecification, requestManager: RequestManager, - callback: Callback -): Cancelable { - const loaded = function(err: Error, tileJSON: any) { - if (err) { - return callback(err); - } else if (tileJSON) { - const result: any = pick( - // explicit source options take precedence over TileJSON - extend(tileJSON, options), - ['tiles', 'minzoom', 'maxzoom', 'attribution', 'bounds', 'scheme', 'tileSize', 'encoding'] - ); - - if (tileJSON.vector_layers) { - result.vectorLayers = tileJSON.vector_layers; - result.vectorLayerIds = result.vectorLayers.map((layer) => { return layer.id; }); - } + abortController: AbortController, +): Promise { + let tileJSON: any = options; + if (options.url) { + const response = await getJSON(requestManager.transformRequest(options.url, ResourceType.Source), abortController); + tileJSON = response.data; + } else { + await browser.frameAsync(abortController); + } + if (tileJSON) { + const result: TileJSON = pick( + // explicit source options take precedence over TileJSON + extend(tileJSON, options), + ['tiles', 'minzoom', 'maxzoom', 'attribution', 'bounds', 'scheme', 'tileSize', 'encoding'] + ); - callback(null, result); + if (tileJSON.vector_layers) { + result.vectorLayers = tileJSON.vector_layers; + result.vectorLayerIds = result.vectorLayers.map((layer) => { return layer.id; }); } - }; - if (options.url) { - return getJSON(requestManager.transformRequest(options.url, ResourceType.Source), loaded); - } else { - return browser.frame(() => loaded(null, options)); + return result; } } diff --git a/src/source/query_features.test.ts b/src/source/query_features.test.ts index b9ff7f8610..29fa78e44f 100644 --- a/src/source/query_features.test.ts +++ b/src/source/query_features.test.ts @@ -5,7 +5,6 @@ import { import {SourceCache} from './source_cache'; import {Transform} from '../geo/transform'; import Point from '@mapbox/point-geometry'; -import {Dispatcher} from '../util/dispatcher'; describe('QueryFeatures#rendered', () => { test('returns empty object if source returns no tiles', () => { @@ -23,12 +22,8 @@ describe('QueryFeatures#source', () => { type: 'geojson', data: {type: 'FeatureCollection', features: []} }, { - getActor() { - return { - send(type, params, callback) { return callback(); } - }; - } - } as any as Dispatcher); + getActor() {} + } as any); const result = querySourceFeatures(sourceCache, {}); expect(result).toEqual([]); }); diff --git a/src/source/raster_dem_tile_source.test.ts b/src/source/raster_dem_tile_source.test.ts index 43bf16bbef..b913e9afa1 100644 --- a/src/source/raster_dem_tile_source.test.ts +++ b/src/source/raster_dem_tile_source.test.ts @@ -2,11 +2,11 @@ import {fakeServer, FakeServer} from 'nise'; import {RasterDEMTileSource} from './raster_dem_tile_source'; import {OverscaledTileID} from './tile_id'; import {RequestManager} from '../util/request_manager'; -import {Dispatcher} from '../util/dispatcher'; import {Tile} from './tile'; +import {waitForMetadataEvent} from '../util/test/util'; function createSource(options, transformCallback?) { - const source = new RasterDEMTileSource('id', options, {send() {}} as any as Dispatcher, options.eventedParent); + const source = new RasterDEMTileSource('id', options, {} as any, options.eventedParent); source.onAdd({ transform: {angle: 0, pitch: 0, showCollisionBoxes: false}, _getMapId: () => 1, @@ -21,7 +21,7 @@ function createSource(options, transformCallback?) { return source; } -describe('RasterTileSource', () => { +describe('RasterDEMTileSource', () => { let server: FakeServer; beforeEach(() => { global.fetch = null; @@ -32,7 +32,7 @@ describe('RasterTileSource', () => { server.restore(); }); - test('transforms request for TileJSON URL', done => { + test('transforms request for TileJSON URL', () => { server.respondWith('/source.json', JSON.stringify({ minzoom: 0, maxzoom: 22, @@ -49,10 +49,9 @@ describe('RasterTileSource', () => { expect(transformSpy.mock.calls[0][0]).toBe('/source.json'); expect(transformSpy.mock.calls[0][1]).toBe('Source'); - done(); }); - test('transforms tile urls before requesting', done => { + test('transforms tile urls before requesting', async () => { server.respondWith('/source.json', JSON.stringify({ minzoom: 0, maxzoom: 22, @@ -62,26 +61,23 @@ describe('RasterTileSource', () => { })); const source = createSource({url: '/source.json'}); const transformSpy = jest.spyOn(source.map._requestManager, 'transformRequest'); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - const tile = { - tileID: new OverscaledTileID(10, 0, 10, 5, 5), - state: 'loading', - loadVectorData () {}, - setExpiryData() {} - } as any as Tile; - source.loadTile(tile, () => {}); - - expect(transformSpy).toHaveBeenCalledTimes(1); - expect(transformSpy.mock.calls[0][0]).toBe('http://example.com/10/5/5.png'); - expect(transformSpy.mock.calls[0][1]).toBe('Tile'); - done(); - - } - }); + const promise = waitForMetadataEvent(source); server.respond(); + await promise; + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData () {}, + setExpiryData() {} + } as any as Tile; + source.loadTile(tile); + + expect(transformSpy).toHaveBeenCalledTimes(1); + expect(transformSpy.mock.calls[0][0]).toBe('http://example.com/10/5/5.png'); + expect(transformSpy.mock.calls[0][1]).toBe('Tile'); }); - test('populates neighboringTiles', done => { + + test('populates neighboringTiles', async () => { server.respondWith('/source.json', JSON.stringify({ minzoom: 0, maxzoom: 22, @@ -89,66 +85,61 @@ describe('RasterTileSource', () => { tiles: ['http://example.com/{z}/{x}/{y}.png'] })); const source = createSource({url: '/source.json'}); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - const tile = { - tileID: new OverscaledTileID(10, 0, 10, 5, 5), - state: 'loading', - loadVectorData () {}, - setExpiryData() {} - } as any as Tile; - source.loadTile(tile, () => {}); - - expect(Object.keys(tile.neighboringTiles)).toEqual([ - new OverscaledTileID(10, 0, 10, 4, 5).key, - new OverscaledTileID(10, 0, 10, 6, 5).key, - new OverscaledTileID(10, 0, 10, 4, 4).key, - new OverscaledTileID(10, 0, 10, 5, 4).key, - new OverscaledTileID(10, 0, 10, 6, 4).key, - new OverscaledTileID(10, 0, 10, 4, 6).key, - new OverscaledTileID(10, 0, 10, 5, 6).key, - new OverscaledTileID(10, 0, 10, 6, 6).key - ]); - - done(); - - } - }); + const promise = waitForMetadataEvent(source); server.respond(); + await promise; + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData () {}, + setExpiryData() {} + } as any as Tile; + source.loadTile(tile); + + expect(Object.keys(tile.neighboringTiles)).toEqual([ + new OverscaledTileID(10, 0, 10, 4, 5).key, + new OverscaledTileID(10, 0, 10, 6, 5).key, + new OverscaledTileID(10, 0, 10, 4, 4).key, + new OverscaledTileID(10, 0, 10, 5, 4).key, + new OverscaledTileID(10, 0, 10, 6, 4).key, + new OverscaledTileID(10, 0, 10, 4, 6).key, + new OverscaledTileID(10, 0, 10, 5, 6).key, + new OverscaledTileID(10, 0, 10, 6, 6).key + ]); }); - test('populates neighboringTiles with wrapped tiles', done => { + test('populates neighboringTiles with wrapped tiles', async () => { server.respondWith('/source.json', JSON.stringify({ minzoom: 0, maxzoom: 22, attribution: 'MapLibre', tiles: ['http://example.com/{z}/{x}/{y}.png'] })); + const source = createSource({url: '/source.json'}); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - const tile = { - tileID: new OverscaledTileID(5, 0, 5, 31, 5), - state: 'loading', - loadVectorData () {}, - setExpiryData() {} - } as any as Tile; - source.loadTile(tile, () => {}); - - expect(Object.keys(tile.neighboringTiles)).toEqual([ - new OverscaledTileID(5, 0, 5, 30, 6).key, - new OverscaledTileID(5, 0, 5, 31, 6).key, - new OverscaledTileID(5, 0, 5, 30, 5).key, - new OverscaledTileID(5, 1, 5, 0, 5).key, - new OverscaledTileID(5, 0, 5, 30, 4).key, - new OverscaledTileID(5, 0, 5, 31, 4).key, - new OverscaledTileID(5, 1, 5, 0, 4).key, - new OverscaledTileID(5, 1, 5, 0, 6).key - ]); - done(); - } - }); + const promise = waitForMetadataEvent(source); + server.respond(); + await promise; + + const tile = { + tileID: new OverscaledTileID(5, 0, 5, 31, 5), + state: 'loading', + loadVectorData() {}, + setExpiryData() {} + } as any as Tile; + source.loadTile(tile); + + expect(Object.keys(tile.neighboringTiles)).toEqual([ + new OverscaledTileID(5, 0, 5, 30, 6).key, + new OverscaledTileID(5, 0, 5, 31, 6).key, + new OverscaledTileID(5, 0, 5, 30, 5).key, + new OverscaledTileID(5, 1, 5, 0, 5).key, + new OverscaledTileID(5, 0, 5, 30, 4).key, + new OverscaledTileID(5, 0, 5, 31, 4).key, + new OverscaledTileID(5, 1, 5, 0, 4).key, + new OverscaledTileID(5, 1, 5, 0, 6).key + ]); }); it('serializes options', () => { diff --git a/src/source/raster_dem_tile_source.ts b/src/source/raster_dem_tile_source.ts index 19d052245e..dbb11342c5 100644 --- a/src/source/raster_dem_tile_source.ts +++ b/src/source/raster_dem_tile_source.ts @@ -13,9 +13,7 @@ import type {DEMEncoding} from '../data/dem_data'; import type {Source} from './source'; import type {Dispatcher} from '../util/dispatcher'; import type {Tile} from './tile'; -import type {Callback} from '../types/callback'; import type {RasterDEMSourceSpecification} from '@maplibre/maplibre-gl-style-spec'; -import type {ExpiryData} from '../util/ajax'; import {isOffscreenCanvasDistorted} from '../util/offscreen_canvas_distorted'; import {RGBAImage} from '../util/image'; @@ -54,25 +52,28 @@ export class RasterDEMTileSource extends RasterTileSource implements Source { this.baseShift = options.baseShift; } - loadTile(tile: Tile, callback: Callback) { + override async loadTile(tile: Tile): Promise { const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme); const request = this.map._requestManager.transformRequest(url, ResourceType.Tile); tile.neighboringTiles = this._getNeighboringTiles(tile.tileID); - tile.request = ImageRequest.getImage(request, async (err: Error, img: (HTMLImageElement | ImageBitmap), expiry: ExpiryData) => { - delete tile.request; + tile.abortController = new AbortController(); + try { + const response = await ImageRequest.getImage(request, tile.abortController, this.map._refreshExpiredTiles); + delete tile.abortController; if (tile.aborted) { tile.state = 'unloaded'; - callback(null); - } else if (err) { - tile.state = 'errored'; - callback(err); - } else if (img) { - if (this.map._refreshExpiredTiles) tile.setExpiryData(expiry); + return; + } + if (response && response.data) { + const img = response.data; + if (this.map._refreshExpiredTiles && response.cacheControl && response.expires) { + tile.setExpiryData({cacheControl: response.cacheControl, expires: response.expires}); + } const transfer = isImageBitmap(img) && offscreenCanvasSupported(); - const rawImageData = transfer ? img : await readImageNow(img); + const rawImageData = transfer ? img : await this.readImageNow(img); const params = { + type: this.type, uid: tile.uid, - coord: tile.tileID, source: this.id, rawImageData, encoding: this.encoding, @@ -84,38 +85,37 @@ export class RasterDEMTileSource extends RasterTileSource implements Source { if (!tile.actor || tile.state === 'expired') { tile.actor = this.dispatcher.getActor(); - tile.actor.send('loadDEMTile', params, done); - } - } - }, this.map._refreshExpiredTiles); - - async function readImageNow(img: ImageBitmap | HTMLImageElement): Promise { - if (typeof VideoFrame !== 'undefined' && isOffscreenCanvasDistorted()) { - const width = img.width + 2; - const height = img.height + 2; - try { - return new RGBAImage({width, height}, await readImageUsingVideoFrame(img, -1, -1, width, height)); - } catch (e) { - // fall-back to browser canvas decoding + /* eslint-disable require-atomic-updates */ + const data = await tile.actor.sendAsync({type: 'loadDEMTile', data: params}); + tile.dem = data; + tile.needsHillshadePrepare = true; + tile.needsTerrainPrepare = true; + tile.state = 'loaded'; + /* eslint-enable require-atomic-updates */ } } - return browser.getImageData(img, 1); - } - - function done(err, data) { - if (err) { + } catch (err) { + delete tile.abortController; + if (tile.aborted) { + tile.state = 'unloaded'; + } else if (err) { tile.state = 'errored'; - callback(err); + throw err; } + } + } - if (data) { - tile.dem = data; - tile.needsHillshadePrepare = true; - tile.needsTerrainPrepare = true; - tile.state = 'loaded'; - callback(null); + async readImageNow(img: ImageBitmap | HTMLImageElement): Promise { + if (typeof VideoFrame !== 'undefined' && isOffscreenCanvasDistorted()) { + const width = img.width + 2; + const height = img.height + 2; + try { + return new RGBAImage({width, height}, await readImageUsingVideoFrame(img, -1, -1, width, height)); + } catch (e) { + // fall-back to browser canvas decoding } } + return browser.getImageData(img, 1); } _getNeighboringTiles(tileID: OverscaledTileID) { @@ -148,7 +148,7 @@ export class RasterDEMTileSource extends RasterTileSource implements Source { return neighboringTiles; } - unloadTile(tile: Tile) { + async unloadTile(tile: Tile) { if (tile.demTexture) this.map.painter.saveTileTexture(tile.demTexture); if (tile.fbo) { tile.fbo.destroy(); @@ -159,7 +159,7 @@ export class RasterDEMTileSource extends RasterTileSource implements Source { tile.state = 'unloaded'; if (tile.actor) { - tile.actor.send('removeDEMTile', {uid: tile.uid, source: this.id}); + await tile.actor.sendAsync({type: 'removeDEMTile', data: {type: this.type, uid: tile.uid, source: this.id}}); } } } diff --git a/src/source/raster_dem_tile_worker_source.test.ts b/src/source/raster_dem_tile_worker_source.test.ts index 0641912f57..f76e2e68a5 100644 --- a/src/source/raster_dem_tile_worker_source.test.ts +++ b/src/source/raster_dem_tile_worker_source.test.ts @@ -3,20 +3,17 @@ import {DEMData} from '../data/dem_data'; import {WorkerDEMTileParameters} from './worker_source'; describe('loadTile', () => { - test('loads DEM tile', done => { + test('loads DEM tile', async () => { const source = new RasterDEMTileWorkerSource(); - source.loadTile({ + const data = await source.loadTile({ source: 'source', uid: '0', rawImageData: {data: new Uint8ClampedArray(256), height: 8, width: 8}, dim: 256 - } as any as WorkerDEMTileParameters, (err, data) => { - if (err) done(err); - expect(Object.keys(source.loaded)).toEqual(['0']); - expect(data instanceof DEMData).toBeTruthy(); - done(); - }); + } as any as WorkerDEMTileParameters); + expect(Object.keys(source.loaded)).toEqual(['0']); + expect(data instanceof DEMData).toBeTruthy(); }); }); @@ -30,7 +27,8 @@ describe('removeTile', () => { source.removeTile({ source: 'source', - uid: '0' + uid: '0', + type: 'raster-dem', }); expect(source.loaded).toEqual({}); diff --git a/src/source/raster_dem_tile_worker_source.ts b/src/source/raster_dem_tile_worker_source.ts index d283804633..f654ca1b8d 100644 --- a/src/source/raster_dem_tile_worker_source.ts +++ b/src/source/raster_dem_tile_worker_source.ts @@ -3,7 +3,6 @@ import {RGBAImage} from '../util/image'; import type {Actor} from '../util/actor'; import type { WorkerDEMTileParameters, - WorkerDEMTileCallback, TileParameters } from './worker_source'; import {getImageData, isImageBitmap} from '../util/util'; @@ -16,17 +15,17 @@ export class RasterDEMTileWorkerSource { this.loaded = {}; } - async loadTile(params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) { + async loadTile(params: WorkerDEMTileParameters): Promise { const {uid, encoding, rawImageData, redFactor, greenFactor, blueFactor, baseShift} = params; const width = rawImageData.width + 2; const height = rawImageData.height + 2; - const imagePixels: RGBAImage = isImageBitmap(rawImageData) ? + const imagePixels: RGBAImage | ImageData = isImageBitmap(rawImageData) ? new RGBAImage({width, height}, await getImageData(rawImageData, -1, -1, width, height)) : rawImageData; const dem = new DEMData(uid, imagePixels, encoding, redFactor, greenFactor, blueFactor, baseShift); this.loaded = this.loaded || {}; this.loaded[uid] = dem; - callback(null, dem); + return dem; } removeTile(params: TileParameters) { diff --git a/src/source/raster_tile_source.test.ts b/src/source/raster_tile_source.test.ts index 74f589fd7e..76fcdfb3a1 100644 --- a/src/source/raster_tile_source.test.ts +++ b/src/source/raster_tile_source.test.ts @@ -15,9 +15,7 @@ function createSource(options, transformCallback?) { getPixelRatio() { return 1; } } as any); - source.on('error', (e) => { - throw e.error; - }); + source.on('error', () => { }); // to prevent console log of errors return source; } @@ -124,7 +122,7 @@ describe('RasterTileSource', () => { loadVectorData () {}, setExpiryData() {} } as any as Tile; - source.loadTile(tile, () => {}); + source.loadTile(tile); expect(transformSpy).toHaveBeenCalledTimes(1); expect(transformSpy.mock.calls[0][0]).toBe('http://example.com/10/5/5.png'); expect(transformSpy.mock.calls[0][1]).toBe('Tile'); @@ -154,7 +152,7 @@ describe('RasterTileSource', () => { tileID: new OverscaledTileID(10, 0, 10, 5, 5), state: 'loading' } as any as Tile; - source.loadTile(tile, () => { + source.loadTile(tile).then(() => { expect(imageConstructorSpy).toHaveBeenCalledTimes(1); expect(tile.state).toBe('loaded'); done(); @@ -178,7 +176,7 @@ describe('RasterTileSource', () => { test('cancels TileJSON request if removed', () => { const source = createSource({url: '/source.json'}); source.onRemove(); - expect((server.requests.pop() as any).aborted).toBe(true); + expect((server.lastRequest as any).aborted).toBe(true); }); it('serializes options', () => { diff --git a/src/source/raster_tile_source.ts b/src/source/raster_tile_source.ts index 66630c5099..74e6491aaa 100644 --- a/src/source/raster_tile_source.ts +++ b/src/source/raster_tile_source.ts @@ -13,8 +13,6 @@ import type {OverscaledTileID} from './tile_id'; import type {Map} from '../ui/map'; import type {Dispatcher} from '../util/dispatcher'; import type {Tile} from './tile'; -import type {Callback} from '../types/callback'; -import type {Cancelable} from '../types/cancelable'; import type { RasterSourceSpecification, RasterDEMSourceSpecification @@ -67,7 +65,7 @@ export class RasterTileSource extends Evented implements Source { _loaded: boolean; _options: RasterSourceSpecification | RasterDEMSourceSpecification; - _tileJSONRequest: Cancelable; + _tileJSONRequest: AbortController; constructor(id: string, options: RasterSourceSpecification | RasterDEMSourceSpecification, dispatcher: Dispatcher, eventedParent: Evented) { super(); @@ -87,15 +85,15 @@ export class RasterTileSource extends Evented implements Source { extend(this, pick(options, ['url', 'scheme', 'tileSize'])); } - load() { + async load() { this._loaded = false; this.fire(new Event('dataloading', {dataType: 'source'})); - this._tileJSONRequest = loadTileJson(this._options, this.map._requestManager, (err, tileJSON) => { + this._tileJSONRequest = new AbortController(); + try { + const tileJSON = await loadTileJson(this._options, this.map._requestManager, this._tileJSONRequest); this._tileJSONRequest = null; this._loaded = true; - if (err) { - this.fire(new ErrorEvent(err)); - } else if (tileJSON) { + if (tileJSON) { extend(this, tileJSON); if (tileJSON.bounds) this.tileBounds = new TileBounds(tileJSON.bounds, this.minzoom, this.maxzoom); @@ -105,7 +103,10 @@ export class RasterTileSource extends Evented implements Source { this.fire(new Event('data', {dataType: 'source', sourceDataType: 'metadata'})); this.fire(new Event('data', {dataType: 'source', sourceDataType: 'content'})); } - }); + } catch (err) { + this._tileJSONRequest = null; + this.fire(new ErrorEvent(err)); + } } loaded(): boolean { @@ -119,14 +120,15 @@ export class RasterTileSource extends Evented implements Source { onRemove() { if (this._tileJSONRequest) { - this._tileJSONRequest.cancel(); + this._tileJSONRequest.abort(); this._tileJSONRequest = null; } } setSourceProperty(callback: Function) { if (this._tileJSONRequest) { - this._tileJSONRequest.cancel(); + this._tileJSONRequest.abort(); + this._tileJSONRequest = null; } callback(); @@ -156,22 +158,23 @@ export class RasterTileSource extends Evented implements Source { return !this.tileBounds || this.tileBounds.contains(tileID.canonical); } - loadTile(tile: Tile, callback: Callback) { + async loadTile(tile: Tile): Promise { const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme); - tile.request = ImageRequest.getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), (err, img, expiry) => { - delete tile.request; - + tile.abortController = new AbortController(); + try { + const response = await ImageRequest.getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), tile.abortController, this.map._refreshExpiredTiles); + delete tile.abortController; if (tile.aborted) { tile.state = 'unloaded'; - callback(null); - } else if (err) { - tile.state = 'errored'; - callback(err); - } else if (img) { - if (this.map._refreshExpiredTiles && expiry) tile.setExpiryData(expiry); - + return; + } + if (response && response.data) { + if (this.map._refreshExpiredTiles && response.cacheControl && response.expires) { + tile.setExpiryData({cacheControl: response.cacheControl, expires: response.expires}); + } const context = this.map.painter.context; const gl = context.gl; + const img = response.data; tile.texture = this.map.painter.getTileTexture(img.width); if (tile.texture) { tile.texture.update(img, {useMipmap: true}); @@ -183,25 +186,30 @@ export class RasterTileSource extends Evented implements Source { gl.texParameterf(gl.TEXTURE_2D, context.extTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, context.extTextureFilterAnisotropicMax); } } - tile.state = 'loaded'; - - callback(null); } - }, this.map._refreshExpiredTiles); + } catch (err) { + delete tile.abortController; + if (tile.aborted) { + tile.state = 'unloaded'; + } else if (err) { + tile.state = 'errored'; + throw err; + } + } } - abortTile(tile: Tile, callback: Callback) { - if (tile.request) { - tile.request.cancel(); - delete tile.request; + async abortTile(tile: Tile) { + if (tile.abortController) { + tile.abortController.abort(); + delete tile.abortController; } - callback(); } - unloadTile(tile: Tile, callback: Callback) { - if (tile.texture) this.map.painter.saveTileTexture(tile.texture); - callback(); + async unloadTile(tile: Tile) { + if (tile.texture) { + this.map.painter.saveTileTexture(tile.texture); + } } hasTransition() { diff --git a/src/source/rtl_text_plugin.ts b/src/source/rtl_text_plugin.ts index 249919cad6..6e00b675ee 100644 --- a/src/source/rtl_text_plugin.ts +++ b/src/source/rtl_text_plugin.ts @@ -3,34 +3,44 @@ import {browser} from '../util/browser'; import {Event, Evented} from '../util/evented'; import {isWorker} from '../util/util'; -const status = { - unavailable: 'unavailable', // Not loaded - deferred: 'deferred', // The plugin URL has been specified, but loading has been deferred - loading: 'loading', // request in-flight - loaded: 'loaded', - error: 'error' -}; +/** + * The possible option of the plugin's status + * + * `unavailable`: Not loaded. + * + * `deferred`: The plugin URL has been specified, but loading has been deferred. + * + * `loading`: request in-flight. + * + * `loaded`: The plugin is now loaded + * + * `error`: The plugin failed to load + */ +type RTLPlginStatus = 'unavailable' | 'deferred' | 'loading' | 'loaded' | 'error'; +/** + * The RTL plugin state + */ export type PluginState = { - pluginStatus: typeof status[keyof typeof status]; + pluginStatus: RTLPlginStatus; pluginURL: string; }; /** * An error callback */ -type ErrorCallback = (error?: Error | null) => void; +type ErrorCallback = (error?: Error | string | null) => void; type PluginStateSyncCallback = (state: PluginState) => void; -let _completionCallback = null; +let _completionCallback: ErrorCallback = null; //Variables defining the current state of the plugin -let pluginStatus = status.unavailable; +let pluginStatus: RTLPlginStatus = 'unavailable'; let pluginURL = null; -export const triggerPluginCompletionEvent = function(error: Error | string) { +export const triggerPluginCompletionEvent = (error: string | Error) => { // NetworkError's are not correctly reflected by the plugin status which prevents reloading plugin if (error && typeof error === 'string' && error.indexOf('NetworkError') > -1) { - pluginStatus = status.error; + pluginStatus = 'error'; } if (_completionCallback) { @@ -44,11 +54,11 @@ function sendPluginStateToWorker() { export const evented = new Evented(); -export const getRTLTextPluginStatus = function () { +export const getRTLTextPluginStatus = () => { return pluginStatus; }; -export const registerForPluginStateChange = function(callback: PluginStateSyncCallback) { +export const registerForPluginStateChange = (callback: PluginStateSyncCallback) => { // Do an initial sync of the state callback({pluginStatus, pluginURL}); // Listen for all future state changes @@ -56,18 +66,18 @@ export const registerForPluginStateChange = function(callback: PluginStateSyncCa return callback; }; -export const clearRTLTextPlugin = function() { - pluginStatus = status.unavailable; +export const clearRTLTextPlugin = () => { + pluginStatus = 'unavailable'; pluginURL = null; _completionCallback = null; }; -export const setRTLTextPlugin = function(url: string, callback: ErrorCallback, deferred: boolean = false) { - if (pluginStatus === status.deferred || pluginStatus === status.loading || pluginStatus === status.loaded) { +export const setRTLTextPlugin = (url: string, callback?: ErrorCallback, deferred: boolean = false) => { + if (pluginStatus === 'deferred' || pluginStatus === 'loading' || pluginStatus === 'loaded') { throw new Error('setRTLTextPlugin cannot be called multiple times.'); } pluginURL = browser.resolveURL(url); - pluginStatus = status.deferred; + pluginStatus = 'deferred'; _completionCallback = callback; sendPluginStateToWorker(); @@ -77,26 +87,24 @@ export const setRTLTextPlugin = function(url: string, callback: ErrorCallback, d } }; -export const downloadRTLTextPlugin = function() { - if (pluginStatus !== status.deferred || !pluginURL) { +export const downloadRTLTextPlugin = () => { + if (pluginStatus !== 'deferred' || !pluginURL) { throw new Error('rtl-text-plugin cannot be downloaded unless a pluginURL is specified'); } - pluginStatus = status.loading; + pluginStatus = 'loading'; sendPluginStateToWorker(); - if (pluginURL) { - getArrayBuffer({url: pluginURL}, (error) => { - if (error) { - triggerPluginCompletionEvent(error); - } else { - pluginStatus = status.loaded; - sendPluginStateToWorker(); - } - }); - } + getArrayBuffer({url: pluginURL}, new AbortController()).then(() => { + pluginStatus = 'loaded'; + sendPluginStateToWorker(); + }).catch((error) => { + if (error) { + triggerPluginCompletionEvent(error); + } + }); }; export const plugin: { - applyArabicShaping: Function; + applyArabicShaping: (text: string) => string; processBidirectionalText: ((b: string, a: Array) => Array); processStyledBidirectionalText: ((c: string, b: Array, a: Array) => Array<[string, Array]>); isLoaded: () => boolean; @@ -109,32 +117,32 @@ export const plugin: { processBidirectionalText: null, processStyledBidirectionalText: null, isLoaded() { - return pluginStatus === status.loaded || // Main Thread: loaded if the completion callback returned successfully + return pluginStatus === 'loaded' || // Main Thread: loaded if the completion callback returned successfully plugin.applyArabicShaping != null; // Web-worker: loaded if the plugin functions have been compiled }, isLoading() { // Main Thread Only: query the loading status, this function does not return the correct value in the worker context. - return pluginStatus === status.loading; + return pluginStatus === 'loading'; }, setState(state: PluginState) { // Worker thread only: this tells the worker threads that the plugin is available on the Main thread - if (!isWorker()) throw new Error('Cannot set the state of the rtl-text-plugin when not in the web-worker context'); + if (!isWorker(self)) throw new Error('Cannot set the state of the rtl-text-plugin when not in the web-worker context'); pluginStatus = state.pluginStatus; pluginURL = state.pluginURL; }, isParsed(): boolean { - if (!isWorker()) throw new Error('rtl-text-plugin is only parsed on the worker-threads'); + if (!isWorker(self)) throw new Error('rtl-text-plugin is only parsed on the worker-threads'); return plugin.applyArabicShaping != null && plugin.processBidirectionalText != null && plugin.processStyledBidirectionalText != null; }, getPluginURL(): string { - if (!isWorker()) throw new Error('rtl-text-plugin url can only be queried from the worker threads'); + if (!isWorker(self)) throw new Error('rtl-text-plugin url can only be queried from the worker threads'); return pluginURL; } }; -export const lazyLoadRTLTextPlugin = function() { +export const lazyLoadRTLTextPlugin = () => { if (!plugin.isLoading() && !plugin.isLoaded() && getRTLTextPluginStatus() === 'deferred' diff --git a/src/source/source.ts b/src/source/source.ts index 34c5ce8876..622dddc5ac 100644 --- a/src/source/source.ts +++ b/src/source/source.ts @@ -12,7 +12,6 @@ import type {Event, Evented} from '../util/evented'; import type {Map} from '../ui/map'; import type {Tile} from './tile'; import type {OverscaledTileID, CanonicalTileID} from './tile_id'; -import type {Callback} from '../types/callback'; import type {CanvasSourceSpecification} from '../source/canvas_source'; const registeredSources = {} as {[key:string]: SourceClass}; @@ -33,9 +32,21 @@ export interface Source { * The id for the source. Must not be used by any existing source. */ id: string; + /** + * The minimum zoom level for the source. + */ minzoom: number; + /** + * The maximum zoom level for the source. + */ maxzoom: number; + /** + * The tile size for the source. + */ tileSize: number; + /** + * The attribution for the source. + */ attribution?: string; /** * `true` if zoom levels are rounded to the nearest integer in the source data, `false` if they are floor-ed to the nearest integer. @@ -51,22 +62,60 @@ export interface Source { */ reparseOverscaled?: boolean; vectorLayerIds?: Array; + /** + * True if the source has transiotion, false otherwise. + */ hasTransition(): boolean; + /** + * True if the source is loaded, false otherwise. + */ loaded(): boolean; + /** + * An ability to fire an event to all the listeners, see {@link Evented} + * @param event - The event to fire + */ fire(event: Event): unknown; - readonly onAdd?: (map: Map) => void; - readonly onRemove?: (map: Map) => void; - loadTile(tile: Tile, callback: Callback): void; - readonly hasTile?: (tileID: OverscaledTileID) => boolean; - readonly abortTile?: (tile: Tile, callback: Callback) => void; - readonly unloadTile?: (tile: Tile, callback: Callback) => void; + /** + * This method is called when the source is added to the map. + * @param map - The map instance + */ + onAdd?(map: Map): void; + /** + * This method is called when the source is removed from the map. + * @param map - The map instance + */ + onRemove?(map: Map): void; + /** + * This method does the heavy lifting of loading a tile. + * In most cases it will defer the work to the relevant worker source. + * @param tile - The tile to load + */ + loadTile(tile: Tile): Promise; + /** + * True is the tile is part of the source, false otherwise. + * @param tileID - The tile ID + */ + hasTile?(tileID: OverscaledTileID): boolean; + /** + * Allows to abort a tile loading. + * @param tile - The tile to abort + */ + abortTile?(tile: Tile): Promise; + /** + * Allows to unload a tile. + * @param tile - The tile to unload + */ + unloadTile?(tile: Tile): Promise; /** * @returns A plain (stringifiable) JS object representing the current state of the source. * Creating a source using the returned object as the `options` should result in a Source that is * equivalent to this one. */ serialize(): any; - readonly prepare?: () => void; + /** + * Allows to execute a prepare step before the source is used. + */ + prepare?(): void; } /** @@ -133,7 +182,3 @@ export const getSourceType = (name: string): SourceClass => { export const setSourceType = (name: string, type: SourceClass) => { registeredSources[name] = type; }; - -export interface Actor { - send(type: string, data: any, callback: Callback): void; -} diff --git a/src/source/source_cache.test.ts b/src/source/source_cache.test.ts index 0bf9e8faae..804dee9e2c 100644 --- a/src/source/source_cache.test.ts +++ b/src/source/source_cache.test.ts @@ -1,5 +1,5 @@ import {SourceCache} from './source_cache'; -import {setSourceType} from './source'; +import {Source, setSourceType} from './source'; import {Tile} from './tile'; import {OverscaledTileID} from './tile_id'; import {Transform} from '../geo/transform'; @@ -11,13 +11,16 @@ import {browser} from '../util/browser'; import {Dispatcher} from '../util/dispatcher'; import {Callback} from '../types/callback'; import {TileBounds} from './tile_bounds'; +import {sleep} from '../util/test/util'; -class SourceMock extends Evented { +class SourceMock extends Evented implements Source { id: string; minzoom: number; maxzoom: number; hasTile: (tileID: OverscaledTileID) => boolean; sourceOptions: any; + type: string; + tileSize: number; constructor(id: string, sourceOptions: any, _dispatcher, eventedParent: Evented) { super(); @@ -31,13 +34,18 @@ class SourceMock extends Evented { this.hasTile = sourceOptions.hasTile; } } - loadTile(tile: Tile, callback: Callback) { + loadTile(tile: Tile, callback?: Callback): Promise { if (this.sourceOptions.expires) { tile.setExpiryData({ expires: this.sourceOptions.expires }); } - setTimeout(callback, 0); + if (callback) { + setTimeout(callback, 0); + } else { + return new Promise(resolve => setTimeout(resolve, 0)); + } + } loaded() { return true; @@ -50,9 +58,12 @@ class SourceMock extends Evented { this.fire(new Event('data', {dataType: 'source', sourceDataType: 'metadata'})); } } - abortTile() {} - unloadTile() {} + async abortTile() {} + async unloadTile() {} serialize() {} + hasTransition(): boolean { + return false; + } } // Add a mocked source type for use in these tests @@ -84,13 +95,12 @@ afterEach(() => { describe('SourceCache#addTile', () => { test('loads tile when uncached', done => { const tileID = new OverscaledTileID(0, 0, 0, 0, 0); - const sourceCache = createSourceCache({ - loadTile(tile) { - expect(tile.tileID).toEqual(tileID); - expect(tile.uses).toBe(0); - done(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + expect(tile.tileID).toEqual(tileID); + expect(tile.uses).toBe(0); + done(); + }; sourceCache.onAdd(undefined); sourceCache._addTile(tileID); }); @@ -109,17 +119,15 @@ describe('SourceCache#addTile', () => { test('updates feature state on added uncached tile', done => { const tileID = new OverscaledTileID(0, 0, 0, 0, 0); let updateFeaturesSpy; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - sourceCache.on('data', () => { - expect(updateFeaturesSpy).toHaveBeenCalledTimes(1); - done(); - }); - updateFeaturesSpy = jest.spyOn(tile, 'setFeatureState'); - tile.state = 'loaded'; - callback(); - } - }); + const sourceCache = createSourceCache({}); + sourceCache._source.loadTile = async (tile) => { + sourceCache.on('data', () => { + expect(updateFeaturesSpy).toHaveBeenCalledTimes(1); + done(); + }); + updateFeaturesSpy = jest.spyOn(tile, 'setFeatureState'); + tile.state = 'loaded'; + }; sourceCache.onAdd(undefined); sourceCache._addTile(tileID); }); @@ -129,13 +137,12 @@ describe('SourceCache#addTile', () => { let load = 0, add = 0; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - load++; - callback(); - } - }).on('dataloading', () => { add++; }); + const sourceCache = createSourceCache({}); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + load++; + }; + sourceCache.on('dataloading', () => { add++; }); const tr = new Transform(); tr.width = 512; @@ -153,12 +160,10 @@ describe('SourceCache#addTile', () => { test('updates feature state on cached tile', () => { const tileID = new OverscaledTileID(0, 0, 0, 0, 0); - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - callback(); - } - }); + const sourceCache = createSourceCache({}); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; const tr = new Transform(); tr.width = 512; @@ -184,11 +189,10 @@ describe('SourceCache#addTile', () => { sourceCache._setTileReloadTimer = (id) => { sourceCache._timers[id] = setTimeout(() => {}, 0); }; - sourceCache._loadTile = (tile, callback) => { + sourceCache._source.loadTile = async (tile) => { tile.state = 'loaded'; tile.getExpiryTimeout = () => 1000 * 60; sourceCache._setTileReloadTimer(tileID.key, tile); - callback(); }; const tr = new Transform(); @@ -222,13 +226,12 @@ describe('SourceCache#addTile', () => { let load = 0, add = 0; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - load++; - callback(); - } - }).on('dataloading', () => { add++; }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + load++; + }; + sourceCache.on('dataloading', () => { add++; }); const t1 = sourceCache._addTile(tileID); const t2 = sourceCache._addTile(new OverscaledTileID(0, 1, 0, 0, 0)); @@ -276,16 +279,13 @@ describe('SourceCache#removeTile', () => { }); }); - test('caches (does not unload) loaded tile', done => { + test('caches (does not unload) loaded tile', () => { const tileID = new OverscaledTileID(0, 0, 0, 0, 0); - const sourceCache = createSourceCache({ - loadTile(tile) { - tile.state = 'loaded'; - }, - unloadTile() { - done('test failed: unloadTile has been called'); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; + sourceCache._source.unloadTile = jest.fn(); const tr = new Transform(); tr.width = 512; @@ -295,7 +295,7 @@ describe('SourceCache#removeTile', () => { sourceCache._addTile(tileID); sourceCache._removeTile(tileID.key); - done(); + expect(sourceCache._source.unloadTile).not.toHaveBeenCalled(); }); test('aborts and unloads unfinished tile', () => { @@ -303,16 +303,15 @@ describe('SourceCache#removeTile', () => { let abort = 0, unload = 0; - const sourceCache = createSourceCache({ - abortTile(tile) { - expect(tile.tileID).toEqual(tileID); - abort++; - }, - unloadTile(tile) { - expect(tile.tileID).toEqual(tileID); - unload++; - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.abortTile = async (tile) => { + expect(tile.tileID).toEqual(tileID); + abort++; + }; + sourceCache._source.unloadTile = async (tile) => { + expect(tile.tileID).toEqual(tileID); + unload++; + }; sourceCache._addTile(tileID); sourceCache._removeTile(tileID.key); @@ -325,24 +324,21 @@ describe('SourceCache#removeTile', () => { test('_tileLoaded after _removeTile skips tile.added', () => { const tileID = new OverscaledTileID(0, 0, 0, 0, 0); - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.added = undefined; - sourceCache._removeTile(tileID.key); - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async () => { + sourceCache._removeTile(tileID.key); + }; sourceCache.map = {painter: {crossTileSymbolIndex: '', tileExtentVAO: {}}} as any; sourceCache._addTile(tileID); }); test('fires dataabort event', async () => { - const sourceCache = createSourceCache({ - loadTile() { - // Do not call back in order to make sure the tile is removed before it is loaded. - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = () => { + // Do not call back in order to make sure the tile is removed before it is loaded. + return new Promise(() => {}); + }; const tileID = new OverscaledTileID(0, 0, 0, 0, 0); const tile = sourceCache._addTile(tileID); const abortPromise = sourceCache.once('dataabort'); @@ -354,12 +350,10 @@ describe('SourceCache#removeTile', () => { }); test('does not fire dataabort event when the tile has already been loaded', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; const tileID = new OverscaledTileID(0, 0, 0, 0, 0); sourceCache._addTile(tileID); const onAbort = jest.fn(); @@ -370,15 +364,13 @@ describe('SourceCache#removeTile', () => { test('does not fire data event when the tile has already been aborted', () => { const onData = jest.fn(); - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - sourceCache.once('dataabort', () => { - tile.state = 'loaded'; - callback(); - expect(onData).toHaveBeenCalledTimes(0); - }); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + sourceCache.once('dataabort', () => { + tile.state = 'loaded'; + expect(onData).toHaveBeenCalledTimes(0); + }); + }; sourceCache.once('data', onData); const tileID = new OverscaledTileID(0, 0, 0, 0, 0); sourceCache._addTile(tileID); @@ -437,11 +429,11 @@ describe('SourceCache / Source lifecycle', () => { const transform = new Transform(); transform.resize(511, 511); transform.zoom = 0; - const sourceCache = createSourceCache({ - loadTile (tile, callback) { - callback('error'); - } - }).on('data', (e) => { + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async () => { + throw new Error('Error loading tile'); + }; + sourceCache.on('data', (e) => { if (e.dataType === 'source' && e.sourceDataType === 'metadata') { sourceCache.update(transform); } @@ -488,13 +480,11 @@ describe('SourceCache / Source lifecycle', () => { const expected = [new OverscaledTileID(0, 0, 0, 0, 0).key, new OverscaledTileID(0, 0, 0, 0, 0).key]; expect.assertions(expected.length); - const sourceCache = createSourceCache({ - loadTile (tile, callback) { - expect(tile.tileID.key).toBe(expected.shift()); - tile.loaded = true; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + expect(tile.tileID.key).toBe(expected.shift()); + tile.state = 'loaded'; + }; sourceCache.on('data', (e) => { if (e.dataType === 'source' && e.sourceDataType === 'metadata') { @@ -511,14 +501,12 @@ describe('SourceCache / Source lifecycle', () => { transform.resize(511, 511); transform.zoom = 1; - const sourceCache = createSourceCache({ - loadTile (tile, callback) { - // this transform will try to load the four tiles at z1 and a single z0 tile - // we only expect _reloadTile to be called with the 'loaded' z0 tile - tile.state = tile.tileID.canonical.z === 1 ? 'errored' : 'loaded'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + // this transform will try to load the four tiles at z1 and a single z0 tile + // we only expect _reloadTile to be called with the 'loaded' z0 tile + tile.state = tile.tileID.canonical.z === 1 ? 'errored' : 'loaded'; + }; const reloadTileSpy = jest.spyOn(sourceCache, '_reloadTile'); sourceCache.on('data', (e) => { @@ -595,12 +583,10 @@ describe('SourceCache#update', () => { transform.resize(511, 511); transform.zoom = 0; - const sourceCache = createSourceCache({ - loadTile: (tile, callback) => { - tile.state = 'loaded'; - callback(null); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -629,12 +615,10 @@ describe('SourceCache#update', () => { transform.resize(511, 511); transform.zoom = 0; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = (tile.tileID.key === new OverscaledTileID(0, 0, 0, 0, 0).key) ? 'loaded' : 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = (tile.tileID.key === new OverscaledTileID(0, 0, 0, 0, 0).key) ? 'loaded' : 'loading'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -663,12 +647,10 @@ describe('SourceCache#update', () => { transform.zoom = 0; transform.center = new LngLat(360, 0); - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = (tile.tileID.key === new OverscaledTileID(0, 1, 0, 0, 0).key) ? 'loaded' : 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = (tile.tileID.key === new OverscaledTileID(0, 1, 0, 0, 0).key) ? 'loaded' : 'loading'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -696,14 +678,12 @@ describe('SourceCache#update', () => { transform.resize(511, 511); transform.zoom = 2; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.timeAdded = Infinity; - tile.state = 'loaded'; - tile.registerFadeDuration(100); - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.timeAdded = Infinity; + tile.state = 'loaded'; + tile.registerFadeDuration(100); + }; (sourceCache._source as any).type = 'raster'; @@ -732,14 +712,12 @@ describe('SourceCache#update', () => { transform.resize(511, 511); transform.zoom = 0; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.timeAdded = Infinity; - tile.state = 'loaded'; - tile.registerFadeDuration(100); - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.timeAdded = Infinity; + tile.state = 'loaded'; + tile.registerFadeDuration(100); + }; (sourceCache._source as any).type = 'raster'; @@ -765,15 +743,12 @@ describe('SourceCache#update', () => { transform.resize(511, 511); transform.zoom = 1; - const sourceCache = createSourceCache({ - + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { // not setting fadeEndTime because class Tile default is 0, and need to be tested - loadTile(tile, callback) { - tile.timeAdded = Date.now(); - tile.state = 'loaded'; - callback(); - } - }); + tile.timeAdded = Date.now(); + tile.state = 'loaded'; + }; (sourceCache._source as any).type = 'raster'; @@ -802,14 +777,12 @@ describe('SourceCache#update', () => { let time = start; jest.spyOn(browser, 'now').mockImplementation(() => time); - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.timeAdded = browser.now(); - tile.state = 'loaded'; - tile.fadeEndTime = browser.now() + fadeTime; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.timeAdded = browser.now(); + tile.state = 'loaded'; + tile.fadeEndTime = browser.now() + fadeTime; + }; (sourceCache._source as any).type = 'raster'; @@ -845,13 +818,10 @@ describe('SourceCache#update', () => { // use slightly offset center so that sort order is better defined transform.center = new LngLat(-0.001, 0.001); - const sourceCache = createSourceCache({ - reparseOverscaled: true, - loadTile(tile, callback) { - tile.state = tile.tileID.overscaledZ === 16 ? 'loaded' : 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache({reparseOverscaled: true}); + sourceCache._source.loadTile = async (tile) => { + tile.state = tile.tileID.overscaledZ === 16 ? 'loaded' : 'loading'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -910,12 +880,10 @@ describe('SourceCache#_updateRetainedTiles', () => { test('loads ideal tiles if they exist', () => { const stateCache = {}; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = stateCache[tile.tileID.key] || 'errored'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = stateCache[tile.tileID.key] || 'errored'; + }; const getTileSpy = jest.spyOn(sourceCache, 'getTile'); const idealTile = new OverscaledTileID(1, 0, 1, 1, 1); @@ -926,12 +894,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('retains all loaded children ', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'errored'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'errored'; + }; const idealTile = new OverscaledTileID(3, 0, 3, 1, 2); sourceCache._tiles[idealTile.key] = new Tile(idealTile, undefined); @@ -966,12 +932,10 @@ describe('SourceCache#_updateRetainedTiles', () => { test('adds parent tile if ideal tile errors and no child tiles are loaded', () => { const stateCache = {}; - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = stateCache[tile.tileID.key] || 'errored'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = stateCache[tile.tileID.key] || 'errored'; + }; jest.spyOn(sourceCache, '_addTile'); const getTileSpy = jest.spyOn(sourceCache, 'getTile'); @@ -997,12 +961,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('don\'t use wrong parent tile', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'errored'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'errored'; + }; const idealTile = new OverscaledTileID(2, 0, 2, 0, 0); sourceCache._tiles[idealTile.key] = new Tile(idealTile, undefined); @@ -1031,12 +993,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('use parent tile when ideal tile is not loaded', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const idealTile = new OverscaledTileID(1, 0, 1, 0, 1); const parentTile = new OverscaledTileID(0, 0, 0, 0, 0); sourceCache._tiles[idealTile.key] = new Tile(idealTile, undefined); @@ -1076,12 +1036,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('don\'t load parent if all immediate children are loaded', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const idealTile = new OverscaledTileID(2, 0, 2, 1, 1); const loadedTiles = [new OverscaledTileID(3, 0, 3, 2, 2), new OverscaledTileID(3, 0, 3, 3, 2), new OverscaledTileID(3, 0, 3, 2, 3), new OverscaledTileID(3, 0, 3, 3, 3)]; @@ -1098,12 +1056,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('prefer loaded child tiles to parent tiles', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const idealTile = new OverscaledTileID(1, 0, 1, 0, 0); const loadedTiles = [new OverscaledTileID(0, 0, 0, 0, 0), new OverscaledTileID(2, 0, 2, 0, 0)]; loadedTiles.forEach(t => { @@ -1144,13 +1100,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('don\'t use tiles below minzoom', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - }, - minzoom: 2 - }); + const sourceCache = createSourceCache({minzoom: 2}); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const idealTile = new OverscaledTileID(2, 0, 2, 0, 0); const loadedTiles = [new OverscaledTileID(1, 0, 1, 0, 0)]; loadedTiles.forEach(t => { @@ -1161,6 +1114,8 @@ describe('SourceCache#_updateRetainedTiles', () => { const getTileSpy = jest.spyOn(sourceCache, 'getTile'); const retained = sourceCache._updateRetainedTiles([idealTile], 2); + sleep(10); + expect(getTileSpy.mock.calls.map((c) => { return c[0]; })).toEqual([]); expect(retained).toEqual({ @@ -1171,13 +1126,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('use overzoomed tile above maxzoom', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - }, - maxzoom: 2 - }); + const sourceCache = createSourceCache({maxzoom: 2}); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const idealTile = new OverscaledTileID(2, 0, 2, 0, 0); const getTileSpy = jest.spyOn(sourceCache, 'getTile'); @@ -1199,12 +1151,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('dont\'t ascend multiple times if a tile is not found', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const idealTiles = [new OverscaledTileID(8, 0, 8, 0, 0), new OverscaledTileID(8, 0, 8, 1, 0)]; const getTileSpy = jest.spyOn(sourceCache, 'getTile'); @@ -1241,12 +1191,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('Only retain loaded parent tile when zooming in', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; let idealTiles = [new OverscaledTileID(9, 0, 9, 0, 0), new OverscaledTileID(9, 0, 9, 1, 0)]; let retained = sourceCache._updateRetainedTiles(idealTiles, 9); @@ -1280,12 +1228,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('Only retain loaded child tile when zooming out', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; let idealTiles = [new OverscaledTileID(7, 0, 7, 0, 0), new OverscaledTileID(7, 0, 7, 1, 0)]; let retained = sourceCache._updateRetainedTiles(idealTiles, 7); @@ -1319,13 +1265,10 @@ describe('SourceCache#_updateRetainedTiles', () => { }); test('adds correct loaded parent tiles for overzoomed tiles', () => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loading'; - callback(); - }, - maxzoom: 7 - }); + const sourceCache = createSourceCache({maxzoom: 7}); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + }; const loadedTiles = [new OverscaledTileID(7, 0, 7, 0, 0), new OverscaledTileID(7, 0, 7, 1, 0)]; loadedTiles.forEach(t => { sourceCache._tiles[t.key] = new Tile(t, undefined); @@ -1352,16 +1295,15 @@ describe('SourceCache#clearTiles', () => { let abort = 0, unload = 0; - const sourceCache = createSourceCache({ - abortTile(tile) { - expect(tile.tileID).toEqual(coord); - abort++; - }, - unloadTile(tile) { - expect(tile.tileID).toEqual(coord); - unload++; - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.abortTile = async (tile) => { + expect(tile.tileID).toEqual(coord); + abort++; + }; + sourceCache._source.unloadTile = async (tile) => { + expect(tile.tileID).toEqual(coord); + unload++; + }; sourceCache.onAdd(undefined); sourceCache._addTile(coord); @@ -1401,13 +1343,10 @@ describe('SourceCache#tilesIn', () => { transform.zoom = 1; transform.center = new LngLat(0, 1); - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - tile.additionalRadius = 0; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1447,16 +1386,14 @@ describe('SourceCache#tilesIn', () => { test('reparsed overscaled tiles', () => { const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - tile.additionalRadius = 0; - callback(); - }, reparseOverscaled: true, minzoom: 1, maxzoom: 1, tileSize: 512 }); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1498,12 +1435,14 @@ describe('SourceCache#tilesIn', () => { test('overscaled tiles', done => { const sourceCache = createSourceCache({ - loadTile(tile, callback) { tile.state = 'loaded'; callback(); }, reparseOverscaled: false, minzoom: 1, maxzoom: 1, tileSize: 512 }); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1521,12 +1460,10 @@ describe('SourceCache#tilesIn', () => { describe('source cache loaded', () => { test('SourceCache#loaded (no errors)', done => { - const sourceCache = createSourceCache({ - loadTile(tile, callback) { - tile.state = 'loaded'; - callback(); - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loaded'; + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1545,11 +1482,11 @@ describe('source cache loaded', () => { }); test('SourceCache#loaded (with errors)', done => { - const sourceCache = createSourceCache({ - loadTile(tile) { - tile.state = 'errored'; - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'errored'; + throw new Error('Error'); + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1568,11 +1505,11 @@ describe('source cache loaded', () => { }); test('SourceCache#loaded (unused)', done => { - const sourceCache = createSourceCache({ - loadTile(tile) { - tile.state = 'errored'; - } - }, false); + const sourceCache = createSourceCache(undefined, false); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'errored'; + throw new Error('Error'); + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1584,11 +1521,11 @@ describe('source cache loaded', () => { }); test('SourceCache#loaded (unusedForTerrain)', done => { - const sourceCache = createSourceCache({ - loadTile(tile) { - tile.state = 'errored'; - } - }, false); + const sourceCache = createSourceCache(undefined, false); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'errored'; + throw new Error('Error'); + }; sourceCache.usedForTerrain = false; sourceCache.on('data', (e) => { @@ -1601,11 +1538,11 @@ describe('source cache loaded', () => { }); test('SourceCache#loaded (not loaded when no update)', done => { - const sourceCache = createSourceCache({ - loadTile(tile) { - tile.state = 'errored'; - } - }); + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'errored'; + throw new Error('Error'); + }; sourceCache.on('data', (e) => { if (e.sourceDataType === 'metadata') { @@ -1617,18 +1554,19 @@ describe('source cache loaded', () => { }); test('SourceCache#loaded (on last tile load)', done => { - const sourceCache = createSourceCache({ - hasTile(tileID: OverscaledTileID) { - return !this.tileBounds || this.tileBounds.contains(tileID.canonical); - }, - loadTile(tile, callback) { - tile.state = 'loading'; + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + return new Promise((resolve) => { setTimeout(() => { tile.state = 'loaded'; - callback(); + resolve(); }); - } - }); + }); + }; + sourceCache._source.hasTile = function (tileID: OverscaledTileID) { + return !this.tileBounds || this.tileBounds.contains(tileID.canonical); + }; const tr = new Transform(); tr.zoom = 10; @@ -1654,27 +1592,28 @@ describe('source cache loaded', () => { test('SourceCache#loaded (tiles outside bounds, idle)', done => { const japan = new TileBounds([122.74, 19.33, 149.0, 45.67]); - const sourceCache = createSourceCache({ - onAdd() { - if (this.sourceOptions.noLoad) return; - if (this.sourceOptions.error) { - this.fire(new ErrorEvent(this.sourceOptions.error)); - } else { - this.fire(new Event('data', {dataType: 'source', sourceDataType: 'metadata'})); - this.fire(new Event('data', {dataType: 'source', sourceDataType: 'content'})); - } - }, - hasTile(tileID: OverscaledTileID) { - return japan.contains(tileID.canonical); - }, - loadTile(tile, callback) { - tile.state = 'loading'; + const sourceCache = createSourceCache(); + sourceCache._source.loadTile = async (tile) => { + tile.state = 'loading'; + return new Promise((resolve) => { setTimeout(() => { tile.state = 'loaded'; - callback(); + resolve(); }); + }); + }; + sourceCache._source.onAdd = function() { + if (this.sourceOptions.noLoad) return; + if (this.sourceOptions.error) { + this.fire(new ErrorEvent(this.sourceOptions.error)); + } else { + this.fire(new Event('data', {dataType: 'source', sourceDataType: 'metadata'})); + this.fire(new Event('data', {dataType: 'source', sourceDataType: 'content'})); } - }); + }; + sourceCache._source.hasTile = (tileID: OverscaledTileID) => { + return japan.contains(tileID.canonical); + }; sourceCache.on('data', (e) => { if (e.sourceDataType !== 'idle') { @@ -1842,7 +1781,7 @@ describe('SourceCache reloads expiring tiles', () => { expiryDate.setMilliseconds(expiryDate.getMilliseconds() + 50); const sourceCache = createSourceCache({expires: expiryDate}); - sourceCache._reloadTile = (id, state) => { + sourceCache._reloadTile = async (id, state) => { expect(state).toBe('expired'); done(); }; diff --git a/src/source/source_cache.ts b/src/source/source_cache.ts index 8a6d997fb4..d10a1ee640 100644 --- a/src/source/source_cache.ts +++ b/src/source/source_cache.ts @@ -18,7 +18,6 @@ import type {Style} from '../style/style'; import type {Dispatcher} from '../util/dispatcher'; import type {Transform} from '../geo/transform'; import type {TileState} from './tile'; -import type {Callback} from '../types/callback'; import type {SourceSpecification} from '@maplibre/maplibre-gl-style-spec'; import type {MapSourceDataEvent} from '../ui/events'; import {Terrain} from '../render/terrain'; @@ -105,7 +104,7 @@ export class SourceCache extends Evented { this._source = createSource(id, options, dispatcher, this); this._tiles = {}; - this._cache = new TileCache(0, this._unloadTile.bind(this)); + this._cache = new TileCache(0, (tile) => this._unloadTile(tile)); this._timers = {}; this._cacheTimers = {}; this._maxTileCacheSize = null; @@ -171,18 +170,29 @@ export class SourceCache extends Evented { if (this.transform) this.update(this.transform, this.terrain); } - _loadTile(tile: Tile, callback: Callback) { - return this._source.loadTile(tile, callback); + async _loadTile(tile: Tile, id: string, state: TileState): Promise { + try { + await this._source.loadTile(tile); + this._tileLoaded(tile, id, state); + } catch (err) { + tile.state = 'errored'; + if ((err as any).status !== 404) { + this._source.fire(new ErrorEvent(err, {tile})); + } else { + // continue to try loading parent/children tiles if a tile doesn't exist (404) + this.update(this.transform, this.terrain); + } + } } _unloadTile(tile: Tile) { if (this._source.unloadTile) - return this._source.unloadTile(tile, () => {}); + this._source.unloadTile(tile); } _abortTile(tile: Tile) { if (this._source.abortTile) - this._source.abortTile(tile, () => {}); + this._source.abortTile(tile); this._source.fire(new Event('dataabort', {tile, coord: tile.tileID, dataType: 'source'})); } @@ -254,7 +264,7 @@ export class SourceCache extends Evented { } } - _reloadTile(id: string, state: TileState) { + async _reloadTile(id: string, state: TileState) { const tile = this._tiles[id]; // this potentially does not address all underlying @@ -269,19 +279,10 @@ export class SourceCache extends Evented { if (tile.state !== 'loading') { tile.state = state; } - - this._loadTile(tile, this._tileLoaded.bind(this, tile, id, state)); + await this._loadTile(tile, id, state); } - _tileLoaded(tile: Tile, id: string, previousState: TileState, err?: Error | null) { - if (err) { - tile.state = 'errored'; - if ((err as any).status !== 404) this._source.fire(new ErrorEvent(err, {tile})); - // continue to try loading parent/children tiles if a tile doesn't exist (404) - else this.update(this.transform, this.terrain); - return; - } - + _tileLoaded(tile: Tile, id: string, previousState: TileState) { tile.timeAdded = browser.now(); if (previousState === 'expired') tile.refreshedUponExpiration = true; this._setTileReloadTimer(id, tile); @@ -814,7 +815,7 @@ export class SourceCache extends Evented { if (!tile) { tile = new Tile(tileID, this._source.tileSize * tileID.overscaleFactor()); - this._loadTile(tile, this._tileLoaded.bind(this, tile, tileID.key, tile.state)); + this._loadTile(tile, tileID.key, tile.state); } tile.uses++; diff --git a/src/source/tile.ts b/src/source/tile.ts index cc180ec561..32c0a6b8df 100644 --- a/src/source/tile.ts +++ b/src/source/tile.ts @@ -28,7 +28,6 @@ import type {OverscaledTileID} from './tile_id'; import type {Framebuffer} from '../gl/framebuffer'; import type {Transform} from '../geo/transform'; import type {LayerFeatureStates} from './source_state'; -import type {Cancelable} from '../types/cancelable'; import type {FilterSpecification} from '@maplibre/maplibre-gl-style-spec'; import type Point from '@mapbox/point-geometry'; import {mat4} from 'gl-matrix'; @@ -47,7 +46,6 @@ import {ExpiryData} from '../util/ajax'; export type TileState = 'loading' | 'loaded' | 'reloading' | 'unloaded' | 'errored' | 'expired'; /** - * @internal * A tile object is the combination of a Coordinate, which defines * its place, as well as a unique ID and data tracking for its content */ @@ -81,12 +79,12 @@ export class Tile { aborted: boolean; needsHillshadePrepare: boolean; needsTerrainPrepare: boolean; - request: Cancelable; + abortController: AbortController; texture: any; fbo: Framebuffer; demTexture: Texture; refreshedUponExpiration: boolean; - reloadCallback: any; + reloadPromise: {resolve: () => void; reject: () => void}; resourceTiming: Array; queryPadding: number; diff --git a/src/source/vector_tile_source.test.ts b/src/source/vector_tile_source.test.ts index d2ff756f8f..f955ba1831 100644 --- a/src/source/vector_tile_source.test.ts +++ b/src/source/vector_tile_source.test.ts @@ -6,8 +6,9 @@ import {OverscaledTileID} from './tile_id'; import {Evented} from '../util/evented'; import {RequestManager} from '../util/request_manager'; import fixturesSource from '../../test/unit/assets/source.json' assert {type: 'json'}; -import {getMockDispatcher, getWrapDispatcher} from '../util/test/util'; +import {getMockDispatcher, getWrapDispatcher, sleep, waitForMetadataEvent} from '../util/test/util'; import {Map} from '../ui/map'; +import {WorkerTileParameters} from './worker_source'; function createSource(options, transformCallback?, clearTiles = () => {}) { const source = new VectorTileSource('id', options, getMockDispatcher(), options.eventedParent); @@ -19,9 +20,7 @@ function createSource(options, transformCallback?, clearTiles = () => {}) { getPixelRatio() { return 1; } } as any as Map); - source.on('error', (e) => { - throw e.error; - }); + source.on('error', () => { }); // to prevent console log of errors return source; } @@ -37,7 +36,7 @@ describe('VectorTileSource', () => { server.restore(); }); - test('can be constructed from TileJSON', done => { + test('can be constructed from TileJSON', async () => { const source = createSource({ minzoom: 1, maxzoom: 10, @@ -45,33 +44,26 @@ describe('VectorTileSource', () => { tiles: ['http://example.com/{z}/{x}/{y}.png'] }); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - expect(source.tiles).toEqual(['http://example.com/{z}/{x}/{y}.png']); - expect(source.minzoom).toBe(1); - expect(source.maxzoom).toBe(10); - expect((source as Source).attribution).toBe('MapLibre'); - done(); - } - }); + await waitForMetadataEvent(source); + expect(source.tiles).toEqual(['http://example.com/{z}/{x}/{y}.png']); + expect(source.minzoom).toBe(1); + expect(source.maxzoom).toBe(10); + expect((source as Source).attribution).toBe('MapLibre'); }); - test('can be constructed from a TileJSON URL', done => { + test('can be constructed from a TileJSON URL', async () => { server.respondWith('/source.json', JSON.stringify(fixturesSource)); const source = createSource({url: '/source.json'}); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - expect(source.tiles).toEqual(['http://example.com/{z}/{x}/{y}.png']); - expect(source.minzoom).toBe(1); - expect(source.maxzoom).toBe(10); - expect((source as Source).attribution).toBe('MapLibre'); - done(); - } - }); - + const promise = waitForMetadataEvent(source); server.respond(); + + await promise; + expect(source.tiles).toEqual(['http://example.com/{z}/{x}/{y}.png']); + expect(source.minzoom).toBe(1); + expect(source.maxzoom).toBe(10); + expect((source as Source).attribution).toBe('MapLibre'); }); test('transforms the request for TileJSON URL', () => { @@ -94,7 +86,7 @@ describe('VectorTileSource', () => { server.respond(); }); - test('fires "dataloading" event', done => { + test('fires "dataloading" event', async () => { server.respondWith('/source.json', JSON.stringify(fixturesSource)); const evented = new Evented(); let dataloadingFired = false; @@ -102,13 +94,11 @@ describe('VectorTileSource', () => { dataloadingFired = true; }); const source = createSource({url: '/source.json', eventedParent: evented}); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - if (!dataloadingFired) done('test failed: dataloading not fired'); - done(); - } - }); + const promise = waitForMetadataEvent(source); server.respond(); + + await promise; + expect(dataloadingFired).toBeTruthy(); }); test('serialize URL', () => { @@ -138,7 +128,7 @@ describe('VectorTileSource', () => { }); function testScheme(scheme, expectedURL) { - test(`scheme "${scheme}"`, done => { + test(`scheme "${scheme}"`, async () => { const source = createSource({ minzoom: 1, maxzoom: 10, @@ -147,85 +137,150 @@ describe('VectorTileSource', () => { scheme }); + let receivedMessage = null; + source.dispatcher = getWrapDispatcher()({ - send(type, params) { - expect(type).toBe('loadTile'); - expect(expectedURL).toBe(params.request.url); - done(); + sendAsync(message) { + receivedMessage = message; + return Promise.resolve({}); } }); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') source.loadTile({ - tileID: new OverscaledTileID(10, 0, 10, 5, 5) - } as any as Tile, () => {}); - }); + await waitForMetadataEvent(source); + await source.loadTile({ + loadVectorData() {}, + tileID: new OverscaledTileID(10, 0, 10, 5, 5) + } as any as Tile); + + expect(receivedMessage.type).toBe('loadTile'); + expect(expectedURL).toBe((receivedMessage.data as WorkerTileParameters).request.url); }); } testScheme('xyz', 'http://example.com/10/5/5.png'); testScheme('tms', 'http://example.com/10/5/1018.png'); - test('transforms tile urls before requesting', done => { + test('transforms tile urls before requesting', async () => { server.respondWith('/source.json', JSON.stringify(fixturesSource)); const source = createSource({url: '/source.json'}); const transformSpy = jest.spyOn(source.map._requestManager, 'transformRequest'); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - const tile = { - tileID: new OverscaledTileID(10, 0, 10, 5, 5), - state: 'loading', - loadVectorData () {}, - setExpiryData() {} - } as any as Tile; - source.loadTile(tile, () => {}); - expect(transformSpy).toHaveBeenCalledTimes(1); - expect(transformSpy).toHaveBeenCalledWith('http://example.com/10/5/5.png', 'Tile'); - done(); + const promise = waitForMetadataEvent(source); + server.respond(); + await promise; + + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData() {}, + setExpiryData() {} + } as any as Tile; + source.loadTile(tile); + expect(transformSpy).toHaveBeenCalledTimes(1); + expect(transformSpy).toHaveBeenCalledWith('http://example.com/10/5/5.png', 'Tile'); + }); + + test('loads a tile even in case of 404', async () => { + server.respondWith('/source.json', JSON.stringify(fixturesSource)); + + const source = createSource({url: '/source.json'}); + source.dispatcher = getWrapDispatcher()({ + sendAsync(_message) { + const error = new Error(); + (error as any).status = 404; + return Promise.reject(error); + } + }); + const promise = waitForMetadataEvent(source); + server.respond(); + await promise; + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData: jest.fn(), + setExpiryData() {} + } as any as Tile; + await source.loadTile(tile); + expect(tile.loadVectorData).toHaveBeenCalledTimes(1); + }); + + test('does not load a tile in case of error', async () => { + server.respondWith('/source.json', JSON.stringify(fixturesSource)); + + const source = createSource({url: '/source.json'}); + source.dispatcher = getWrapDispatcher()({ + async sendAsync(_message) { + throw new Error('Error'); } }); + const promise = waitForMetadataEvent(source); + server.respond(); + await promise; + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData: jest.fn(), + setExpiryData() {} + } as any as Tile; + await expect(source.loadTile(tile)).rejects.toThrow('Error'); + expect(tile.loadVectorData).toHaveBeenCalledTimes(0); + }); + + test('loads an empty tile received from worker', async () => { + server.respondWith('/source.json', JSON.stringify(fixturesSource)); + const source = createSource({url: '/source.json'}); + source.dispatcher = getWrapDispatcher()({ + sendAsync(_message) { + return Promise.resolve(null); + } + }); + + const promise = waitForMetadataEvent(source); server.respond(); + await promise; + + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData: jest.fn(), + setExpiryData() {} + } as any as Tile; + await source.loadTile(tile); + expect(tile.loadVectorData).toHaveBeenCalledTimes(1); }); - test('reloads a loading tile properly', done => { + test('reloads a loading tile properly', async () => { const source = createSource({ tiles: ['http://example.com/{z}/{x}/{y}.png'] }); const events = []; source.dispatcher = getWrapDispatcher()({ - send(type, params, cb) { - events.push(type); - if (cb) setTimeout(cb, 0); - return 1; + sendAsync(message) { + events.push(message.type); + return Promise.resolve({}); } }); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - const tile = { - tileID: new OverscaledTileID(10, 0, 10, 5, 5), - state: 'loading', - loadVectorData () { - this.state = 'loaded'; - events.push('tileLoaded'); - }, - setExpiryData() {} - } as any as Tile; - source.loadTile(tile, () => {}); - expect(tile.state).toBe('loading'); - source.loadTile(tile, () => { - expect(events).toEqual( - ['loadTile', 'tileLoaded', 'reloadTile', 'tileLoaded'] - ); - done(); - }); - } - }); + await waitForMetadataEvent(source); + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData () { + this.state = 'loaded'; + events.push('tileLoaded'); + }, + setExpiryData() {} + } as any as Tile; + const initialLoadPromise = source.loadTile(tile); + + expect(tile.state).toBe('loading'); + await source.loadTile(tile); + expect(events).toEqual(['loadTile', 'tileLoaded', 'reloadTile', 'tileLoaded']); + await expect(initialLoadPromise).resolves.toBeUndefined(); }); - test('respects TileJSON.bounds', done => { + test('respects TileJSON.bounds', async () => { const source = createSource({ minzoom: 0, maxzoom: 22, @@ -233,16 +288,13 @@ describe('VectorTileSource', () => { tiles: ['http://example.com/{z}/{x}/{y}.png'], bounds: [-47, -7, -45, -5] }); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - expect(source.hasTile(new OverscaledTileID(8, 0, 8, 96, 132))).toBeFalsy(); - expect(source.hasTile(new OverscaledTileID(8, 0, 8, 95, 132))).toBeTruthy(); - done(); - } - }); + await waitForMetadataEvent(source); + + expect(source.hasTile(new OverscaledTileID(8, 0, 8, 96, 132))).toBeFalsy(); + expect(source.hasTile(new OverscaledTileID(8, 0, 8, 95, 132))).toBeTruthy(); }); - test('does not error on invalid bounds', done => { + test('does not error on invalid bounds', async () => { const source = createSource({ minzoom: 0, maxzoom: 22, @@ -251,15 +303,11 @@ describe('VectorTileSource', () => { bounds: [-47, -7, -45, 91] }); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - expect(source.tileBounds.bounds).toEqual({_sw: {lng: -47, lat: -7}, _ne: {lng: -45, lat: 90}}); - done(); - } - }); + await waitForMetadataEvent(source); + expect(source.tileBounds.bounds).toEqual({_sw: {lng: -47, lat: -7}, _ne: {lng: -45, lat: 90}}); }); - test('respects TileJSON.bounds when loaded from TileJSON', done => { + test('respects TileJSON.bounds when loaded from TileJSON', async () => { server.respondWith('/source.json', JSON.stringify({ minzoom: 0, maxzoom: 22, @@ -269,51 +317,47 @@ describe('VectorTileSource', () => { })); const source = createSource({url: '/source.json'}); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - expect(source.hasTile(new OverscaledTileID(8, 0, 8, 96, 132))).toBeFalsy(); - expect(source.hasTile(new OverscaledTileID(8, 0, 8, 95, 132))).toBeTruthy(); - done(); - } - }); + const promise = waitForMetadataEvent(source); server.respond(); + + await promise; + expect(source.hasTile(new OverscaledTileID(8, 0, 8, 96, 132))).toBeFalsy(); + expect(source.hasTile(new OverscaledTileID(8, 0, 8, 95, 132))).toBeTruthy(); }); - test('respects collectResourceTiming parameter on source', done => { + test('respects collectResourceTiming parameter on source', async () => { const source = createSource({ tiles: ['http://example.com/{z}/{x}/{y}.png'], collectResourceTiming: true }); + let receivedMessage = null; source.dispatcher = getWrapDispatcher()({ - send(type, params, cb) { - expect(params.request.collectResourceTiming).toBeTruthy(); - setTimeout(cb, 0); - done(); + sendAsync(message) { + receivedMessage = message; // do nothing for cache size check dispatch source.dispatcher = getMockDispatcher(); - return 1; + return Promise.resolve({}); } }); - source.on('data', (e) => { - if (e.sourceDataType === 'metadata') { - const tile = { - tileID: new OverscaledTileID(10, 0, 10, 5, 5), - state: 'loading', - loadVectorData () {}, - setExpiryData() {} - } as any as Tile; - source.loadTile(tile, () => {}); - } - }); + await waitForMetadataEvent(source); + const tile = { + tileID: new OverscaledTileID(10, 0, 10, 5, 5), + state: 'loading', + loadVectorData() {}, + setExpiryData() {} + } as any as Tile; + await source.loadTile(tile); + + expect((receivedMessage.data as WorkerTileParameters).request.collectResourceTiming).toBeTruthy(); }); test('cancels TileJSON request if removed', () => { const source = createSource({url: '/source.json'}); source.onRemove(); - expect((server as any).lastRequest.aborted).toBe(true); + expect((server.lastRequest as any).aborted).toBe(true); }); test('supports url property updates', () => { @@ -349,6 +393,7 @@ describe('VectorTileSource', () => { const source = createSource({tiles: ['http://example.com/{z}/{x}/{y}.pbf']}, undefined, clearTiles); source.setTiles(['http://example2.com/{z}/{x}/{y}.pbf']); expect(clearTiles.mock.calls).toHaveLength(0); + await sleep(0); await source.once('data'); expect(clearTiles.mock.calls).toHaveLength(1); }); diff --git a/src/source/vector_tile_source.ts b/src/source/vector_tile_source.ts index 8cdb19c349..326f1a7256 100644 --- a/src/source/vector_tile_source.ts +++ b/src/source/vector_tile_source.ts @@ -10,9 +10,8 @@ import type {OverscaledTileID} from './tile_id'; import type {Map} from '../ui/map'; import type {Dispatcher} from '../util/dispatcher'; import type {Tile} from './tile'; -import type {Callback} from '../types/callback'; -import type {Cancelable} from '../types/cancelable'; import type {VectorSourceSpecification, PromoteIdSpecification} from '@maplibre/maplibre-gl-style-spec'; +import type {WorkerTileResult} from './worker_source'; export type VectorTileSourceOptions = VectorSourceSpecification & { collectResourceTiming?: boolean; @@ -72,7 +71,7 @@ export class VectorTileSource extends Evented implements Source { tileBounds: TileBounds; reparseOverscaled: boolean; isTileClipped: boolean; - _tileJSONRequest: Cancelable; + _tileJSONRequest: AbortController; _loaded: boolean; constructor(id: string, options: VectorTileSourceOptions, dispatcher: Dispatcher, eventedParent: Evented) { @@ -101,16 +100,16 @@ export class VectorTileSource extends Evented implements Source { this.setEventedParent(eventedParent); } - load = () => { + async load() { this._loaded = false; this.fire(new Event('dataloading', {dataType: 'source'})); - this._tileJSONRequest = loadTileJson(this._options, this.map._requestManager, (err, tileJSON) => { + this._tileJSONRequest = new AbortController(); + try { + const tileJSON = await loadTileJson(this._options, this.map._requestManager, this._tileJSONRequest); this._tileJSONRequest = null; this._loaded = true; this.map.style.sourceCaches[this.id].clearTiles(); - if (err) { - this.fire(new ErrorEvent(err)); - } else if (tileJSON) { + if (tileJSON) { extend(this, tileJSON); if (tileJSON.bounds) this.tileBounds = new TileBounds(tileJSON.bounds, this.minzoom, this.maxzoom); @@ -120,8 +119,11 @@ export class VectorTileSource extends Evented implements Source { this.fire(new Event('data', {dataType: 'source', sourceDataType: 'metadata'})); this.fire(new Event('data', {dataType: 'source', sourceDataType: 'content'})); } - }); - }; + } catch (err) { + this._tileJSONRequest = null; + this.fire(new ErrorEvent(err)); + } + } loaded(): boolean { return this._loaded; @@ -138,7 +140,7 @@ export class VectorTileSource extends Evented implements Source { setSourceProperty(callback: Function) { if (this._tileJSONRequest) { - this._tileJSONRequest.cancel(); + this._tileJSONRequest.abort(); } callback(); @@ -177,16 +179,16 @@ export class VectorTileSource extends Evented implements Source { onRemove() { if (this._tileJSONRequest) { - this._tileJSONRequest.cancel(); + this._tileJSONRequest.abort(); this._tileJSONRequest = null; } } - serialize = (): VectorSourceSpecification => { + serialize(): VectorSourceSpecification { return extend({}, this._options); - }; + } - loadTile(tile: Tile, callback: Callback) { + async loadTile(tile: Tile): Promise { const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme); const params = { request: this.map._requestManager.transformRequest(url, ResourceType.Tile), @@ -201,56 +203,68 @@ export class VectorTileSource extends Evented implements Source { promoteId: this.promoteId }; params.request.collectResourceTiming = this._collectResourceTiming; - + let messageType: 'loadTile' | 'reloadTile' = 'reloadTile'; if (!tile.actor || tile.state === 'expired') { tile.actor = this.dispatcher.getActor(); - tile.request = tile.actor.send('loadTile', params, done.bind(this)); + messageType = 'loadTile'; } else if (tile.state === 'loading') { - // schedule tile reloading after it has been loaded - tile.reloadCallback = callback; - } else { - tile.request = tile.actor.send('reloadTile', params, done.bind(this)); + return new Promise((resolve, reject) => { + tile.reloadPromise = {resolve, reject}; + }); } + tile.abortController = new AbortController(); + try { + const data = await tile.actor.sendAsync({type: messageType, data: params}, tile.abortController); + delete tile.abortController; - function done(err, data) { - delete tile.request; - - if (tile.aborted) - return callback(null); + if (tile.aborted) { + return; + } + this._afterTileLoadWorkerResponse(tile, data); + } catch (err) { + delete tile.abortController; + if (tile.aborted) { + return; + } if (err && err.status !== 404) { - return callback(err); + throw err; } + this._afterTileLoadWorkerResponse(tile, null); + } + } - if (data && data.resourceTiming) - tile.resourceTiming = data.resourceTiming; - - if (this.map._refreshExpiredTiles && data) tile.setExpiryData(data); - tile.loadVectorData(data, this.map.painter); + private _afterTileLoadWorkerResponse(tile: Tile, data: WorkerTileResult) { + if (data && data.resourceTiming) { + tile.resourceTiming = data.resourceTiming; + } - callback(null); + if (data && this.map._refreshExpiredTiles) { + tile.setExpiryData(data); + } + tile.loadVectorData(data, this.map.painter); - if (tile.reloadCallback) { - this.loadTile(tile, tile.reloadCallback); - tile.reloadCallback = null; - } + if (tile.reloadPromise) { + const reloadPromise = tile.reloadPromise; + tile.reloadPromise = null; + this.loadTile(tile).then(reloadPromise.resolve).catch(reloadPromise.reject); } } - abortTile(tile: Tile) { - if (tile.request) { - tile.request.cancel(); - delete tile.request; + async abortTile(tile: Tile): Promise { + if (tile.abortController) { + tile.abortController.abort(); + delete tile.abortController; } if (tile.actor) { - tile.actor.send('abortTile', {uid: tile.uid, type: this.type, source: this.id}, undefined); + await tile.actor.sendAsync({type: 'abortTile', data: {uid: tile.uid, type: this.type, source: this.id}}); } } - unloadTile(tile: Tile) { + async unloadTile(tile: Tile): Promise { tile.unloadVectorData(); if (tile.actor) { - tile.actor.send('removeTile', {uid: tile.uid, type: this.type, source: this.id}, undefined); + await tile.actor.sendAsync({type: 'removeTile', data: {uid: tile.uid, type: this.type, source: this.id}}); } } diff --git a/src/source/vector_tile_worker_source.test.ts b/src/source/vector_tile_worker_source.test.ts index 73c82201f4..60f4aefb90 100644 --- a/src/source/vector_tile_worker_source.test.ts +++ b/src/source/vector_tile_worker_source.test.ts @@ -2,16 +2,17 @@ import fs from 'fs'; import path from 'path'; import vt from '@mapbox/vector-tile'; import Protobuf from 'pbf'; -import {VectorTileWorkerSource} from '../source/vector_tile_worker_source'; +import {LoadVectorData, VectorTileWorkerSource} from '../source/vector_tile_worker_source'; import {StyleLayerIndex} from '../style/style_layer_index'; import {fakeServer, type FakeServer} from 'nise'; -import {Actor} from '../util/actor'; +import {IActor} from '../util/actor'; import {TileParameters, WorkerTileParameters, WorkerTileResult} from './worker_source'; import {WorkerTile} from './worker_tile'; -import {setPerformance} from '../util/test/util'; +import {setPerformance, sleep} from '../util/test/util'; +import {ABORT_ERROR} from '../util/abort_error'; describe('vector tile worker source', () => { - const actor = {send: () => {}} as any as Actor; + const actor = {sendAsync: () => Promise.resolve({})} as IActor; let server: FakeServer; beforeEach(() => { @@ -24,51 +25,45 @@ describe('vector tile worker source', () => { server.restore(); jest.clearAllMocks(); }); - test('VectorTileWorkerSource#abortTile aborts pending request', () => { + test('VectorTileWorkerSource#abortTile aborts pending request', async () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); - source.loadTile({ + const loadPromise = source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/abort'} - } as any as WorkerTileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res).toBeFalsy(); - }); + } as any as WorkerTileParameters); - source.abortTile({ + const abortPromise = source.abortTile({ source: 'source', uid: 0 - } as any as TileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res).toBeFalsy(); - }); + } as any as TileParameters); expect(source.loading).toEqual({}); + await expect(abortPromise).resolves.toBeFalsy(); + await expect(loadPromise).rejects.toThrow(ABORT_ERROR); }); - test('VectorTileWorkerSource#removeTile removes loaded tile', () => { + test('VectorTileWorkerSource#removeTile removes loaded tile', async () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); source.loaded = { '0': {} as WorkerTile }; - source.removeTile({ + const res = await source.removeTile({ source: 'source', uid: 0 - } as any as TileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res).toBeFalsy(); - }); + } as any as TileParameters); + expect(res).toBeUndefined(); expect(source.loaded).toEqual({}); }); - test('VectorTileWorkerSource#reloadTile reloads a previously-loaded tile', () => { + test('VectorTileWorkerSource#reloadTile reloads a previously-loaded tile', async () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); - const parse = jest.fn(); + const parse = jest.fn().mockReturnValue(Promise.resolve({} as WorkerTileResult)); source.loaded = { '0': { @@ -78,18 +73,15 @@ describe('vector tile worker source', () => { } as any as WorkerTile }; - const callback = jest.fn(); - source.reloadTile({uid: 0} as any as WorkerTileParameters, callback); + const reloadPromise = source.reloadTile({uid: 0} as any as WorkerTileParameters); expect(parse).toHaveBeenCalledTimes(1); - - parse.mock.calls[0][4](); - expect(callback).toHaveBeenCalledTimes(1); + await expect(reloadPromise).resolves.toBeTruthy(); }); - test('VectorTileWorkerSource#loadTile reparses tile if the reloadTile has been called during parsing', (done) => { + test('VectorTileWorkerSource#loadTile reparses tile if the reloadTile has been called during parsing', async () => { const rawTileData = new Uint8Array([]); - function loadVectorData(params, callback) { - return callback(null, { + const loadVectorData: LoadVectorData = async (_params, _abortController) => { + return { vectorTile: { layers: { test: { @@ -112,8 +104,8 @@ describe('vector tile worker source', () => { } } as any as vt.VectorTile, rawData: rawTileData - }); - } + }; + }; const layerIndex = new StyleLayerIndex([{ id: 'test', @@ -127,52 +119,51 @@ describe('vector tile worker source', () => { } }]); - const send = jest.fn().mockImplementation((type: string, data: unknown, callback: Function) => { - const res = setTimeout(() => callback(null, - type === 'getImages' ? - {'hello': {width: 1, height: 1, data: new Uint8Array([0])}} : - {'StandardFont-Bold': {width: 1, height: 1, data: new Uint8Array([0])}} - )); - - return { - cancel: () => clearTimeout(res) - }; - }); - const actor = { - send - } as unknown as Actor; - const source = new VectorTileWorkerSource(actor, layerIndex, ['hello'], loadVectorData); + sendAsync: (message: {type: string; data: unknown}, abortController: AbortController) => { + return new Promise((resolve, _reject) => { + const res = setTimeout(() => { + const response = message.type === 'getImages' ? + {'hello': {width: 1, height: 1, data: new Uint8Array([0])}} : + {'StandardFont-Bold': {width: 1, height: 1, data: new Uint8Array([0])}}; + resolve(response); + }, 100); + abortController.signal.addEventListener('abort', () => { + clearTimeout(res); + }); + }); + } + }; + const source = new VectorTileWorkerSource(actor, layerIndex, ['hello']); + source.loadVectorTile = loadVectorData; source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf'} - } as any as WorkerTileParameters, () => { - done.fail('should not be called'); - }); + } as any as WorkerTileParameters).then(() => expect(false).toBeTruthy()); - source.reloadTile({ + // allow promise to run + await sleep(0); + + const res = await source.reloadTile({ source: 'source', - uid: '0', + uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, - } as any as WorkerTileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res).toBeDefined(); - expect(res.rawTileData).toBeDefined(); - expect(res.rawTileData).toStrictEqual(rawTileData); - done(); - }); + } as any as WorkerTileParameters); + expect(res).toBeDefined(); + expect(res.rawTileData).toBeDefined(); + expect(res.rawTileData).toStrictEqual(rawTileData); }); - test('VectorTileWorkerSource#loadTile reparses tile if reloadTile is called during reparsing', (done) => { + test('VectorTileWorkerSource#loadTile reparses tile if reloadTile is called during reparsing', async () => { const rawTileData = new Uint8Array([]); - function loadVectorData(params, callback) { - return callback(null, { + const loadVectorData: LoadVectorData = async (_params, _abortController) => { + return { vectorTile: new vt.VectorTile(new Protobuf(rawTileData)), rawData: rawTileData - }); - } + }; + }; const layerIndex = new StyleLayerIndex([{ id: 'test', @@ -181,41 +172,39 @@ describe('vector tile worker source', () => { type: 'fill' }]); - const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData); + const source = new VectorTileWorkerSource(actor, layerIndex, []); + source.loadVectorTile = loadVectorData; const parseWorkerTileMock = jest .spyOn(WorkerTile.prototype, 'parse') - .mockImplementation(function(data, layerIndex, availableImages, actor, callback) { + .mockImplementation(function(_data, _layerIndex, _availableImages, _actor) { this.status = 'parsing'; - window.setTimeout(() => callback(null, {} as WorkerTileResult), 10); + return new Promise((resolve) => { + setTimeout(() => resolve({} as WorkerTileResult), 20); + }); }); - let loadCallbackCalled = false; - source.loadTile({ + const loadPromise = source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf'} - } as any as WorkerTileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res).toBeDefined(); - loadCallbackCalled = true; - }); + } as any as WorkerTileParameters); - source.reloadTile({ + // let the promise start + await sleep(0); + + const res = await source.reloadTile({ source: 'source', uid: '0', tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, - } as any as WorkerTileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res).toBeDefined(); - expect(parseWorkerTileMock).toHaveBeenCalledTimes(2); - expect(loadCallbackCalled).toBeTruthy(); - done(); - }); + } as any as WorkerTileParameters); + expect(res).toBeDefined(); + expect(parseWorkerTileMock).toHaveBeenCalledTimes(2); + await expect(loadPromise).resolves.toBeTruthy(); }); - test('VectorTileWorkerSource#reloadTile does not reparse tiles with no vectorTile data but does call callback', () => { + test('VectorTileWorkerSource#reloadTile does not reparse tiles with no vectorTile data but does call callback', async () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); @@ -226,18 +215,35 @@ describe('vector tile worker source', () => { } as any as WorkerTile }; - const callback = jest.fn(); - - source.reloadTile({uid: 0} as any as WorkerTileParameters, callback); + await source.reloadTile({uid: 0} as any as WorkerTileParameters); expect(parse).not.toHaveBeenCalled(); - expect(callback).toHaveBeenCalledTimes(1); + }); + + test('VectorTileWorkerSource#loadTile returns null for an empty tile', async () => { + const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); + source.loadVectorTile = (_params, _abortController) => Promise.resolve(null); + const parse = jest.fn(); + + server.respondWith(request => { + request.respond(200, {'Content-Type': 'application/pbf'}, 'something...'); + }); + + const promise = source.loadTile({ + source: 'source', + uid: 0, + tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, + request: {url: 'http://localhost:2900/faketile.pbf'} + } as any as WorkerTileParameters); + server.respond(); + + expect(parse).not.toHaveBeenCalled(); + expect(await promise).toBeNull(); }); - test('VectorTileWorkerSource#returns a good error message when failing to parse a tile', () => { + test('VectorTileWorkerSource#returns a good error message when failing to parse a tile', done => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); - const callback = jest.fn(); server.respondWith(request => { request.respond(200, {'Content-Type': 'application/pbf'}, 'something...'); @@ -248,19 +254,19 @@ describe('vector tile worker source', () => { uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf'} - } as any as WorkerTileParameters, callback); + } as any as WorkerTileParameters).catch((err) => { + expect(err.message).toContain('Unable to parse the tile at'); + done(); + }); server.respond(); expect(parse).not.toHaveBeenCalled(); - expect(callback).toHaveBeenCalledTimes(1); - expect(callback.mock.calls[0][0].message).toContain('Unable to parse the tile at'); }); - test('VectorTileWorkerSource#returns a good error message when failing to parse a gzipped tile', () => { + test('VectorTileWorkerSource#returns a good error message when failing to parse a gzipped tile', done => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); - const callback = jest.fn(); server.respondWith(new Uint8Array([0x1f, 0x8b]).buffer); @@ -269,26 +275,27 @@ describe('vector tile worker source', () => { uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf'} - } as any as WorkerTileParameters, callback); + } as any as WorkerTileParameters).catch((err) => { + expect(err.message).toContain('gzipped'); + done(); + }); server.respond(); expect(parse).not.toHaveBeenCalled(); - expect(callback).toHaveBeenCalledTimes(1); - expect(callback.mock.calls[0][0].message).toContain('gzipped'); }); - test('VectorTileWorkerSource provides resource timing information', done => { + test('VectorTileWorkerSource provides resource timing information', async () => { const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/unit/assets/mbsv5-6-18-23.vector.pbf')); - function loadVectorData(params, callback) { - return callback(null, { + const loadVectorData: LoadVectorData = async (_params, _abortController) => { + return { vectorTile: new vt.VectorTile(new Protobuf(rawTileData)), rawData: rawTileData, cacheControl: null, expires: null - }); - } + }; + }; const exampleResourceTiming = { connectEnd: 473, @@ -318,33 +325,33 @@ describe('vector tile worker source', () => { type: 'fill' }]); - const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData); + const source = new VectorTileWorkerSource(actor, layerIndex, []); + source.loadVectorTile = loadVectorData; window.performance.getEntriesByName = jest.fn().mockReturnValue([exampleResourceTiming]); - source.loadTile({ + const res = await source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf', collectResourceTiming: true} - } as any as WorkerTileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res.resourceTiming[0]).toEqual(exampleResourceTiming); - done(); - }); + } as any as WorkerTileParameters); + + expect(res.resourceTiming[0]).toEqual(exampleResourceTiming); + }); - test('VectorTileWorkerSource provides resource timing information (fallback method)', done => { + test('VectorTileWorkerSource provides resource timing information (fallback method)', async () => { const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/unit/assets/mbsv5-6-18-23.vector.pbf')); - function loadVectorData(params, callback) { - return callback(null, { + const loadVectorData: LoadVectorData = async (_params, _abortController) => { + return { vectorTile: new vt.VectorTile(new Protobuf(rawTileData)), rawData: rawTileData, cacheControl: null, expires: null - }); - } + }; + }; const layerIndex = new StyleLayerIndex([{ id: 'test', @@ -353,7 +360,8 @@ describe('vector tile worker source', () => { type: 'fill' }]); - const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData); + const source = new VectorTileWorkerSource(actor, layerIndex, []); + source.loadVectorTile = loadVectorData; const sampleMarks = [100, 350]; const marks = {}; @@ -374,17 +382,15 @@ describe('vector tile worker source', () => { return null; }); - source.loadTile({ + const res = await source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf', collectResourceTiming: true} - } as any as WorkerTileParameters, (err, res) => { - expect(err).toBeFalsy(); - expect(res.resourceTiming[0]).toEqual( - {'duration': 250, 'entryType': 'measure', 'name': 'http://localhost:2900/faketile.pbf', 'startTime': 100} - ); - done(); - }); + } as any as WorkerTileParameters); + + expect(res.resourceTiming[0]).toEqual( + {'duration': 250, 'entryType': 'measure', 'name': 'http://localhost:2900/faketile.pbf', 'startTime': 100} + ); }); }); diff --git a/src/source/vector_tile_worker_source.ts b/src/source/vector_tile_worker_source.ts index 7c7fca9def..9828305bdb 100644 --- a/src/source/vector_tile_worker_source.ts +++ b/src/source/vector_tile_worker_source.ts @@ -9,13 +9,12 @@ import {RequestPerformance} from '../util/performance'; import type { WorkerSource, WorkerTileParameters, - WorkerTileCallback, - TileParameters + TileParameters, + WorkerTileResult } from '../source/worker_source'; -import type {Actor} from '../util/actor'; +import type {IActor} from '../util/actor'; import type {StyleLayerIndex} from '../style/style_layer_index'; -import type {Callback} from '../types/callback'; import type {VectorTile} from '@mapbox/vector-tile'; export type LoadVectorTileResult = { @@ -30,61 +29,19 @@ type FetchingState = { resourceTiming: any; } -/** - * The callback when finished loading vector data - */ -export type LoadVectorDataCallback = Callback; - export type AbortVectorData = () => void; -export type LoadVectorData = (params: WorkerTileParameters, callback: LoadVectorDataCallback) => AbortVectorData | void; - -/** - * Loads a vector tile - */ -function loadVectorTile(params: WorkerTileParameters, callback: LoadVectorDataCallback) { - const request = getArrayBuffer(params.request, (err?: Error | null, data?: ArrayBuffer | null, cacheControl?: string | null, expires?: string | null) => { - if (err) { - callback(err); - } else if (data) { - try { - const vectorTile = new vt.VectorTile(new Protobuf(data)); - callback(null, { - vectorTile, - rawData: data, - cacheControl, - expires - }); - } catch (ex) { - const bytes = new Uint8Array(data); - const isGzipped = bytes[0] === 0x1f && bytes[1] === 0x8b; - let errorMessage = `Unable to parse the tile at ${params.request.url}, `; - if (isGzipped) { - errorMessage += 'please make sure the data is not gzipped and that you have configured the relevant header in the server'; - } else { - errorMessage += `got error: ${ex.messge}`; - } - callback(new Error(errorMessage)); - } - } - }); - return () => { - request.cancel(); - callback(); - }; -} +export type LoadVectorData = (params: WorkerTileParameters, abortController: AbortController) => Promise; /** * The {@link WorkerSource} implementation that supports {@link VectorTileSource}. * This class is designed to be easily reused to support custom source types * for data formats that can be parsed/converted into an in-memory VectorTile - * representation. To do so, create it with - * `new VectorTileWorkerSource(actor, styleLayers, customLoadVectorDataFunction)`. + * representation. To do so, override its `loadVectorTile` method. */ export class VectorTileWorkerSource implements WorkerSource { - actor: Actor; + actor: IActor; layerIndex: StyleLayerIndex; availableImages: Array; - loadVectorData: LoadVectorData; fetching: {[_: string]: FetchingState }; loading: {[_: string]: WorkerTile}; loaded: {[_: string]: WorkerTile}; @@ -95,38 +52,62 @@ export class VectorTileWorkerSource implements WorkerSource { * {@link VectorTileWorkerSource#loadTile}. The default implementation simply * loads the pbf at `params.url`. */ - constructor(actor: Actor, layerIndex: StyleLayerIndex, availableImages: Array, loadVectorData?: LoadVectorData | null) { + constructor(actor: IActor, layerIndex: StyleLayerIndex, availableImages: Array) { this.actor = actor; this.layerIndex = layerIndex; this.availableImages = availableImages; - this.loadVectorData = loadVectorData || loadVectorTile; this.fetching = {}; this.loading = {}; this.loaded = {}; } + /** + * Loads a vector tile + */ + async loadVectorTile(params: WorkerTileParameters, abortController: AbortController): Promise { + const response = await getArrayBuffer(params.request, abortController); + try { + const vectorTile = new vt.VectorTile(new Protobuf(response.data)); + return { + vectorTile, + rawData: response.data, + cacheControl: response.cacheControl, + expires: response.expires + }; + } catch (ex) { + const bytes = new Uint8Array(response.data); + const isGzipped = bytes[0] === 0x1f && bytes[1] === 0x8b; + let errorMessage = `Unable to parse the tile at ${params.request.url}, `; + if (isGzipped) { + errorMessage += 'please make sure the data is not gzipped and that you have configured the relevant header in the server'; + } else { + errorMessage += `got error: ${ex.messge}`; + } + throw new Error(errorMessage); + } + } + /** * Implements {@link WorkerSource#loadTile}. Delegates to * {@link VectorTileWorkerSource#loadVectorData} (which by default expects * a `params.url` property) for fetching and producing a VectorTile object. */ - loadTile(params: WorkerTileParameters, callback: WorkerTileCallback) { - const uid = params.uid; - - if (!this.loading) - this.loading = {}; + async loadTile(params: WorkerTileParameters): Promise { + const tileUid = params.uid; const perf = (params && params.request && params.request.collectResourceTiming) ? new RequestPerformance(params.request) : false; - const workerTile = this.loading[uid] = new WorkerTile(params); - workerTile.abort = this.loadVectorData(params, (err, response) => { - delete this.loading[uid]; + const workerTile = new WorkerTile(params); + this.loading[tileUid] = workerTile; - if (err || !response) { - workerTile.status = 'done'; - this.loaded[uid] = workerTile; - return callback(err); + const abortController = new AbortController(); + workerTile.abort = abortController; + try { + const response = await this.loadVectorTile(params, abortController); + delete this.loading[tileUid]; + if (!response) { + return null; } const rawTileData = response.rawData; @@ -144,85 +125,75 @@ export class VectorTileWorkerSource implements WorkerSource { } workerTile.vectorTile = response.vectorTile; - workerTile.parse(response.vectorTile, this.layerIndex, this.availableImages, this.actor, (err, result) => { - delete this.fetching[uid]; - if (err || !result) return callback(err); + const parsePromise = workerTile.parse(response.vectorTile, this.layerIndex, this.availableImages, this.actor); + this.loaded[tileUid] = workerTile; + // keep the original fetching state so that reload tile can pick it up if the original parse is cancelled by reloads' parse + this.fetching[tileUid] = {rawTileData, cacheControl, resourceTiming}; + try { + const result = await parsePromise; // Transferring a copy of rawTileData because the worker needs to retain its copy. - callback(null, extend({rawTileData: rawTileData.slice(0)}, result, cacheControl, resourceTiming)); - }); - - this.loaded = this.loaded || {}; - this.loaded[uid] = workerTile; - // keep the original fetching state so that reload tile can pick it up if the original parse is cancelled by reloads' parse - this.fetching[uid] = {rawTileData, cacheControl, resourceTiming}; - }) as AbortVectorData; + return extend({rawTileData: rawTileData.slice(0)}, result, cacheControl, resourceTiming); + } finally { + delete this.fetching[tileUid]; + } + } catch (err) { + delete this.loading[tileUid]; + workerTile.status = 'done'; + this.loaded[tileUid] = workerTile; + throw err; + } } /** * Implements {@link WorkerSource#reloadTile}. */ - reloadTile(params: WorkerTileParameters, callback: WorkerTileCallback) { - const loaded = this.loaded; + async reloadTile(params: WorkerTileParameters): Promise { const uid = params.uid; - if (loaded && loaded[uid]) { - const workerTile = loaded[uid]; - workerTile.showCollisionBoxes = params.showCollisionBoxes; - if (workerTile.status === 'parsing') { - workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor, (err, result) => { - if (err || !result) return callback(err, result); - - // if we have cancelled the original parse, make sure to pass the rawTileData from the original fetch - let parseResult; - if (this.fetching[uid]) { - const {rawTileData, cacheControl, resourceTiming} = this.fetching[uid]; - delete this.fetching[uid]; - parseResult = extend({rawTileData: rawTileData.slice(0)}, result, cacheControl, resourceTiming); - } else { - parseResult = result; - } - - callback(null, parseResult); - }); - } else if (workerTile.status === 'done') { - // if there was no vector tile data on the initial load, don't try and re-parse tile - if (workerTile.vectorTile) { - workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor, callback); - } else { - callback(); - } + if (!this.loaded || !this.loaded[uid]) { + throw new Error('Should not be trying to reload a tile that was never loaded or has been removed'); + } + const workerTile = this.loaded[uid]; + workerTile.showCollisionBoxes = params.showCollisionBoxes; + if (workerTile.status === 'parsing') { + const result = await workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor); + // if we have cancelled the original parse, make sure to pass the rawTileData from the original fetch + let parseResult: WorkerTileResult; + if (this.fetching[uid]) { + const {rawTileData, cacheControl, resourceTiming} = this.fetching[uid]; + delete this.fetching[uid]; + parseResult = extend({rawTileData: rawTileData.slice(0)}, result, cacheControl, resourceTiming); + } else { + parseResult = result; } + return parseResult; + + } + // if there was no vector tile data on the initial load, don't try and re-parse tile + if (workerTile.status === 'done' && workerTile.vectorTile) { + // this seems like a missing case where cache control is lost? see #3309 + return workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor); } } /** * Implements {@link WorkerSource#abortTile}. - * - * @param params - The tile parameters - * @param callback - The callback */ - abortTile(params: TileParameters, callback: WorkerTileCallback) { - const loading = this.loading, - uid = params.uid; + async abortTile(params: TileParameters): Promise { + const loading = this.loading; + const uid = params.uid; if (loading && loading[uid] && loading[uid].abort) { - loading[uid].abort(); + loading[uid].abort.abort(); delete loading[uid]; } - callback(); } /** * Implements {@link WorkerSource#removeTile}. - * - * @param params - The tile parameters - * @param callback - The callback */ - removeTile(params: TileParameters, callback: WorkerTileCallback) { - const loaded = this.loaded, - uid = params.uid; - if (loaded && loaded[uid]) { - delete loaded[uid]; + async removeTile(params: TileParameters): Promise { + if (this.loaded && this.loaded[params.uid]) { + delete this.loaded[params.uid]; } - callback(); } } diff --git a/src/source/video_source.ts b/src/source/video_source.ts index 5aa966dfc5..b14f436a50 100644 --- a/src/source/video_source.ts +++ b/src/source/video_source.ts @@ -66,7 +66,7 @@ export class VideoSource extends ImageSource { this.options = options; } - load = () => { + async load() { this._loaded = false; const options = this.options; @@ -74,29 +74,30 @@ export class VideoSource extends ImageSource { for (const url of options.urls) { this.urls.push(this.map._requestManager.transformRequest(url, ResourceType.Source).url); } - - getVideo(this.urls, (err, video) => { + try { + const video = await getVideo(this.urls); this._loaded = true; - if (err) { - this.fire(new ErrorEvent(err)); - } else if (video) { - this.video = video; - this.video.loop = true; - - // Start repainting when video starts playing. hasTransition() will then return - // true to trigger additional frames as long as the videos continues playing. - this.video.addEventListener('playing', () => { - this.map.triggerRepaint(); - }); - - if (this.map) { - this.video.play(); - } - - this._finishLoading(); + if (!video) { + return; } - }); - }; + this.video = video; + this.video.loop = true; + + // Start repainting when video starts playing. hasTransition() will then return + // true to trigger additional frames as long as the videos continues playing. + this.video.addEventListener('playing', () => { + this.map.triggerRepaint(); + }); + + if (this.map) { + this.video.play(); + } + + this._finishLoading(); + } catch (err) { + this.fire(new ErrorEvent(err)); + } + } /** * Pauses the video. @@ -152,7 +153,7 @@ export class VideoSource extends ImageSource { * * @returns `this` */ - prepare = (): this => { + prepare(): this { if (Object.keys(this.tiles).length === 0 || this.video.readyState < 2) { return; // not enough data for current position } @@ -189,15 +190,15 @@ export class VideoSource extends ImageSource { if (newTilesLoaded) { this.fire(new Event('data', {dataType: 'source', sourceDataType: 'idle', sourceId: this.id})); } - }; + } - serialize = (): VideoSourceSpecification => { + serialize(): VideoSourceSpecification { return { type: 'video', urls: this.urls, coordinates: this.coordinates }; - }; + } hasTransition() { return this.video && !this.video.paused; diff --git a/src/source/worker.test.ts b/src/source/worker.test.ts index 26d320972c..2b5189075e 100644 --- a/src/source/worker.test.ts +++ b/src/source/worker.test.ts @@ -1,46 +1,50 @@ import {fakeServer} from 'nise'; import Worker from './worker'; import {LayerSpecification} from '@maplibre/maplibre-gl-style-spec'; -import {Cancelable} from '../types/cancelable'; import {WorkerGlobalScopeInterface} from '../util/web_worker'; import {CanonicalTileID, OverscaledTileID} from './tile_id'; -import {TileParameters, WorkerSource, WorkerTileCallback, WorkerTileParameters} from './worker_source'; +import {WorkerSource, WorkerTileParameters, WorkerTileResult} from './worker_source'; import {plugin as globalRTLTextPlugin} from './rtl_text_plugin'; -import {ActorTarget} from '../util/actor'; - -const _self = { - addEventListener() {} -} as any as WorkerGlobalScopeInterface & ActorTarget; +import {ActorTarget, IActor} from '../util/actor'; class WorkerSourceMock implements WorkerSource { availableImages: string[]; - constructor(private actor: any) {} - loadTile(_: WorkerTileParameters, __: WorkerTileCallback): void { - this.actor.send('main thread task', {}, () => {}, null); + constructor(private actor: IActor) {} + loadTile(_: WorkerTileParameters): Promise { + return this.actor.sendAsync({type: 'loadTile', data: {} as any}, new AbortController()); } - reloadTile(_: WorkerTileParameters, __: WorkerTileCallback): void { + reloadTile(_: WorkerTileParameters): Promise { throw new Error('Method not implemented.'); } - abortTile(_: TileParameters, __: WorkerTileCallback): void { + abortTile(_: WorkerTileParameters): Promise { throw new Error('Method not implemented.'); } - removeTile(_: TileParameters, __: WorkerTileCallback): void { + removeTile(_: WorkerTileParameters): Promise { throw new Error('Method not implemented.'); } } -describe('load tile', () => { - test('calls callback on error', done => { - const server = fakeServer.create(); +describe('Worker register RTLTextPlugin', () => { + let worker: Worker; + let _self: WorkerGlobalScopeInterface & ActorTarget; + + beforeEach(() => { + _self = { + addEventListener() {} + } as any; + worker = new Worker(_self); global.fetch = null; - const worker = new Worker(_self); - worker.loadTile('0', { + }); + + test('should validate handlers execution in worker for load tile', done => { + const server = fakeServer.create(); + worker.actor.messageHandlers['loadTile']('0', { type: 'vector', source: 'source', uid: '0', tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0} as CanonicalTileID} as any as OverscaledTileID, request: {url: '/error'}// Sinon fake server gives 404 responses by default - } as WorkerTileParameters & { type: string }, (err) => { + } as WorkerTileParameters).catch((err) => { expect(err).toBeTruthy(); server.restore(); done(); @@ -49,42 +53,38 @@ describe('load tile', () => { }); test('isolates different instances\' data', () => { - const worker = new Worker(_self); - - worker.setLayers('0', [ + worker.actor.messageHandlers['setLayers']('0', [ {id: 'one', type: 'circle'} as LayerSpecification - ], () => {}); + ]); - worker.setLayers('1', [ + worker.actor.messageHandlers['setLayers']('1', [ {id: 'one', type: 'circle'} as LayerSpecification, {id: 'two', type: 'circle'} as LayerSpecification, - ], () => {}); + ]); expect(worker.layerIndexes[0]).not.toBe(worker.layerIndexes[1]); }); test('worker source messages dispatched to the correct map instance', done => { - const worker = new Worker(_self); - const workerName = 'test'; + const extenalSourceName = 'test'; - worker.actor.send = (type, data, callback, mapId): Cancelable => { - expect(type).toBe('main thread task'); - expect(mapId).toBe('999'); + worker.actor.sendAsync = (message, abortController) => { + expect(message.type).toBe('loadTile'); + expect(message.targetMapId).toBe('999'); + expect(abortController).toBeDefined(); done(); - return {cancel: () => {}}; + return Promise.resolve({} as any); }; - _self.registerWorkerSource(workerName, WorkerSourceMock); + _self.registerWorkerSource(extenalSourceName, WorkerSourceMock); expect(() => { - _self.registerWorkerSource(workerName, WorkerSourceMock); - }).toThrow(`Worker source with name "${workerName}" already registered.`); + _self.registerWorkerSource(extenalSourceName, WorkerSourceMock); + }).toThrow(`Worker source with name "${extenalSourceName}" already registered.`); - worker.loadTile('999', {type: 'test'} as WorkerTileParameters & { type: string }, () => {}); + worker.actor.messageHandlers['loadTile']('999', {type: extenalSourceName} as WorkerTileParameters); }); -}); -describe('register RTLTextPlugin', () => { test('should not throw and set values in plugin', () => { jest.spyOn(globalRTLTextPlugin, 'isParsed').mockImplementation(() => { return false; @@ -97,9 +97,9 @@ describe('register RTLTextPlugin', () => { }; _self.registerRTLTextPlugin(rtlTextPlugin); - expect(globalRTLTextPlugin['applyArabicShaping']).toBe('test'); - expect(globalRTLTextPlugin['processBidirectionalText']).toBe('test'); - expect(globalRTLTextPlugin['processStyledBidirectionalText']).toBe('test'); + expect(globalRTLTextPlugin.applyArabicShaping).toBe('test'); + expect(globalRTLTextPlugin.processBidirectionalText).toBe('test'); + expect(globalRTLTextPlugin.processStyledBidirectionalText).toBe('test'); }); test('should throw if already parsed', () => { @@ -117,37 +117,25 @@ describe('register RTLTextPlugin', () => { _self.registerRTLTextPlugin(rtlTextPlugin); }).toThrow('RTL text plugin already registered.'); }); -}); -describe('set Referrer', () => { test('Referrer is set', () => { - const worker = new Worker(_self); - worker.setReferrer('fakeId', 'myMap'); + worker.actor.messageHandlers['setReferrer']('fakeId', 'myMap'); expect(worker.referrer).toBe('myMap'); }); -}); -describe('load worker source', () => { test('calls callback on error', done => { const server = fakeServer.create(); - global.fetch = null; - const worker = new Worker(_self); - worker.loadWorkerSource('0', { - url: '/error', - }, (err) => { + worker.actor.messageHandlers['loadWorkerSource']('0', '/error').catch((err) => { expect(err).toBeTruthy(); server.restore(); done(); }); server.respond(); }); -}); -describe('set images', () => { test('set images', () => { - const worker = new Worker(_self); expect(worker.availableImages['0']).toBeUndefined(); - worker.setImages('0', ['availableImages'], () => {}); + worker.actor.messageHandlers['setImages']('0', ['availableImages']); expect(worker.availableImages['0']).toEqual(['availableImages']); }); }); diff --git a/src/source/worker.ts b/src/source/worker.ts index 74ae806d46..2c7d1f7b53 100644 --- a/src/source/worker.ts +++ b/src/source/worker.ts @@ -2,23 +2,22 @@ import {Actor, ActorTarget} from '../util/actor'; import {StyleLayerIndex} from '../style/style_layer_index'; import {VectorTileWorkerSource} from './vector_tile_worker_source'; import {RasterDEMTileWorkerSource} from './raster_dem_tile_worker_source'; -import {GeoJSONWorkerSource} from './geojson_worker_source'; +import {GeoJSONWorkerSource, LoadGeoJSONParameters} from './geojson_worker_source'; import {plugin as globalRTLTextPlugin} from './rtl_text_plugin'; import {isWorker} from '../util/util'; import type { WorkerSource, + WorkerSourceConstructor, WorkerTileParameters, WorkerDEMTileParameters, - WorkerTileCallback, - WorkerDEMTileCallback, TileParameters } from '../source/worker_source'; import type {WorkerGlobalScopeInterface} from '../util/web_worker'; -import type {Callback} from '../types/callback'; import type {LayerSpecification} from '@maplibre/maplibre-gl-style-spec'; import type {PluginState} from './rtl_text_plugin'; +import type {ClusterIDAndSource, GetClusterLeavesParams, RemoveSourceParams, UpdateLayersParamaeters} from '../util/actor_messages'; /** * The Worker class responsidble for background thread related execution @@ -28,11 +27,13 @@ export default class Worker { actor: Actor; layerIndexes: {[_: string]: StyleLayerIndex}; availableImages: {[_: string]: Array}; - workerSourceTypes: { - [_: string]: { - new (...args: any): WorkerSource; - }; - }; + externalWorkerSourceTypes: { [_: string]: WorkerSourceConstructor }; + /** + * This holds a cache for the already created worker source instances. + * The cache is build with the following hierarchy: + * [mapId][sourceType][sourceName]: worker source instance + * sourceType can be 'vector' for example + */ workerSources: { [_: string]: { [_: string]: { @@ -40,6 +41,12 @@ export default class Worker { }; }; }; + /** + * This holds a cache for the already created DEM worker source instances. + * The cache is build with the following hierarchy: + * [mapId][sourceType]: DEM worker source instance + * sourceType can be 'raster-dem' for example + */ demWorkerSources: { [_: string]: { [_: string]: RasterDEMTileWorkerSource; @@ -49,162 +56,156 @@ export default class Worker { constructor(self: WorkerGlobalScopeInterface & ActorTarget) { this.self = self; - this.actor = new Actor(self, this); + this.actor = new Actor(self); this.layerIndexes = {}; this.availableImages = {}; - this.workerSourceTypes = { - vector: VectorTileWorkerSource, - geojson: GeoJSONWorkerSource - }; - - // [mapId][sourceType][sourceName] => worker source instance this.workerSources = {}; this.demWorkerSources = {}; + this.externalWorkerSourceTypes = {}; - this.self.registerWorkerSource = (name: string, WorkerSource: { - new (...args: any): WorkerSource; - }) => { - if (this.workerSourceTypes[name]) { + this.self.registerWorkerSource = (name: string, WorkerSource: WorkerSourceConstructor) => { + if (this.externalWorkerSourceTypes[name]) { throw new Error(`Worker source with name "${name}" already registered.`); } - this.workerSourceTypes[name] = WorkerSource; + this.externalWorkerSourceTypes[name] = WorkerSource; }; // This is invoked by the RTL text plugin when the download via the `importScripts` call has finished, and the code has been parsed. this.self.registerRTLTextPlugin = (rtlTextPlugin: { - applyArabicShaping: Function; - processBidirectionalText: ((b: string, a: Array) => Array); - processStyledBidirectionalText?: ((c: string, b: Array, a: Array) => Array<[string, Array]>); + applyArabicShaping: typeof globalRTLTextPlugin.applyArabicShaping; + processBidirectionalText: typeof globalRTLTextPlugin.processBidirectionalText; + processStyledBidirectionalText?: typeof globalRTLTextPlugin.processStyledBidirectionalText; }) => { if (globalRTLTextPlugin.isParsed()) { throw new Error('RTL text plugin already registered.'); } - globalRTLTextPlugin['applyArabicShaping'] = rtlTextPlugin.applyArabicShaping; - globalRTLTextPlugin['processBidirectionalText'] = rtlTextPlugin.processBidirectionalText; - globalRTLTextPlugin['processStyledBidirectionalText'] = rtlTextPlugin.processStyledBidirectionalText; + globalRTLTextPlugin.applyArabicShaping = rtlTextPlugin.applyArabicShaping; + globalRTLTextPlugin.processBidirectionalText = rtlTextPlugin.processBidirectionalText; + globalRTLTextPlugin.processStyledBidirectionalText = rtlTextPlugin.processStyledBidirectionalText; }; - } - setReferrer(mapID: string, referrer: string) { - this.referrer = referrer; - } + this.actor.registerMessageHandler('loadDEMTile', (mapId: string, params: WorkerDEMTileParameters) => { + return this._getDEMWorkerSource(mapId, params.source).loadTile(params); + }); - setImages(mapId: string, images: Array, callback: WorkerTileCallback) { - this.availableImages[mapId] = images; - for (const workerSource in this.workerSources[mapId]) { - const ws = this.workerSources[mapId][workerSource]; - for (const source in ws) { - ws[source].availableImages = images; - } - } - callback(); - } + this.actor.registerMessageHandler('removeDEMTile', async (mapId: string, params: TileParameters) => { + this._getDEMWorkerSource(mapId, params.source).removeTile(params); + }); - setLayers(mapId: string, layers: Array, callback: WorkerTileCallback) { - this.getLayerIndex(mapId).replace(layers); - callback(); - } + this.actor.registerMessageHandler('getClusterExpansionZoom', async (mapId: string, params: ClusterIDAndSource) => { + return (this._getWorkerSource(mapId, params.type, params.source) as GeoJSONWorkerSource).getClusterExpansionZoom(params); + }); - updateLayers(mapId: string, params: { - layers: Array; - removedIds: Array; - }, callback: WorkerTileCallback) { - this.getLayerIndex(mapId).update(params.layers, params.removedIds); - callback(); - } + this.actor.registerMessageHandler('getClusterChildren', async (mapId: string, params: ClusterIDAndSource) => { + return (this._getWorkerSource(mapId, params.type, params.source) as GeoJSONWorkerSource).getClusterChildren(params); + }); - loadTile(mapId: string, params: WorkerTileParameters & { - type: string; - }, callback: WorkerTileCallback) { - this.getWorkerSource(mapId, params.type, params.source).loadTile(params, callback); - } + this.actor.registerMessageHandler('getClusterLeaves', async (mapId: string, params: GetClusterLeavesParams) => { + return (this._getWorkerSource(mapId, params.type, params.source) as GeoJSONWorkerSource).getClusterLeaves(params); + }); - loadDEMTile(mapId: string, params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) { - this.getDEMWorkerSource(mapId, params.source).loadTile(params, callback); - } + this.actor.registerMessageHandler('loadData', (mapId: string, params: LoadGeoJSONParameters) => { + return (this._getWorkerSource(mapId, params.type, params.source) as GeoJSONWorkerSource).loadData(params); + }); - reloadTile(mapId: string, params: WorkerTileParameters & { - type: string; - }, callback: WorkerTileCallback) { - this.getWorkerSource(mapId, params.type, params.source).reloadTile(params, callback); - } + this.actor.registerMessageHandler('loadTile', (mapId: string, params: WorkerTileParameters) => { + return this._getWorkerSource(mapId, params.type, params.source).loadTile(params); + }); - abortTile(mapId: string, params: TileParameters & { - type: string; - }, callback: WorkerTileCallback) { - this.getWorkerSource(mapId, params.type, params.source).abortTile(params, callback); - } + this.actor.registerMessageHandler('reloadTile', (mapId: string, params: WorkerTileParameters) => { + return this._getWorkerSource(mapId, params.type, params.source).reloadTile(params); + }); - removeTile(mapId: string, params: TileParameters & { - type: string; - }, callback: WorkerTileCallback) { - this.getWorkerSource(mapId, params.type, params.source).removeTile(params, callback); - } + this.actor.registerMessageHandler('abortTile', (mapId: string, params: TileParameters) => { + return this._getWorkerSource(mapId, params.type, params.source).abortTile(params); + }); - removeDEMTile(mapId: string, params: TileParameters) { - this.getDEMWorkerSource(mapId, params.source).removeTile(params); - } + this.actor.registerMessageHandler('removeTile', (mapId: string, params: TileParameters) => { + return this._getWorkerSource(mapId, params.type, params.source).removeTile(params); + }); - removeSource(mapId: string, params: { - source: string; - } & { - type: string; - }, callback: WorkerTileCallback) { + this.actor.registerMessageHandler('removeSource', async (mapId: string, params: RemoveSourceParams) => { + if (!this.workerSources[mapId] || + !this.workerSources[mapId][params.type] || + !this.workerSources[mapId][params.type][params.source]) { + return; + } - if (!this.workerSources[mapId] || - !this.workerSources[mapId][params.type] || - !this.workerSources[mapId][params.type][params.source]) { - return; - } + const worker = this.workerSources[mapId][params.type][params.source]; + delete this.workerSources[mapId][params.type][params.source]; - const worker = this.workerSources[mapId][params.type][params.source]; - delete this.workerSources[mapId][params.type][params.source]; + if (worker.removeSource !== undefined) { + worker.removeSource(params); + } + }); + + this.actor.registerMessageHandler('setReferrer', async (_mapId: string, params: string) => { + this.referrer = params; + }); + + this.actor.registerMessageHandler('syncRTLPluginState', (mapId: string, params: PluginState) => { + return this._syncRTLPluginState(mapId, params); + }); + + this.actor.registerMessageHandler('loadWorkerSource', async (_mapId: string, params: string) => { + try { + this.self.importScripts(params); + } catch (ex) { + // This is done since some error messages are not serializable + throw ex.toString(); + } + }); - if (worker.removeSource !== undefined) { - worker.removeSource(params, callback); - } else { - callback(); - } + this.actor.registerMessageHandler('setImages', (mapId: string, params: string[]) => { + return this._setImages(mapId, params); + }); + + this.actor.registerMessageHandler('updateLayers', async (mapId: string, params: UpdateLayersParamaeters) => { + this._getLayerIndex(mapId).update(params.layers, params.removedIds); + }); + + this.actor.registerMessageHandler('setLayers', async (mapId: string, params: Array) => { + this._getLayerIndex(mapId).replace(params); + }); } - /** - * Load a {@link WorkerSource} script at params.url. The script is run - * (using importScripts) with `registerWorkerSource` in scope, which is a - * function taking `(name, workerSourceObject)`. - */ - loadWorkerSource(map: string, params: { - url: string; - }, callback: Callback) { - try { - this.self.importScripts(params.url); - callback(); - } catch (e) { - callback(e.toString()); + private async _setImages(mapId: string, images: Array): Promise { + this.availableImages[mapId] = images; + for (const workerSource in this.workerSources[mapId]) { + const ws = this.workerSources[mapId][workerSource]; + for (const source in ws) { + ws[source].availableImages = images; + } } } - syncRTLPluginState(map: string, state: PluginState, callback: Callback) { + private async _syncRTLPluginState(map: string, state: PluginState): Promise { try { globalRTLTextPlugin.setState(state); const pluginURL = globalRTLTextPlugin.getPluginURL(); if ( globalRTLTextPlugin.isLoaded() && - !globalRTLTextPlugin.isParsed() && - pluginURL != null // Not possible when `isLoaded` is true, but keeps flow happy + !globalRTLTextPlugin.isParsed() && + pluginURL != null // Not possible when `isLoaded` is true, but keeps flow happy ) { this.self.importScripts(pluginURL); const complete = globalRTLTextPlugin.isParsed(); - const error = complete ? undefined : new Error(`RTL Text Plugin failed to import scripts from ${pluginURL}`); - callback(error, complete); + if (complete) { + return complete; + } + throw new Error(`RTL Text Plugin failed to import scripts from ${pluginURL}`); } - } catch (e) { - callback(e.toString()); + return false; + } catch (ex) { + // This is done since some error messages are not serializable + throw ex.toString(); + } } - getAvailableImages(mapId: string) { + private _getAvailableImages(mapId: string) { let availableImages = this.availableImages[mapId]; if (!availableImages) { @@ -214,7 +215,7 @@ export default class Worker { return availableImages; } - getLayerIndex(mapId: string) { + private _getLayerIndex(mapId: string) { let layerIndexes = this.layerIndexes[mapId]; if (!layerIndexes) { layerIndexes = this.layerIndexes[mapId] = new StyleLayerIndex(); @@ -222,7 +223,14 @@ export default class Worker { return layerIndexes; } - getWorkerSource(mapId: string, sourceType: string, sourceName: string): WorkerSource { + /** + * This is basically a lazy initialization of a worker per mapId and sourceType and sourceName + * @param mapId - the mapId + * @param sourceType - the source type - 'vector' for example + * @param sourceName - the source name - 'osm' for example + * @returns a new instance or a cached one + */ + private _getWorkerSource(mapId: string, sourceType: string, sourceName: string): WorkerSource { if (!this.workerSources[mapId]) this.workerSources[mapId] = {}; if (!this.workerSources[mapId][sourceType]) @@ -230,30 +238,47 @@ export default class Worker { if (!this.workerSources[mapId][sourceType][sourceName]) { // use a wrapped actor so that we can attach a target mapId param - // to any messages invoked by the WorkerSource + // to any messages invoked by the WorkerSource, this is very important when there are multiple maps const actor = { - send: (type, data, callback) => { - this.actor.send(type, data, callback, mapId); + sendAsync: (message, abortController) => { + message.targetMapId = mapId; + return this.actor.sendAsync(message, abortController); } }; - this.workerSources[mapId][sourceType][sourceName] = new (this.workerSourceTypes[sourceType] as any)((actor as any), this.getLayerIndex(mapId), this.getAvailableImages(mapId)); + switch (sourceType) { + case 'vector': + this.workerSources[mapId][sourceType][sourceName] = new VectorTileWorkerSource(actor, this._getLayerIndex(mapId), this._getAvailableImages(mapId)); + break; + case 'geojson': + this.workerSources[mapId][sourceType][sourceName] = new GeoJSONWorkerSource(actor, this._getLayerIndex(mapId), this._getAvailableImages(mapId)); + break; + default: + this.workerSources[mapId][sourceType][sourceName] = new (this.externalWorkerSourceTypes[sourceType])(actor, this._getLayerIndex(mapId), this._getAvailableImages(mapId)); + break; + } } return this.workerSources[mapId][sourceType][sourceName]; } - getDEMWorkerSource(mapId: string, source: string) { + /** + * This is basically a lazy initialization of a worker per mapId and source + * @param mapId - the mapId + * @param sourceType - the source type - 'raster-dem' for example + * @returns a new instance or a cached one + */ + private _getDEMWorkerSource(mapId: string, sourceType: string) { if (!this.demWorkerSources[mapId]) this.demWorkerSources[mapId] = {}; - if (!this.demWorkerSources[mapId][source]) { - this.demWorkerSources[mapId][source] = new RasterDEMTileWorkerSource(); + if (!this.demWorkerSources[mapId][sourceType]) { + this.demWorkerSources[mapId][sourceType] = new RasterDEMTileWorkerSource(); } - return this.demWorkerSources[mapId][source]; + return this.demWorkerSources[mapId][sourceType]; } } -if (isWorker()) { - (self as any).worker = new Worker(self as any); +if (isWorker(self)) { + self.worker = new Worker(self); } diff --git a/src/source/worker_source.ts b/src/source/worker_source.ts index fd6741b446..8f5306ca42 100644 --- a/src/source/worker_source.ts +++ b/src/source/worker_source.ts @@ -1,4 +1,4 @@ -import type {RequestParameters} from '../util/ajax'; +import type {ExpiryData, RequestParameters} from '../util/ajax'; import type {RGBAImage, AlphaImage} from '../util/image'; import type {GlyphPositions} from '../render/glyph_atlas'; import type {ImageAtlas} from '../render/image_atlas'; @@ -6,21 +6,31 @@ import type {OverscaledTileID} from './tile_id'; import type {Bucket} from '../data/bucket'; import type {FeatureIndex} from '../data/feature_index'; import type {CollisionBoxArray} from '../data/array_types.g'; -import type {DEMData, DEMEncoding} from '../data/dem_data'; +import type {DEMEncoding} from '../data/dem_data'; import type {StyleGlyph} from '../style/style_glyph'; import type {StyleImage} from '../style/style_image'; import type {PromoteIdSpecification} from '@maplibre/maplibre-gl-style-spec'; +import {RemoveSourceParams as RemoveSourceParameters} from '../util/actor_messages'; +import type {IActor} from '../util/actor'; +import type {StyleLayerIndex} from '../style/style_layer_index'; +/** + * Parameters to identify a tile + */ export type TileParameters = { + type: string; source: string; - uid: string; + uid: string | number; }; +/** + * Parameters that are send when requesting to load a tile to the worker + */ export type WorkerTileParameters = TileParameters & { tileID: OverscaledTileID; - request: RequestParameters; + request?: RequestParameters; zoom: number; - maxZoom: number; + maxZoom?: number; tileSize: number; promoteId: PromoteIdSpecification; pixelRatio: number; @@ -29,14 +39,11 @@ export type WorkerTileParameters = TileParameters & { returnDependencies?: boolean; }; +/** + * The paremeters needed in order to load a DEM tile + */ export type WorkerDEMTileParameters = TileParameters & { - coord: { - z: number; - x: number; - y: number; - w: number; - }; - rawImageData: RGBAImage | ImageBitmap; + rawImageData: RGBAImage | ImageBitmap | ImageData; encoding: DEMEncoding; redFactor: number; greenFactor: number; @@ -45,10 +52,9 @@ export type WorkerDEMTileParameters = TileParameters & { }; /** - * @internal * The worker tile's result type */ -export type WorkerTileResult = { +export type WorkerTileResult = ExpiryData & { buckets: Array; imageAtlas: ImageAtlas; glyphAtlasImage: AlphaImage; @@ -68,51 +74,44 @@ export type WorkerTileResult = { glyphPositions?: GlyphPositions | null; }; -export type WorkerTileCallback = (error?: Error | null, result?: WorkerTileResult | null) => void; -export type WorkerDEMTileCallback = (err?: Error | null, result?: DEMData | null) => void; +/** + * This is how the @see {@link WorkerSource} constructor should look like. + */ +export interface WorkerSourceConstructor { + new (actor: IActor, layerIndex: StyleLayerIndex, availableImages: Array): WorkerSource; +} /** - * May be implemented by custom source types to provide code that can be run on - * the WebWorkers. In addition to providing a custom - * {@link WorkerSource#loadTile}, any other methods attached to a `WorkerSource` - * implementation may also be targeted by the {@link Source} via - * `dispatcher.getActor().send('source-type.methodname', params, callback)`. - * + * `WorkerSource` should be implemented by custom source types to provide code that can be run on the WebWorkers. + * Each of the methods has a relevant event that triggers it from the main thread with the relevant parameters. * @see {@link Map#addSourceType} */ export interface WorkerSource { availableImages: Array; - // Disabled due to https://github.com/facebook/flow/issues/5208 - // constructor(actor: Actor, layerIndex: StyleLayerIndex): WorkerSource; /** * Loads a tile from the given params and parse it into buckets ready to send * back to the main thread for rendering. Should call the callback with: * `{ buckets, featureIndex, collisionIndex, rawTileData}`. */ - loadTile(params: WorkerTileParameters, callback: WorkerTileCallback): void; + loadTile(params: WorkerTileParameters): Promise; /** * Re-parses a tile that has already been loaded. Yields the same data as * {@link WorkerSource#loadTile}. */ - reloadTile(params: WorkerTileParameters, callback: WorkerTileCallback): void; + reloadTile(params: WorkerTileParameters): Promise; /** * Aborts loading a tile that is in progress. */ - abortTile(params: TileParameters, callback: WorkerTileCallback): void; + abortTile(params: TileParameters): Promise; /** * Removes this tile from any local caches. */ - removeTile(params: TileParameters, callback: WorkerTileCallback): void; + removeTile(params: TileParameters): Promise; /** * Tells the WorkerSource to abort in-progress tasks and release resources. * The foreground Source is responsible for ensuring that 'removeSource' is * the last message sent to the WorkerSource. */ - removeSource?: ( - params: { - source: string; - }, - callback: WorkerTileCallback - ) => void; + removeSource?: (params: RemoveSourceParameters) => Promise; } diff --git a/src/source/worker_tile.test.ts b/src/source/worker_tile.test.ts index c914ee28d0..813bc71e56 100644 --- a/src/source/worker_tile.test.ts +++ b/src/source/worker_tile.test.ts @@ -3,7 +3,6 @@ import {GeoJSONWrapper, Feature} from '../source/geojson_wrapper'; import {OverscaledTileID} from '../source/tile_id'; import {StyleLayerIndex} from '../style/style_layer_index'; import {WorkerTileParameters} from './worker_source'; -import {Actor} from '../util/actor'; import {VectorTile} from '@mapbox/vector-tile'; function createWorkerTile() { @@ -27,7 +26,7 @@ function createWrapper() { } describe('worker tile', () => { - test('WorkerTile#parse', done => { + test('WorkerTile#parse', async () => { const layerIndex = new StyleLayerIndex([{ id: 'test', source: 'source', @@ -35,14 +34,11 @@ describe('worker tile', () => { }]); const tile = createWorkerTile(); - tile.parse(createWrapper(), layerIndex, [], {} as Actor, (err, result) => { - expect(err).toBeFalsy(); - expect(result.buckets[0]).toBeTruthy(); - done(); - }); + const result = await tile.parse(createWrapper(), layerIndex, [], {} as any); + expect(result.buckets[0]).toBeTruthy(); }); - test('WorkerTile#parse skips hidden layers', done => { + test('WorkerTile#parse skips hidden layers', async () => { const layerIndex = new StyleLayerIndex([{ id: 'test-hidden', source: 'source', @@ -51,14 +47,11 @@ describe('worker tile', () => { }]); const tile = createWorkerTile(); - tile.parse(createWrapper(), layerIndex, [], {} as Actor, (err, result) => { - expect(err).toBeFalsy(); - expect(result.buckets).toHaveLength(0); - done(); - }); + const result = await tile.parse(createWrapper(), layerIndex, [], {} as any); + expect(result.buckets).toHaveLength(0); }); - test('WorkerTile#parse skips layers without a corresponding source layer', done => { + test('WorkerTile#parse skips layers without a corresponding source layer', async () => { const layerIndex = new StyleLayerIndex([{ id: 'test', source: 'source', @@ -67,14 +60,11 @@ describe('worker tile', () => { }]); const tile = createWorkerTile(); - tile.parse({layers: {}}, layerIndex, [], {} as Actor, (err, result) => { - expect(err).toBeFalsy(); - expect(result.buckets).toHaveLength(0); - done(); - }); + const result = await tile.parse({layers: {}}, layerIndex, [], {} as any); + expect(result.buckets).toHaveLength(0); }); - test('WorkerTile#parse warns once when encountering a v1 vector tile layer', done => { + test('WorkerTile#parse warns once when encountering a v1 vector tile layer', async () => { const layerIndex = new StyleLayerIndex([{ id: 'test', source: 'source', @@ -93,14 +83,11 @@ describe('worker tile', () => { const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}); const tile = createWorkerTile(); - tile.parse(data, layerIndex, [], {} as Actor, (err) => { - expect(err).toBeFalsy(); - expect(spy.mock.calls[0][0]).toMatch(/does not use vector tile spec v2/); - done(); - }); + await tile.parse(data, layerIndex, [], {} as any); + expect(spy.mock.calls[0][0]).toMatch(/does not use vector tile spec v2/); }); - test('WorkerTile#parse would request all types of dependencies', done => { + test('WorkerTile#parse would request all types of dependencies', async () => { const tile = createWorkerTile(); const layerIndex = new StyleLayerIndex([{ id: '1', @@ -144,29 +131,25 @@ describe('worker tile', () => { } } as any as VectorTile; - const send = jest.fn().mockImplementation((type: string, data: unknown, callback: Function) => { - setTimeout(() => callback(null, - type === 'getImages' ? - {'hello': {width: 1, height: 1, data: new Uint8Array([0])}} : - {'StandardFont-Bold': {width: 1, height: 1, data: new Uint8Array([0])}} - )); + const sendAsync = jest.fn().mockImplementation((message: {type: string; data: any}) => { + const response = message.type === 'getImages' ? + {'hello': {width: 1, height: 1, data: new Uint8Array([0])}} : + {'StandardFont-Bold': {width: 1, height: 1, data: new Uint8Array([0])}}; + return Promise.resolve(response); }); const actorMock = { - send - } as unknown as Actor; - tile.parse(data, layerIndex, ['hello'], actorMock, (err, result) => { - expect(err).toBeFalsy(); - expect(result).toBeDefined(); - expect(send).toHaveBeenCalledTimes(3); - expect(send).toHaveBeenCalledWith('getImages', expect.objectContaining({'icons': ['hello'], 'type': 'icons'}), expect.any(Function)); - expect(send).toHaveBeenCalledWith('getImages', expect.objectContaining({'icons': ['hello'], 'type': 'patterns'}), expect.any(Function)); - expect(send).toHaveBeenCalledWith('getGlyphs', expect.objectContaining({'source': 'source', 'type': 'glyphs', 'stacks': {'StandardFont-Bold': [101, 115, 116]}}), expect.any(Function)); - done(); - }); + sendAsync + }; + const result = await tile.parse(data, layerIndex, ['hello'], actorMock); + expect(result).toBeDefined(); + expect(sendAsync).toHaveBeenCalledTimes(3); + expect(sendAsync).toHaveBeenCalledWith(expect.objectContaining({data: expect.objectContaining({'icons': ['hello'], 'type': 'icons'})}), expect.any(Object)); + expect(sendAsync).toHaveBeenCalledWith(expect.objectContaining({data: expect.objectContaining({'icons': ['hello'], 'type': 'patterns'})}), expect.any(Object)); + expect(sendAsync).toHaveBeenCalledWith(expect.objectContaining({data: expect.objectContaining({'source': 'source', 'type': 'glyphs', 'stacks': {'StandardFont-Bold': [101, 115, 116]}})}), expect.any(Object)); }); - test('WorkerTile#parse would cancel and only event once on repeated reparsing', done => { + test('WorkerTile#parse would cancel and only event once on repeated reparsing', async () => { const tile = createWorkerTile(); const layerIndex = new StyleLayerIndex([{ id: '1', @@ -211,35 +194,33 @@ describe('worker tile', () => { } as any as VectorTile; let cancelCount = 0; - const send = jest.fn().mockImplementation((type: string, data: unknown, callback: Function) => { - const res = setTimeout(() => callback(null, - type === 'getImages' ? - {'hello': {width: 1, height: 1, data: new Uint8Array([0])}} : - {'StandardFont-Bold': {width: 1, height: 1, data: new Uint8Array([0])}} - )); - - return { - cancel: () => { + const sendAsync = jest.fn().mockImplementation((message: {type: string; data: unknown}, abortController: AbortController) => { + return new Promise((resolve, _reject) => { + const res = setTimeout(() => { + const response = message.type === 'getImages' ? + {'hello': {width: 1, height: 1, data: new Uint8Array([0])}} : + {'StandardFont-Bold': {width: 1, height: 1, data: new Uint8Array([0])}}; + resolve(response); + } + ); + abortController.signal.addEventListener('abort', () => { cancelCount += 1; clearTimeout(res); - } - }; + }); + }); }); const actorMock = { - send - } as unknown as Actor; - tile.parse(data, layerIndex, ['hello'], actorMock, () => done.fail('should not be called')); - tile.parse(data, layerIndex, ['hello'], actorMock, () => done.fail('should not be called')); - tile.parse(data, layerIndex, ['hello'], actorMock, (err, result) => { - expect(err).toBeFalsy(); - expect(result).toBeDefined(); - expect(cancelCount).toBe(6); - expect(send).toHaveBeenCalledTimes(9); - expect(send).toHaveBeenCalledWith('getImages', expect.objectContaining({'icons': ['hello'], 'type': 'icons'}), expect.any(Function)); - expect(send).toHaveBeenCalledWith('getImages', expect.objectContaining({'icons': ['hello'], 'type': 'patterns'}), expect.any(Function)); - expect(send).toHaveBeenCalledWith('getGlyphs', expect.objectContaining({'source': 'source', 'type': 'glyphs', 'stacks': {'StandardFont-Bold': [101, 115, 116]}}), expect.any(Function)); - done(); - }); + sendAsync + }; + tile.parse(data, layerIndex, ['hello'], actorMock).then(() => expect(false).toBeTruthy()); + tile.parse(data, layerIndex, ['hello'], actorMock).then(() => expect(false).toBeTruthy()); + const result = await tile.parse(data, layerIndex, ['hello'], actorMock); + expect(result).toBeDefined(); + expect(cancelCount).toBe(6); + expect(sendAsync).toHaveBeenCalledTimes(9); + expect(sendAsync).toHaveBeenCalledWith(expect.objectContaining({data: expect.objectContaining({'icons': ['hello'], 'type': 'icons'})}), expect.any(Object)); + expect(sendAsync).toHaveBeenCalledWith(expect.objectContaining({data: expect.objectContaining({'icons': ['hello'], 'type': 'patterns'})}), expect.any(Object)); + expect(sendAsync).toHaveBeenCalledWith(expect.objectContaining({data: expect.objectContaining({'source': 'source', 'type': 'glyphs', 'stacks': {'StandardFont-Bold': [101, 115, 116]}})}), expect.any(Object)); }); }); diff --git a/src/source/worker_tile.ts b/src/source/worker_tile.ts index 3a13b4ce5f..35c8770cc4 100644 --- a/src/source/worker_tile.ts +++ b/src/source/worker_tile.ts @@ -13,22 +13,20 @@ import {EvaluationParameters} from '../style/evaluation_parameters'; import {OverscaledTileID} from './tile_id'; import type {Bucket} from '../data/bucket'; -import type {Actor} from '../util/actor'; +import type {IActor} from '../util/actor'; import type {StyleLayer} from '../style/style_layer'; import type {StyleLayerIndex} from '../style/style_layer_index'; -import type {StyleImage} from '../style/style_image'; -import type {StyleGlyph} from '../style/style_glyph'; import type { WorkerTileParameters, - WorkerTileCallback, + WorkerTileResult, } from '../source/worker_source'; import type {PromoteIdSpecification} from '@maplibre/maplibre-gl-style-spec'; import type {VectorTile} from '@mapbox/vector-tile'; -import {Cancelable} from '../types/cancelable'; +import type {GetGlyphsResponse, GetImagesResponse} from '../util/actor_messages'; export class WorkerTile { tileID: OverscaledTileID; - uid: string; + uid: string | number; zoom: number; pixelRatio: number; tileSize: number; @@ -43,10 +41,9 @@ export class WorkerTile { data: VectorTile; collisionBoxArray: CollisionBoxArray; - abort: (() => void); + abort: AbortController; vectorTile: VectorTile; - inFlightDependencies: Cancelable[]; - dependencySentinel: number; + inFlightDependencies: AbortController[]; constructor(params: WorkerTileParameters) { this.tileID = new OverscaledTileID(params.tileID.overscaledZ, params.tileID.wrap, params.tileID.canonical.z, params.tileID.canonical.x, params.tileID.canonical.y); @@ -61,10 +58,9 @@ export class WorkerTile { this.returnDependencies = !!params.returnDependencies; this.promoteId = params.promoteId; this.inFlightDependencies = []; - this.dependencySentinel = -1; } - parse(data: VectorTile, layerIndex: StyleLayerIndex, availableImages: Array, actor: Actor, callback: WorkerTileCallback) { + async parse(data: VectorTile, layerIndex: StyleLayerIndex, availableImages: Array, actor: IActor): Promise { this.status = 'parsing'; this.data = data; @@ -132,114 +128,72 @@ export class WorkerTile { } } - let error: Error; - let glyphMap: { - [_: string]: { - [_: number]: StyleGlyph; - }; - }; - let iconMap: {[_: string]: StyleImage}; - let patternMap: {[_: string]: StyleImage}; - const stacks = mapObject(options.glyphDependencies, (glyphs) => Object.keys(glyphs).map(Number)); - this.inFlightDependencies.forEach((request) => request?.cancel()); + this.inFlightDependencies.forEach((request) => request?.abort()); this.inFlightDependencies = []; - // cancelling seems to be not sufficient, we seems to still manage to get a callback hit, so use a sentinel to drop stale results - const dependencySentinel = ++this.dependencySentinel; + let getGlyphsPromise = Promise.resolve({}); if (Object.keys(stacks).length) { - this.inFlightDependencies.push(actor.send('getGlyphs', {uid: this.uid, stacks, source: this.source, tileID: this.tileID, type: 'glyphs'}, (err, result) => { - if (dependencySentinel !== this.dependencySentinel) { - return; - } - if (!error) { - error = err; - glyphMap = result; - maybePrepare.call(this); - } - })); - } else { - glyphMap = {}; + const abortController = new AbortController(); + this.inFlightDependencies.push(abortController); + getGlyphsPromise = actor.sendAsync({type: 'getGlyphs', data: {stacks, source: this.source, tileID: this.tileID, type: 'glyphs'}}, abortController); } const icons = Object.keys(options.iconDependencies); + let getIconsPromise = Promise.resolve({}); if (icons.length) { - this.inFlightDependencies.push(actor.send('getImages', {icons, source: this.source, tileID: this.tileID, type: 'icons'}, (err, result) => { - if (dependencySentinel !== this.dependencySentinel) { - return; - } - if (!error) { - error = err; - iconMap = result; - maybePrepare.call(this); - } - })); - } else { - iconMap = {}; + const abortController = new AbortController(); + this.inFlightDependencies.push(abortController); + getIconsPromise = actor.sendAsync({type: 'getImages', data: {icons, source: this.source, tileID: this.tileID, type: 'icons'}}, abortController); } const patterns = Object.keys(options.patternDependencies); + let getPatternsPromise = Promise.resolve({}); if (patterns.length) { - this.inFlightDependencies.push(actor.send('getImages', {icons: patterns, source: this.source, tileID: this.tileID, type: 'patterns'}, (err, result) => { - if (dependencySentinel !== this.dependencySentinel) { - return; - } - if (!error) { - error = err; - patternMap = result; - maybePrepare.call(this); - } - })); - } else { - patternMap = {}; + const abortController = new AbortController(); + this.inFlightDependencies.push(abortController); + getPatternsPromise = actor.sendAsync({type: 'getImages', data: {icons: patterns, source: this.source, tileID: this.tileID, type: 'patterns'}}, abortController); } - maybePrepare.call(this); - - function maybePrepare() { - if (error) { - return callback(error); - } else if (glyphMap && iconMap && patternMap) { - const glyphAtlas = new GlyphAtlas(glyphMap); - const imageAtlas = new ImageAtlas(iconMap, patternMap); - - for (const key in buckets) { - const bucket = buckets[key]; - if (bucket instanceof SymbolBucket) { - recalculateLayers(bucket.layers, this.zoom, availableImages); - performSymbolLayout({ - bucket, - glyphMap, - glyphPositions: glyphAtlas.positions, - imageMap: iconMap, - imagePositions: imageAtlas.iconPositions, - showCollisionBoxes: this.showCollisionBoxes, - canonical: this.tileID.canonical - }); - } else if (bucket.hasPattern && - (bucket instanceof LineBucket || - bucket instanceof FillBucket || - bucket instanceof FillExtrusionBucket)) { - recalculateLayers(bucket.layers, this.zoom, availableImages); - bucket.addFeatures(options, this.tileID.canonical, imageAtlas.patternPositions); - } - } - - this.status = 'done'; - callback(null, { - buckets: Object.values(buckets).filter(b => !b.isEmpty()), - featureIndex, - collisionBoxArray: this.collisionBoxArray, - glyphAtlasImage: glyphAtlas.image, - imageAtlas, - // Only used for benchmarking: - glyphMap: this.returnDependencies ? glyphMap : null, - iconMap: this.returnDependencies ? iconMap : null, - glyphPositions: this.returnDependencies ? glyphAtlas.positions : null + const [glyphMap, iconMap, patternMap] = await Promise.all([getGlyphsPromise, getIconsPromise, getPatternsPromise]); + const glyphAtlas = new GlyphAtlas(glyphMap); + const imageAtlas = new ImageAtlas(iconMap, patternMap); + + for (const key in buckets) { + const bucket = buckets[key]; + if (bucket instanceof SymbolBucket) { + recalculateLayers(bucket.layers, this.zoom, availableImages); + performSymbolLayout({ + bucket, + glyphMap, + glyphPositions: glyphAtlas.positions, + imageMap: iconMap, + imagePositions: imageAtlas.iconPositions, + showCollisionBoxes: this.showCollisionBoxes, + canonical: this.tileID.canonical }); + } else if (bucket.hasPattern && + (bucket instanceof LineBucket || + bucket instanceof FillBucket || + bucket instanceof FillExtrusionBucket)) { + recalculateLayers(bucket.layers, this.zoom, availableImages); + bucket.addFeatures(options, this.tileID.canonical, imageAtlas.patternPositions); } } + + this.status = 'done'; + return { + buckets: Object.values(buckets).filter(b => !b.isEmpty()), + featureIndex, + collisionBoxArray: this.collisionBoxArray, + glyphAtlasImage: glyphAtlas.image, + imageAtlas, + // Only used for benchmarking: + glyphMap: this.returnDependencies ? glyphMap : null, + iconMap: this.returnDependencies ? iconMap : null, + glyphPositions: this.returnDependencies ? glyphAtlas.positions : null + }; } } diff --git a/src/style/load_glyph_range.test.ts b/src/style/load_glyph_range.test.ts index 12500f9ebf..f79334a301 100644 --- a/src/style/load_glyph_range.test.ts +++ b/src/style/load_glyph_range.test.ts @@ -5,7 +5,7 @@ import {loadGlyphRange} from './load_glyph_range'; import {fakeServer} from 'nise'; import {bufferToArrayBuffer} from '../util/test/util'; -test('loadGlyphRange', done => { +test('loadGlyphRange', async () => { global.fetch = null; const transform = jest.fn().mockImplementation((url) => { @@ -17,25 +17,24 @@ test('loadGlyphRange', done => { const server = fakeServer.create(); server.respondWith(bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/0-255.pbf')))); - loadGlyphRange('Arial Unicode MS', 0, 'https://localhost/fonts/v1/{fontstack}/{range}.pbf', manager, (err, result) => { - expect(err).toBeFalsy(); - expect(transform).toHaveBeenCalledTimes(1); - expect(transform).toHaveBeenCalledWith('https://localhost/fonts/v1/Arial Unicode MS/0-255.pbf', 'Glyphs'); - - expect(Object.keys(result)).toHaveLength(223); - for (const key in result) { - const id = Number(key); - const glyph = result[id]; - - expect(glyph.id).toBe(Number(id)); - expect(glyph.metrics).toBeTruthy(); - expect(typeof glyph.metrics.width).toBe('number'); - expect(typeof glyph.metrics.height).toBe('number'); - expect(typeof glyph.metrics.top).toBe('number'); - expect(typeof glyph.metrics.advance).toBe('number'); - } - done(); - }); + const promise = loadGlyphRange('Arial Unicode MS', 0, 'https://localhost/fonts/v1/{fontstack}/{range}.pbf', manager); server.respond(); + const result = await promise; + + expect(transform).toHaveBeenCalledTimes(1); + expect(transform).toHaveBeenCalledWith('https://localhost/fonts/v1/Arial Unicode MS/0-255.pbf', 'Glyphs'); + + expect(Object.keys(result)).toHaveLength(223); + for (const key in result) { + const id = Number(key); + const glyph = result[id]; + + expect(glyph.id).toBe(Number(id)); + expect(glyph.metrics).toBeTruthy(); + expect(typeof glyph.metrics.width).toBe('number'); + expect(typeof glyph.metrics.height).toBe('number'); + expect(typeof glyph.metrics.top).toBe('number'); + expect(typeof glyph.metrics.advance).toBe('number'); + } expect(server.requests[0].url).toBe('https://localhost/fonts/v1/Arial Unicode MS/0-255.pbf'); }); diff --git a/src/style/load_glyph_range.ts b/src/style/load_glyph_range.ts index 6a454caa90..ba63c10a4b 100644 --- a/src/style/load_glyph_range.ts +++ b/src/style/load_glyph_range.ts @@ -5,15 +5,11 @@ import {parseGlyphPbf} from './parse_glyph_pbf'; import type {StyleGlyph} from './style_glyph'; import type {RequestManager} from '../util/request_manager'; -import type {Callback} from '../types/callback'; -export function loadGlyphRange(fontstack: string, +export async function loadGlyphRange(fontstack: string, range: number, urlTemplate: string, - requestManager: RequestManager, - callback: Callback<{ - [_: number]: StyleGlyph | null; - }>) { + requestManager: RequestManager): Promise<{[_: number]: StyleGlyph | null}> { const begin = range * 256; const end = begin + 255; @@ -22,17 +18,15 @@ export function loadGlyphRange(fontstack: string, ResourceType.Glyphs ); - getArrayBuffer(request, (err?: Error | null, data?: ArrayBuffer | null) => { - if (err) { - callback(err); - } else if (data) { - const glyphs = {}; + const response = await getArrayBuffer(request, new AbortController()); + if (!response || !response.data) { + throw new Error(`Could not load glyph range. range: ${range}, ${begin}-${end}`); + } + const glyphs = {}; - for (const glyph of parseGlyphPbf(data)) { - glyphs[glyph.id] = glyph; - } + for (const glyph of parseGlyphPbf(response.data)) { + glyphs[glyph.id] = glyph; + } - callback(null, glyphs); - } - }); + return glyphs; } diff --git a/src/style/load_sprite.test.ts b/src/style/load_sprite.test.ts index 6aaa068f0e..e55d849347 100644 --- a/src/style/load_sprite.test.ts +++ b/src/style/load_sprite.test.ts @@ -3,26 +3,28 @@ import path from 'path'; import {RequestManager} from '../util/request_manager'; import {loadSprite} from './load_sprite'; import {type FakeServer, fakeServer} from 'nise'; -import * as util from '../util/util'; import {bufferToArrayBuffer} from '../util/test/util'; +import {ABORT_ERROR} from '../util/abort_error'; +import * as util from '../util/util'; describe('loadSprite', () => { let server: FakeServer; beforeEach(() => { - jest.spyOn(util, 'arrayBufferToImageBitmap').mockImplementation((data: ArrayBuffer, callback: (err?: Error | null, image?: ImageBitmap | null) => void) => { - createImageBitmap(new ImageData(1024, 824)).then((imgBitmap) => { - callback(null, imgBitmap); - }).catch((e) => { - callback(new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`)); - }); + jest.spyOn(util, 'arrayBufferToImageBitmap').mockImplementation(async (_data: ArrayBuffer) => { + try { + const img = await createImageBitmap(new ImageData(1024, 824)); + return img; + } catch (e) { + throw new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`); + } }); global.fetch = null; server = fakeServer.create(); }); - test('backwards compatibility: single string is treated as a URL for the default sprite', done => { + test('backwards compatibility: single string is treated as a URL for the default sprite', async () => { const transform = jest.fn().mockImplementation((url, type) => { return {url, type}; }); @@ -32,31 +34,29 @@ describe('loadSprite', () => { server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); - loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 1, (err, result) => { - expect(err).toBeFalsy(); + const promise = loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 1, new AbortController()); - expect(transform).toHaveBeenCalledTimes(2); - expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1.json', 'SpriteJSON'); - expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1.png', 'SpriteImage'); + server.respond(); - expect(Object.keys(result)).toHaveLength(1); - expect(Object.keys(result)[0]).toBe('default'); + const result = await promise; - Object.values(result['default']).forEach(styleImage => { - expect(styleImage.spriteData).toBeTruthy(); - expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); - }); + expect(transform).toHaveBeenCalledTimes(2); + expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1.json', 'SpriteJSON'); + expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1.png', 'SpriteImage'); - done(); - }); + expect(Object.keys(result)).toHaveLength(1); + expect(Object.keys(result)[0]).toBe('default'); - server.respond(); + Object.values(result['default']).forEach(styleImage => { + expect(styleImage.spriteData).toBeTruthy(); + expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); + }); expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); }); - test('array of objects support', done => { + test('array of objects support', async () => { const transform = jest.fn().mockImplementation((url, type) => { return {url, type}; }); @@ -68,40 +68,38 @@ describe('loadSprite', () => { server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png')))); - loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}, {id: 'sprite2', url: 'http://localhost:9966/test/unit/assets/sprite2'}], manager, 1, (err, result) => { - expect(err).toBeFalsy(); + const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}, {id: 'sprite2', url: 'http://localhost:9966/test/unit/assets/sprite2'}], manager, 1, new AbortController()); - expect(transform).toHaveBeenCalledTimes(4); - expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1.json', 'SpriteJSON'); - expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1.png', 'SpriteImage'); - expect(transform).toHaveBeenNthCalledWith(3, 'http://localhost:9966/test/unit/assets/sprite2.json', 'SpriteJSON'); - expect(transform).toHaveBeenNthCalledWith(4, 'http://localhost:9966/test/unit/assets/sprite2.png', 'SpriteImage'); + server.respond(); - expect(Object.keys(result)).toHaveLength(2); - expect(Object.keys(result)[0]).toBe('sprite1'); - expect(Object.keys(result)[1]).toBe('sprite2'); + const result = await promise; + expect(transform).toHaveBeenCalledTimes(4); + expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1.json', 'SpriteJSON'); + expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1.png', 'SpriteImage'); + expect(transform).toHaveBeenNthCalledWith(3, 'http://localhost:9966/test/unit/assets/sprite2.json', 'SpriteJSON'); + expect(transform).toHaveBeenNthCalledWith(4, 'http://localhost:9966/test/unit/assets/sprite2.png', 'SpriteImage'); - Object.values(result['sprite1']).forEach(styleImage => { - expect(styleImage.spriteData).toBeTruthy(); - expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); - }); + expect(Object.keys(result)).toHaveLength(2); + expect(Object.keys(result)[0]).toBe('sprite1'); + expect(Object.keys(result)[1]).toBe('sprite2'); - Object.values(result['sprite2']).forEach(styleImage => { - expect(styleImage.spriteData).toBeTruthy(); - expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); - }); + Object.values(result['sprite1']).forEach(styleImage => { + expect(styleImage.spriteData).toBeTruthy(); + expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); + }); - done(); + Object.values(result['sprite2']).forEach(styleImage => { + expect(styleImage.spriteData).toBeTruthy(); + expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); }); - server.respond(); expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); expect(server.requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json'); expect(server.requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png'); }); - test('error in callback', done => { + test('server returns error', async () => { const transform = jest.fn().mockImplementation((url, type) => { return {url, type}; }); @@ -109,21 +107,14 @@ describe('loadSprite', () => { const manager = new RequestManager(transform); server.respondWith((xhr) => xhr.respond(500)); - let last = false; - loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, (err, result) => { - expect(err).toBeTruthy(); - expect(result).toBeUndefined(); - if (!last) { - done(); - last = true; - } - }); - + const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, new AbortController()); server.respond(); + + await expect(promise).rejects.toThrow(/AJAXError.*500.*/); expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); }); - test('request canceling', done => { + test('request canceling', async () => { const transform = jest.fn().mockImplementation((url, type) => { return {url, type}; }); @@ -133,25 +124,20 @@ describe('loadSprite', () => { server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); - const cancelable = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, () => {}); - - setTimeout(() => { - cancelable.cancel(); + const abortController = new AbortController(); + const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, abortController); + abortController.abort(); - expect((server.requests[0] as any).aborted).toBeTruthy(); - expect((server.requests[1] as any).aborted).toBeTruthy(); + expect((server.requests[0] as any).aborted).toBeTruthy(); + expect((server.requests[1] as any).aborted).toBeTruthy(); - done(); - }); - - setTimeout(() => { - server.respond(); - expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); - expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); - }, 10); + await expect(promise).rejects.toThrow(ABORT_ERROR); + server.respond(); + expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); + expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); }); - test('pixelRatio is respected', done => { + test('pixelRatio is respected', async () => { const transform = jest.fn().mockImplementation((url, type) => { return {url, type}; }); @@ -161,25 +147,22 @@ describe('loadSprite', () => { server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); - loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 2, (err, result) => { - expect(err).toBeFalsy(); - - expect(transform).toHaveBeenCalledTimes(2); - expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1@2x.json', 'SpriteJSON'); - expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1@2x.png', 'SpriteImage'); + const promise = loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 2, new AbortController()); + server.respond(); - expect(Object.keys(result)).toHaveLength(1); - expect(Object.keys(result)[0]).toBe('default'); + const result = await promise; + expect(transform).toHaveBeenCalledTimes(2); + expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1@2x.json', 'SpriteJSON'); + expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1@2x.png', 'SpriteImage'); - Object.values(result['default']).forEach(styleImage => { - expect(styleImage.spriteData).toBeTruthy(); - expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); - }); + expect(Object.keys(result)).toHaveLength(1); + expect(Object.keys(result)[0]).toBe('default'); - done(); + Object.values(result['default']).forEach(styleImage => { + expect(styleImage.spriteData).toBeTruthy(); + expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); }); - server.respond(); expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.png'); }); diff --git a/src/style/load_sprite.ts b/src/style/load_sprite.ts index 2a36afe710..ebe5a021b7 100644 --- a/src/style/load_sprite.ts +++ b/src/style/load_sprite.ts @@ -1,4 +1,4 @@ -import {getJSON} from '../util/ajax'; +import {GetResourceResponse, getJSON} from '../util/ajax'; import {ImageRequest} from '../util/image_request'; import {ResourceType} from '../util/request_manager'; @@ -6,82 +6,53 @@ import {browser} from '../util/browser'; import {coerceSpriteToArray} from '../util/style'; import type {SpriteSpecification} from '@maplibre/maplibre-gl-style-spec'; -import type {StyleImage} from './style_image'; +import type {SpriteJSON, StyleImage} from './style_image'; import type {RequestManager} from '../util/request_manager'; -import type {Callback} from '../types/callback'; -import type {Cancelable} from '../types/cancelable'; -export function loadSprite( +export type LoadSpriteResult = { + [spriteName: string]: { + [id: string]: StyleImage; + }; +} + +export async function loadSprite( originalSprite: SpriteSpecification, requestManager: RequestManager, pixelRatio: number, - callback: Callback<{[spriteName: string]: {[id: string]: StyleImage}}> -): Cancelable { + abortController: AbortController, +): Promise { const spriteArray = coerceSpriteToArray(originalSprite); - const spriteArrayLength = spriteArray.length; const format = pixelRatio > 1 ? '@2x' : ''; - const combinedRequestsMap: {[requestKey: string]: Cancelable} = {}; - const jsonsMap: {[id: string]: any} = {}; - const imagesMap: {[id: string]: (HTMLImageElement | ImageBitmap)} = {}; + const jsonsMap: {[id: string]: Promise>} = {}; + const imagesMap: {[id: string]: Promise>} = {}; for (const {id, url} of spriteArray) { const jsonRequestParameters = requestManager.transformRequest(requestManager.normalizeSpriteURL(url, format, '.json'), ResourceType.SpriteJSON); - const jsonRequestKey = `${id}_${jsonRequestParameters.url}`; // use id_url as requestMap key to make sure it is unique - combinedRequestsMap[jsonRequestKey] = getJSON(jsonRequestParameters, (err?: Error | null, data?: any | null) => { - delete combinedRequestsMap[jsonRequestKey]; - jsonsMap[id] = data; - doOnceCompleted(callback, jsonsMap, imagesMap, err, spriteArrayLength); - }); + jsonsMap[id] = getJSON(jsonRequestParameters, abortController); const imageRequestParameters = requestManager.transformRequest(requestManager.normalizeSpriteURL(url, format, '.png'), ResourceType.SpriteImage); - const imageRequestKey = `${id}_${imageRequestParameters.url}`; // use id_url as requestMap key to make sure it is unique - combinedRequestsMap[imageRequestKey] = ImageRequest.getImage(imageRequestParameters, (err, img) => { - delete combinedRequestsMap[imageRequestKey]; - imagesMap[id] = img; - doOnceCompleted(callback, jsonsMap, imagesMap, err, spriteArrayLength); - }); + imagesMap[id] = ImageRequest.getImage(imageRequestParameters, abortController); } - return { - cancel() { - for (const requst of Object.values(combinedRequestsMap)) { - requst.cancel(); - } - } - }; + await Promise.all([...Object.values(jsonsMap), ...Object.values(imagesMap)]); + return doOnceCompleted(jsonsMap, imagesMap); } /** - * @param callbackFunc - the callback function (both erro and success) * @param jsonsMap - JSON data map * @param imagesMap - image data map - * @param err - error object - * @param expectedResultCounter - number of expected JSON or Image results when everything is finished, respectively. */ -function doOnceCompleted( - callbackFunc:Callback<{[spriteName: string]: {[id: string]: StyleImage}}>, - jsonsMap:{[id: string]: any}, - imagesMap:{[id: string]: (HTMLImageElement | ImageBitmap)}, - err: Error, - expectedResultCounter: number): void { - - if (err) { - callbackFunc(err); - return; - } - - if (expectedResultCounter !== Object.values(jsonsMap).length || expectedResultCounter !== Object.values(imagesMap).length) { - // not done yet, nothing to do - return; - } +async function doOnceCompleted( + jsonsMap:{[id: string]: Promise>}, + imagesMap:{[id: string]: Promise>}): Promise { const result = {} as {[spriteName: string]: {[id: string]: StyleImage}}; for (const spriteName in jsonsMap) { result[spriteName] = {}; - const context = browser.getImageCanvasContext(imagesMap[spriteName]); - const json = jsonsMap[spriteName]; + const context = browser.getImageCanvasContext((await imagesMap[spriteName]).data); + const json = (await jsonsMap[spriteName]).data; for (const id in json) { const {width, height, x, y, sdf, pixelRatio, stretchX, stretchY, content} = json[id]; @@ -90,5 +61,5 @@ function doOnceCompleted( } } - callbackFunc(null, result); + return result; } diff --git a/src/style/style.test.ts b/src/style/style.test.ts index bdc325c83d..946f85ebdc 100644 --- a/src/style/style.test.ts +++ b/src/style/style.test.ts @@ -80,12 +80,13 @@ function createStyle(map = getStubMap()) { } let server: FakeServer; -let mockConsoleError; +let mockConsoleError: jest.SpyInstance; beforeEach(() => { global.fetch = null; server = fakeServer.create(); mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => { }); + clearRTLTextPlugin(); }); afterEach(() => { @@ -95,12 +96,8 @@ afterEach(() => { describe('Style', () => { test('registers plugin state change listener', () => { - clearRTLTextPlugin(); - - jest.spyOn(Style, 'registerForPluginStateChange'); const style = new Style(getStubMap()); const mockStyleDispatcherBroadcast = jest.spyOn(style.dispatcher, 'broadcast'); - expect(Style.registerForPluginStateChange).toHaveBeenCalledTimes(1); setRTLTextPlugin('/plugin.js', undefined); expect(mockStyleDispatcherBroadcast.mock.calls[0][0]).toBe('syncRTLPluginState'); @@ -111,7 +108,6 @@ describe('Style', () => { }); test('loads plugin immediately if already registered', done => { - clearRTLTextPlugin(); server.respondWith('/plugin.js', 'doesn\'t matter'); setRTLTextPlugin('/plugin.js', (error) => { expect(error).toMatch(/Cannot set the state of the rtl-text-plugin when not in the web-worker context/); @@ -151,13 +147,12 @@ describe('Style', () => { clearRTLTextPlugin(); server.respondWith('/plugin.js', 'doesn\'t matter'); const _broadcast = style.dispatcher.broadcast; - style.dispatcher.broadcast = function (type, state, callback) { + style.dispatcher.broadcast = function (type, state) { if (type === 'syncRTLPluginState') { // Mock a response from four workers saying they've loaded the plugin - callback(undefined, [true, true, true, true]); - } else { - _broadcast(type, state, callback); + return Promise.resolve([true, true, true, true]) as any; } + return _broadcast(type, state); }; setRTLTextPlugin('/plugin.js', (error) => { expect(error).toBeUndefined(); @@ -291,7 +286,7 @@ describe('Style#loadJSON', () => { }); }); - test('Validate sprite image extraction', done => { + test('Validate sprite image extraction', async () => { // Stubbing to bypass Web APIs that supported by jsdom: // * `URL.createObjectURL` in ajax.getImage (https://github.com/tmpvar/jsdom/issues/1721) // * `canvas.getContext('2d')` in browser.getImageData @@ -311,25 +306,23 @@ describe('Style#loadJSON', () => { 'sprite': 'http://example.com/sprite' }); - style.once('data', (e) => { - expect(e.target).toBe(style); - expect(e.dataType).toBe('style'); + const firstDataEvent = await style.once('data'); + expect(firstDataEvent.target).toBe(style); + expect(firstDataEvent.dataType).toBe('style'); - style.once('data', (e) => { - expect(e.target).toBe(style); - expect(e.dataType).toBe('style'); - style.imageManager.getImages(['image1'], (error, response) => { - const image = response['image1']; - expect(image.data).toBeInstanceOf(RGBAImage); - expect(image.data.width).toBe(1); - expect(image.data.height).toBe(1); - expect(image.pixelRatio).toBe(1); - done(); - }); - }); + const secondDataPromise = style.once('data'); - server.respond(); - }); + server.respond(); + + const secondDateEvent = await secondDataPromise; + expect(secondDateEvent.target).toBe(style); + expect(secondDateEvent.dataType).toBe('style'); + const response = await style.imageManager.getImages(['image1']); + const image = response['image1']; + expect(image.data).toBeInstanceOf(RGBAImage); + expect(image.data.width).toBe(1); + expect(image.data.height).toBe(1); + expect(image.pixelRatio).toBe(1); }); test('validates the style', done => { @@ -563,9 +556,10 @@ describe('Style#_load', () => { }); const _broadcastSpyOn = jest.spyOn(style.dispatcher, 'broadcast') - .mockImplementation((type: string, data) => { + .mockImplementation((type, data) => { dispatchType = type; dispatchData = data; + return Promise.resolve({} as any); }); style._load(styleSpec, {}); @@ -577,7 +571,7 @@ describe('Style#_load', () => { expect(dispatchData[0].id).toBe('background'); // cleanup - _broadcastSpyOn.mockReset(); + _broadcastSpyOn.mockRestore(); }); test('validate style when validate option is true', () => { @@ -643,18 +637,16 @@ describe('Style#_remove', () => { }); }); - test('deregisters plugin listener', done => { + test('deregisters plugin listener', async () => { const style = new Style(getStubMap()); style.loadJSON(createStyleJSON()); const mockStyleDispatcherBroadcast = jest.spyOn(style.dispatcher, 'broadcast'); - style.on('style.load', () => { - style._remove(); + await style.once('style.load'); + style._remove(); - rtlTextPluginEvented.fire(new Event('pluginStateChange')); - expect(mockStyleDispatcherBroadcast).not.toHaveBeenCalledWith('syncRTLPluginState'); - done(); - }); + rtlTextPluginEvented.fire(new Event('pluginStateChange')); + expect(mockStyleDispatcherBroadcast).not.toHaveBeenCalledWith('syncRTLPluginState'); }); }); @@ -688,6 +680,7 @@ describe('Style#update', () => { expect(value['layers'].map((layer) => { return layer.id; })).toEqual(['first', 'third']); expect(value['removedIds']).toEqual(['second']); done(); + return Promise.resolve({} as any); }; style.update({} as EvaluationParameters); @@ -1972,6 +1965,7 @@ describe('Style#setFilter', () => { expect(value['layers'][0].id).toBe('symbol'); expect(value['layers'][0].filter).toEqual(['==', 'id', 1]); done(); + return Promise.resolve({} as any); }; style.setFilter('symbol', ['==', 'id', 1]); @@ -2010,6 +2004,7 @@ describe('Style#setFilter', () => { expect(value['layers'][0].id).toBe('symbol'); expect(value['layers'][0].filter).toEqual(['==', 'id', 2]); done(); + return Promise.resolve({} as any); }; filter[2] = 2; style.setFilter('symbol', filter); @@ -2069,6 +2064,7 @@ describe('Style#setFilter', () => { expect(value['layers'][0].id).toBe('symbol'); expect(value['layers'][0].filter).toBe('notafilter'); done(); + return Promise.resolve({} as any); }; style.setFilter('symbol', 'notafilter' as any as FilterSpecification, {validate: false}); @@ -2108,6 +2104,7 @@ describe('Style#setLayerZoomRange', () => { expect(key).toBe('updateLayers'); expect(value['layers'].map((layer) => { return layer.id; })).toEqual(['symbol']); done(); + return Promise.resolve({} as any); }; style.setLayerZoomRange('symbol', 5, 12); expect(style.getLayer('symbol').minzoom).toBe(5); @@ -2516,6 +2513,7 @@ describe('Style#addSourceType', () => { if (type === 'loadWorkerSource') { done('test failed'); } + return Promise.resolve({} as any); }; style.addSourceType('foo', sourceType, (arg1, arg2) => { @@ -2532,9 +2530,9 @@ describe('Style#addSourceType', () => { style.dispatcher.broadcast = (type, params) => { if (type === 'loadWorkerSource') { - expect(params['name']).toBe('bar'); - expect(params['url']).toBe('worker-source.js'); + expect(params).toBe('worker-source.js'); done(); + return Promise.resolve({} as any); } }; diff --git a/src/style/style.ts b/src/style/style.ts index a43d0ad4c2..c8b98c42df 100644 --- a/src/style/style.ts +++ b/src/style/style.ts @@ -43,12 +43,10 @@ const emitValidationErrors = (evented: Evented, errors?: ReadonlyArray<{ import type {Map} from '../ui/map'; import type {Transform} from '../geo/transform'; import type {StyleImage} from './style_image'; -import type {StyleGlyph} from './style_glyph'; import type {Callback} from '../types/callback'; import type {EvaluationParameters} from './evaluation_parameters'; import type {Placement} from '../symbol/placement'; -import type {Cancelable} from '../types/cancelable'; -import type {RequestParameters, ResponseCallback} from '../util/ajax'; +import type {GetResourceResponse, RequestParameters} from '../util/ajax'; import type { LayerSpecification, FilterSpecification, @@ -59,7 +57,7 @@ import type { } from '@maplibre/maplibre-gl-style-spec'; import type {CustomLayerInterface} from './style_layer/custom_style_layer'; import type {Validator} from './validate_style'; -import type {OverscaledTileID} from '../source/tile_id'; +import type {GetGlyphsParamerters, GetGlyphsResponse, GetImagesParamerters, GetImagesResponse} from '../util/actor_messages'; const supportedDiffOperations = pick(diffOperations, [ 'addLayer', @@ -209,8 +207,9 @@ export class Style extends Evented { lineAtlas: LineAtlas; light: Light; - _request: Cancelable; - _spriteRequest: Cancelable; + _frameRequest: AbortController; + _loadStyleRequest: AbortController; + _spriteRequest: AbortController; _layers: {[_: string]: StyleLayer}; _serializedLayers: {[_: string]: LayerSpecification}; _order: Array; @@ -236,13 +235,20 @@ export class Style extends Evented { placement: Placement; z: number; - static registerForPluginStateChange: typeof registerForPluginStateChange; - constructor(map: Map, options: StyleOptions = {}) { super(); this.map = map; - this.dispatcher = new Dispatcher(getGlobalWorkerPool(), this, map._getMapId()); + this.dispatcher = new Dispatcher(getGlobalWorkerPool(), map._getMapId()); + this.dispatcher.registerMessageHandler('getGlyphs', (mapId, params) => { + return this.getGlyphs(mapId, params); + }); + this.dispatcher.registerMessageHandler('getImages', (mapId, params) => { + return this.getImages(mapId, params); + }); + this.dispatcher.registerMessageHandler('getResource', (mapId, params, abortController) => { + return this.getResource(mapId, params, abortController); + }); this.imageManager = new ImageManager(); this.imageManager.setEventedParent(this); this.glyphManager = new GlyphManager(map._requestManager, options.localIdeographFontFamily); @@ -263,29 +269,31 @@ export class Style extends Evented { this.dispatcher.broadcast('setReferrer', getReferrer()); const self = this; - this._rtlTextPluginCallback = Style.registerForPluginStateChange((event) => { + this._rtlTextPluginCallback = registerForPluginStateChange((event) => { const state = { pluginStatus: event.pluginStatus, pluginURL: event.pluginURL }; - self.dispatcher.broadcast('syncRTLPluginState', state, (err, results) => { - triggerPluginCompletionEvent(err); - if (results) { + self.dispatcher.broadcast('syncRTLPluginState', state) + .then((results) => { + triggerPluginCompletionEvent(undefined); + if (!results) { + return; + } const allComplete = results.every((elem) => elem); - if (allComplete) { - for (const id in self.sourceCaches) { - const sourceType = self.sourceCaches[id].getSource().type; - if (sourceType === 'vector' || sourceType === 'geojson') { - // Non-vector sources don't have any symbols buckets to reload when the RTL text plugin loads - // They also load more quickly, so they're more likely to have already displaying tiles - // that would be unnecessarily booted by the plugin load event - self.sourceCaches[id].reload(); // Should be a no-op if the plugin loads before any tiles load - } + if (!allComplete) { + return; + } + for (const id in self.sourceCaches) { + const sourceType = self.sourceCaches[id].getSource().type; + if (sourceType === 'vector' || sourceType === 'geojson') { + // Non-vector sources don't have any symbols buckets to reload when the RTL text plugin loads + // They also load more quickly, so they're more likely to have already displaying tiles + // that would be unnecessarily booted by the plugin load event + self.sourceCaches[id].reload(); // Should be a no-op if the plugin loads before any tiles load } } - } - - }); + }).catch((err: string) => triggerPluginCompletionEvent(err)); }); this.on('data', (event) => { @@ -319,12 +327,14 @@ export class Style extends Evented { options.validate : true; const request = this.map._requestManager.transformRequest(url, ResourceType.Style); - this._request = getJSON(request, (error?: Error | null, json?: any | null) => { - this._request = null; + this._loadStyleRequest = new AbortController(); + getJSON(request, this._loadStyleRequest).then((response) => { + this._loadStyleRequest = null; + this._load(response.data, options, previousStyle); + }).catch((error) => { + this._loadStyleRequest = null; if (error) { this.fire(new ErrorEvent(error)); - } else if (json) { - this._load(json, options, previousStyle); } }); } @@ -332,11 +342,12 @@ export class Style extends Evented { loadJSON(json: StyleSpecification, options: StyleSetterOptions & StyleSwapOptions = {}, previousStyle?: StyleSpecification) { this.fire(new Event('dataloading', {dataType: 'style'})); - this._request = browser.frame(() => { - this._request = null; + this._frameRequest = new AbortController(); + browser.frameAsync(this._frameRequest).then(() => { + this._frameRequest = null; options.validate = options.validate !== false; this._load(json, options, previousStyle); - }); + }).catch(() => {}); // ignore abort } loadEmpty() { @@ -396,11 +407,11 @@ export class Style extends Evented { _loadSprite(sprite: SpriteSpecification, isUpdate: boolean = false, completion: (err: Error) => void = undefined) { this.imageManager.setLoaded(false); - this._spriteRequest = loadSprite(sprite, this.map._requestManager, this.map.getPixelRatio(), (err, images) => { + this._spriteRequest = new AbortController(); + let err: Error; + loadSprite(sprite, this.map._requestManager, this.map.getPixelRatio(), this._spriteRequest).then((images) => { this._spriteRequest = null; - if (err) { - this.fire(new ErrorEvent(err)); - } else if (images) { + if (images) { for (const spriteId in images) { this._spritesImagesIds[spriteId] = []; @@ -428,7 +439,11 @@ export class Style extends Evented { } } } - + }).catch((error) => { + this._spriteRequest = null; + err = error; + this.fire(new ErrorEvent(err)); + }).finally(() => { this.imageManager.setLoaded(true); this._availableImages = this.imageManager.listImages(); @@ -1411,10 +1426,7 @@ export class Style extends Evented { return callback(null, null); } - this.dispatcher.broadcast('loadWorkerSource', { - name, - url: SourceType.workerSourceURL - }, callback); + this.dispatcher.broadcast('loadWorkerSource', SourceType.workerSourceURL.toString()).then(() => callback()).catch(callback); } getLight() { @@ -1461,12 +1473,16 @@ export class Style extends Evented { } _remove(mapRemoved: boolean = true) { - if (this._request) { - this._request.cancel(); - this._request = null; + if (this._frameRequest) { + this._frameRequest.abort(); + this._frameRequest = null; + } + if (this._loadStyleRequest) { + this._loadStyleRequest.abort(); + this._loadStyleRequest = null; } if (this._spriteRequest) { - this._spriteRequest.cancel(); + this._spriteRequest.abort(); this._spriteRequest = null; } rtlTextPluginEvented.off('pluginStateChange', this._rtlTextPluginCallback); @@ -1583,17 +1599,8 @@ export class Style extends Evented { // Callbacks from web workers - getImages( - mapId: string, - params: { - icons: Array; - source: string; - tileID: OverscaledTileID; - type: string; - }, - callback: Callback<{[_: string]: StyleImage}> - ) { - this.imageManager.getImages(params.icons, callback); + async getImages(mapId: string | number, params: GetImagesParamerters): Promise { + const images = await this.imageManager.getImages(params.icons); // Apply queued image changes before setting the tile's dependencies so that the tile // is not reloaded unnecessarily. Without this forced update the reload could happen in cases @@ -1609,29 +1616,22 @@ export class Style extends Evented { if (sourceCache) { sourceCache.setDependencies(params.tileID.key, params.type, params.icons); } + return images; } - getGlyphs( - mapId: string, - params: { - stacks: {[_: string]: Array}; - source: string; - tileID: OverscaledTileID; - type: string; - }, - callback: Callback<{[_: string]: {[_: number]: StyleGlyph}}> - ) { - this.glyphManager.getGlyphs(params.stacks, callback); + async getGlyphs(mapId: string | number, params: GetGlyphsParamerters): Promise { + const glypgs = await this.glyphManager.getGlyphs(params.stacks); const sourceCache = this.sourceCaches[params.source]; if (sourceCache) { // we are not setting stacks as dependencies since for now // we just need to know which tiles have glyph dependencies sourceCache.setDependencies(params.tileID.key, params.type, ['']); } + return glypgs; } - getResource(mapId: string, params: RequestParameters, callback: ResponseCallback): Cancelable { - return makeRequest(params, callback); + getResource(mapId: string | number, params: RequestParameters, abortController: AbortController): Promise> { + return makeRequest(params, abortController); } getGlyphsUrl() { @@ -1741,5 +1741,3 @@ export class Style extends Evented { } } } - -Style.registerForPluginStateChange = registerForPluginStateChange; diff --git a/src/style/style_glyph.ts b/src/style/style_glyph.ts index 35efaad542..29dd48ac0a 100644 --- a/src/style/style_glyph.ts +++ b/src/style/style_glyph.ts @@ -1,5 +1,8 @@ import type {AlphaImage} from '../util/image'; +/** + * Some metices related to a glyph + */ export type GlyphMetrics = { width: number; height: number; @@ -13,7 +16,6 @@ export type GlyphMetrics = { }; /** - * @internal * A style glyph type */ export type StyleGlyph = { diff --git a/src/style/style_image.ts b/src/style/style_image.ts index bcfadccab7..e3b2106150 100644 --- a/src/style/style_image.ts +++ b/src/style/style_image.ts @@ -2,6 +2,13 @@ import {RGBAImage} from '../util/image'; import type {Map} from '../ui/map'; +export type SpriteJSON = {[id: string]: StyleImageMetadata & { + width: number; + height: number; + x: number; + y: number; +};} + /** * The sprite data */ diff --git a/src/types/tilejson.ts b/src/types/tilejson.ts index a2542eb397..b5ba81fba6 100644 --- a/src/types/tilejson.ts +++ b/src/types/tilejson.ts @@ -12,4 +12,6 @@ export type TileJSON = { maxzoom?: number; bounds?: [number, number, number, number]; center?: [number, number, number]; + vectorLayers: any; + vectorLayerIds: Array; }; diff --git a/src/ui/control/geolocate_control.test.ts b/src/ui/control/geolocate_control.test.ts index 00b3186fa9..49d518bb7c 100644 --- a/src/ui/control/geolocate_control.test.ts +++ b/src/ui/control/geolocate_control.test.ts @@ -1,6 +1,6 @@ import geolocation from 'mock-geolocation'; import {LngLatBounds} from '../../geo/lng_lat_bounds'; -import {createMap, beforeMapTest} from '../../util/test/util'; +import {createMap, beforeMapTest, sleep} from '../../util/test/util'; import {GeolocateControl} from './geolocate_control'; jest.mock('../../util/geolocation_support', () => ( { @@ -30,7 +30,7 @@ describe('GeolocateControl with no options', () => { beforeEach(() => { beforeMapTest(); map = createMap(undefined, undefined); - (checkGeolocationSupport as any as jest.SpyInstance).mockImplementationOnce((cb) => cb(true)); + (checkGeolocationSupport as any as jest.SpyInstance).mockImplementationOnce(() => Promise.resolve(true)); }); afterEach(() => { @@ -38,15 +38,19 @@ describe('GeolocateControl with no options', () => { }); test('is disabled when there\'s no support', async () => { - (checkGeolocationSupport as any as jest.SpyInstance).mockReset().mockImplementationOnce((cb) => cb(false)); + (checkGeolocationSupport as any as jest.SpyInstance).mockReset().mockImplementationOnce(() => Promise.resolve(false)); const geolocate = new GeolocateControl(undefined); + const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}); map.addControl(geolocate); + await sleep(0); expect(geolocate._geolocateButton.disabled).toBeTruthy(); + spy.mockRestore(); }); test('is enabled when there no support', async () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); + await sleep(0); expect(geolocate._geolocateButton.disabled).toBeFalsy(); }); @@ -59,33 +63,33 @@ describe('GeolocateControl with no options', () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); - await new Promise(process.nextTick); + await sleep(0); expect(geolocate._geolocateButton.disabled).toBeFalsy(); }); - test('error event', done => { + test('error event', async () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); - - geolocate.on('error', (error) => { - expect(error.code).toBe(2); - expect(error.message).toBe('error message'); - done(); - }); + const errorPromise = geolocate.once('error'); geolocate._geolocateButton.dispatchEvent(click); + geolocation.sendError({code: 2, message: 'error message'}); + const error = await errorPromise; + + expect(error.code).toBe(2); + expect(error.message).toBe('error message'); }); - test('does not throw if removed quickly', done => { + test('does not throw if removed quickly', () => { (checkGeolocationSupport as any as jest.SpyInstance).mockReset() - .mockImplementationOnce((cb) => { - return Promise.resolve(true) - .then(result => { - expect(() => cb(result)).not.toThrow(); - }) - .finally(done); + .mockImplementationOnce(() => { + return new Promise(resolve => { + setTimeout(() => { + resolve(true); + }, 10); + }); }); const geolocate = new GeolocateControl(undefined); @@ -93,73 +97,75 @@ describe('GeolocateControl with no options', () => { map.removeControl(geolocate); }); - test('outofmaxbounds event in active lock state', done => { + test('outofmaxbounds event in active lock state', async () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); + await sleep(0); map.setMaxBounds([[0, 0], [10, 10]]); geolocate._watchState = 'ACTIVE_LOCK'; const click = new window.Event('click'); - geolocate.on('outofmaxbounds', (position) => { - expect(geolocate._watchState).toBe('ACTIVE_ERROR'); - expect(position.coords.latitude).toBe(10); - expect(position.coords.longitude).toBe(20); - expect(position.coords.accuracy).toBe(3); - expect(position.timestamp).toBe(4); - done(); - }); + const outofmaxboundsPromise = geolocate.once('outofmaxbounds'); geolocate._geolocateButton.dispatchEvent(click); geolocation.send({latitude: 10, longitude: 20, accuracy: 3, timestamp: 4}); + const position = await outofmaxboundsPromise; + + expect(geolocate._watchState).toBe('ACTIVE_ERROR'); + expect(position.coords.latitude).toBe(10); + expect(position.coords.longitude).toBe(20); + expect(position.coords.accuracy).toBe(3); + expect(position.timestamp).toBe(4); }); - test('outofmaxbounds event in background state', done => { + test('outofmaxbounds event in background state', async () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); + await sleep(0); map.setMaxBounds([[0, 0], [10, 10]]); geolocate._watchState = 'BACKGROUND'; const click = new window.Event('click'); - geolocate.on('outofmaxbounds', (position) => { - expect(geolocate._watchState).toBe('BACKGROUND_ERROR'); - expect(position.coords.latitude).toBe(10); - expect(position.coords.longitude).toBe(20); - expect(position.coords.accuracy).toBe(3); - expect(position.timestamp).toBe(4); - done(); - }); + const promise = geolocate.once('outofmaxbounds'); geolocate._geolocateButton.dispatchEvent(click); geolocation.send({latitude: 10, longitude: 20, accuracy: 3, timestamp: 4}); + const position = await promise; + expect(geolocate._watchState).toBe('BACKGROUND_ERROR'); + expect(position.coords.latitude).toBe(10); + expect(position.coords.longitude).toBe(20); + expect(position.coords.accuracy).toBe(3); + expect(position.timestamp).toBe(4); }); - test('geolocate event', done => { + test('geolocate event', async () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); - geolocate.on('geolocate', (position) => { - expect(position.coords.latitude).toBe(10); - expect(position.coords.longitude).toBe(20); - expect(position.coords.accuracy).toBe(30); - expect(position.timestamp).toBe(40); - done(); - }); + const promise = geolocate.once('geolocate'); geolocate._geolocateButton.dispatchEvent(click); geolocation.send({latitude: 10, longitude: 20, accuracy: 30, timestamp: 40}); + + const position = await promise; + expect(position.coords.latitude).toBe(10); + expect(position.coords.longitude).toBe(20); + expect(position.coords.accuracy).toBe(30); + expect(position.timestamp).toBe(40); }); - test('trigger', () => { + test('trigger', async () => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); - + await sleep(0); expect(geolocate.trigger()).toBeTruthy(); }); - test('trigger and then error when tracking user location should get to active error state', () => { + test('trigger and then error when tracking user location should get to active error state', async () => { const geolocate = new GeolocateControl({trackUserLocation: true}); map.addControl(geolocate); + await sleep(0); geolocate.trigger(); geolocation.sendError({code: 2, message: 'error message'}); @@ -184,7 +190,7 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const moveEndPromise = map.once('moveend'); @@ -194,7 +200,7 @@ describe('GeolocateControl with no options', () => { expect(map.getZoom()).toBe(10); }); - test('with removed before Geolocation callback', () => { + test('was removed before Geolocation support was checked', () => { expect(() => { const geolocate = new GeolocateControl(undefined); map.addControl(geolocate); @@ -212,7 +218,7 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const moveEndPromise = map.once('moveend'); @@ -232,7 +238,7 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const moveEndPromise = map.once('moveend'); @@ -264,7 +270,7 @@ describe('GeolocateControl with no options', () => { ).toBeFalsy(); }); - test('watching map updates recenter on location with dot', done => { + test('watching map updates recenter on location with dot', async () => { const geolocate = new GeolocateControl({ trackUserLocation: true, showUserLocation: true, @@ -273,38 +279,32 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); - let moveendCount = 0; - map.once('moveend', () => { - // moveend was being called a second time, this ensures that we don't run the tests a second time - if (moveendCount > 0) return; - moveendCount++; - - expect(lngLatAsFixed(map.getCenter(), 4)).toEqual({lat: '10.0000', lng: '20.0000'}); - expect(geolocate._userLocationDotMarker._map).toBeTruthy(); - expect( - geolocate._userLocationDotMarker._element.classList.contains('maplibregl-user-location-dot-stale') - ).toBeFalsy(); - map.once('moveend', () => { - expect(lngLatAsFixed(map.getCenter(), 4)).toEqual({lat: '40.0000', lng: '50.0000'}); - geolocate.once('error', () => { - expect(geolocate._userLocationDotMarker._map).toBeTruthy(); - expect( - geolocate._userLocationDotMarker._element.classList.contains('maplibregl-user-location-dot-stale') - ).toBeTruthy(); - done(); - }); - geolocation.changeError({code: 2, message: 'position unavaliable'}); - }); - geolocation.change({latitude: 40, longitude: 50, accuracy: 60}); - }); + const firstMoveEnd = map.once('moveend'); geolocate._geolocateButton.dispatchEvent(click); geolocation.send({latitude: 10, longitude: 20, accuracy: 30}); + + await firstMoveEnd; + + expect(lngLatAsFixed(map.getCenter(), 4)).toEqual({lat: '10.0000', lng: '20.0000'}); + expect(geolocate._userLocationDotMarker._map).toBeTruthy(); + expect( + geolocate._userLocationDotMarker._element.classList.contains('maplibregl-user-location-dot-stale') + ).toBeFalsy(); + const secontMoveEnd = map.once('moveend'); + geolocation.change({latitude: 40, longitude: 50, accuracy: 60}); + await secontMoveEnd; + expect(lngLatAsFixed(map.getCenter(), 4)).toEqual({lat: '40.0000', lng: '50.0000'}); + const errorPromise = geolocate.once('error'); + geolocation.changeError({code: 2, message: 'position unavaliable'}); + await errorPromise; + expect(geolocate._userLocationDotMarker._map).toBeTruthy(); + expect(geolocate._userLocationDotMarker._element.classList.contains('maplibregl-user-location-dot-stale')).toBeTruthy(); }); - test('watching map background event', done => { + test('watching map background event', async () => { const geolocate = new GeolocateControl({ trackUserLocation: true, fitBoundsOptions: { @@ -312,32 +312,25 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); - let moveendCount = 0; - map.once('moveend', () => { - // moveend was being called a second time, this ensures that we don't run the tests a second time - if (moveendCount > 0) return; - moveendCount++; - - geolocate.once('trackuserlocationend', () => { - expect(map.getCenter()).toEqual({lng: 10, lat: 5}); - done(); - }); - - // manually pan the map away from the geolocation position which should trigger the 'trackuserlocationend' event above - map.jumpTo({ - center: [10, 5] - }); - }); + const moveEndPromise = map.once('moveend'); // click the button to activate it into the enabled watch state geolocate._geolocateButton.dispatchEvent(click); // send through a location update which should reposition the map and trigger the 'moveend' event above geolocation.send({latitude: 10, longitude: 20, accuracy: 30}); + await moveEndPromise; + const trackPromise = geolocate.once('trackuserlocationend'); + // manually pan the map away from the geolocation position which should trigger the 'trackuserlocationend' event above + map.jumpTo({ + center: [10, 5] + }); + await trackPromise; + expect(map.getCenter()).toEqual({lng: 10, lat: 5}); }); - test('watching map background state', done => { + test('watching map background state', async () => { const geolocate = new GeolocateControl({ trackUserLocation: true, fitBoundsOptions: { @@ -345,33 +338,26 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); - let moveendCount = 0; - map.once('moveend', () => { - // moveend was being called a second time, this ensures that we don't run the tests a second time - if (moveendCount > 0) return; - moveendCount++; - - map.once('moveend', () => { - geolocate.once('geolocate', () => { - expect(map.getCenter()).toEqual({lng: 10, lat: 5}); - done(); - }); - // update the geolocation position, since we are in background state when 'geolocate' is triggered above, the camera shouldn't have changed - geolocation.change({latitude: 0, longitude: 0, accuracy: 10}); - }); - - // manually pan the map away from the geolocation position which should trigger the 'moveend' event above - map.jumpTo({ - center: [10, 5] - }); - }); + const moveEndPromise = map.once('moveend'); // click the button to activate it into the enabled watch state geolocate._geolocateButton.dispatchEvent(click); // send through a location update which should reposition the map and trigger the 'moveend' event above geolocation.send({latitude: 10, longitude: 20, accuracy: 30}); + await moveEndPromise; + const secondMoveEnd = map.once('moveend'); + // manually pan the map away from the geolocation position which should trigger the 'moveend' event above + map.jumpTo({ + center: [10, 5] + }); + await secondMoveEnd; + const geolocatePromise = geolocate.once('geolocate'); + // update the geolocation position, since we are in background state when 'geolocate' is triggered above, the camera shouldn't have changed + geolocation.change({latitude: 0, longitude: 0, accuracy: 10}); + await geolocatePromise; + expect(map.getCenter()).toEqual({lng: 10, lat: 5}); }); test('trackuserlocationstart event', async () => { @@ -382,7 +368,7 @@ describe('GeolocateControl with no options', () => { } }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const promise = geolocate.once('trackuserlocationstart'); @@ -396,7 +382,7 @@ describe('GeolocateControl with no options', () => { trackUserLocation: true, }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const geolocatePromise = geolocate.once('geolocate'); @@ -413,7 +399,7 @@ describe('GeolocateControl with no options', () => { trackUserLocation: true, }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const geolocatePromise = geolocate.once('geolocate'); @@ -434,7 +420,7 @@ describe('GeolocateControl with no options', () => { showAccuracyCircle: false, }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const geolocatePromise = geolocate.once('geolocate'); @@ -456,7 +442,7 @@ describe('GeolocateControl with no options', () => { showUserLocation: true, }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const geolocatePromise = geolocate.once('geolocate'); @@ -474,12 +460,10 @@ describe('GeolocateControl with no options', () => { map.zoomTo(12, {duration: 0}); await zoomendPromise; expect(geolocate._circleElement.style.width).toBe('79px'); - console.log(geolocate._circleElement.style.width); zoomendPromise = map.once('zoomend'); map.zoomTo(10, {duration: 0}); await zoomendPromise; expect(geolocate._circleElement.style.width).toBe('20px'); - console.log(geolocate._circleElement.style.width); zoomendPromise = map.once('zoomend'); // test with smaller radius @@ -487,12 +471,10 @@ describe('GeolocateControl with no options', () => { map.zoomTo(20, {duration: 0}); await zoomendPromise; expect(geolocate._circleElement.style.width).toBe('19982px'); - console.log(geolocate._circleElement.style.width); zoomendPromise = map.once('zoomend'); map.zoomTo(18, {duration: 0}); await zoomendPromise; expect(geolocate._circleElement.style.width).toBe('4996px'); - console.log(geolocate._circleElement.style.width); }); test('shown even if trackUserLocation = false', async () => { @@ -502,7 +484,7 @@ describe('GeolocateControl with no options', () => { showAccuracyCircle: true, }); map.addControl(geolocate); - + await sleep(0); const click = new window.Event('click'); const geolocatePromise = geolocate.once('geolocate'); diff --git a/src/ui/control/geolocate_control.ts b/src/ui/control/geolocate_control.ts index 1399435f87..88c9c1f131 100644 --- a/src/ui/control/geolocate_control.ts +++ b/src/ui/control/geolocate_control.ts @@ -234,7 +234,7 @@ export class GeolocateControl extends Evented implements IControl { onAdd(map: Map) { this._map = map; this._container = DOM.create('div', 'maplibregl-ctrl maplibregl-ctrl-group'); - checkGeolocationSupport(this._setupUI); + checkGeolocationSupport().then((supported) => this._setupUI(supported)); return this._container; } @@ -519,8 +519,7 @@ export class GeolocateControl extends Evented implements IControl { this._map.on('zoom', this._onZoom); } - this._geolocateButton.addEventListener('click', - this.trigger.bind(this)); + this._geolocateButton.addEventListener('click', () => this.trigger()); this._setup = true; diff --git a/src/ui/events.ts b/src/ui/events.ts index 8d2dd6fad3..ce73398947 100644 --- a/src/ui/events.ts +++ b/src/ui/events.ts @@ -438,7 +438,7 @@ export type MapStyleDataEvent = MapLibreEvent & { * * @group Event Related */ -export type MapSourceDataEvent = MapLibreEvent & { +export type MapSourceDataEvent = MapLibreEvent & { dataType: 'source'; /** * True if the event has a `dataType` of `source` and the source has no outstanding network requests. diff --git a/src/ui/handler/dblclick_zoom.test.ts b/src/ui/handler/dblclick_zoom.test.ts index 33f762a7f6..d4d231f9c3 100644 --- a/src/ui/handler/dblclick_zoom.test.ts +++ b/src/ui/handler/dblclick_zoom.test.ts @@ -55,37 +55,31 @@ describe('dbclick_zoom', () => { map.remove(); }); - test('DoubleClickZoomHandler zooms on double tap if touchstart events are < 300ms apart', done => { + test('DoubleClickZoomHandler zooms on double tap if touchstart events are < 300ms apart', async () => { const map = createMap(); const zoom = jest.fn(); map.on('zoomstart', zoom); - simulateDoubleTap(map, 100).then(() => { - expect(zoom).toHaveBeenCalled(); - - map.remove(); - done(); - }); + await simulateDoubleTap(map, 100); + expect(zoom).toHaveBeenCalled(); + map.remove(); }); - test('DoubleClickZoomHandler does not zoom on double tap if touchstart events are > 500ms apart', done => { + test('DoubleClickZoomHandler does not zoom on double tap if touchstart events are > 500ms apart', async () => { const map = createMap(); const zoom = jest.fn(); map.on('zoom', zoom); - simulateDoubleTap(map, 500).then(() => { - expect(zoom).not.toHaveBeenCalled(); - - map.remove(); - done(); - }); + await simulateDoubleTap(map, 500); + expect(zoom).not.toHaveBeenCalled(); + map.remove(); }); - test('DoubleClickZoomHandler does not zoom on double tap if touchstart events are in different locations', done => { + test('DoubleClickZoomHandler does not zoom on double tap if touchstart events are in different locations', async () => { const map = createMap(); const zoom = jest.fn(); @@ -93,26 +87,20 @@ describe('dbclick_zoom', () => { const canvas = map.getCanvas(); - const simulateTwoDifferentTaps = () => { - return new Promise(resolve => { - simulate.touchstart(canvas, {touches: [{clientX: 0, clientY: 0}]}); + await new Promise(resolve => { + simulate.touchstart(canvas, {touches: [{clientX: 0, clientY: 0}]}); + simulate.touchend(canvas); + setTimeout(() => { + simulate.touchstart(canvas, {touches: [{clientX: 30.5, clientY: 30.5}]}); simulate.touchend(canvas); - setTimeout(() => { - simulate.touchstart(canvas, {touches: [{clientX: 30.5, clientY: 30.5}]}); - simulate.touchend(canvas); - map._renderTaskQueue.run(); - resolve(undefined); - }, 100); - }); - }; - - simulateTwoDifferentTaps().then(() => { - expect(zoom).not.toHaveBeenCalled(); - - map.remove(); - done(); + map._renderTaskQueue.run(); + resolve(undefined); + }, 100); }); + expect(zoom).not.toHaveBeenCalled(); + + map.remove(); }); test('DoubleClickZoomHandler zooms on the second touchend event of a double tap', () => { @@ -149,7 +137,7 @@ describe('dbclick_zoom', () => { }); - test('DoubleClickZoomHandler does not zoom on double tap if second touchend is >300ms after first touchstart', done => { + test('DoubleClickZoomHandler does not zoom on double tap if second touchend is >300ms after first touchstart', async () => { const map = createMap(); const zoom = jest.fn(); @@ -157,23 +145,17 @@ describe('dbclick_zoom', () => { const canvas = map.getCanvas(); - const simulateSlowSecondTap = () => { - return new Promise(resolve => { - simulate.touchstart(canvas); + await new Promise(resolve => { + simulate.touchstart(canvas); + simulate.touchend(canvas); + simulate.touchstart(canvas); + setTimeout(() => { simulate.touchend(canvas); - simulate.touchstart(canvas); - setTimeout(() => { - simulate.touchend(canvas); - map._renderTaskQueue.run(); - resolve(undefined); - }, 300); - }); - }; - - simulateSlowSecondTap().then(() => { - expect(zoom).not.toHaveBeenCalled(); - - done(); + map._renderTaskQueue.run(); + resolve(undefined); + }, 300); }); + + expect(zoom).not.toHaveBeenCalled(); }); }); diff --git a/src/ui/map.test.ts b/src/ui/map.test.ts index ad577fc75e..3676fef015 100755 --- a/src/ui/map.test.ts +++ b/src/ui/map.test.ts @@ -1,5 +1,5 @@ import {Map, MapOptions} from './map'; -import {createMap, setErrorWebGlContext, beforeMapTest} from '../util/test/util'; +import {createMap, setErrorWebGlContext, beforeMapTest, sleep} from '../util/test/util'; import {LngLat} from '../geo/lng_lat'; import {Tile} from '../source/tile'; import {OverscaledTileID} from '../source/tile_id'; @@ -288,7 +288,7 @@ describe('Map', () => { }); - test('setStyle back to the first style should work', done => { + test('setStyle back to the first style should work', async () => { const redStyle = {version: 8 as const, sources: {}, layers: [ {id: 'background', type: 'background' as const, paint: {'background-color': 'red'}}, ]}; @@ -296,13 +296,13 @@ describe('Map', () => { {id: 'background', type: 'background' as const, paint: {'background-color': 'blue'}}, ]}; const map = createMap({style: redStyle}); + const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}); map.setStyle(blueStyle); - map.once('style.load', () => { - map.setStyle(redStyle); - const serializedStyle = map.style.serialize(); - expect(serializedStyle.layers[0].paint['background-color']).toBe('red'); - done(); - }); + await map.once('style.load'); + map.setStyle(redStyle); + const serializedStyle = map.style.serialize(); + expect(serializedStyle.layers[0].paint['background-color']).toBe('red'); + spy.mockRestore(); }); test('style transform overrides unmodified map transform', done => { @@ -554,39 +554,42 @@ describe('Map', () => { describe('#is_Loaded', () => { - test('Map#isSourceLoaded', done => { + test('Map#isSourceLoaded', async () => { const style = createStyle(); const map = createMap({style}); - map.on('load', () => { + await map.once('load'); + const promise = new Promise((resolve) => { map.on('data', (e) => { if (e.dataType === 'source' && e.sourceDataType === 'idle') { expect(map.isSourceLoaded('geojson')).toBe(true); - done(); + resolve(); } }); - map.addSource('geojson', createStyleSource()); - expect(map.isSourceLoaded('geojson')).toBe(false); }); + map.addSource('geojson', createStyleSource()); + expect(map.isSourceLoaded('geojson')).toBe(false); + await promise; }); - test('Map#isSourceLoaded (equivalent to event.isSourceLoaded)', done => { + test('Map#isSourceLoaded (equivalent to event.isSourceLoaded)', async () => { const style = createStyle(); const map = createMap({style}); - map.on('load', () => { - map.on('data', (e) => { + await map.once('load'); + const promise = new Promise((resolve) => { + map.on('data', (e: MapSourceDataEvent) => { if (e.dataType === 'source' && 'source' in e) { - const sourceDataEvent = e as MapSourceDataEvent; - expect(map.isSourceLoaded('geojson')).toBe(sourceDataEvent.isSourceLoaded); - if (sourceDataEvent.sourceDataType === 'idle') { - done(); + expect(map.isSourceLoaded('geojson')).toBe(e.isSourceLoaded); + if (e.sourceDataType === 'idle') { + resolve(); } } }); - map.addSource('geojson', createStyleSource()); - expect(map.isSourceLoaded('geojson')).toBe(false); }); + map.addSource('geojson', createStyleSource()); + expect(map.isSourceLoaded('geojson')).toBe(false); + await promise; }); test('Map#isStyleLoaded', done => { @@ -930,7 +933,7 @@ describe('Map', () => { observerCallback(); observerCallback(); expect(resizeSpy).toHaveBeenCalledTimes(1); - await new Promise((resolve) => { setTimeout(resolve, 100); }); + await sleep(100); expect(resizeSpy).toHaveBeenCalledTimes(2); }); @@ -1519,6 +1522,7 @@ describe('Map', () => { map.style.dispatcher.broadcast = function (key, value: any) { expect(key).toBe('updateLayers'); expect(value.layers.map((layer) => { return layer.id; })).toEqual(['symbol']); + return Promise.resolve({} as any); }; map.setLayoutProperty('symbol', 'text-transform', 'lowercase'); @@ -2205,9 +2209,11 @@ describe('Map', () => { describe('error event', () => { test('logs errors to console when it has NO listeners', () => { + // to avoid seeing error in the console in Jest + let stub = jest.spyOn(console, 'error').mockImplementation(() => {}); const map = createMap(); - const stub = jest.spyOn(console, 'error').mockImplementation(() => {}); stub.mockReset(); + stub = jest.spyOn(console, 'error').mockImplementation(() => {}); const error = new Error('test'); map.fire(new ErrorEvent(error)); expect(stub).toHaveBeenCalledTimes(1); @@ -2387,7 +2393,7 @@ describe('Map', () => { }); - test('map fires `styleimagemissing` for missing icons', done => { + test('map fires `styleimagemissing` for missing icons', async () => { const map = createMap(); const id = 'missing-image'; @@ -2402,14 +2408,12 @@ describe('Map', () => { expect(map.hasImage(id)).toBeFalsy(); - map.style.imageManager.getImages([id], (alwaysNull, generatedImage) => { - expect(generatedImage[id].data.width).toEqual(sampleImage.width); - expect(generatedImage[id].data.height).toEqual(sampleImage.height); - expect(generatedImage[id].data.data).toEqual(sampleImage.data); - expect(called).toBe(id); - expect(map.hasImage(id)).toBeTruthy(); - done(); - }); + const generatedImage = await map.style.imageManager.getImages([id]); + expect(generatedImage[id].data.width).toEqual(sampleImage.width); + expect(generatedImage[id].data.height).toEqual(sampleImage.height); + expect(generatedImage[id].data.data).toEqual(sampleImage.data); + expect(called).toBe(id); + expect(map.hasImage(id)).toBeTruthy(); }); test('map getImage matches addImage, uintArray', () => { diff --git a/src/ui/map.ts b/src/ui/map.ts index 4ecd20d645..ab33791f36 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -3,7 +3,7 @@ import {browser} from '../util/browser'; import {DOM} from '../util/dom'; import packageJSON from '../../package.json' assert {type: 'json'}; -import {getJSON} from '../util/ajax'; +import {GetResourceResponse, getJSON} from '../util/ajax'; import {ImageRequest} from '../util/image_request'; import type {GetImageCallback} from '../util/image_request'; @@ -49,7 +49,6 @@ import type {DoubleClickZoomHandler} from './handler/shim/dblclick_zoom'; import type {TwoFingersTouchZoomRotateHandler} from './handler/shim/two_fingers_touch'; import {defaultLocale} from './default_locale'; import type {TaskID} from '../util/task_queue'; -import type {Cancelable} from '../types/cancelable'; import type { FilterSpecification, StyleSpecification, @@ -468,7 +467,7 @@ export class Map extends Camera { _canvas: HTMLCanvasElement; _maxTileCacheSize: number; _maxTileCacheZoomLevels: number; - _frame: Cancelable; + _frameRequest: AbortController; _styleDirty: boolean; _sourcesDirty: boolean; _placementDirty: boolean; @@ -1828,11 +1827,11 @@ export class Map extends Camera { if (typeof style === 'string') { const url = style; const request = this._requestManager.transformRequest(url, ResourceType.Style); - getJSON(request, (error?: Error | null, json?: any | null) => { + getJSON(request, new AbortController()).then((response) => { + this._updateDiff(response.data, options); + }).catch((error) => { if (error) { this.fire(new ErrorEvent(error)); - } else if (json) { - this._updateDiff(json, options); } }); } else if (typeof style === 'object') { @@ -2305,21 +2304,25 @@ export class Map extends Camera { * domains must support [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS). * * @param url - The URL of the image file. Image file must be in png, webp, or jpg format. - * @param callback - Expecting `callback(error, data)`. Called when the image has loaded or with an error argument if there is an error. + * @param callback - if not provided, this method will return a promise, otherwise use `callback(error, data)`. Called when the image has loaded or with an error argument if there is an error. * * @example * Load an image from an external URL. * ```ts - * map.loadImage('http://placekitten.com/50/50', function(error, image) { - * if (error) throw error; - * // Add the loaded image to the style's sprite with the ID 'kitten'. - * map.addImage('kitten', image); - * }); + * const response = await map.loadImage('http://placekitten.com/50/50'); + * // Add the loaded image to the style's sprite with the ID 'kitten'. + * map.addImage('kitten', response.data); * ``` * @see [Add an icon to the map](https://maplibre.org/maplibre-gl-js/docs/examples/add-image/) */ - loadImage(url: string, callback: GetImageCallback) { - ImageRequest.getImage(this._requestManager.transformRequest(url, ResourceType.Image), callback); + loadImage(url: string, callback?: GetImageCallback): Promise> { + if (!callback) { + return ImageRequest.getImage(this._requestManager.transformRequest(url, ResourceType.Image), new AbortController()); + } else { + ImageRequest.getImage(this._requestManager.transformRequest(url, ResourceType.Image), new AbortController()) + .then((response) => callback(null, response.data, {cacheControl: response.cacheControl, expires: response.expires})) + .catch(callback); + } } /** @@ -3038,9 +3041,9 @@ export class Map extends Camera { _contextLost = (event: any) => { event.preventDefault(); - if (this._frame) { - this._frame.cancel(); - this._frame = null; + if (this._frameRequest) { + this._frameRequest.abort(); + this._frameRequest = null; } this.fire(new Event('webglcontextlost', {originalEvent: event})); }; @@ -3253,9 +3256,9 @@ export class Map extends Camera { redraw(): this { if (this.style) { // cancel the scheduled update - if (this._frame) { - this._frame.cancel(); - this._frame = null; + if (this._frameRequest) { + this._frameRequest.abort(); + this._frameRequest = null; } this._render(0); } @@ -3277,9 +3280,9 @@ export class Map extends Camera { for (const control of this._controls) control.onRemove(this); this._controls = []; - if (this._frame) { - this._frame.cancel(); - this._frame = null; + if (this._frameRequest) { + this._frameRequest.abort(); + this._frameRequest = null; } this._renderTaskQueue.clear(); this.painter.destroy(); @@ -3322,12 +3325,13 @@ export class Map extends Camera { * @see [Add an animated icon to the map](https://maplibre.org/maplibre-gl-js/docs/examples/add-image-animated/) */ triggerRepaint() { - if (this.style && !this._frame) { - this._frame = browser.frame((paintStartTimeStamp: number) => { + if (this.style && !this._frameRequest) { + this._frameRequest = new AbortController(); + browser.frameAsync(this._frameRequest).then((paintStartTimeStamp: number) => { PerformanceUtils.frame(paintStartTimeStamp); - this._frame = null; + this._frameRequest = null; this._render(paintStartTimeStamp); - }); + }).catch(() => {}); // ignore abort error } } diff --git a/src/util/abort_error.ts b/src/util/abort_error.ts new file mode 100644 index 0000000000..0deb738f8c --- /dev/null +++ b/src/util/abort_error.ts @@ -0,0 +1,21 @@ +/** + * An error message to use when an operation is aborted + */ +export const ABORT_ERROR = 'AbortError'; + +/** + * Check if an error is an abort error + * @param error - An error object + * @returns - true if the error is an abort error + */ +export function isAbortError(error: Error): boolean { + return error.message === ABORT_ERROR; +} + +/** + * Use this when you need to create an abort error. + * @returns An error object with the message "AbortError" + */ +export function createAbortError(): Error { + return new Error(ABORT_ERROR); +} diff --git a/src/util/actor.test.ts b/src/util/actor.test.ts index 06ad375df5..d1759aea8d 100644 --- a/src/util/actor.test.ts +++ b/src/util/actor.test.ts @@ -1,106 +1,189 @@ import {Actor, ActorTarget} from './actor'; -import {workerFactory} from './web_worker'; -import {MessageBus} from '../../test/unit/lib/web_worker_mock'; - -const originalWorker = global.Worker; - -function setTestWorker(MockWorker: { new(...args: any): any}) { - (global as any).Worker = function Worker(_: string) { - const parentListeners = []; - const workerListeners = []; - const parentBus = new MessageBus(workerListeners, parentListeners); - const workerBus = new MessageBus(parentListeners, workerListeners); - - parentBus.target = workerBus; - workerBus.target = parentBus; - - new MockWorker(workerBus); - - return parentBus; - }; +import {WorkerGlobalScopeInterface, workerFactory} from './web_worker'; +import {setGlobalWorker} from '../../test/unit/lib/web_worker_mock'; +import {sleep} from './test/util'; +import {ABORT_ERROR, createAbortError} from './abort_error'; + +class MockWorker { + self: any; + actor: Actor; + constructor(self) { + this.self = self; + this.actor = new Actor(self); + } } describe('Actor', () => { + let originalWorker; + beforeAll(() => { + originalWorker = global.Worker; + setGlobalWorker(MockWorker); + }); afterAll(() => { global.Worker = originalWorker; }); - test('forwards responses to correct callback', done => { - setTestWorker(class MockWorker { - self: any; - actor: Actor; - constructor(self) { - this.self = self; - this.actor = new Actor(self, this); - } - getTile(mapId, params, callback) { - setTimeout(callback, 0, null, params); - } - getWorkerSource() { return null; } + test('forwards responses to correct handler', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', async (_mapId, params) => { + await sleep(0); + return params.clusterId; }); - const worker = workerFactory(); + const m1 = new Actor(worker, '1'); + const m2 = new Actor(worker, '2'); - const m1 = new Actor(worker, {} as any, '1'); - const m2 = new Actor(worker, {} as any, '2'); + const p1 = m1.sendAsync({type: 'getClusterExpansionZoom', data: {type: 'geojson', source: '', clusterId: 1729}}); + const p2 = m2.sendAsync({type: 'getClusterExpansionZoom', data: {type: 'geojson', source: '', clusterId: 4104}}); - let callbackCount = 0; - m1.send('getTile', {value: 1729}, (err, response) => { - expect(err).toBeFalsy(); - expect(response).toEqual({value: 1729}); - callbackCount++; - if (callbackCount === 2) { - done(); - } + await Promise.all([p1, p2]); + await expect(p1).resolves.toBe(1729); + await expect(p2).resolves.toBe(4104); + }); + + test('cancel a request does not reject or resolve a promise', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', async (_mapId, params) => { + await sleep(200); + return params.clusterId; }); - m2.send('getTile', {value: 4104}, (err, response) => { - expect(err).toBeFalsy(); - expect(response).toEqual({value: 4104}); - callbackCount++; - if (callbackCount === 2) { - done(); - } + + const m1 = new Actor(worker, '1'); + + let received = false; + const abortController = new AbortController(); + const p1 = m1.sendAsync({type: 'getClusterExpansionZoom', data: {type: 'geojson', source: '', clusterId: 1729}}, abortController) + .then(() => { received = true; }) + .catch(() => { received = true; }); + + abortController.abort(); + + const p2 = new Promise((resolve) => (setTimeout(resolve, 500))); + + await Promise.any([p1, p2]); + expect(received).toBeFalsy(); + }); + + test('aborting a request will successfully abort it', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + let gotAbortSignal = false; + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', (_mapId, _params, handlerAbortController) => { + return new Promise((resolve, reject) => { + handlerAbortController.signal.addEventListener('abort', () => { + gotAbortSignal = true; + reject(createAbortError()); + }); + setTimeout(resolve, 200); + }); }); + + const m1 = new Actor(worker, '1'); + + let received = false; + const abortController = new AbortController(); + m1.sendAsync({type: 'getClusterExpansionZoom', data: {type: 'geojson', source: '', clusterId: 1729}}, abortController) + .then(() => { received = true; }) + .catch(() => { received = true; }); + + abortController.abort(); + + await sleep(500); + + expect(received).toBeFalsy(); + expect(gotAbortSignal).toBeTruthy(); }); - test('targets worker-initiated messages to correct map instance', done => { - let workerActor; + test('cancel a request that must be queued will not call the method at all', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + const actor = new Actor(worker, '1'); - setTestWorker(class MockWorker { - self: any; - actor: Actor; - constructor(self) { - this.self = self; - this.actor = workerActor = new Actor(self, this); - } - getWorkerSource() { return null; } - }); + const spy = jest.fn().mockReturnValue(Promise.resolve({})); + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', spy); - const worker = workerFactory(); + let received = false; + const abortController = new AbortController(); + const p1 = actor.sendAsync({type: 'getClusterExpansionZoom', data: {type: 'geojson', source: '', clusterId: 1729}, mustQueue: true}, abortController) + .then(() => { received = true; }) + .catch(() => { received = true; }); - new Actor(worker, { - test () { done(); } - } as any, '1'); - new Actor(worker, { - test () { - done('test failed'); - } - } as any, '2'); + abortController.abort(); + + const p2 = new Promise((resolve) => (setTimeout(resolve, 500))); - workerActor.send('test', {}, () => {}, '1'); + await Promise.any([p1, p2]); + expect(received).toBeFalsy(); + expect(spy).not.toHaveBeenCalled(); }); test('#remove unbinds event listener', done => { const actor = new Actor({ - addEventListener (type, callback, useCapture) { + addEventListener(type, callback, useCapture) { this._addEventListenerArgs = [type, callback, useCapture]; }, - removeEventListener (type, callback, useCapture) { + removeEventListener(type, callback, useCapture) { expect([type, callback, useCapture]).toEqual(this._addEventListenerArgs); done(); } - } as ActorTarget, {} as any, null); + } as ActorTarget, null); actor.remove(); }); + test('send a messege that is rejected', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + const actor = new Actor(worker, '1'); + + worker.worker.actor.registerMessageHandler('abortTile', () => Promise.reject(createAbortError())); + + await expect(async () => actor.sendAsync({type: 'abortTile', data: {} as any})).rejects.toThrow(ABORT_ERROR); + }); + + test('send a messege that must be queued, it should still arrive', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + const actor = new Actor(worker, '1'); + + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', () => Promise.resolve(42)); + + const response = await actor.sendAsync({type: 'getClusterExpansionZoom', data: {} as any, mustQueue: true}); + + expect(response).toBe(42); + }); + + test('send a messege is not registered should throw', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + const actor = new Actor(worker, '1'); + + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', () => Promise.resolve(42)); + + await expect(async () => actor.sendAsync({type: 'abortTile', data: {} as any})).rejects.toThrow(/Could not find a registered handler for.*/); + }); + + test('should not process a message with the wrong map id', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + const actor = new Actor(worker, '1'); + + worker.worker.actor.mapId = '2'; + + const spy = jest.fn().mockReturnValue(Promise.resolve({})); + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', spy); + + actor.sendAsync({type: 'getClusterExpansionZoom', data: {} as any, targetMapId: '1'}); + + await sleep(100); + + expect(spy).not.toHaveBeenCalled(); + }); + + test('should not process a message with the wrong origin', async () => { + const worker = workerFactory() as any as WorkerGlobalScopeInterface & ActorTarget; + const actor = new Actor(worker, '1'); + + const spy = jest.fn().mockReturnValue(Promise.resolve({})); + worker.worker.actor.registerMessageHandler('getClusterExpansionZoom', spy); + + actor.target.postMessage({type: 'getClusterExpansionZoom', data: {} as any, origin: 'https://example.com'}); + + await sleep(100); + + expect(spy).not.toHaveBeenCalled(); + }); }); diff --git a/src/util/actor.ts b/src/util/actor.ts index 5bdc7d3291..654bcf2526 100644 --- a/src/util/actor.ts +++ b/src/util/actor.ts @@ -1,14 +1,13 @@ -import {isWorker} from './util'; +import {Subscription, isWorker, subscribe} from './util'; import {serialize, deserialize, Serialized} from './web_worker_transfer'; import {ThrottledInvoker} from './throttled_invoker'; import type {Transferable} from '../types/transferable'; -import type {Cancelable} from '../types/cancelable'; -import type {WorkerSource} from '../source/worker_source'; -import type {OverscaledTileID} from '../source/tile_id'; -import type {Callback} from '../types/callback'; -import type {StyleGlyph} from '../style/style_glyph'; +import type {ActorMessage, MessageType, RequestResponseMessageMap} from './actor_messages'; +/** + * An interface to be sent to the actor in order for it to allow communication between the worker and the main thread + */ export interface ActorTarget { addEventListener: typeof window.addEventListener; removeEventListener: typeof window.removeEventListener; @@ -16,173 +15,159 @@ export interface ActorTarget { terminate?: () => void; } -export interface WorkerSourceProvider { - getWorkerSource(mapId: string | number, sourceType: string, sourceName: string): WorkerSource; -} - -export interface GlyphsProvider { - getGlyphs(mapId: string, params: { - stacks: {[_: string]: Array}; - source: string; - tileID: OverscaledTileID; - type: string; - }, - callback: Callback<{[_: string]: {[_: number]: StyleGlyph}}> - ); -} - -export type MessageType = '' | '' | -'geojson.getClusterExpansionZoom' | 'geojson.getClusterChildren' | 'geojson.getClusterLeaves' | 'geojson.loadData' | -'removeSource' | 'loadWorkerSource' | 'loadDEMTile' | 'removeDEMTile' | -'removeTile' | 'reloadTile' | 'abortTile' | 'loadTile' | 'getTile' | -'getGlyphs' | 'getImages' | 'setImages' | -'syncRTLPluginState' | 'setReferrer' | 'setLayers' | 'updateLayers'; - -export type MessageData = { +/** + * This is used to define the parameters of the message that is sent to the worker and back + */ +type MessageData = { id: string; - type: MessageType; + type: MessageType | '' | ''; + origin: string; data?: Serialized; targetMapId?: string | number | null; mustQueue?: boolean; error?: Serialized | null; - hasCallback?: boolean; sourceMapId: string | number | null; } -export type Message = { - data: MessageData; +type ResolveReject = { + resolve: (value?: RequestResponseMessageMap[MessageType][1]) => void; + reject: (reason?: Error) => void; } +/** + * This interface allowing to substitute only the sendAsync method of the Actor class. + */ +export interface IActor { + sendAsync(message: ActorMessage, abortController?: AbortController): Promise; +} + +export type MessageHandler = (mapId: string | number, params: RequestResponseMessageMap[T][0], abortController?: AbortController) => Promise + /** * An implementation of the [Actor design pattern](http://en.wikipedia.org/wiki/Actor_model) * that maintains the relationship between asynchronous tasks and the objects * that spin them off - in this case, tasks like parsing parts of styles, * owned by the styles */ -export class Actor { +export class Actor implements IActor { target: ActorTarget; - parent: WorkerSourceProvider | GlyphsProvider; mapId: string | number | null; - callbacks: { [x: number]: Function}; + resolveRejects: { [x: string]: ResolveReject}; name: string; tasks: { [x: number]: MessageData }; taskQueue: Array; - cancelCallbacks: { [x: number]: () => void }; + abortControllers: { [x: number | string]: AbortController }; invoker: ThrottledInvoker; globalScope: ActorTarget; + messageHandlers: { [x in MessageType]?: MessageHandler}; + subscription: Subscription; /** * @param target - The target * @param parent - The parent * @param mapId - A unique identifier for the Map instance using this Actor. */ - constructor(target: ActorTarget, parent: WorkerSourceProvider | GlyphsProvider, mapId?: string | number) { + constructor(target: ActorTarget, mapId?: string | number) { this.target = target; - this.parent = parent; this.mapId = mapId; - this.callbacks = {}; + this.resolveRejects = {}; this.tasks = {}; this.taskQueue = []; - this.cancelCallbacks = {}; - this.invoker = new ThrottledInvoker(this.process); - this.target.addEventListener('message', this.receive, false); - this.globalScope = isWorker() ? target : window; + this.abortControllers = {}; + this.messageHandlers = {}; + this.invoker = new ThrottledInvoker(() => this.process()); + this.subscription = subscribe(this.target, 'message', (message) => this.receive(message), false); + this.globalScope = isWorker(self) ? target : window; + } + + registerMessageHandler(type: T, handler: MessageHandler) { + this.messageHandlers[type] = handler; } /** * Sends a message from a main-thread map to a Worker or from a Worker back to * a main-thread map instance. - * - * @param type - The name of the target method to invoke or '[source-type].[source-name].name' for a method on a WorkerSource. - * @param targetMapId - A particular mapId to which to send this message. + * @param message - the message to send + * @param abortController - an optional AbortController to abort the request + * @returns a promise that will be resolved with the response data */ - send( - type: MessageType, - data: unknown, - callback?: Function | null, - targetMapId?: string | null, - mustQueue: boolean = false - ): Cancelable { - // We're using a string ID instead of numbers because they are being used as object keys - // anyway, and thus stringified implicitly. We use random IDs because an actor may receive - // message from multiple other actors which could run in different execution context. A - // linearly increasing ID could produce collisions. - const id = Math.round((Math.random() * 1e18)).toString(36).substring(0, 10); - if (callback) { - this.callbacks[id] = callback; - } - const buffers: Array = []; - const message: MessageData = { - id, - type, - hasCallback: !!callback, - targetMapId, - mustQueue, - sourceMapId: this.mapId, - data: serialize(data, buffers) - }; - - this.target.postMessage(message, {transfer: buffers}); - return { - cancel: () => { - if (callback) { - // Set the callback to null so that it never fires after the request is aborted. - delete this.callbacks[id]; - } - const cancelMessage: MessageData = { - id, - type: '', - targetMapId, - sourceMapId: this.mapId - }; - this.target.postMessage(cancelMessage); + sendAsync(message: ActorMessage, abortController?: AbortController): Promise { + return new Promise((resolve, reject) => { + // We're using a string ID instead of numbers because they are being used as object keys + // anyway, and thus stringified implicitly. We use random IDs because an actor may receive + // message from multiple other actors which could run in different execution context. A + // linearly increasing ID could produce collisions. + const id = Math.round((Math.random() * 1e18)).toString(36).substring(0, 10); + this.resolveRejects[id] = { + resolve, + reject + }; + if (abortController) { + abortController.signal.addEventListener('abort', () => { + delete this.resolveRejects[id]; + const cancelMessage: MessageData = { + id, + type: '', + origin: location.origin, + targetMapId: message.targetMapId, + sourceMapId: this.mapId + }; + this.target.postMessage(cancelMessage); + // In case of abort the current behavior is to keep the promise pending. + }, {once: true}); } - }; + const buffers: Array = []; + const messageToPost: MessageData = { + ...message, + id, + sourceMapId: this.mapId, + origin: location.origin, + data: serialize(message.data, buffers) + }; + this.target.postMessage(messageToPost, {transfer: buffers}); + }); } - receive = (message: Message) => { + receive(message: {data: MessageData}) { const data = message.data; const id = data.id; - - if (!id) { + if (data.origin !== location.origin) { return; } - if (data.targetMapId && this.mapId !== data.targetMapId) { return; } - if (data.type === '') { // Remove the original request from the queue. This is only possible if it // hasn't been kicked off yet. The id will remain in the queue, but because // there is no associated task, it will be dropped once it's time to execute it. delete this.tasks[id]; - const cancel = this.cancelCallbacks[id]; - delete this.cancelCallbacks[id]; - if (cancel) { - cancel(); - } - } else { - if (isWorker() || data.mustQueue) { - // In workers, store the tasks that we need to process before actually processing them. This - // is necessary because we want to keep receiving messages, and in particular, - // messages. Some tasks may take a while in the worker thread, so before - // executing the next task in our queue, postMessage preempts this and - // messages can be processed. We're using a MessageChannel object to get throttle the - // process() flow to one at a time. - this.tasks[id] = data; - this.taskQueue.push(id); - this.invoker.trigger(); - } else { - // In the main thread, process messages immediately so that other work does not slip in - // between getting partial data back from workers. - this.processTask(id, data); + const abortController = this.abortControllers[id]; + delete this.abortControllers[id]; + if (abortController) { + abortController.abort(); } + return; + } + if (isWorker(self) || data.mustQueue) { + // In workers, store the tasks that we need to process before actually processing them. This + // is necessary because we want to keep receiving messages, and in particular, + // messages. Some tasks may take a while in the worker thread, so before + // executing the next task in our queue, postMessage preempts this and + // messages can be processed. We're using a MessageChannel object to get throttle the + // process() flow to one at a time. + this.tasks[id] = data; + this.taskQueue.push(id); + this.invoker.trigger(); + return; } - }; + // In the main thread, process messages immediately so that other work does not slip in + // between getting partial data back from workers. + this.processTask(id, data); + } - process = () => { - if (!this.taskQueue.length) { + process() { + if (this.taskQueue.length === 0) { return; } const id = this.taskQueue.shift(); @@ -191,7 +176,7 @@ export class Actor { // Schedule another process call if we know there's more to process _before_ invoking the // current task. This is necessary so that processing continues even if the current task // doesn't execute successfully. - if (this.taskQueue.length) { + if (this.taskQueue.length > 0) { this.invoker.trigger(); } if (!task) { @@ -200,64 +185,56 @@ export class Actor { } this.processTask(id, task); - }; + } - processTask(id: string, task: MessageData) { + async processTask(id: string, task: MessageData) { if (task.type === '') { - // The done() function in the counterpart has been called, and we are now - // firing the callback in the originating actor, if there is one. - const callback = this.callbacks[id]; - delete this.callbacks[id]; - if (callback) { - // If we get a response, but don't have a callback, the request was canceled. - if (task.error) { - callback(deserialize(task.error)); - } else { - callback(null, deserialize(task.data)); - } + // The `completeTask` function in the counterpart actor has been called, and we are now + // resolving or rejecting the promise in the originating actor, if there is one. + const resolveReject = this.resolveRejects[id]; + delete this.resolveRejects[id]; + if (!resolveReject) { + // If we get a response, but don't have a resolve or reject, the request was canceled. + return; } - } else { - let completed = false; - const buffers: Array = []; - const done = task.hasCallback ? (err: Error, data?: any) => { - completed = true; - delete this.cancelCallbacks[id]; - const responseMessage: MessageData = { - id, - type: '', - sourceMapId: this.mapId, - error: err ? serialize(err) : null, - data: serialize(data, buffers) - }; - this.target.postMessage(responseMessage, {transfer: buffers}); - } : (_) => { - completed = true; - }; - - let callback: Cancelable = null; - const params = deserialize(task.data); - if (this.parent[task.type]) { - // task.type == 'loadTile', 'removeTile', etc. - callback = this.parent[task.type](task.sourceMapId, params, done); - } else if ('getWorkerSource' in this.parent) { - // task.type == sourcetype.method - const keys = task.type.split('.'); - const scope = this.parent.getWorkerSource(task.sourceMapId, keys[0], (params as any).source); - callback = scope[keys[1]](params, done); + if (task.error) { + resolveReject.reject(deserialize(task.error) as Error); } else { - // No function was found. - done(new Error(`Could not find function ${task.type}`)); - } - - if (!completed && callback && callback.cancel) { - // Allows canceling the task as long as it hasn't been completed yet. - this.cancelCallbacks[id] = callback.cancel; + resolveReject.resolve(deserialize(task.data)); } + return; } + if (!this.messageHandlers[task.type]) { + this.completeTask(id, new Error(`Could not find a registered handler for ${task.type}`)); + return; + } + const params = deserialize(task.data) as RequestResponseMessageMap[MessageType][0]; + const abortController = new AbortController(); + this.abortControllers[id] = abortController; + try { + const data = await this.messageHandlers[task.type](task.sourceMapId, params, abortController); + this.completeTask(id, null, data); + } catch (err) { + this.completeTask(id, err); + } + } + + completeTask(id: string, err: Error, data?: RequestResponseMessageMap[MessageType][1]) { + const buffers: Array = []; + delete this.abortControllers[id]; + const responseMessage: MessageData = { + id, + type: '', + sourceMapId: this.mapId, + origin: location.origin, + error: err ? serialize(err) : null, + data: serialize(data, buffers) + }; + this.target.postMessage(responseMessage, {transfer: buffers}); } remove() { this.invoker.remove(); - this.target.removeEventListener('message', this.receive, false); + this.subscription.unsubscribe(); } } diff --git a/src/util/actor_messages.ts b/src/util/actor_messages.ts new file mode 100644 index 0000000000..474b565232 --- /dev/null +++ b/src/util/actor_messages.ts @@ -0,0 +1,124 @@ +import type {LoadGeoJSONParameters} from '../source/geojson_worker_source'; +import type {TileParameters, WorkerDEMTileParameters, WorkerTileParameters, WorkerTileResult} from '../source/worker_source'; +import type {DEMData} from '../data/dem_data'; +import type {StyleImage} from '../style/style_image'; +import type {StyleGlyph} from '../style/style_glyph'; +import type {PluginState} from '../source/rtl_text_plugin'; +import type {LayerSpecification} from '@maplibre/maplibre-gl-style-spec'; +import type {OverscaledTileID} from '../source/tile_id'; +import type {GetResourceResponse, RequestParameters} from './ajax'; + +/** + * The parameters needed in order to get information about the cluster + */ +export type ClusterIDAndSource = { + type: 'geojson'; + clusterId: number; + source: string; +}; + +/** + * Parameters needed to get the leaves of a cluster + */ +export type GetClusterLeavesParams = ClusterIDAndSource & { limit: number; offset: number }; + +/** + * The result of the call to load a geojson source + */ +export type GeoJSONWorkerSourceLoadDataResult = { + resourceTiming?: {[_: string]: Array}; + abandoned?: boolean; +}; + +/** + * Parameters needed to remove a source + */ +export type RemoveSourceParams = { + source: string; + type: string; +} + +/** + * Parameters needed to update the layers + */ +export type UpdateLayersParamaeters = { + layers: Array; + removedIds: Array; +} + +/** + * Parameters needed to get the images + */ +export type GetImagesParamerters = { + icons: Array; + source: string; + tileID: OverscaledTileID; + type: string; +} + +/** + * Parameters needed to get the glyphs + */ +export type GetGlyphsParamerters = { + type: string; + stacks: {[_: string]: Array}; + source: string; + tileID: OverscaledTileID; +} + +/** + * A response object returned when requesting glyphs + */ +export type GetGlyphsResponse = { + [stack: string]: { + [id: number]: StyleGlyph; + }; +} + +/** + * A response object returned when requesting images + */ +export type GetImagesResponse = {[_: string]: StyleImage} + +/** + * This is basically a mapping between all the calls that are made to and from the workers. + * The key is the event name, the first parameter is the event input type, and the last parameter is the output type. + */ +export type RequestResponseMessageMap = { + 'loadDEMTile': [WorkerDEMTileParameters, DEMData]; + 'getClusterExpansionZoom': [ClusterIDAndSource, number]; + 'getClusterChildren': [ClusterIDAndSource, Array]; + 'getClusterLeaves': [GetClusterLeavesParams, Array]; + 'loadData': [LoadGeoJSONParameters, GeoJSONWorkerSourceLoadDataResult]; + 'loadTile': [WorkerTileParameters, WorkerTileResult]; + 'reloadTile': [WorkerTileParameters, WorkerTileResult]; + 'getGlyphs': [GetGlyphsParamerters, GetGlyphsResponse]; + 'getImages': [GetImagesParamerters, GetImagesResponse]; + 'setImages': [string[], void]; + 'setLayers': [Array, void]; + 'updateLayers': [UpdateLayersParamaeters, void]; + 'syncRTLPluginState': [PluginState, boolean]; + 'setReferrer': [string, void]; + 'removeSource': [RemoveSourceParams, void]; + 'loadWorkerSource': [string, void]; + 'removeTile': [TileParameters, void]; + 'abortTile': [TileParameters, void]; + 'removeDEMTile': [TileParameters, void]; + 'getResource': [RequestParameters, GetResourceResponse]; +} + +/** + * All the possible message types that can be sent to and from the worker + */ +export type MessageType = keyof RequestResponseMessageMap; + +/** + * The message to be sent by the actor + */ +export type ActorMessage = { + type: T; + data: RequestResponseMessageMap[T][0]; + targetMapId?: string | number | null; + mustQueue?: boolean; + sourceMapId?: string | number | null; +}; diff --git a/src/util/ajax.test.ts b/src/util/ajax.test.ts index f3a6146cf6..c7df501a3b 100644 --- a/src/util/ajax.test.ts +++ b/src/util/ajax.test.ts @@ -1,13 +1,11 @@ import { getArrayBuffer, getJSON, - postData, AJAXError, sameOrigin } from './ajax'; import {fakeServer, type FakeServer} from 'nise'; -import {destroyFetchMock, FetchMock, RequestMock, setupFetchMock} from './test/mock_fetch'; function readAsText(blob) { return new Promise((resolve, reject) => { @@ -28,70 +26,66 @@ describe('ajax', () => { server.restore(); }); - test('getArrayBuffer, 404', done => { + test('getArrayBuffer, 404', async () => { server.respondWith(request => { request.respond(404, undefined, '404 Not Found'); }); - getArrayBuffer({url: 'http://example.com/test.bin'}, async (error) => { + + try { + const promise = getArrayBuffer({url: 'http://example.com/test.bin'}, new AbortController()); + server.respond(); + await promise; + } catch (error) { const ajaxError = error as AJAXError; const body = await readAsText(ajaxError.body); expect(ajaxError.status).toBe(404); expect(ajaxError.statusText).toBe('Not Found'); expect(ajaxError.url).toBe('http://example.com/test.bin'); expect(body).toBe('404 Not Found'); - done(); - }); - server.respond(); + } }); - test('getJSON', done => { + test('getJSON', async () => { server.respondWith(request => { request.respond(200, {'Content-Type': 'application/json'}, '{"foo": "bar"}'); }); - getJSON({url: ''}, (error, body) => { - expect(error).toBeFalsy(); - expect(body).toEqual({foo: 'bar'}); - done(); - }); + const promise = getJSON({url: ''}, new AbortController()); server.respond(); + + const body = await promise; + expect(body.data).toEqual({foo: 'bar'}); }); - test('getJSON, invalid syntax', done => { + test('getJSON, invalid syntax', async () => { server.respondWith(request => { request.respond(200, {'Content-Type': 'application/json'}, 'how do i even'); }); - getJSON({url: ''}, (error) => { - expect(error).toBeTruthy(); - done(); - }); + const promise = getJSON({url: ''}, new AbortController()); server.respond(); + try { + await promise; + } catch (error) { + expect(error).toBeTruthy(); + } }); - test('getJSON, 404', done => { + test('getJSON, 404', async () => { server.respondWith(request => { request.respond(404, undefined, '404 Not Found'); }); - getJSON({url: 'http://example.com/test.json'}, async (error) => { + const promise = getJSON({url: 'http://example.com/test.json'}, new AbortController()); + server.respond(); + + try { + await promise; + } catch (error) { const ajaxError = error as AJAXError; const body = await readAsText(ajaxError.body); expect(ajaxError.status).toBe(404); expect(ajaxError.statusText).toBe('Not Found'); expect(ajaxError.url).toBe('http://example.com/test.json'); expect(body).toBe('404 Not Found'); - done(); - }); - server.respond(); - }); - - test('postData, 204(no content): no error', done => { - server.respondWith(request => { - request.respond(204, undefined, undefined); - }); - postData({url: 'api.mapbox.com'}, (error) => { - expect(error).toBeNull(); - done(); - }); - server.respond(); + } }); test('sameOrigin method', () => { @@ -144,34 +138,34 @@ describe('ajax', () => { }); describe('requests parameters', () => { - let fetch: FetchMock; - beforeEach(() => { - fetch = setupFetchMock(); - }); + test('should be provided to fetch API in getArrayBuffer function', async () => { + server.respondWith(new ArrayBuffer(1)); + + const promise = getArrayBuffer({url: 'http://example.com/test-params.json', cache: 'force-cache', headers: {'Authorization': 'Bearer 123'}}, new AbortController()); + server.respond(); + await promise; - afterEach(() => { - destroyFetchMock(); + expect(server.requests).toHaveLength(1); + expect(server.requests[0].url).toBe('http://example.com/test-params.json'); + expect(server.requests[0].method).toBe('GET'); + expect(server.requests[0].requestHeaders['Authorization']).toBe('Bearer 123'); }); - test('should be provided to fetch API in getArrayBuffer function', (done) => { - getArrayBuffer({url: 'http://example.com/test-params.json', cache: 'force-cache', headers: {'Authorization': 'Bearer 123'}}, () => { - expect(fetch).toHaveBeenCalledTimes(1); - expect(fetch).toHaveBeenCalledWith(expect.objectContaining({url: 'http://example.com/test-params.json', method: 'GET', cache: 'force-cache'})); - expect((fetch.mock.calls[0][0] as RequestMock).headers.get('Authorization')).toBe('Bearer 123'); + test('should be provided to fetch API in getJSON function', async () => { - done(); + server.respondWith(request => { + request.respond(200, {'Content-Type': 'application/json'}, '{"foo": "bar"}'); }); - }); - test('should be provided to fetch API in getJSON function', (done) => { - getJSON({url: 'http://example.com/test-params.json', cache: 'force-cache', headers: {'Authorization': 'Bearer 123'}}, () => { - expect(fetch).toHaveBeenCalledTimes(1); - expect(fetch).toHaveBeenCalledWith(expect.objectContaining({url: 'http://example.com/test-params.json', method: 'GET', cache: 'force-cache'})); - expect((fetch.mock.calls[0][0] as RequestMock).headers.get('Authorization')).toBe('Bearer 123'); + const promise = getJSON({url: 'http://example.com/test-params.json', cache: 'force-cache', headers: {'Authorization': 'Bearer 123'}}, new AbortController()); + server.respond(); + await promise; - done(); - }); + expect(server.requests).toHaveLength(1); + expect(server.requests[0].url).toBe('http://example.com/test-params.json'); + expect(server.requests[0].method).toBe('GET'); + expect(server.requests[0].requestHeaders['Authorization']).toBe('Bearer 123'); }); }); }); diff --git a/src/util/ajax.ts b/src/util/ajax.ts index 8119d208ca..bd27e08e92 100644 --- a/src/util/ajax.ts +++ b/src/util/ajax.ts @@ -1,9 +1,14 @@ -import {extend, warnOnce, isWorker} from './util'; +import {extend, isWorker} from './util'; import {config} from './config'; +import {createAbortError} from './abort_error'; -import type {Callback} from '../types/callback'; import type {Cancelable} from '../types/cancelable'; +/** + * A type used to store the tile's expiration date and cache control definition + */ +export type ExpiryData = {cacheControl?: string | null; expires?: Date | string | null}; + /** * A `RequestParameters` object to be returned from Map.options.transformRequest callbacks. * @example @@ -38,7 +43,7 @@ export type RequestParameters = { */ body?: string; /** - * Response body type to be returned `'string' | 'json' | 'arrayBuffer'`. + * Response body type to be returned. */ type?: 'string' | 'json' | 'arrayBuffer' | 'image'; /** @@ -55,6 +60,13 @@ export type RequestParameters = { cache?: RequestCache; }; +/** + * The response object returned from a successful AJAx request + */ +export type GetResourceResponse = ExpiryData & { + data: T; +} + /** * The response callback used in various places */ @@ -62,7 +74,7 @@ export type ResponseCallback = ( error?: Error | null, data?: T | null, cacheControl?: string | null, - expires?: string | null + expires?: string | Date | null ) => void; /** @@ -104,24 +116,28 @@ export class AJAXError extends Error { } } -// Ensure that we're sending the correct referrer from blob URL worker bundles. -// For files loaded from the local file system, `location.origin` will be set -// to the string(!) "null" (Firefox), or "file://" (Chrome, Safari, Edge, IE), -// and we will set an empty referrer. Otherwise, we're using the document's URL. -/* global self */ -export const getReferrer = isWorker() ? - () => (self as any).worker && (self as any).worker.referrer : - () => (window.location.protocol === 'blob:' ? window.parent : window).location.href; +/** + * Ensure that we're sending the correct referrer from blob URL worker bundles. + * For files loaded from the local file system, `location.origin` will be set + * to the string(!) "null" (Firefox), or "file://" (Chrome, Safari, Edge), + * and we will set an empty referrer. Otherwise, we're using the document's URL. + */ +export const getReferrer = () => isWorker(self) ? + self.worker && self.worker.referrer : + (window.location.protocol === 'blob:' ? window.parent : window).location.href; export const getProtocolAction = url => config.REGISTERED_PROTOCOLS[url.substring(0, url.indexOf('://'))]; -// Determines whether a URL is a file:// URL. This is obviously the case if it begins -// with file://. Relative URLs are also file:// URLs iff the original document was loaded -// via a file:// URL. +/** + * Determines whether a URL is a file:// URL. This is obviously the case if it begins + * with file://. Relative URLs are also file:// URLs iff the original document was loaded + * via a file:// URL. + * @param url - The URL to check + * @returns `true` if the URL is a file:// URL, `false` otherwise + */ const isFileURL = url => /^file:/.test(url) || (/^file:/.test(getReferrer()) && !/^\w+:/.test(url)); -function makeFetchRequest(requestParameters: RequestParameters, callback: ResponseCallback): Cancelable { - const controller = new AbortController(); +async function makeFetchRequest(requestParameters: RequestParameters, abortController: AbortController): Promise> { const request = new Request(requestParameters.url, { method: requestParameters.method || 'GET', body: requestParameters.body, @@ -129,160 +145,142 @@ function makeFetchRequest(requestParameters: RequestParameters, callback: Respon headers: requestParameters.headers, cache: requestParameters.cache, referrer: getReferrer(), - signal: controller.signal + signal: abortController.signal }); - let complete = false; - let aborted = false; if (requestParameters.type === 'json') { request.headers.set('Accept', 'application/json'); } - const validateOrFetch = (err, cachedResponse?, responseIsFresh?) => { - if (aborted) return; + const response = await fetch(request); + if (!response.ok) { + const body = await response.blob(); + throw new AJAXError(response.status, response.statusText, requestParameters.url, body); + } + const parsePromise = (requestParameters.type === 'arrayBuffer' || requestParameters.type === 'image') ? response.arrayBuffer() : + requestParameters.type === 'json' ? response.json() : + response.text(); + const result = await parsePromise; + if (abortController.signal.aborted) { + throw createAbortError(); + } + return {data: result, cacheControl: response.headers.get('Cache-Control'), expires: response.headers.get('Expires')}; +} + +function makeXMLHttpRequest(requestParameters: RequestParameters, abortController: AbortController): Promise> { + return new Promise((resolve, reject) => { + const xhr: XMLHttpRequest = new XMLHttpRequest(); - if (err) { - // Do fetch in case of cache error. - // HTTP pages in Edge trigger a security error that can be ignored. - if (err.message !== 'SecurityError') { - warnOnce(err); - } + xhr.open(requestParameters.method || 'GET', requestParameters.url, true); + if (requestParameters.type === 'arrayBuffer' || requestParameters.type === 'image') { + xhr.responseType = 'arraybuffer'; } - - if (cachedResponse && responseIsFresh) { - return finishRequest(cachedResponse); + for (const k in requestParameters.headers) { + xhr.setRequestHeader(k, requestParameters.headers[k]); } - - if (cachedResponse) { - // We can't do revalidation with 'If-None-Match' because then the - // request doesn't have simple cors headers. + if (requestParameters.type === 'json') { + xhr.responseType = 'text'; + xhr.setRequestHeader('Accept', 'application/json'); } - - fetch(request).then(response => { - if (response.ok) { - return finishRequest(response); - - } else { - return response.blob().then(body => callback(new AJAXError(response.status, response.statusText, requestParameters.url, body))); - } - }).catch(error => { - if (error.code === 20) { - // silence expected AbortError + xhr.withCredentials = requestParameters.credentials === 'include'; + xhr.onerror = () => { + reject(new Error(xhr.statusText)); + }; + xhr.onload = () => { + if (abortController.signal.aborted) { return; } - callback(new Error(error.message)); - }); - }; - - const finishRequest = (response) => { - ( - (requestParameters.type === 'arrayBuffer' || requestParameters.type === 'image') ? response.arrayBuffer() : - requestParameters.type === 'json' ? response.json() : - response.text() - ).then(result => { - if (aborted) return; - complete = true; - callback(null, result, response.headers.get('Cache-Control'), response.headers.get('Expires')); - }).catch(err => { - if (!aborted) callback(new Error(err.message)); - }); - }; - - validateOrFetch(null, null); - - return {cancel: () => { - aborted = true; - if (!complete) controller.abort(); - }}; -} - -function makeXMLHttpRequest(requestParameters: RequestParameters, callback: ResponseCallback): Cancelable { - const xhr: XMLHttpRequest = new XMLHttpRequest(); - - xhr.open(requestParameters.method || 'GET', requestParameters.url, true); - if (requestParameters.type === 'arrayBuffer' || requestParameters.type === 'image') { - xhr.responseType = 'arraybuffer'; - } - for (const k in requestParameters.headers) { - xhr.setRequestHeader(k, requestParameters.headers[k]); - } - if (requestParameters.type === 'json') { - xhr.responseType = 'text'; - xhr.setRequestHeader('Accept', 'application/json'); - } - xhr.withCredentials = requestParameters.credentials === 'include'; - xhr.onerror = () => { - callback(new Error(xhr.statusText)); - }; - xhr.onload = () => { - if (((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) && xhr.response !== null) { - let data: unknown = xhr.response; - if (requestParameters.type === 'json') { - // We're manually parsing JSON here to get better error messages. - try { - data = JSON.parse(xhr.response); - } catch (err) { - return callback(err); + if (((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) && xhr.response !== null) { + let data: unknown = xhr.response; + if (requestParameters.type === 'json') { + // We're manually parsing JSON here to get better error messages. + try { + data = JSON.parse(xhr.response); + } catch (err) { + reject(err); + return; + } } + resolve({data, cacheControl: xhr.getResponseHeader('Cache-Control'), expires: xhr.getResponseHeader('Expires')}); + } else { + const body = new Blob([xhr.response], {type: xhr.getResponseHeader('Content-Type')}); + reject(new AJAXError(xhr.status, xhr.statusText, requestParameters.url, body)); } - callback(null, data, xhr.getResponseHeader('Cache-Control'), xhr.getResponseHeader('Expires')); - } else { - const body = new Blob([xhr.response], {type: xhr.getResponseHeader('Content-Type')}); - callback(new AJAXError(xhr.status, xhr.statusText, requestParameters.url, body)); - } - }; - xhr.send(requestParameters.body); - return {cancel: () => xhr.abort()}; + }; + abortController.signal.addEventListener('abort', () => { + xhr.abort(); + reject(createAbortError()); + }); + xhr.send(requestParameters.body); + }); } -export const makeRequest = function(requestParameters: RequestParameters, callback: ResponseCallback): Cancelable { - // We're trying to use the Fetch API if possible. However, in some situations we can't use it: - // - IE11 doesn't support it at all. In this case, we dispatch the request to the main thread so - // that we can get an accruate referrer header. - // - Safari exposes window.AbortController, but it doesn't work actually abort any requests in - // some versions (see https://bugs.webkit.org/show_bug.cgi?id=174980#c2) - // - Requests for resources with the file:// URI scheme don't work with the Fetch API either. In - // this case we unconditionally use XHR on the current thread since referrers don't matter. +/** + * We're trying to use the Fetch API if possible. However, requests for resources with the file:// URI scheme don't work with the Fetch API. + * In this case we unconditionally use XHR on the current thread since referrers don't matter. + * This method can also use the registered method if `addProtocol` was called. + * @param requestParameters - The request parameters + * @param abortController - The abort controller allowing to cancel the request + * @returns a promise resolving to the response, including cache control and expiry data + */ +export const makeRequest = function(requestParameters: RequestParameters, abortController: AbortController): Promise> { if (/:\/\//.test(requestParameters.url) && !(/^https?:|^file:/.test(requestParameters.url))) { - if (isWorker() && (self as any).worker && (self as any).worker.actor) { - return (self as any).worker.actor.send('getResource', requestParameters, callback); + if (isWorker(self) && self.worker && self.worker.actor) { + return self.worker.actor.sendAsync({type: 'getResource', data: requestParameters}, abortController); } - if (!isWorker()) { - const action = getProtocolAction(requestParameters.url) || makeFetchRequest; - return action(requestParameters, callback); + if (!isWorker(self) && getProtocolAction(requestParameters.url)) { + return promiseFromAddProtocolCallback(getProtocolAction(requestParameters.url))(requestParameters, abortController); } } if (!isFileURL(requestParameters.url)) { if (fetch && Request && AbortController && Object.prototype.hasOwnProperty.call(Request.prototype, 'signal')) { - return makeFetchRequest(requestParameters, callback); + return silenceOnAbort(makeFetchRequest(requestParameters, abortController), abortController); } - if (isWorker() && (self as any).worker && (self as any).worker.actor) { - const queueOnMainThread = true; - return (self as any).worker.actor.send('getResource', requestParameters, callback, undefined, queueOnMainThread); + if (isWorker(self) && self.worker && self.worker.actor) { + return self.worker.actor.sendAsync({type: 'getResource', data: requestParameters, mustQueue: true}, abortController); } } - return makeXMLHttpRequest(requestParameters, callback); + return makeXMLHttpRequest(requestParameters, abortController); }; -export const getJSON = function(requestParameters: RequestParameters, callback: ResponseCallback): Cancelable { - return makeRequest(extend(requestParameters, {type: 'json'}), callback); -}; +// This needs to be removed in general, see #3308 +function silenceOnAbort(promise: Promise, abortController: AbortController): Promise { + return new Promise((resolve, reject) => { + promise + .then(result => { if (!abortController.signal.aborted) resolve(result); }) + .catch(error => { if (!abortController.signal.aborted) reject(error); }); + }); +} + +function promiseFromAddProtocolCallback(method: (requestParameters: RequestParameters, callback: ResponseCallback) => Cancelable): (requestParameters: RequestParameters, abortController: AbortController) => Promise> { + return (requestParameters: RequestParameters, abortController: AbortController): Promise> => { + return new Promise>((resolve, reject) => { + const callback = (err: Error, data: any, cacheControl: string | null, expires: string | null) => { + if (err) { + reject(err); + } else { + resolve({data, cacheControl, expires}); + } + }; + const canelable = method(requestParameters, callback); + abortController.signal.addEventListener('abort', () => { + canelable.cancel(); + reject(createAbortError()); + }); + }); + }; +} -export const getArrayBuffer = function( - requestParameters: RequestParameters, - callback: ResponseCallback -): Cancelable { - return makeRequest(extend(requestParameters, {type: 'arrayBuffer'}), callback); +export const getJSON = (requestParameters: RequestParameters, abortController: AbortController): Promise<{data: T} & ExpiryData> => { + return makeRequest(extend(requestParameters, {type: 'json'}), abortController); }; -export const postData = function(requestParameters: RequestParameters, callback: ResponseCallback): Cancelable { - return makeRequest(extend(requestParameters, {method: 'POST'}), callback); +export const getArrayBuffer = (requestParameters: RequestParameters, abortController: AbortController): Promise<{data: ArrayBuffer} & ExpiryData> => { + return makeRequest(extend(requestParameters, {type: 'arrayBuffer'}), abortController); }; export function sameOrigin(inComingUrl: string) { - // URL class should be available everywhere - // https://developer.mozilla.org/en-US/docs/Web/API/URL - // In addtion, a relative URL "/foo" or "./foo" will throw exception in its ctor, + // A relative URL "/foo" or "./foo" will throw exception in URL's ctor, // try-catch is expansive so just use a heuristic check to avoid it // also check data URL if (!inComingUrl || @@ -295,23 +293,21 @@ export function sameOrigin(inComingUrl: string) { const locationObj = window.location; return urlObj.protocol === locationObj.protocol && urlObj.host === locationObj.host; } -/** - * A type used to store the tile's expiration date and cache control definition - */ -export type ExpiryData = {cacheControl?: string | null; expires?: Date | string | null}; -export const getVideo = function(urls: Array, callback: Callback): Cancelable { + +export const getVideo = (urls: Array): Promise => { const video: HTMLVideoElement = window.document.createElement('video'); video.muted = true; - video.onloadstart = function() { - callback(null, video); - }; - for (let i = 0; i < urls.length; i++) { - const s: HTMLSourceElement = window.document.createElement('source'); - if (!sameOrigin(urls[i])) { - video.crossOrigin = 'Anonymous'; + return new Promise((resolve) => { + video.onloadstart = () => { + resolve(video); + }; + for (const url of urls) { + const s: HTMLSourceElement = window.document.createElement('source'); + if (!sameOrigin(url)) { + video.crossOrigin = 'Anonymous'; + } + s.src = url; + video.appendChild(s); } - s.src = urls[i]; - video.appendChild(s); - } - return {cancel: () => {}}; + }); }; diff --git a/src/util/browser.ts b/src/util/browser.ts index 6ba3b6f1e7..bf2c2a0e1d 100755 --- a/src/util/browser.ts +++ b/src/util/browser.ts @@ -1,3 +1,4 @@ +import {createAbortError} from './abort_error'; import type {Cancelable} from '../types/cancelable'; const now = typeof performance !== 'undefined' && performance && performance.now ? @@ -21,6 +22,16 @@ export const browser = { return {cancel: () => cancelAnimationFrame(frame)}; }, + frameAsync(abortController: AbortController): Promise { + return new Promise((resolve, reject) => { + const frame = requestAnimationFrame(resolve); + abortController.signal.addEventListener('abort', () => { + cancelAnimationFrame(frame); + reject(createAbortError()); + }); + }); + }, + getImageData(img: HTMLImageElement | ImageBitmap, padding: number = 0): ImageData { const context = this.getImageCanvasContext(img); return context.getImageData(-padding, -padding, img.width as number + 2 * padding, img.height as number + 2 * padding); diff --git a/src/util/dispatcher.test.ts b/src/util/dispatcher.test.ts index c1e78a0dee..7c3fe66c6b 100644 --- a/src/util/dispatcher.test.ts +++ b/src/util/dispatcher.test.ts @@ -17,7 +17,7 @@ describe('Dispatcher', () => { } } as any as WorkerPool; - const dispatcher = new Dispatcher(workerPool, {} as any, mapId); + const dispatcher = new Dispatcher(workerPool, mapId); expect(dispatcher.actors.map((actor) => { return actor.target; })).toEqual(workers); dispatcher.remove(); expect(dispatcher.actors).toHaveLength(0); @@ -42,7 +42,7 @@ describe('Dispatcher', () => { } } as any as WorkerPool; - let dispatcher = new Dispatcher(workerPool, {} as any, mapId); + let dispatcher = new Dispatcher(workerPool, mapId); expect(dispatcher.actors.map((actor) => { return actor.target; })).toEqual(workers); // Remove dispatcher, but map is not disposed (During style change) @@ -51,7 +51,7 @@ describe('Dispatcher', () => { expect(releaseCalled).toHaveLength(0); // Create new instance of dispatcher - dispatcher = new Dispatcher(workerPool, {} as any, mapId); + dispatcher = new Dispatcher(workerPool, mapId); expect(dispatcher.actors.map((actor) => { return actor.target; })).toEqual(workers); dispatcher.remove(true); // mapRemoved = true expect(dispatcher.actors).toHaveLength(0); @@ -67,7 +67,7 @@ describe('Dispatcher', () => { WorkerPool.workerCount = 4; const workerPool = new WorkerPool(); - const dispatcher = new Dispatcher(workerPool, {} as any, mapId); + const dispatcher = new Dispatcher(workerPool, mapId); dispatcher.remove(); expect(actorsRemoved).toHaveLength(4); }); diff --git a/src/util/dispatcher.ts b/src/util/dispatcher.ts index fd9b15dc42..70baa75fd8 100644 --- a/src/util/dispatcher.ts +++ b/src/util/dispatcher.ts @@ -1,8 +1,8 @@ -import {asyncAll} from './util'; -import {Actor, GlyphsProvider, MessageType} from './actor'; +import {Actor, MessageHandler} from './actor'; import type {WorkerPool} from './worker_pool'; import type {WorkerSource} from '../source/worker_source'; /* eslint-disable-line */ // this is used for the docs' import +import type {MessageType, RequestResponseMessageMap} from './actor_messages'; /** * Responsible for sending messages from a {@link Source} to an associated * {@link WorkerSource}. @@ -13,7 +13,7 @@ export class Dispatcher { currentActor: number; id: string | number; - constructor(workerPool: WorkerPool, parent: GlyphsProvider, mapId: string | number) { + constructor(workerPool: WorkerPool, mapId: string | number) { this.workerPool = workerPool; this.actors = []; this.currentActor = 0; @@ -21,7 +21,7 @@ export class Dispatcher { const workers = this.workerPool.acquire(mapId); for (let i = 0; i < workers.length; i++) { const worker = workers[i]; - const actor = new Actor(worker, parent, mapId); + const actor = new Actor(worker, mapId); actor.name = `Worker ${i}`; this.actors.push(actor); } @@ -31,11 +31,12 @@ export class Dispatcher { /** * Broadcast a message to all Workers. */ - broadcast(type: MessageType, data: unknown, cb?: (...args: any[]) => any) { - cb = cb || function () {}; - asyncAll(this.actors, (actor, done) => { - actor.send(type, data, done); - }, cb); + broadcast(type: T, data: RequestResponseMessageMap[T][0]): Promise { + const promises: Promise[] = []; + for (const actor of this.actors) { + promises.push(actor.sendAsync({type, data})); + } + return Promise.all(promises); } /** @@ -52,4 +53,10 @@ export class Dispatcher { this.actors = []; if (mapRemoved) this.workerPool.release(this.id); } + + public registerMessageHandler(type: T, handler: MessageHandler) { + for (const actor of this.actors) { + actor.registerMessageHandler(type, handler); + } + } } diff --git a/src/util/geolocation_support.test.ts b/src/util/geolocation_support.test.ts index 7641a40471..45f0ff6106 100644 --- a/src/util/geolocation_support.test.ts +++ b/src/util/geolocation_support.test.ts @@ -5,51 +5,39 @@ describe('checkGeolocationSupport', () => { jest.resetModules(); }); - test('it should return false if geolocation is not defined', done => { - checkGeolocationSupport((returnValue: boolean) => { - expect(returnValue).toBeFalsy(); - done(); - }); + test('it should return false if geolocation is not defined', async () => { + await expect(checkGeolocationSupport()).resolves.toBeFalsy(); }); - test('it should return the cached value on second call', done => { - checkGeolocationSupport((returnValue) => { - expect(returnValue).toBeFalsy(); - (window.navigator as any).geolocation = {}; - checkGeolocationSupport((rv) => { - expect(rv).toBe(returnValue); - done(); - }); - }); + test('it should return the cached value on second call', async () => { + const returnValue = await checkGeolocationSupport(); + expect(returnValue).toBeFalsy(); + (window.navigator as any).geolocation = {}; + const rv = await checkGeolocationSupport(); + expect(rv).toBe(returnValue); }); - test('it should return the true if geolocation is defined', done => { + test('it should return the true if geolocation is defined', async () => { (window.navigator as any).geolocation = {}; - checkGeolocationSupport((returnValue) => { - expect(returnValue).toBeTruthy(); - done(); - }, true); + const returnValue = await checkGeolocationSupport(true); + expect(returnValue).toBeTruthy(); }); - test('it should check permissions if possible', done => { + test('it should check permissions if possible', async () => { (window.navigator as any).geolocation = {}; (window.navigator as any).permissions = { query: () => Promise.resolve({state: 'granted'}) }; - checkGeolocationSupport((returnValue) => { - expect(returnValue).toBeTruthy(); - done(); - }, true); + const returnValue = await checkGeolocationSupport(true); + expect(returnValue).toBeTruthy(); }); - test('it should check permissions and geolocation for iOS 16 promise rejection', done => { + test('it should check permissions and geolocation for iOS 16 promise rejection', async () => { (window.navigator as any).geolocation = undefined; (window.navigator as any).permissions = { query: () => Promise.reject(new Error('pemissions error')) }; - checkGeolocationSupport((returnValue) => { - expect(returnValue).toBeFalsy(); - done(); - }, true); + const returnValue = await checkGeolocationSupport(true); + expect(returnValue).toBeFalsy(); }); }); diff --git a/src/util/geolocation_support.ts b/src/util/geolocation_support.ts index d64940a0a0..e0da3c3f94 100644 --- a/src/util/geolocation_support.ts +++ b/src/util/geolocation_support.ts @@ -1,24 +1,23 @@ let supportsGeolocation; -export function checkGeolocationSupport(callback: (supported: boolean) => void, forceRecalculation = false): void { +export async function checkGeolocationSupport(forceRecalculation = false): Promise { if (supportsGeolocation !== undefined && !forceRecalculation) { - callback(supportsGeolocation); - } else if (window.navigator.permissions !== undefined) { - // navigator.permissions has incomplete browser support - // http://caniuse.com/#feat=permissions-api - // Test for the case where a browser disables Geolocation because of an - // insecure origin - window.navigator.permissions.query({name: 'geolocation'}).then((p) => { - supportsGeolocation = p.state !== 'denied'; - callback(supportsGeolocation); - }).catch(() => { - // Fix for iOS16 which rejects query but still supports geolocation - supportsGeolocation = !!window.navigator.geolocation; - callback(supportsGeolocation); - }); - - } else { + return supportsGeolocation; + } + if (window.navigator.permissions === undefined) { supportsGeolocation = !!window.navigator.geolocation; - callback(supportsGeolocation); + return supportsGeolocation; + } + // navigator.permissions has incomplete browser support + // http://caniuse.com/#feat=permissions-api + // Test for the case where a browser disables Geolocation because of an + // insecure origin + try { + const permissions = await window.navigator.permissions.query({name: 'geolocation'}); + supportsGeolocation = permissions.state !== 'denied'; // eslint-disable-line require-atomic-updates + } catch { + // Fix for iOS16 which rejects query but still supports geolocation + supportsGeolocation = !!window.navigator.geolocation; // eslint-disable-line require-atomic-updates } + return supportsGeolocation; } diff --git a/src/util/image.ts b/src/util/image.ts index 27b13c815d..b3878dc06b 100644 --- a/src/util/image.ts +++ b/src/util/image.ts @@ -82,7 +82,6 @@ function copyImage(srcImg: any, dstImg: any, srcPt: Point2D, dstPt: Point2D, siz } /** - * @internal * An image with alpha color value */ export class AlphaImage { diff --git a/src/util/image_request.test.ts b/src/util/image_request.test.ts index b1f9724883..93ffca8252 100644 --- a/src/util/image_request.test.ts +++ b/src/util/image_request.test.ts @@ -1,8 +1,9 @@ import {config} from './config'; import {webpSupported} from './webp_supported'; -import {stubAjaxGetImage} from './test/util'; +import {sleep, stubAjaxGetImage} from './test/util'; import {fakeServer, type FakeServer} from 'nise'; -import {ImageRequest, ImageRequestQueueItem} from './image_request'; +import {ImageRequest} from './image_request'; +import {isAbortError} from './abort_error'; import * as ajax from './ajax'; describe('ImageRequest', () => { @@ -17,73 +18,86 @@ describe('ImageRequest', () => { server.restore(); }); - test('getImage respects maxParallelImageRequests', done => { + test('getImage respects maxParallelImageRequests', async () => { server.respondWith(request => request.respond(200, {'Content-Type': 'image/png'}, '')); const maxRequests = config.MAX_PARALLEL_IMAGE_REQUESTS; - let callbackCount = 0; - function callback(err) { - if (err) return; - // last request is only added after we got a response from one of the previous ones - expect(server.requests).toHaveLength(maxRequests + callbackCount); - callbackCount++; - if (callbackCount === 2) { - done(); - } - } - for (let i = 0; i < maxRequests + 1; i++) { - ImageRequest.getImage({url: ''}, callback); + const promises: Promise[] = []; + for (let i = 0; i < maxRequests + 5; i++) { + promises.push(ImageRequest.getImage({url: ''}, new AbortController())); + } expect(server.requests).toHaveLength(maxRequests); - server.requests[0].respond(undefined, undefined, undefined); - server.requests[1].respond(undefined, undefined, undefined); + server.requests[0].respond(200); + await promises[0]; + expect(server.requests).toHaveLength(maxRequests + 1); + server.requests[1].respond(200); + await promises[1]; + expect(server.requests).toHaveLength(maxRequests + 2); + }); + + test('getImage respects maxParallelImageRequests and continues to respond even when server returns 404', async () => { + server.respondWith(request => request.respond(404)); + + const maxRequests = config.MAX_PARALLEL_IMAGE_REQUESTS; + + for (let i = 0; i < maxRequests + 5; i++) { + ImageRequest.getImage({url: ''}, new AbortController()).catch(() => {}); + } + expect(server.requests).toHaveLength(maxRequests); + server.respond(); + await sleep(0); + expect(server.requests).toHaveLength(maxRequests + 5); }); - test('Cancel: getImage cancelling frees up request for maxParallelImageRequests', done => { - server.respondWith(request => request.respond(200, {'Content-Type': 'image/png'}, '')); + test('Cancel: getImage cancelling frees up request for maxParallelImageRequests', async () => { const maxRequests = config.MAX_PARALLEL_IMAGE_REQUESTS; for (let i = 0; i < maxRequests + 1; i++) { - ImageRequest.getImage({url: ''}, () => done('test failed: getImage callback was called')).cancel(); + const abortController = new AbortController(); + ImageRequest.getImage({url: ''}, abortController).catch((e) => expect(isAbortError(e)).toBeTruthy()); + abortController.abort(); + await sleep(0); } expect(server.requests).toHaveLength(maxRequests + 1); - done(); }); - test('Cancel: getImage requests that were once queued are still abortable', done => { + test('Cancel: getImage requests that were once queued are still abortable', async () => { const maxRequests = config.MAX_PARALLEL_IMAGE_REQUESTS; - const requests = []; + const abortControllers: AbortController[] = []; for (let i = 0; i < maxRequests; i++) { - requests.push(ImageRequest.getImage({url: ''}, () => {})); + const abortController = new AbortController(); + abortControllers.push(abortController); + ImageRequest.getImage({url: ''}, abortController).catch(() => {}); } // the limit of allowed requests is reached expect(server.requests).toHaveLength(maxRequests); const queuedURL = 'this-is-the-queued-request'; - const queued = ImageRequest.getImage({url: queuedURL}, () => done('test failed: getImage callback was called')); + const abortController = new AbortController(); + ImageRequest.getImage({url: queuedURL}, abortController).catch((e) => expect(isAbortError(e)).toBeTruthy()); // the new requests is queued because the limit is reached expect(server.requests).toHaveLength(maxRequests); // cancel the first request to let the queued request start - requests[0].cancel(); + abortControllers[0].abort(); + await sleep(0); expect(server.requests).toHaveLength(maxRequests + 1); // abort the previously queued request and confirm that it is aborted const queuedRequest = server.requests[server.requests.length - 1]; expect(queuedRequest.url).toBe(queuedURL); expect((queuedRequest as any).aborted).toBeUndefined(); - queued.cancel(); + abortController.abort(); expect((queuedRequest as any).aborted).toBe(true); - - done(); }); - test('getImage sends accept/webp when supported', done => { + test('getImage sends accept/webp when supported', async () => { server.respondWith((request) => { expect(request.requestHeaders.accept.includes('image/webp')).toBeTruthy(); request.respond(200, {'Content-Type': 'image/webp'}, ''); @@ -92,133 +106,123 @@ describe('ImageRequest', () => { // mock webp support webpSupported.supported = true; - ImageRequest.getImage({url: ''}, () => { done(); }); + const promise = ImageRequest.getImage({url: ''}, new AbortController()); server.respond(); + + await expect(promise).resolves.toBeDefined(); }); - test('getImage uses createImageBitmap when supported', done => { + test('getImage uses createImageBitmap when supported', async () => { server.respondWith(request => request.respond(200, {'Content-Type': 'image/png', 'Cache-Control': 'cache', 'Expires': 'expires'}, '')); stubAjaxGetImage(() => Promise.resolve(new ImageBitmap())); + const promise = ImageRequest.getImage({url: ''}, new AbortController()); + server.respond(); - ImageRequest.getImage({url: ''}, (err, img, expiry) => { - if (err) done(err); - expect(img).toBeInstanceOf(ImageBitmap); - expect(expiry.cacheControl).toBe('cache'); - expect(expiry.expires).toBe('expires'); - done(); - }); + const response = await promise; - server.respond(); + expect(response.data).toBeInstanceOf(ImageBitmap); + expect(response.cacheControl).toBe('cache'); + expect(response.expires).toBe('expires'); }); - test('getImage using createImageBitmap throws exception', done => { + test('getImage using createImageBitmap throws exception', async () => { server.respondWith(request => request.respond(200, {'Content-Type': 'image/png', 'Cache-Control': 'cache', 'Expires': 'expires'}, '')); stubAjaxGetImage(() => Promise.reject(new Error('error'))); - ImageRequest.getImage({url: ''}, (err, img) => { - expect(img).toBeFalsy(); - if (err) done(); - }); + const promise = ImageRequest.getImage({url: ''}, new AbortController()); server.respond(); + + await expect(promise).rejects.toThrow(); }); - test('getImage uses HTMLImageElement when createImageBitmap is not supported', done => { + test('getImage uses HTMLImageElement when createImageBitmap is not supported', async () => { const makeRequestSky = jest.spyOn(ajax, 'makeRequest'); server.respondWith(request => request.respond(200, {'Content-Type': 'image/png', 'Cache-Control': 'cache', 'Expires': 'expires'}, '')); - ImageRequest.getImage({url: ''}, (err, img, expiry) => { - if (err) done(`get image failed with error ${err.message}`); - expect(img).toBeInstanceOf(HTMLImageElement); - expect(expiry.cacheControl).toBe('cache'); - expect(expiry.expires).toBe('expires'); - done(); - }); + const promise = ImageRequest.getImage({url: ''}, new AbortController()); server.respond(); expect(makeRequestSky).toHaveBeenCalledTimes(1); makeRequestSky.mockClear(); + const response = await promise; + expect(response.data).toBeInstanceOf(HTMLImageElement); + expect(response.cacheControl).toBe('cache'); + expect(response.expires).toBe('expires'); }); - test('getImage using HTMLImageElement with same-origin credentials', done => { + test('getImage using HTMLImageElement with same-origin credentials', async () => { const makeRequestSky = jest.spyOn(ajax, 'makeRequest'); - ImageRequest.getImage({url: '', credentials: 'same-origin'}, (err, img: HTMLImageElement) => { - if (err) done(err); - expect(img).toBeInstanceOf(HTMLImageElement); - expect(img.crossOrigin).toBe('anonymous'); - done(); - }, false); + const promise = ImageRequest.getImage({url: '', credentials: 'same-origin'}, new AbortController(), false); expect(makeRequestSky).toHaveBeenCalledTimes(0); makeRequestSky.mockClear(); + + const response = await promise; + + expect(response.data).toBeInstanceOf(HTMLImageElement); + expect((response.data as HTMLImageElement).crossOrigin).toBe('anonymous'); }); - test('getImage using HTMLImageElement with include credentials', done => { + test('getImage using HTMLImageElement with include credentials', async () => { const makeRequestSky = jest.spyOn(ajax, 'makeRequest'); - ImageRequest.getImage({url: '', credentials: 'include'}, (err, img: HTMLImageElement) => { - if (err) done(err); - expect(img).toBeInstanceOf(HTMLImageElement); - expect(img.crossOrigin).toBe('use-credentials'); - done(); - }, false); + const promise = ImageRequest.getImage({url: '', credentials: 'include'}, new AbortController(), false); expect(makeRequestSky).toHaveBeenCalledTimes(0); makeRequestSky.mockClear(); + + const response = await promise; + + expect(response.data).toBeInstanceOf(HTMLImageElement); + expect((response.data as HTMLImageElement).crossOrigin).toBe('use-credentials'); }); - test('getImage using HTMLImageElement with accept header', done => { + test('getImage using HTMLImageElement with accept header', async () => { const makeRequestSky = jest.spyOn(ajax, 'makeRequest'); - ImageRequest.getImage({url: '', credentials: 'include', headers: {accept: 'accept'}}, - (err, img: HTMLImageElement) => { - if (err) done(err); - expect(img).toBeInstanceOf(HTMLImageElement); - expect(img.crossOrigin).toBe('use-credentials'); - done(); - }, false); + const promise = ImageRequest.getImage({url: '', credentials: 'include', headers: {accept: 'accept'}}, new AbortController(), false); expect(makeRequestSky).toHaveBeenCalledTimes(0); makeRequestSky.mockClear(); + + const response = await promise; + expect(response.data).toBeInstanceOf(HTMLImageElement); + expect((response.data as HTMLImageElement).crossOrigin).toBe('use-credentials'); }); test('getImage uses makeRequest when custom Headers are added', () => { const makeRequestSky = jest.spyOn(ajax, 'makeRequest'); - ImageRequest.getImage({url: '', credentials: 'include', headers: {custom: 'test', accept: 'image'}}, - () => {}, - false); + ImageRequest.getImage({url: '', credentials: 'include', headers: {custom: 'test', accept: 'image'}}, new AbortController(), false); expect(makeRequestSky).toHaveBeenCalledTimes(1); makeRequestSky.mockClear(); }); - test('getImage request returned 404 response for fetch request', done => { + test('getImage request returned 404 response for fetch request', async () => { server.respondWith(request => request.respond(404)); - ImageRequest.getImage({url: ''}, (err) => { - if (err) done(); - else done('Image download should have failed'); - }); + const promise = ImageRequest.getImage({url: ''}, new AbortController()); server.respond(); + + await expect(promise).rejects.toThrow('Not Found'); }); - test('getImage request failed for HTTPImageRequest', done => { - ImageRequest.getImage({url: 'error'}, (err) => { - if (err) done(); - else done('Image download should have failed'); - }, false); + test('getImage request failed for HTTPImageRequest', async () => { + const promise = ImageRequest.getImage({url: 'error'}, new AbortController(), false); + await expect(promise).rejects.toThrow(/Could not load image.*/); }); - test('Cancel: getImage request cancelled for HTTPImageRequest', done => { + test('Cancel: getImage request cancelled for HTTPImageRequest', async () => { let imageUrl; const requestUrl = 'test'; // eslint-disable-next-line accessor-pairs @@ -228,51 +232,50 @@ describe('ImageRequest', () => { } }); - const request = ImageRequest.getImage({url: requestUrl}, () => { - done('Callback should not be called in case image request is cancelled'); - }, false); + const abortController = new AbortController(); + ImageRequest.getImage({url: requestUrl}, abortController, false).catch(() => {}); expect(imageUrl).toBe(requestUrl); - expect(request.cancelled).toBeFalsy(); - request.cancel(); - expect(request.cancelled).toBeTruthy(); + expect(abortController.signal.aborted).toBeFalsy(); + abortController.abort(); + expect(abortController.signal.aborted).toBeTruthy(); expect(imageUrl).toBe(''); - done(); }); - test('Cancel: getImage request cancelled', done => { + test('Cancel: getImage request cancelled', async () => { server.respondWith(request => request.respond(200, {'Content-Type': 'image/png', 'Cache-Control': 'cache', 'Expires': 'expires'}, '')); - const request = ImageRequest.getImage({url: ''}, () => { - done('Callback should not be called in case image request is cancelled'); - }); + const abortController = new AbortController(); + let response = false; + ImageRequest.getImage({url: ''}, abortController) + .then(() => { response = true; }) + .catch(() => { response = true; }); - expect(request.cancelled).toBeFalsy(); - request.cancel(); - expect(request.cancelled).toBeTruthy(); + abortController.abort(); server.respond(); - done(); + + expect(response).toBeFalsy(); }); - test('Cancel: Cancellation of an image which has not yet been requested', () => { + test('Cancel: Cancellation of an image which has not yet been requested', async () => { const maxRequests = config.MAX_PARALLEL_IMAGE_REQUESTS; let callbackCounter = 0; - function callback() { - callbackCounter++; - } - const requests: ImageRequestQueueItem[] = []; + const promiseCallback = () => { callbackCounter++; }; + + const abortConstollers: {url: string; abortController: AbortController}[] = []; for (let i = 0; i < maxRequests + 100; i++) { - requests.push(ImageRequest.getImage({url: `${i}`}, callback)); + const url = `${i}`; + const abortController = new AbortController(); + abortConstollers.push({url, abortController}); + ImageRequest.getImage({url}, abortController).then(promiseCallback).catch(() => {}); } - // Request should have been initiated - expect(requests[0].innerRequest).toBeDefined(); - requests[0].cancel(); - + abortConstollers[0].abortController.abort(); + await sleep(0); // Queue should move forward and next request is made expect(server.requests).toHaveLength(maxRequests + 1); @@ -280,10 +283,9 @@ describe('ImageRequest', () => { expect(callbackCounter).toBe(0); // Cancel request which is not yet issued. It should not fire callback - const nextRequestInQueue = requests[server.requests.length]; - expect(nextRequestInQueue.innerRequest).toBeUndefined(); - const cancelledImageUrl = nextRequestInQueue.requestParameters.url; - nextRequestInQueue.cancel(); + const nextRequestInQueue = abortConstollers[server.requests.length]; + const cancelledImageUrl = nextRequestInQueue.url; + nextRequestInQueue.abortController.abort(); // Queue should not move forward as cancelled image was sitting in queue expect(server.requests).toHaveLength(maxRequests + 1); @@ -291,6 +293,7 @@ describe('ImageRequest', () => { // On server response, next image queued should not be the cancelled image server.requests[1].respond(200); + await sleep(0); expect(callbackCounter).toBe(1); expect(server.requests).toHaveLength(maxRequests + 2); // Verify that the last request made skipped the cancelled image request @@ -306,12 +309,10 @@ describe('ImageRequest', () => { callbackHandles.push(ImageRequest.addThrottleControl(() => true)); let callbackCounter = 0; - function callback() { - callbackCounter++; - } + const promiseCallback = () => { callbackCounter++; }; for (let i = 0; i < maxRequestsPerFrame + 1; i++) { - ImageRequest.getImage({url: ''}, callback); + ImageRequest.getImage({url: ''}, new AbortController()).then(promiseCallback); } expect(server.requests).toHaveLength(maxRequestsPerFrame); @@ -330,12 +331,10 @@ describe('ImageRequest', () => { const controlId = ImageRequest.addThrottleControl(() => true); let callbackCounter = 0; - function callback() { - callbackCounter++; - } + const promiseCallback = () => { callbackCounter++; }; for (let i = 0; i < maxRequests; i++) { - ImageRequest.getImage({url: ''}, callback); + ImageRequest.getImage({url: ''}, new AbortController()).then(promiseCallback); } // Should only fire request to a max allowed per frame @@ -352,12 +351,10 @@ describe('ImageRequest', () => { const controlId = ImageRequest.addThrottleControl(() => false); let callbackCounter = 0; - function callback() { - callbackCounter++; - } + const promiseCallback = () => { callbackCounter++; }; for (let i = 0; i < maxRequests + 100; i++) { - ImageRequest.getImage({url: ''}, callback); + ImageRequest.getImage({url: ''}, new AbortController()).then(promiseCallback); } // all should be processed because throttle control is returning false @@ -369,7 +366,7 @@ describe('ImageRequest', () => { ImageRequest.removeThrottleControl(controlId); }); - test('throttling: removing throttling client will process all requests', () => { + test('throttling: removing throttling client will process all requests', async () => { const requestParameter = {'Content-Type': 'image/png', url: ''}; const maxRequestsPerFrame = config.MAX_PARALLEL_IMAGE_REQUESTS_PER_FRAME; @@ -380,16 +377,13 @@ describe('ImageRequest', () => { ImageRequest.addThrottleControl(() => throttlingClient); } - let callbackCounter = 0; - function callback() { - callbackCounter++; - } - // make 2 times + 1 more requests const requestsMade = 2 * maxRequestsPerFrame + 1; - const imageResults: ImageRequestQueueItem[] = []; + const completedMap: {[index: number]: boolean} = {}; for (let i = 0; i < requestsMade; i++) { - imageResults.push(ImageRequest.getImage(requestParameter, callback)); + const promise = ImageRequest.getImage(requestParameter, new AbortController()); + promise.catch(() => {}); + promise.then(() => { completedMap[i] = true; }); } // up to the config value @@ -400,14 +394,15 @@ describe('ImageRequest', () => { // unleash it by removing the throttling client ImageRequest.removeThrottleControl(throttlingIndex); + await sleep(0); expect(server.requests).toHaveLength(requestsMade); // all pending - expect(callbackCounter).toBe(1); + expect(Object.keys(completedMap)).toHaveLength(1); // everything should still be pending except itemIndexToComplete for (let i = 0; i < maxRequestsPerFrame + 1; i++) { - expect(imageResults[i].completed).toBe(i === itemIndexToComplete); + expect(completedMap[i]).toBe(i === itemIndexToComplete ? true : undefined); } }); }); diff --git a/src/util/image_request.ts b/src/util/image_request.ts index e00b395e1f..c8c0163161 100644 --- a/src/util/image_request.ts +++ b/src/util/image_request.ts @@ -1,10 +1,9 @@ -import type {Cancelable} from '../types/cancelable'; -import {RequestParameters, ExpiryData, makeRequest, sameOrigin, getProtocolAction} from './ajax'; -import type {Callback} from '../types/callback'; +import {RequestParameters, ExpiryData, makeRequest, sameOrigin, getProtocolAction, GetResourceResponse} from './ajax'; import {arrayBufferToImageBitmap, arrayBufferToImage, extend, isWorker, isImageBitmap} from './util'; import {webpSupported} from './webp_supported'; import {config} from './config'; +import {createAbortError} from './abort_error'; /** * The callback that is being called after an image was fetched @@ -13,13 +12,13 @@ export type GetImageCallback = (error?: Error | null, image?: HTMLImageElement | type ImageQueueThrottleControlCallback = () => boolean; -export type ImageRequestQueueItem = Cancelable & { +export type ImageRequestQueueItem = { requestParameters: RequestParameters; supportImageRefresh: boolean; - callback: GetImageCallback; - cancelled: boolean; - completed: boolean; - innerRequest?: Cancelable; + state: 'queued' | 'running' | 'completed'; + abortController: AbortController; + onError: (error: Error) => void; + onSuccess: (response: GetResourceResponse) => void; } type ImageQueueThrottleCallbackDictionary = { @@ -95,78 +94,60 @@ export namespace ImageRequest { * @returns `true` if any callback is causing the queue to be throttled. */ const isThrottled = (): boolean => { - const allControlKeys = Object.keys(throttleControlCallbacks); - let throttleingRequested = false; - if (allControlKeys.length > 0) { - for (const key of allControlKeys) { - throttleingRequested = throttleControlCallbacks[key](); - if (throttleingRequested) { - break; - } + for (const key of Object.keys(throttleControlCallbacks)) { + if (throttleControlCallbacks[key]()) { + return true; } } - return throttleingRequested; + return false; }; /** * Request to load an image. * @param requestParameters - Request parameters. - * @param callback - Callback to issue when the request completes. + * @param abortController - allows to abort the request. * @param supportImageRefresh - `true`, if the image request need to support refresh based on cache headers. - * @returns Cancelable request. + * @returns - A promise resolved when the image is loaded. */ - export const getImage = ( - requestParameters: RequestParameters, - callback: GetImageCallback, - supportImageRefresh: boolean = true - ): ImageRequestQueueItem => { - if (webpSupported.supported) { - if (!requestParameters.headers) { - requestParameters.headers = {}; - } - requestParameters.headers.accept = 'image/webp,*/*'; - } - - const request:ImageRequestQueueItem = { - requestParameters, - supportImageRefresh, - callback, - cancelled: false, - completed: false, - cancel: () => { - if (!request.completed && !request.cancelled) { - request.cancelled = true; - - // Only reduce currentParallelImageRequests, if the image request was issued. - if (request.innerRequest) { - request.innerRequest.cancel(); - currentParallelImageRequests--; - } - - // in the case of cancelling, it WILL move on - processQueue(); + export const getImage = (requestParameters: RequestParameters, abortController: AbortController, supportImageRefresh: boolean = true): Promise> => { + return new Promise>((resolve, reject) => { + if (webpSupported.supported) { + if (!requestParameters.headers) { + requestParameters.headers = {}; } + requestParameters.headers.accept = 'image/webp,*/*'; } - }; + extend(requestParameters, {type: 'image'}); + const request: ImageRequestQueueItem = { + abortController, + requestParameters, + supportImageRefresh, + state: 'queued', + onError: (error: Error) => { + reject(error); + }, + onSuccess: (response) => { + resolve(response); + } + }; - imageRequestQueue.push(request); - processQueue(); - return request; + imageRequestQueue.push(request); + processQueue(); + }); }; - const arrayBufferToCanvasImageSource = (data: ArrayBuffer, callback: Callback) => { + const arrayBufferToCanvasImageSource = (data: ArrayBuffer): Promise => { const imageBitmapSupported = typeof createImageBitmap === 'function'; if (imageBitmapSupported) { - arrayBufferToImageBitmap(data, callback); + return arrayBufferToImageBitmap(data); } else { - arrayBufferToImage(data, callback); + return arrayBufferToImage(data); } }; - const doImageRequest = (itemInQueue: ImageRequestQueueItem): Cancelable => { - const {requestParameters, supportImageRefresh, callback} = itemInQueue; - extend(requestParameters, {type: 'image'}); - + const doImageRequest = async (itemInQueue: ImageRequestQueueItem) => { + itemInQueue.state = 'running'; + const {requestParameters, supportImageRefresh, onError, onSuccess, abortController} = itemInQueue; // - If refreshExpiredTiles is false, then we can use HTMLImageElement to download raster images. // - Fetch/XHR (via MakeRequest API) will be used to download images for following scenarios: // 1. Style image sprite will had a issue with HTMLImageElement as described @@ -177,49 +158,34 @@ export namespace ImageRequest { // let makeRequest handle it. // - HtmlImageElement request automatically adds accept header for all the browser supported images const canUseHTMLImageElement = supportImageRefresh === false && - !isWorker() && + !isWorker(self) && !getProtocolAction(requestParameters.url) && (!requestParameters.headers || Object.keys(requestParameters.headers).reduce((acc, item) => acc && item === 'accept', true)); - const action = canUseHTMLImageElement ? getImageUsingHtmlImage : makeRequest; - return action( - requestParameters, - (err?: Error | null, - data?: HTMLImageElement | ImageBitmap | ArrayBuffer | null, - cacheControl?: string | null, - expires?: string | null) => { - onImageResponse(itemInQueue, callback, err, data, cacheControl, expires); - }); - }; - - const onImageResponse = ( - itemInQueue: ImageRequestQueueItem, - callback:GetImageCallback, - err?: Error | null, - data?: HTMLImageElement | ImageBitmap | ArrayBuffer | null, - cacheControl?: string | null, - expires?: string | null): void => { - if (err) { - callback(err); - } else if (data instanceof HTMLImageElement || isImageBitmap(data)) { - // User using addProtocol can directly return HTMLImageElement/ImageBitmap type - // If HtmlImageElement is used to get image then response type will be HTMLImageElement - callback(null, data); - } else if (data) { - const decoratedCallback = (imgErr?: Error | null, imgResult?: CanvasImageSource | null) => { - if (imgErr != null) { - callback(imgErr); - } else if (imgResult != null) { - callback(null, imgResult as (HTMLImageElement | ImageBitmap), {cacheControl, expires}); - } - }; - arrayBufferToCanvasImageSource(data, decoratedCallback); - } - if (!itemInQueue.cancelled) { - itemInQueue.completed = true; + currentParallelImageRequests++; + + const getImagePromise = canUseHTMLImageElement ? + getImageUsingHtmlImage(requestParameters, abortController) : + makeRequest(requestParameters, abortController); + + try { + const response = await getImagePromise; + delete itemInQueue.abortController; + itemInQueue.state = 'completed'; + if (response.data instanceof HTMLImageElement || isImageBitmap(response.data)) { + // User using addProtocol can directly return HTMLImageElement/ImageBitmap type + // If HtmlImageElement is used to get image then response type will be HTMLImageElement + onSuccess(response as GetResourceResponse); + } else if (response.data) { + const img = await arrayBufferToCanvasImageSource(response.data); + onSuccess({data: img, cacheControl: response.cacheControl, expires: response.expires}); + } + } catch (err) { + delete itemInQueue.abortController; + onError(err); + } finally { currentParallelImageRequests--; - processQueue(); } }; @@ -239,49 +205,46 @@ export namespace ImageRequest { numImageRequests++) { const topItemInQueue: ImageRequestQueueItem = imageRequestQueue.shift(); - if (topItemInQueue.cancelled) { + if (topItemInQueue.abortController.signal.aborted) { numImageRequests--; continue; } - - const innerRequest = doImageRequest(topItemInQueue); - - currentParallelImageRequests++; - - topItemInQueue.innerRequest = innerRequest; + doImageRequest(topItemInQueue); } }; - const getImageUsingHtmlImage = (requestParameters: RequestParameters, callback: GetImageCallback): Cancelable => { - const image = new Image() as HTMLImageElementWithPriority; - const url = requestParameters.url; - let requestCancelled = false; - const credentials = requestParameters.credentials; - if (credentials && credentials === 'include') { - image.crossOrigin = 'use-credentials'; - } else if ((credentials && credentials === 'same-origin') || !sameOrigin(url)) { - image.crossOrigin = 'anonymous'; - } + const getImageUsingHtmlImage = (requestParameters: RequestParameters, abortController: AbortController): Promise> => { + return new Promise>((resolve, reject) => { - image.fetchPriority = 'high'; - image.onload = () => { - callback(null, image); - image.onerror = image.onload = null; - }; - image.onerror = () => { - if (!requestCancelled) { - callback(new Error('Could not load image. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.')); + const image = new Image() as HTMLImageElementWithPriority; + const url = requestParameters.url; + const credentials = requestParameters.credentials; + if (credentials && credentials === 'include') { + image.crossOrigin = 'use-credentials'; + } else if ((credentials && credentials === 'same-origin') || !sameOrigin(url)) { + image.crossOrigin = 'anonymous'; } - image.onerror = image.onload = null; - }; - image.src = url; - return { - cancel: () => { - requestCancelled = true; + + abortController.signal.addEventListener('abort', () => { // Set src to '' to actually cancel the request image.src = ''; - } - }; + reject(createAbortError()); + }); + + image.fetchPriority = 'high'; + image.onload = () => { + image.onerror = image.onload = null; + resolve({data: image}); + }; + image.onerror = () => { + image.onerror = image.onload = null; + if (abortController.signal.aborted) { + return; + } + reject(new Error('Could not load image. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.')); + }; + image.src = url; + }); }; } diff --git a/src/util/task_queue.ts b/src/util/task_queue.ts index b7389e9ed6..1718bee66d 100644 --- a/src/util/task_queue.ts +++ b/src/util/task_queue.ts @@ -1,4 +1,4 @@ -export type TaskID = number; // can't mark opaque due to https://github.com/flowtype/flow-remove-types/pull/61 +export type TaskID = number; type Task = { callback: (timeStamp: number) => void; diff --git a/src/util/test/mock_fetch.ts b/src/util/test/mock_fetch.ts deleted file mode 100644 index db6e7b13cc..0000000000 --- a/src/util/test/mock_fetch.ts +++ /dev/null @@ -1,51 +0,0 @@ -export class RequestMock implements Partial { - public readonly cache: RequestCache; - public readonly headers: Headers = new Headers(); - public readonly method?: string; - public readonly url?: string; - - public get signal(): AbortSignal { - return null; - } - - constructor(input: RequestInfo | URL, init?: RequestInit) { - this.cache = typeof input === 'object' && 'cache' in input ? input.cache : init.cache; - this.method = typeof input === 'object' && 'method' in input ? input.method : init.method; - this.url = typeof input === 'object' && 'url' in input ? input.url : input.toString(); - this.headers = typeof input === 'object' && 'headers' in input ? new Headers(input.headers) : new Headers(init.headers || {}); - } -} - -class AbortControllerMock { - public signal: AbortSignal; - - public abort(): void {} -} - -export type FetchMock = jest.Mock, [input: RequestInfo | URL, init?: RequestInit], any>; - -let _AbortController: typeof AbortController; -let _Request: typeof Request; -let _fetch: typeof fetch; - -export function destroyFetchMock(): void { - global.AbortController = _AbortController ?? global.AbortController; - global.Request = _Request ?? global.Request; - global.fetch = _fetch ?? global.fetch; -} - -export function setupFetchMock(): FetchMock { - _AbortController = _AbortController ?? global.AbortController; - _Request = _Request ?? global.Request; - _fetch = _fetch ?? global.fetch; - - const fetchMock = jest.fn(async (_input: RequestInfo | URL, _init?: RequestInit): Promise => { - return {}; - }); - - global.AbortController = AbortControllerMock; - global.Request = RequestMock as unknown as typeof Request; - global.fetch = fetchMock as any; - - return fetchMock; -} diff --git a/src/util/test/util.ts b/src/util/test/util.ts index 39e63097ad..75514e39a1 100644 --- a/src/util/test/util.ts +++ b/src/util/test/util.ts @@ -2,6 +2,8 @@ import {Map} from '../../ui/map'; import {extend} from '../../util/util'; import {Dispatcher} from '../../util/dispatcher'; import {setWebGlContext} from './mock_webgl'; +import {IActor} from '../actor'; +import type {Evented} from '../evented'; export function createMap(options?, callback?) { const container = window.document.createElement('div'); @@ -96,10 +98,10 @@ export function beforeMapTest() { } export function getWrapDispatcher() { - const wrapDispatcher = (dispatcher) => { + const wrapDispatcher = (actor: IActor) => { return { getActor() { - return dispatcher; + return actor; } } as any as Dispatcher; }; @@ -111,7 +113,7 @@ export function getMockDispatcher() { const wrapDispatcher = getWrapDispatcher(); const mockDispatcher = wrapDispatcher({ - send() {} + sendAsync() { return Promise.resolve({}); }, }); return mockDispatcher; @@ -128,7 +130,9 @@ export function stubAjaxGetImage(createImageBitmap) { set(url: string) { if (url === 'error') { this.onerror(); - } else this.onload(); + } else if (this.onload) { + this.onload(); + } } }); } @@ -144,3 +148,22 @@ export function bufferToArrayBuffer(data: Buffer): ArrayBuffer { data.copy(view); return view.buffer; } + +/** + * This allows test to wait for a certain amount of time before continuing. + * @param milliseconds - the amount of time to wait in milliseconds + * @returns - a promise that resolves after the specified amount of time + */ +export const sleep = (milliseconds: number = 0) => { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +}; + +export function waitForMetadataEvent(source: Evented): Promise { + return new Promise((resolve) => { + source.on('data', (e) => { + if (e.sourceDataType === 'metadata') { + resolve(); + } + }); + }); +} diff --git a/src/util/throttled_invoker.ts b/src/util/throttled_invoker.ts index f697a23652..e16522662c 100644 --- a/src/util/throttled_invoker.ts +++ b/src/util/throttled_invoker.ts @@ -1,40 +1,41 @@ /** - * Invokes the wrapped function in a non-blocking way when trigger() is called. Invocation requests - * are ignored until the function was actually invoked. + * Invokes the wrapped function in a non-blocking way when trigger() is called. + * Invocation requests are ignored until the function was actually invoked. */ export class ThrottledInvoker { _channel: MessageChannel; _triggered: boolean; - _callback: Function; + _methodToThrottle: Function; - constructor(callback: Function) { - this._callback = callback; + constructor(methodToThrottle: Function) { + this._methodToThrottle = methodToThrottle; this._triggered = false; if (typeof MessageChannel !== 'undefined') { this._channel = new MessageChannel(); this._channel.port2.onmessage = () => { this._triggered = false; - this._callback(); + this._methodToThrottle(); }; } } trigger() { - if (!this._triggered) { - this._triggered = true; - if (this._channel) { - this._channel.port1.postMessage(true); - } else { - setTimeout(() => { - this._triggered = false; - this._callback(); - }, 0); - } + if (this._triggered) { + return; + } + this._triggered = true; + if (this._channel) { + this._channel.port1.postMessage(true); + } else { + setTimeout(() => { + this._triggered = false; + this._methodToThrottle(); + }, 0); } } remove() { delete this._channel; - this._callback = () => {}; + this._methodToThrottle = () => {}; } } diff --git a/src/util/util.test.ts b/src/util/util.test.ts index 47ede250b3..2754108c8f 100644 --- a/src/util/util.test.ts +++ b/src/util/util.test.ts @@ -1,5 +1,5 @@ import Point from '@mapbox/point-geometry'; -import {arraysIntersect, asyncAll, bezier, clamp, clone, deepEqual, easeCubicInOut, extend, filterObject, findLineIntersection, isClosedPolygon, isCounterClockwise, isPowerOfTwo, keysDifference, mapObject, nextPowerOfTwo, parseCacheControl, pick, readImageDataUsingOffscreenCanvas, readImageUsingVideoFrame, uniqueId, wrap} from './util'; +import {arraysIntersect, bezier, clamp, clone, deepEqual, easeCubicInOut, extend, filterObject, findLineIntersection, isClosedPolygon, isCounterClockwise, isPowerOfTwo, keysDifference, mapObject, nextPowerOfTwo, parseCacheControl, pick, readImageDataUsingOffscreenCanvas, readImageUsingVideoFrame, uniqueId, wrap} from './util'; import {Canvas} from 'canvas'; describe('util', () => { @@ -14,50 +14,6 @@ describe('util', () => { expect(pick({a: 1, b: 2, c: 3}, ['a', 'c', 'd'])).toEqual({a: 1, c: 3}); expect(typeof uniqueId() === 'number').toBeTruthy(); - test('asyncAll - sync', done => { - expect(asyncAll([0, 1, 2], (data, callback) => { - callback(null, data); - }, (err, results) => { - expect(err).toBeFalsy(); - expect(results).toEqual([0, 1, 2]); - })).toBeUndefined(); - done(); - }); - - test('asyncAll - async', done => { - expect(asyncAll([4, 0, 1, 2], (data, callback) => { - setTimeout(() => { - callback(null, data); - }, data); - }, (err, results) => { - expect(err).toBeFalsy(); - expect(results).toEqual([4, 0, 1, 2]); - done(); - })).toBeUndefined(); - }); - - test('asyncAll - error', done => { - expect(asyncAll([4, 0, 1, 2], (data, callback) => { - setTimeout(() => { - callback(new Error('hi'), data); - }, data); - }, (err, results) => { - expect(err && err.message).toBe('hi'); - expect(results).toEqual([4, 0, 1, 2]); - done(); - })).toBeUndefined(); - }); - - test('asyncAll - empty', done => { - expect(asyncAll([], (data, callback) => { - callback(null, 'foo'); - }, (err, results) => { - expect(err).toBeFalsy(); - expect(results).toEqual([]); - })).toBeUndefined(); - done(); - }); - test('isPowerOfTwo', done => { expect(isPowerOfTwo(1)).toBe(true); expect(isPowerOfTwo(2)).toBe(true); @@ -116,20 +72,6 @@ describe('util', () => { done(); }); - test('asyncAll', done => { - let expectedValue = 1; - asyncAll([], (callback) => { callback(); }, () => { - expect('immediate callback').toBeTruthy(); - }); - asyncAll([1, 2, 3], (number, callback) => { - expect(number).toBe(expectedValue++); - expect(callback instanceof Function).toBeTruthy(); - callback(null, 0); - }, () => { - done(); - }); - }); - test('mapObject', () => { expect.assertions(6); expect(mapObject({}, () => { expect(false).toBeTruthy(); })).toEqual({}); diff --git a/src/util/util.ts b/src/util/util.ts index 13e0c7db9e..0c182a1db9 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,8 +1,8 @@ import Point from '@mapbox/point-geometry'; import UnitBezier from '@mapbox/unitbezier'; -import type {Callback} from '../types/callback'; import {isOffscreenCanvasDistorted} from './offscreen_canvas_distorted'; import type {Size} from './image'; +import type {WorkerGlobalScopeInterface} from './web_worker'; /** * Given a value `t` that varies between 0 and 1, return @@ -65,33 +65,6 @@ export function wrap(n: number, min: number, max: number): number { return (w === min) ? max : w; } -/** - * Call an asynchronous function on an array of arguments, - * calling `callback` with the completed results of all calls. - * - * @param array - input to each call of the async function. - * @param fn - an async function with signature (data, callback) - * @param callback - a callback run after all async work is done. - * called with an array, containing the results of each async call. - */ -export function asyncAll( - array: Array, - fn: (item: Item, fnCallback: Callback) => void, - callback: Callback> -) { - if (!array.length) { return callback(null, []); } - let remaining = array.length; - const results = new Array(array.length); - let error = null; - array.forEach((item, i) => { - fn(item, (err, result) => { - if (err) error = err; - results[i] = (result as any as Result); // https://github.com/facebook/flow/issues/2123 - if (--remaining === 0) callback(error, results); - }); - }); -} - /** * Compute the difference between the keys in one object and the keys * in another object. @@ -384,7 +357,7 @@ export function sphericalToCartesian([r, azimuthal, polar]: [number, number, num * * @returns `true` if the when run in the web-worker context. */ -export function isWorker(): boolean { +export function isWorker(self: any): self is WorkerGlobalScopeInterface { // @ts-ignore return typeof WorkerGlobalScope !== 'undefined' && typeof self !== 'undefined' && self instanceof WorkerGlobalScope; } @@ -481,16 +454,16 @@ export function isImageBitmap(image: any): image is ImageBitmap { * ArrayBuffers. * * @param data - Data to convert - * @param callback - A callback executed after the conversion is finished. Invoked with error (if any) as the first argument and resulting image bitmap (when no error) as the second + * @returns - A promise resolved when the conversion is finished */ -export function arrayBufferToImageBitmap(data: ArrayBuffer, callback: (err?: Error | null, image?: ImageBitmap | null) => void) { +export const arrayBufferToImageBitmap = async (data: ArrayBuffer): Promise => { const blob: Blob = new Blob([new Uint8Array(data)], {type: 'image/png'}); - createImageBitmap(blob).then((imgBitmap) => { - callback(null, imgBitmap); - }).catch((e) => { - callback(new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`)); - }); -} + try { + return createImageBitmap(blob); + } catch (e) { + throw new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`); + } +}; const transparentPngUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII='; @@ -502,23 +475,25 @@ const transparentPngUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA * ArrayBuffers. * * @param data - Data to convert - * @param callback - A callback executed after the conversion is finished. Invoked with error (if any) as the first argument and resulting image element (when no error) as the second - */ -export function arrayBufferToImage(data: ArrayBuffer, callback: (err?: Error | null, image?: HTMLImageElement | null) => void) { - const img: HTMLImageElement = new Image(); - img.onload = () => { - callback(null, img); - URL.revokeObjectURL(img.src); - // prevent image dataURI memory leak in Safari; - // but don't free the image immediately because it might be uploaded in the next frame - // https://github.com/mapbox/mapbox-gl-js/issues/10226 - img.onload = null; - window.requestAnimationFrame(() => { img.src = transparentPngUrl; }); - }; - img.onerror = () => callback(new Error('Could not load image. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.')); - const blob: Blob = new Blob([new Uint8Array(data)], {type: 'image/png'}); - img.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl; -} + * @returns - A promise resolved when the conversion is finished + */ +export const arrayBufferToImage = (data: ArrayBuffer): Promise => { + return new Promise((resolve, reject) => { + const img: HTMLImageElement = new Image(); + img.onload = () => { + resolve(img); + URL.revokeObjectURL(img.src); + // prevent image dataURI memory leak in Safari; + // but don't free the image immediately because it might be uploaded in the next frame + // https://github.com/mapbox/mapbox-gl-js/issues/10226 + img.onload = null; + window.requestAnimationFrame(() => { img.src = transparentPngUrl; }); + }; + img.onerror = () => reject(new Error('Could not load image. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.')); + const blob: Blob = new Blob([new Uint8Array(data)], {type: 'image/png'}); + img.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl; + }); +}; /** * Computes the webcodecs VideoFrame API options to select a rectangle out of @@ -667,3 +642,30 @@ export async function getImageData( } return readImageDataUsingOffscreenCanvas(image, x, y, width, height); } + +export interface Subscription { + unsubscribe(): void; +} + +export interface Subscriber { + addEventListener: typeof window.addEventListener; + removeEventListener: typeof window.removeEventListener; +} + +/** + * This method is used in order to register an event listener using a lambda function. + * The return value will allow unsubscribing from the event, without the need to store the method reference. + * @param target - The target + * @param message - The message + * @param listener - The listener + * @param options - The options + * @returns a subscription object that can be used to unsubscribe from the event + */ +export function subscribe(target: Subscriber, message: keyof WindowEventMap, listener: (...args: any) => void, options: boolean | AddEventListenerOptions): Subscription { + target.addEventListener(message, listener, options); + return { + unsubscribe: () => { + target.removeEventListener(message, listener, options); + } + }; +} diff --git a/src/util/web_worker.ts b/src/util/web_worker.ts index 6a2db7e576..e26bc74090 100644 --- a/src/util/web_worker.ts +++ b/src/util/web_worker.ts @@ -1,16 +1,12 @@ import {config} from './config'; - -import type {WorkerSource} from '../source/worker_source'; +import type {default as MaplibreWorker} from '../source/worker'; +import type {WorkerSourceConstructor} from '../source/worker_source'; export interface WorkerGlobalScopeInterface { importScripts(...urls: Array): void; - registerWorkerSource: ( - b: string, - a: { - new(...args: any): WorkerSource; - } - ) => void; + registerWorkerSource: (sourceName: string, sourceConstrucor: WorkerSourceConstructor) => void; registerRTLTextPlugin: (_: any) => void; + worker: MaplibreWorker; } export function workerFactory() { diff --git a/src/util/web_worker_transfer.ts b/src/util/web_worker_transfer.ts index 49fb990e42..026b1a12ad 100644 --- a/src/util/web_worker_transfer.ts +++ b/src/util/web_worker_transfer.ts @@ -7,10 +7,16 @@ import {AJAXError} from './ajax'; import type {Transferable} from '../types/transferable'; import {isImageBitmap} from './util'; +/** + * A class that is serizlized to and json, that can be constructed back to the original class in the worker or in the main thread + */ type SerializedObject = { [_: string]: S; }; +/** + * All the possible values that can be serialized and sent to and from the worker + */ export type Serialized = null | void | boolean | number | string | Boolean | Number | String | Date | RegExp | ArrayBuffer | ArrayBufferView | ImageData | ImageBitmap | Blob | Array | SerializedObject; type Registry = { @@ -156,7 +162,7 @@ export function serialize(input: unknown, transferables?: Array | const klass = (input.constructor as any); const name = klass._classRegistryKey; if (!name) { - throw new Error('can\'t serialize object of unregistered class'); + throw new Error(`can't serialize object of unregistered class ${klass.name}`); } if (!registry[name]) throw new Error(`${name} is not registered.`); diff --git a/test/bench/lib/create_map.ts b/test/bench/lib/create_map.ts index 1ab43afa79..def8226abf 100644 --- a/test/bench/lib/create_map.ts +++ b/test/bench/lib/create_map.ts @@ -27,9 +27,9 @@ const createMap = (options: any): Promise => { .on(options.idle ? 'idle' : 'load', () => { if (options.stubRender) { // If there's a pending rerender, cancel it. - if (map._frame) { - map._frame.cancel(); - map._frame = null; + if (map._frameRequest) { + map._frameRequest.abort(); + map._frameRequest = null; } } resolve(map); diff --git a/test/bench/lib/tile_parser.ts b/test/bench/lib/tile_parser.ts index cc0098ce09..b765b4c00c 100644 --- a/test/bench/lib/tile_parser.ts +++ b/test/bench/lib/tile_parser.ts @@ -14,6 +14,7 @@ import type {WorkerTileResult} from '../../../src/source/worker_source'; import type {OverscaledTileID} from '../../../src/source/tile_id'; import type {TileJSON} from '../../../src/types/tilejson'; import type {Map} from '../../../src/ui/map'; +import type {IActor} from '../../../src/util/actor'; class StubMap extends Evented { style: Style; @@ -57,9 +58,7 @@ export default class TileParser { icons: any; glyphs: any; style: Style; - actor: { - send: Function; - }; + actor: IActor; constructor(styleJSON: StyleSpecification, sourceID: string) { this.styleJSON = styleJSON; @@ -69,41 +68,33 @@ export default class TileParser { this.icons = {}; } - loadImages(params: any, callback: Function) { + async loadImages(params: any) { const key = JSON.stringify(params); - if (this.icons[key]) { - callback(null, this.icons[key]); - } else { - this.style.getImages('', params, (err, icons) => { - this.icons[key] = icons; - callback(err, icons); - }); + if (!this.icons[key]) { + this.icons[key] = await this.style.getImages('', params); } + return this.icons[key]; } - loadGlyphs(params: any, callback: Function) { + async loadGlyphs(params: any) { const key = JSON.stringify(params); - if (this.glyphs[key]) { - callback(null, this.glyphs[key]); - } else { - this.style.getGlyphs('', params, (err, glyphs) => { - this.glyphs[key] = glyphs; - callback(err, glyphs); - }); + if (!this.glyphs[key]) { + this.glyphs[key] = await this.style.getGlyphs('', params); } + return this.glyphs[key]; } setup(): Promise { const parser = this; this.actor = { - send(action, params, callback) { - setTimeout(() => { - if (action === 'getImages') { - parser.loadImages(params, callback); - } else if (action === 'getGlyphs') { - parser.loadGlyphs(params, callback); - } else throw new Error(`Invalid action ${action}`); - }, 0); + sendAsync(message) { + if (message.type === 'getImages') { + return parser.loadImages(message.data); + } + if (message.type === 'getGlyphs') { + return parser.loadGlyphs(message.data); + } + throw new Error(`Invalid action ${message.type}`); } }; @@ -130,6 +121,7 @@ export default class TileParser { returnDependencies?: boolean ): Promise { const workerTile = new WorkerTile({ + type: 'benchmark', tileID: tile.tileID, zoom: tile.tileID.overscaledZ, tileSize: 512, @@ -145,14 +137,6 @@ export default class TileParser { const vectorTile = new VT.VectorTile(new Protobuf(tile.buffer)); - return new Promise((resolve, reject) => { - workerTile.parse(vectorTile, this.layerIndex, [], ((this.actor as any)), (err, result) => { - if (err) { - reject(err); - } else { - resolve(result); - } - }); - }); + return workerTile.parse(vectorTile, this.layerIndex, [], this.actor); } } diff --git a/test/build/min.test.ts b/test/build/min.test.ts index e65eaad00b..2f2c67b55f 100644 --- a/test/build/min.test.ts +++ b/test/build/min.test.ts @@ -36,7 +36,7 @@ describe('test min build', () => { const decreaseQuota = 4096; // feel free to update this value after you've checked that it has changed on purpose :-) - const expectedBytes = 761777; + const expectedBytes = 768888; expect(actualBytes - expectedBytes).toBeLessThan(increaseQuota); expect(expectedBytes - actualBytes).toBeLessThan(decreaseQuota); diff --git a/test/build/sourcemaps.test.ts b/test/build/sourcemaps.test.ts index b14f0aaf00..25c5f49c0e 100644 --- a/test/build/sourcemaps.test.ts +++ b/test/build/sourcemaps.test.ts @@ -83,6 +83,6 @@ describe('main sourcemap', () => { const s1 = setMinus(actualEntriesInSourcemapJSON, expectedEntriesInSourcemapJSON); expect(s1.length).toBeLessThan(5); const s2 = setMinus(expectedEntriesInSourcemapJSON, actualEntriesInSourcemapJSON); - expect(s2.length).toBeLessThan(15); + expect(s2.length).toBeLessThan(16); }); }); diff --git a/test/integration/browser/browser.test.ts b/test/integration/browser/browser.test.ts index b0cb7f5885..a232547030 100644 --- a/test/integration/browser/browser.test.ts +++ b/test/integration/browser/browser.test.ts @@ -5,6 +5,7 @@ import type {Server} from 'http'; import type {AddressInfo} from 'net'; import type {Map} from '../../../src/ui/map'; import type {default as MapLibreGL} from '../../../src/index'; +import {sleep} from '../../../src/util/test/util'; const testWidth = 800; const testHeight = 600; @@ -109,7 +110,7 @@ describe('Browser tests', () => { steps: 10 }); await page.mouse.up(); - await new Promise(r => setTimeout(r, 200)); + await sleep(200); return page.evaluate(() => { return map.getCenter(); @@ -135,7 +136,7 @@ describe('Browser tests', () => { await page.setViewport({width: 400, height: 400, deviceScaleFactor: 2}); - await new Promise(r => setTimeout(r, 200)); + await sleep(200); const canvas = await page.$('.maplibregl-canvas'); const canvasBB = await canvas?.boundingBox(); @@ -149,7 +150,7 @@ describe('Browser tests', () => { document.getElementById('map')!.style.width = '200px'; document.getElementById('map')!.style.height = '200px'; }); - await new Promise(resolve => setTimeout(resolve, 1000)); + await sleep(1000); const canvas = await page.$('.maplibregl-canvas'); const canvasBB = await canvas?.boundingBox(); diff --git a/test/integration/render/tests/debug/raster/expected-macos-m2.png b/test/integration/render/tests/debug/raster/expected-macos-m2.png new file mode 100644 index 0000000000000000000000000000000000000000..cceff22965f92b4fb9779e6bd304b8c600f02b69 GIT binary patch literal 286983 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 NBwzc9qL`zqyrzkABkhVj;12kNwB26l=70I& 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 I;3fh82a!IRKL7v# literal 0 HcmV?d00001 diff --git a/test/integration/render/tests/debug/tile-raster/expected-macos-m2.png b/test/integration/render/tests/debug/tile-raster/expected-macos-m2.png new file mode 100644 index 0000000000000000000000000000000000000000..071e69ca8fc27bc8b38b3a9d0bb1ba0a1b7bace0 GIT binary patch literal 622078 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ℜpOv2A`j12mDGTmTUAUV-Mt0s4+k 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