Skip to content

Commit

Permalink
Merge pull request #1780 from googlefonts/font-sources-instances-refa…
Browse files Browse the repository at this point in the history
…ctor

FontSourcesInstancer (JS) refactor + new prop + method
  • Loading branch information
justvanrossum authored Nov 12, 2024
2 parents 52e1bff + 6dd8e03 commit fb8acca
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 15 deletions.
43 changes: 28 additions & 15 deletions src/fontra/client/core/font-sources-instancer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
34 changes: 34 additions & 0 deletions test-js/test-font-sources-instancer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});

0 comments on commit fb8acca

Please sign in to comment.