Skip to content

Commit

Permalink
VectorTileWorkerSource: fix reload for original's load parse would no…
Browse files Browse the repository at this point in the history
…t pass the rawTileData and meta (#2941)

* fix reload for original's load parse would not pass the rawTileData

* remove fetching state after base load

* add changelog

* update the tests to check for rawTileData to be passed on reload that cancels load

* remove unused import

* nit: change interface to type, test the case when reparsing is done after mocked load callback is called
  • Loading branch information
ambientlight committed Aug 5, 2023
1 parent 01e5f51 commit bd37870
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

### 🐞 Bug fixes

- VectorTileWorkerSource: fix reload for original's load parse would not pass the rawTileData and meta. ([#2941](https://github.com/maplibre/maplibre-gl-js/pull/2941))
- _...Add new stuff here..._

## 3.2.1
Expand Down
79 changes: 79 additions & 0 deletions src/source/vector_tile_worker_source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,85 @@ describe('vector tile worker source', () => {
});

test('VectorTileWorkerSource#loadTile reparses tile if the reloadTile has been called during parsing', (done) => {
const rawTileData = new Uint8Array([]);
function loadVectorData(params, callback) {
return callback(null, {
vectorTile: {
layers: {
test: {
version: 2,
name: 'test',
extent: 8192,
length: 1,
feature: (featureIndex: number) => ({
extent: 8192,
type: 1,
id: featureIndex,
properties: {
name: 'test'
},
loadGeometry () {
return [[{x: 0, y: 0}]];
}
})
}
}
} as any as vt.VectorTile,
rawData: rawTileData
});
}

const layerIndex = new StyleLayerIndex([{
id: 'test',
source: 'source',
'source-layer': 'test',
type: 'symbol',
layout: {
'icon-image': 'hello',
'text-font': ['StandardFont-Bold'],
'text-field': '{name}'
}
}]);

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);
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');
});

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(res.rawTileData).toBeDefined();
expect(res.rawTileData).toStrictEqual(rawTileData);
done();
});
});

test('VectorTileWorkerSource#loadTile reparses tile if reloadTile is called during reparsing', (done) => {
const rawTileData = new Uint8Array([]);
function loadVectorData(params, callback) {
return callback(null, {
Expand Down
27 changes: 26 additions & 1 deletion src/source/vector_tile_worker_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export type LoadVectorTileResult = {
resourceTiming?: Array<PerformanceResourceTiming>;
} & ExpiryData;

type FetchingState = {
rawTileData: ArrayBuffer;
cacheControl: ExpiryData;
resourceTiming: any;
}

/**
* The callback when finished loading vector data
*/
Expand Down Expand Up @@ -66,6 +72,7 @@ export class VectorTileWorkerSource implements WorkerSource {
layerIndex: StyleLayerIndex;
availableImages: Array<string>;
loadVectorData: LoadVectorData;
fetching: {[_: string]: FetchingState };
loading: {[_: string]: WorkerTile};
loaded: {[_: string]: WorkerTile};

Expand All @@ -80,6 +87,7 @@ export class VectorTileWorkerSource implements WorkerSource {
this.layerIndex = layerIndex;
this.availableImages = availableImages;
this.loadVectorData = loadVectorData || loadVectorTile;
this.fetching = {};
this.loading = {};
this.loaded = {};
}
Expand Down Expand Up @@ -124,6 +132,7 @@ 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);

// Transferring a copy of rawTileData because the worker needs to retain its copy.
Expand All @@ -132,6 +141,8 @@ export class VectorTileWorkerSource implements WorkerSource {

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;
}

Expand All @@ -145,7 +156,21 @@ export class VectorTileWorkerSource implements WorkerSource {
const workerTile = loaded[uid];
workerTile.showCollisionBoxes = params.showCollisionBoxes;
if (workerTile.status === 'parsing') {
workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor, callback);
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) {
Expand Down

0 comments on commit bd37870

Please sign in to comment.