From 9d3609a7155139afc4d5dd8c8d68728d582bd62f Mon Sep 17 00:00:00 2001 From: Pomax Date: Tue, 31 Mar 2026 16:49:45 -0700 Subject: [PATCH 1/2] add name decoding.... oh and remove jest testing >_> --- package.json | 8 ++--- src/opentype/tables/simple/name.js | 28 +++++++++++++++- testing/manual/custom/issue-85.js | 6 ++-- testing/manual/custom/test.out | 1 - testing/manual/index.html | 25 +++++++------- testing/node/athena.ruby.test.js | 18 +++++----- testing/node/gsub/issue-113/gsub.test.js | 20 ++++++----- testing/node/gsub/issue-153/gsub.test.js | 34 ++++++++++--------- testing/node/gsub/test-gsub.js | 20 +++++------ testing/node/ibm.plex.sans.thai.test.js | 27 +++++++++++++++ testing/node/issue-114/flaticon.test.js | 24 +++++++------- testing/node/mehr.nastaliq.test.js | 18 +++++----- testing/node/source.code.pro.test.js | 42 +++++++++++++----------- 13 files changed, 166 insertions(+), 105 deletions(-) delete mode 100644 testing/manual/custom/test.out create mode 100644 testing/node/ibm.plex.sans.thai.test.js diff --git a/package.json b/package.json index bb2a539..7d81776 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,11 @@ "terser": "terser lib-font.browser.js -o lib-font.browser.js", "test:browser": "run-p test:server test:playwright", "test:cleanup": "rm -rf ./test-results", - "test:node:jest": "npm run test:jest -- ./testing/node/", - "test:node:native": "node --test \"./testing/native-node/**/*.js\"", - "test:jest": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --verbose=false", + "test:node": "node --test \"./testing/node/**/*.test.js\" \"./testing/native-node/**/*.js\"", "test:manual": "http-server -o testing/manual/index.html", "test:playwright": "playwright test ./testing/browser/playwright.test.js", "test:server": "node ./testing/browser/server.js", - "test": "run-s clean test:node:jest test:node:native bundle test:browser test:cleanup" + "test": "run-s clean test:node bundle test:browser test:cleanup" }, "repository": { "type": "git", @@ -45,10 +43,8 @@ "homepage": "https://github.com/Pomax/lib-font#readme", "devDependencies": { "@playwright/test": "^1.56.1", - "cross-env": "^7.0.2", "express": "^4.17.1", "http-server": "^0.12.3", - "jest": "^26.6.3", "npm-run-all": "^4.1.5", "open-cli": "^6.0.1", "prettier": "^2.1.1", diff --git a/src/opentype/tables/simple/name.js b/src/opentype/tables/simple/name.js index ec3be87..d73940e 100644 --- a/src/opentype/tables/simple/name.js +++ b/src/opentype/tables/simple/name.js @@ -2,6 +2,12 @@ import { Parser } from "../../../parser.js"; import { SimpleTable } from "../simple-table.js"; import lazy from "../../../lazy.js"; +const decoders = { + mac: new TextDecoder(`macintosh`), + shiftJIS: new TextDecoder(`shift-jis`), + big5: new TextDecoder(`big5`), +}; + /** * The OpenType `name` table. * @@ -38,7 +44,27 @@ class name extends SimpleTable { */ get(nameID) { let record = this.nameRecords.find((record) => record.nameID === nameID); - if (record) return record.string; + if (!record) return; + + const { platformID, encodingID, string } = record; + const bytes = new Uint8Array( + Array.from(string).map((s) => s.codePointAt(0)) + ); + + if (platformID === 1) { + return decoders.mac.decode(bytes); + } + + if (platformID === 3) { + if (encodingID === 2) { + return decoders.shiftJIS.decode(bytes); + } + if (encodingID === 4) { + return decoders.big5.decode(bytes); + } + } + + return string; } } diff --git a/testing/manual/custom/issue-85.js b/testing/manual/custom/issue-85.js index da2f668..15b0be5 100644 --- a/testing/manual/custom/issue-85.js +++ b/testing/manual/custom/issue-85.js @@ -1,4 +1,3 @@ -import fs from "fs"; import { Font } from "../../../lib-font.js"; const font = new Font("testfont"); @@ -7,6 +6,5 @@ font.src = "../../../fonts/IBMPlexSansThai-Light.ttf"; font.onload = (evt) => { let font = evt.detail.font; const { name } = font.opentype.tables; - console.log(name); - fs.writeFileSync(`test.out`, `name: ${name.get(9)}`, `utf-8`); -}; \ No newline at end of file + console.log(name, name.get(9)); +}; diff --git a/testing/manual/custom/test.out b/testing/manual/custom/test.out deleted file mode 100644 index a1d4b50..0000000 --- a/testing/manual/custom/test.out +++ /dev/null @@ -1 +0,0 @@ -name: Mike Abbink, Paul van der Laan, Pieter van Rosmalen, Ben Mitchell, Mark Fršmberg \ No newline at end of file diff --git a/testing/manual/index.html b/testing/manual/index.html index bf13627..0717491 100644 --- a/testing/manual/index.html +++ b/testing/manual/index.html @@ -1,14 +1,17 @@ - + - - - LibFont unit tests - - - + + + LibFont unit tests + + + + + + + +

Please open dev tools for now

+ diff --git a/testing/node/athena.ruby.test.js b/testing/node/athena.ruby.test.js index b1bd4d2..39c5e5a 100644 --- a/testing/node/athena.ruby.test.js +++ b/testing/node/athena.ruby.test.js @@ -1,19 +1,21 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; import { Font } from "../../lib-font.js"; import { testGSUB } from "./gsub/test-gsub.js"; const font = new Font("athena ruby"); describe("Basic font testing", () => { - beforeAll((done) => { - font.onerror = (err) => { - throw err; - }; - font.onload = async () => done(); - font.src = "./fonts/AthenaRuby_b018.ttf"; - }); + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/AthenaRuby_b018.ttf"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "AthenaRuby_b018.ttf"); + })); test("font loaded", () => { - expect(font.opentype).toBeDefined(); + assert.ok(font.opentype !== undefined); }); test("GSUB format 3 variant access", () => { diff --git a/testing/node/gsub/issue-113/gsub.test.js b/testing/node/gsub/issue-113/gsub.test.js index 91ee080..b71845e 100644 --- a/testing/node/gsub/issue-113/gsub.test.js +++ b/testing/node/gsub/issue-113/gsub.test.js @@ -1,18 +1,20 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; import { Font } from "../../../../lib-font.js"; const font = new Font("GSUB type 7 redirect testing"); describe("GSUB type 7 checks", () => { - beforeAll(async (done) => { - font.onerror = (err) => { - throw err; - }; - font.onload = async () => done(); - font.src = `./fonts/Lato-Regular.ttf`; - }); + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/Lato-Regular.ttf"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "Lato-Regular.ttf"); + })); test("font loaded", () => { - expect(font.opentype).toBeDefined(); + assert.ok(font.opentype !== undefined); }); test("has all expected type 7 redirects", () => { @@ -41,7 +43,7 @@ describe("GSUB type 7 checks", () => { }); }); - expect(sequence.slice(0,30)).toEqual([ + assert.deepStrictEqual(sequence.slice(0,30), [ [26, 7, "dflt", 0, 6, 3], [26, 7, "dflt", 1, 6, 3], [28, 7, "dflt", 0, 6, 3], diff --git a/testing/node/gsub/issue-153/gsub.test.js b/testing/node/gsub/issue-153/gsub.test.js index 86f7f77..a5f107b 100644 --- a/testing/node/gsub/issue-153/gsub.test.js +++ b/testing/node/gsub/issue-153/gsub.test.js @@ -1,18 +1,20 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; import { Font } from "../../../../lib-font.js"; const font = new Font("GSUB type 6 subformat 2 testing"); describe("GSUB 6.2 checks", () => { - beforeAll(async (done) => { - font.onerror = (err) => { - throw err; - }; - font.onload = async () => done(); - font.src = `./fonts/Bangers-Regular.ttf`; - }); + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/Bangers-Regular.ttf"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "Bangers-Regular.ttf"); + })); test("font loaded", () => { - expect(font.opentype).toBeDefined(); + assert.ok(font.opentype !== undefined); }); test("has all expected type 7 redirects", () => { @@ -44,7 +46,7 @@ describe("GSUB 6.2 checks", () => { }); }); - expect(sequence.slice(0, 30)).toEqual([ + assert.deepStrictEqual(sequence.slice(0, 30), [ [0, 1, "dflt", 0, 1, 2], [1, 3, "dflt", 0, 3, 1], [20, 1, "dflt", 0, 1, 2], @@ -79,7 +81,7 @@ describe("GSUB 6.2 checks", () => { // I have no idea if this is correct atm const lookup6dot2 = subtables[4]; - expect(lookup6dot2).toEqual({ + assert.deepStrictEqual({...lookup6dot2}, { type: 6, format: 2, coverageOffset: 432, @@ -92,14 +94,14 @@ describe("GSUB 6.2 checks", () => { // I have no idea if this is correct atm const classSet = lookup6dot2.getChainSubClassSet(1); - expect(classSet).toEqual({ + assert.deepStrictEqual({...classSet}, { chainSubClassRuleCount: 1, chainSubClassRuleOffsets: [512], }); // I have no idea if this is correct atm const subclass = classSet.getSubClass(0); - expect(subclass).toEqual({ + assert.deepStrictEqual({...subclass, substLookupRecords: subclass.substLookupRecords.map(r => ({...r}))}, { backtrackGlyphCount: 0, backtrackSequence: [], inputGlyphCount: 1, @@ -123,9 +125,9 @@ describe("GSUB 6.2 checks", () => { const inputClassDef = subtable.getInputClassDef(); - expect(inputClassDef.classFormat).toBe(2); + assert.strictEqual(inputClassDef.classFormat, 2); - expect(inputClassDef.classRangeRecords).toEqual([ + assert.deepStrictEqual(inputClassDef.classRangeRecords.map(r => ({...r})), [ { startGlyphID: 272, endGlyphID: 272, class: 2 }, // i { startGlyphID: 288, endGlyphID: 288, class: 1 }, // j ]); @@ -139,7 +141,7 @@ describe("GSUB 6.2 checks", () => { const backtrackClassDef = subtable.getBacktrackClassDef(); // Bangers has no backtrack chars for this lookup - expect(backtrackClassDef.classRangeRecords).toEqual([]); + assert.deepStrictEqual(backtrackClassDef.classRangeRecords, []); }); test("getLookaheadClassDef returns multiple definitions", () => { @@ -164,7 +166,7 @@ describe("GSUB 6.2 checks", () => { // hookabovecomb // uni030F // uni0312 - expect(lookaheadClassDef.classRangeRecords).toEqual([ + assert.deepStrictEqual(lookaheadClassDef.classRangeRecords.map(r => ({...r})), [ { startGlyphID: 525, endGlyphID: 529, class: 1 }, { startGlyphID: 531, endGlyphID: 538, class: 1 }, { startGlyphID: 540, endGlyphID: 540, class: 1 }, diff --git a/testing/node/gsub/test-gsub.js b/testing/node/gsub/test-gsub.js index dcbf32f..92bbd32 100644 --- a/testing/node/gsub/test-gsub.js +++ b/testing/node/gsub/test-gsub.js @@ -1,4 +1,4 @@ -import { expect } from "@jest/globals"; +import assert from "node:assert"; import { profiles } from "../font-profiles/profiles.js"; function testGSUB(font, tests) { @@ -6,47 +6,47 @@ function testGSUB(font, tests) { const { cmap, name, GSUB } = font.opentype.tables; - expect(GSUB).toBeDefined(); - expect(cmap).toBeDefined(); - expect(name).toBeDefined(); + assert.ok(GSUB !== undefined); + assert.ok(cmap !== undefined); + assert.ok(name !== undefined); let scripts = GSUB.getSupportedScripts(); - expect(scripts).toEqual(Object.keys(expectation)); + assert.deepStrictEqual(scripts, Object.keys(expectation)); scripts.forEach((script) => { tests.script.forEach(fn => fn(script)); let langsys = GSUB.getSupportedLangSys(script); - expect(langsys).toEqual(expectation[script].langsys); + assert.deepStrictEqual(langsys, expectation[script].langsys); langsys.forEach((lang) => { let langSysTable = GSUB.getLangSysTable(script, lang); let features = GSUB.getFeatures(langSysTable); let featureCount = features.length; - expect(featureCount).toEqual(expectation[script].features[lang].length); + assert.deepStrictEqual(featureCount, expectation[script].features[lang].length); features.forEach((feature) => { tests.feature.forEach(fn => fn(feature)); const lookupIDs = feature.lookupListIndices; - const test = { + const actual = { script, lang, feature: feature.featureTag, lookupIDs }; - const match = { + const expected = { script, lang, feature: feature.featureTag, lookupIDs: expectation[script].features[lang].lookups[feature.featureTag] }; - expect(test).toEqual(match); + assert.deepStrictEqual(actual, expected); lookupIDs.forEach((id) => { const lookup = GSUB.getLookup(id); diff --git a/testing/node/ibm.plex.sans.thai.test.js b/testing/node/ibm.plex.sans.thai.test.js new file mode 100644 index 0000000..995a7f4 --- /dev/null +++ b/testing/node/ibm.plex.sans.thai.test.js @@ -0,0 +1,27 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; +import { Font } from "../../lib-font.js"; + +const font = new Font("ibm plex sans thai"); + +describe("IBM Plex Sans Thai", () => { + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/IBMPlexSansThai-Light.ttf"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "IBMPlexSansThai-Light.ttf"); + })); + + test("font loaded", () => { + assert.ok(font.opentype !== undefined); + }); + + test("name table ID 9 contains expected designer string", () => { + const { name } = font.opentype.tables; + assert.strictEqual( + name.get(9), + "Mike Abbink, Paul van der Laan, Pieter van Rosmalen, Ben Mitchell, Mark Frömberg" + ); + }); +}); diff --git a/testing/node/issue-114/flaticon.test.js b/testing/node/issue-114/flaticon.test.js index 191e24c..efd7b5f 100644 --- a/testing/node/issue-114/flaticon.test.js +++ b/testing/node/issue-114/flaticon.test.js @@ -1,28 +1,30 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; import { Font } from "../../../lib-font.js"; const font = new Font("flaticon"); describe("Basic font testing", () => { - beforeAll((done) => { - font.onerror = (err) => { - throw err; - }; - font.onload = async () => done(); - font.src = "./fonts/issue-114/Flaticon.woff2"; - }); + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/issue-114/Flaticon.woff2"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "Flaticon.woff2"); + })); test("font loaded", () => { - expect(font.opentype).toBeDefined(); + assert.ok(font.opentype !== undefined); }); test("has name table", () => { const { name } = font.opentype.tables; - expect(name).toBeDefined(); - expect(name.count).toBe(14); + assert.ok(name !== undefined); + assert.strictEqual(name.count, 14); const ID3 = `FontForge 2.0 : Flaticon : 21-12-2019`; - expect(name.get(3)).toBe(ID3); + assert.strictEqual(name.get(3), ID3); }); }); diff --git a/testing/node/mehr.nastaliq.test.js b/testing/node/mehr.nastaliq.test.js index 2a53da3..b2366d1 100644 --- a/testing/node/mehr.nastaliq.test.js +++ b/testing/node/mehr.nastaliq.test.js @@ -1,19 +1,21 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; import { Font } from "../../lib-font.js"; import { testGSUB } from "./gsub/test-gsub.js"; const font = new Font("mehr nastaliq"); describe("Basic font testing", () => { - beforeAll((done) => { - font.onerror = (err) => { - throw err; - }; - font.onload = async () => done(); - font.src = "./fonts/MehrNastaliqWeb-Regular.ttf"; - }); + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/MehrNastaliqWeb-Regular.ttf"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "MehrNastaliqWeb-Regular.ttf"); + })); test("font loaded", () => { - expect(font.opentype).toBeDefined(); + assert.ok(font.opentype !== undefined); }); test("GSUB format 6/8 functionality", () => { diff --git a/testing/node/source.code.pro.test.js b/testing/node/source.code.pro.test.js index 5932247..6e8e081 100644 --- a/testing/node/source.code.pro.test.js +++ b/testing/node/source.code.pro.test.js @@ -1,3 +1,6 @@ +import fs from "node:fs"; +import { describe, test, before } from "node:test"; +import assert from "node:assert"; import { Font } from "../../lib-font.js"; import { testGSUB } from "./gsub/test-gsub.js"; @@ -5,16 +8,15 @@ const font = new Font("source code pro"); let letterFor = function(){}; describe("Basic font testing", () => { - beforeAll((done) => { - font.onerror = (err) => { - throw err; - }; - font.onload = async () => done(); - font.src = "./fonts/SourceCodePro/SourceCodePro-Regular.ttf"; - }); + before(() => new Promise((resolve, reject) => { + font.onerror = (err) => reject(err); + font.onload = () => resolve(); + const buffer = fs.readFileSync("./fonts/SourceCodePro/SourceCodePro-Regular.ttf"); + font.fromDataBuffer(Uint8Array.from(buffer).buffer, "SourceCodePro-Regular.ttf"); + })); test("font loaded", () => { - expect(font.opentype).toBeDefined(); + assert.ok(font.opentype !== undefined); letterFor = function(glyphid) { let reversed = font.opentype.tables.cmap.reverse(glyphid); @@ -23,22 +25,22 @@ describe("Basic font testing", () => { }); test("Glyph support", () => { - expect(font.supports(`f`)).toBe(true); - expect(font.supports(`i`)).toBe(true); - expect(font.supports(String.fromCharCode(0xffff))).toBe(false); + assert.strictEqual(font.supports(`f`), true); + assert.strictEqual(font.supports(`i`), true); + assert.strictEqual(font.supports(String.fromCharCode(0xffff)), false); }); test("HEAD table", () => { const head = font.opentype.tables.head; - expect(head).toBeDefined(); - - expect(head.magicNumber).toBe(1594834165); - expect(head.fontDirectionHint).toBe(2); - expect(head.unitsPerEm).toBe(1000); - expect(head.xMin).toBe(-193); - expect(head.xMax).toBe(793); - expect(head.yMin).toBe(-454); - expect(head.yMax).toBe(1060); + assert.ok(head !== undefined); + + assert.strictEqual(head.magicNumber, 1594834165); + assert.strictEqual(head.fontDirectionHint, 2); + assert.strictEqual(head.unitsPerEm, 1000); + assert.strictEqual(head.xMin, -193); + assert.strictEqual(head.xMax, 793); + assert.strictEqual(head.yMin, -454); + assert.strictEqual(head.yMax, 1060); }); test("GSUB table", () => { From a93c8d14f83174ab7a9299b0717ca9941158712d Mon Sep 17 00:00:00 2001 From: Pomax Date: Tue, 31 Mar 2026 16:52:38 -0700 Subject: [PATCH 2/2] restore manual index --- testing/manual/index.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/testing/manual/index.html b/testing/manual/index.html index 0717491..2046f6e 100644 --- a/testing/manual/index.html +++ b/testing/manual/index.html @@ -6,10 +6,7 @@ - - +

Please open dev tools for now