diff --git a/src/fontra/client/core/font-sources-instancer.js b/src/fontra/client/core/font-sources-instancer.js index 6cd78db9f..70607d521 100644 --- a/src/fontra/client/core/font-sources-instancer.js +++ b/src/fontra/client/core/font-sources-instancer.js @@ -15,35 +15,43 @@ export class FontSourcesInstancer { } _setup() { - this.fontSourcesList = Object.values(this.fontSources).filter( + this._fontSourcesList = Object.values(this.fontSources).filter( (source) => !source.isSparse ); this.fontAxesSourceSpace = mapAxesFromUserSpaceToSourceSpace(this.fontAxes); - this.defaultLocation = Object.fromEntries( + this.defaultSourceLocation = Object.fromEntries( this.fontAxesSourceSpace.map((axis) => [axis.name, axis.defaultValue]) ); - this.sourcesByLocationString = Object.fromEntries( - this.fontSourcesList.map((source) => [ - locationToString({ ...this.defaultLocation, ...source.location }), - source, + this._sourceIdsByLocationString = Object.fromEntries( + Object.entries(this.fontSources).map(([sourceIdentifier, source]) => [ + locationToString({ ...this.defaultSourceLocation, ...source.location }), + sourceIdentifier, ]) ); + this.defaultSourceIdentifier = + this._sourceIdsByLocationString[locationToString(this.defaultSourceLocation)]; + this._instanceCache = new LRUCache(50); } + getLocationIdentifierForLocation(location) { + location = { ...this.defaultSourceLocation, ...location }; + return this._sourceIdsByLocationString[locationToString(location)]; + } + get model() { if (!this._model) { - const locations = this.fontSourcesList.map((source) => source.location); + const locations = this._fontSourcesList.map((source) => source.location); this._model = new DiscreteVariationModel(locations, this.fontAxesSourceSpace); } return this._model; } get deltas() { - const guidelinesAreCompatible = areGuidelinesCompatible(this.fontSourcesList); - const customDatasAreCompatible = areCustomDatasCompatible(this.fontSourcesList); + const guidelinesAreCompatible = areGuidelinesCompatible(this._fontSourcesList); + const customDatasAreCompatible = areCustomDatasCompatible(this._fontSourcesList); - const fixedSourceValues = this.fontSourcesList.map((source) => { + const fixedSourceValues = this._fontSourcesList.map((source) => { return { ...source, location: null, @@ -58,17 +66,22 @@ export class FontSourcesInstancer { } instantiate(sourceLocation) { - if (!this.fontSourcesList.length) { + if (!this._fontSourcesList.length) { return undefined; } - sourceLocation = { ...this.defaultLocation, ...sourceLocation }; + sourceLocation = { ...this.defaultSourceLocation, ...sourceLocation }; const locationString = locationToString(sourceLocation); - if (locationString in this.sourcesByLocationString) { - return this.sourcesByLocationString[locationString]; + const sourceIdentifier = this._sourceIdsByLocationString[locationString]; + let sourceInstance = sourceIdentifier + ? this.fontSources[sourceIdentifier] + : undefined; + + if (sourceInstance && !sourceInstance.isSparse) { + return sourceInstance; } - let sourceInstance = this._instanceCache.get(locationString); + sourceInstance = this._instanceCache.get(locationString); if (!sourceInstance) { const deltas = this.deltas; diff --git a/test-js/test-font-sources-instancer.js b/test-js/test-font-sources-instancer.js index d14c492a8..6e22214a8 100644 --- a/test-js/test-font-sources-instancer.js +++ b/test-js/test-font-sources-instancer.js @@ -109,9 +109,43 @@ describe("FontSourcesInstancer Tests", () => { expect(sourceInstance).to.deep.equal(testItem.expectedSource); }); + it("Default location identifier", () => { + const fsi = new FontSourcesInstancer(testAxes, testSources); + expect(fsi.defaultSourceIdentifier).to.equal("source1"); + expect(fsi.defaultSourceLocation).to.deep.equal({ Weight: 400, Width: 50 }); + }); + + parametrize( + "FontSourcesInstancer.getLocationIdentifierForLocation", + [ + { location: {}, locationIdentifier: "source1" }, + { location: { Weight: 400 }, locationIdentifier: "source1" }, + { location: { Width: 50 }, locationIdentifier: "source1" }, + { location: { Weight: 400, Width: 50 }, locationIdentifier: "source1" }, + { location: { Weight: 900 }, locationIdentifier: "source2" }, + { location: { Weight: 900, Width: 50 }, locationIdentifier: "source2" }, + { location: { Width: 100 }, locationIdentifier: "source3" }, + { location: { Weight: 900, Width: 100 }, locationIdentifier: "source4" }, + { location: { Weight: 800, Width: 100 }, locationIdentifier: undefined }, + { + location: { Weight: 900, Width: 100, UnknownAxis: 120 }, + locationIdentifier: undefined, + }, + ], + (testItem) => { + const fsi = new FontSourcesInstancer(testAxes, testSources); + expect(fsi.getLocationIdentifierForLocation(testItem.location)).to.equal( + testItem.locationIdentifier + ); + } + ); + it("Empty sources list", () => { const fsi = new FontSourcesInstancer([], {}); const sourceInstance = fsi.instantiate({}); expect(sourceInstance).to.deep.equal(undefined); + expect(fsi.defaultSourceIdentifier).to.equal(undefined); + expect(fsi.defaultSourceLocation).to.deep.equal({}); + expect(fsi.getLocationIdentifierForLocation({})).to.equal(undefined); }); });