diff --git a/backend/font_util/font.ts b/backend/font_util/font.ts index 83bbd2f..74e88e9 100644 --- a/backend/font_util/font.ts +++ b/backend/font_util/font.ts @@ -1,4 +1,5 @@ -import { Font, type FontEditor } from "fonteditor-core"; +import { Font } from "../../vendor/fonteditor-core/lib/ttf/font.js"; +import type { FontEditor } from "../../vendor/fonteditor-core/lib/ttf/font.js"; /** * 字体裁剪的所有可配置步骤 diff --git a/debug_profiling.ts b/debug_profiling.ts new file mode 100644 index 0000000..d4c3159 --- /dev/null +++ b/debug_profiling.ts @@ -0,0 +1,48 @@ +/** + * 精确分段计时:找出当前真正的瓶颈 + */ +import { readFile } from "node:fs/promises"; +import { Font } from "./vendor/fonteditor-core/lib/ttf/font.js"; + +const FONT_PATH = "font/令东齐伋复刻体.ttf"; +const raw = await readFile(FONT_PATH); +const fontBuffer = new Uint8Array(raw).buffer; + +const testCases = [ + { label: "8个汉字", subset: [..."天地玄黄宇宙洪荒"].map(c => c.codePointAt(0)!) }, + { label: "千字文前段", subset: [..."天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔"].map(c => c.codePointAt(0)!) }, +]; + +const ROUNDS = 30; + +for (const { label, subset } of testCases) { + let createSum = 0, optimizeSum = 0, sortSum = 0, writeSum = 0; + + for (let i = 0; i < ROUNDS; i++) { + let t0 = performance.now(); + const font = Font.create(fontBuffer, { type: "ttf", subset }); + let t1 = performance.now(); + createSum += t1 - t0; + + const optimized = font.optimize(); + let t2 = performance.now(); + optimizeSum += t2 - t1; + + const sorted = optimized.sort(); + let t3 = performance.now(); + sortSum += t3 - t2; + + const result = sorted.write({ type: "ttf" }); + let t4 = performance.now(); + writeSum += t4 - t3; + } + + const total = createSum + optimizeSum + sortSum + writeSum; + console.log(`${label} (${ROUNDS} rounds):`); + console.log(` create: ${createSum.toFixed(1)}ms (${(createSum / total * 100).toFixed(1)}%)`); + console.log(` optimize: ${optimizeSum.toFixed(1)}ms (${(optimizeSum / total * 100).toFixed(1)}%)`); + console.log(` sort: ${sortSum.toFixed(1)}ms (${(sortSum / total * 100).toFixed(1)}%)`); + console.log(` write: ${writeSum.toFixed(1)}ms (${(writeSum / total * 100).toFixed(1)}%)`); + console.log(` total: ${total.toFixed(1)}ms`); + console.log(); +} diff --git a/debug_table_timing3.ts b/debug_table_timing3.ts new file mode 100644 index 0000000..0b61919 --- /dev/null +++ b/debug_table_timing3.ts @@ -0,0 +1,51 @@ +/** + * 精确表读取计时 + */ +import { readFile } from "node:fs/promises"; + +const FONT_PATH = "font/令东齐伋复刻体.ttf"; +const raw = await readFile(FONT_PATH); +const fontBuffer = new Uint8Array(raw).buffer; + +const ROUNDS = 20; +const tableTimes: Record = {}; + +for (let r = 0; r < ROUNDS; r++) { + const ReaderModule = await import("./vendor/fonteditor-core/lib/ttf/reader.js"); + const Reader = (ReaderModule as any).default || ReaderModule; + const DirectoryModule = await import("./vendor/fonteditor-core/lib/ttf/table/directory.js"); + const Directory = (DirectoryModule as any).default || DirectoryModule; + const supportModule = await import("./vendor/fonteditor-core/lib/ttf/table/support.js"); + const support = (supportModule as any).default || supportModule; + + const reader = new Reader(fontBuffer, 0, fontBuffer.byteLength, false); + const ttf: any = {}; + + ttf.version = reader.readFixed(0); + ttf.numTables = reader.readUint16(); + ttf.searchRange = reader.readUint16(); + ttf.entrySelector = reader.readUint16(); + ttf.rangeShift = reader.readUint16(); + ttf.tables = new Directory(reader.offset).read(reader, ttf); + ttf.readOptions = { subset: [..."天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔"].map(c => c.codePointAt(0)) }; + + for (const tableName of Object.keys(support)) { + if (ttf.tables[tableName]) { + const offset = ttf.tables[tableName].offset; + const t0 = performance.now(); + ttf[tableName] = new support[tableName](offset).read(reader, ttf); + const t1 = performance.now(); + tableTimes[tableName] = (tableTimes[tableName] || 0) + (t1 - t0); + } + } + reader.dispose(); +} + +const total = Object.values(tableTimes).reduce((a: number, b: number) => a + b, 0); +const sorted = Object.entries(tableTimes).sort((a, b) => b[1] - a[1]); + +console.log(`表读取时间 (${ROUNDS} rounds):`); +for (const [name, time] of sorted) { + console.log(` ${name.padEnd(8)} ${time.toFixed(1).padStart(8)}ms ${(time / total * 100).toFixed(1).padStart(3)}%`); +} +console.log(` ${'total'.padEnd(8)} ${total.toFixed(1).padStart(8)}ms`); diff --git a/package.json b/package.json index 18256fd..f3a1cc5 100644 --- a/package.json +++ b/package.json @@ -15,18 +15,20 @@ "release": "pnpm build && pnpm build_backend && pnpm docker_build && pnpm docker_push" }, "dependencies": { - "fonteditor-core": "file:./vendor/fonteditor-core", "solid-js": "^1.9.12", "web-streams-polyfill": "^4.2.0" }, "devDependencies": { "@types/node": "^25.5.2", + "@xmldom/xmldom": "^0.9.9", + "jsdom": "^29.0.2", "skia-canvas": "^3.0.8", "tsup": "^8.5.1", "typescript": "^6.0.2", "undici": "^8.0.2", "vite": "^8.0.7", "vite-plugin-pilot": "^1.0.19", - "vite-plugin-solid": "^2.11.12" + "vite-plugin-solid": "^2.11.12", + "vitest": "^4.1.3" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53fdd9f..720416f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - fonteditor-core: - specifier: file:./vendor/fonteditor-core - version: file:vendor/fonteditor-core solid-js: specifier: ^1.9.12 version: 1.9.12 @@ -21,6 +18,12 @@ importers: '@types/node': specifier: ^25.5.2 version: 25.5.2 + '@xmldom/xmldom': + specifier: ^0.9.9 + version: 0.9.9 + jsdom: + specifier: ^29.0.2 + version: 29.0.2 skia-canvas: specifier: ^3.0.8 version: 3.0.8 @@ -42,9 +45,23 @@ importers: vite-plugin-solid: specifier: ^2.11.12 version: 2.11.12(solid-js@1.9.12)(vite@8.0.7(@types/node@25.5.2)(esbuild@0.27.7)) + vitest: + specifier: ^4.1.3 + version: 4.1.3(@types/node@25.5.2)(jsdom@29.0.2)(vite@8.0.7(@types/node@25.5.2)(esbuild@0.27.7)) packages: + '@asamuzakjp/css-color@5.1.8': + resolution: {integrity: sha512-OISPR9c2uPo23rUdvfEQiLPjoMLOpEeLNnP5iGkxr6tDDxJd3NjD+6fxY0mdaMbIPUjFGL4HFOJqLvow5q4aqQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@7.0.8': + resolution: {integrity: sha512-erMO6FgtM02dC24NGm0xufMzWz5OF0wXKR7BpvGD973bq/GbmR8/DbxNZbj0YevQ5hlToJaWSVK/G9/NDgGEVw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -126,6 +143,46 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.1.1': + resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.0.2': + resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.2': + resolution: {integrity: sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@emnapi/core@1.9.1': resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} @@ -291,6 +348,15 @@ packages: cpu: [x64] os: [win32] + '@exodus/bytes@1.15.0': + resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -552,6 +618,9 @@ packages: cpu: [x64] os: [win32] + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -567,15 +636,50 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/node@25.5.2': resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==} - '@xmldom/xmldom@0.8.12': - resolution: {integrity: sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==} - engines: {node: '>=10.0.0'} + '@vitest/expect@4.1.3': + resolution: {integrity: sha512-CW8Q9KMtXDGHj0vCsqui0M5KqRsu0zm0GNDW7Gd3U7nZ2RFpPKSCpeCXoT+/+5zr1TNlsoQRDEz+LzZUyq6gnQ==} + + '@vitest/mocker@4.1.3': + resolution: {integrity: sha512-XN3TrycitDQSzGRnec/YWgoofkYRhouyVQj4YNsJ5r/STCUFqMrP4+oxEv3e7ZbLi4og5kIHrZwekDJgw6hcjw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.3': + resolution: {integrity: sha512-hYqqwuMbpkkBodpRh4k4cQSOELxXky1NfMmQvOfKvV8zQHz8x8Dla+2wzElkMkBvSAJX5TRGHJAQvK0TcOafwg==} + + '@vitest/runner@4.1.3': + resolution: {integrity: sha512-VwgOz5MmT0KhlUj40h02LWDpUBVpflZ/b7xZFA25F29AJzIrE+SMuwzFf0b7t4EXdwRNX61C3B6auIXQTR3ttA==} + + '@vitest/snapshot@4.1.3': + resolution: {integrity: sha512-9l+k/J9KG5wPJDX9BcFFzhhwNjwkRb8RsnYhaT1vPY7OufxmQFc9sZzScRCPTiETzl37mrIWVY9zxzmdVeJwDQ==} + + '@vitest/spy@4.1.3': + resolution: {integrity: sha512-ujj5Uwxagg4XUIfAUyRQxAg631BP6e9joRiN99mr48Bg9fRs+5mdUElhOoZ6rP5mBr8Bs3lmrREnkrQWkrsTCw==} + + '@vitest/utils@4.1.3': + resolution: {integrity: sha512-Pc/Oexse/khOWsGB+w3q4yzA4te7W4gpZZAvk+fr8qXfTURZUMj5i7kuxsNK5mP/dEB6ao3jfr0rs17fHhbHdw==} + + '@xmldom/xmldom@0.9.9': + resolution: {integrity: sha512-qycIHAucxy/LXAYIjmLmtQ8q9GPnMbnjG1KXhWm9o5sCr6pOYDATkMPiTNa6/v8eELyqOQ2FsEqeoFYmgv/gJg==} + engines: {node: '>=14.6'} acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} @@ -589,6 +693,10 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + babel-plugin-jsx-dom-expressions@0.40.6: resolution: {integrity: sha512-v3P1MW46Lm7VMpAkq0QfyzLWWkC8fh+0aE5Km4msIgDx5kjenHU0pF2s+4/NH8CQn/kla6+Hvws+2AF7bfV5qQ==} peerDependencies: @@ -608,6 +716,9 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -626,6 +737,10 @@ packages: caniuse-lite@1.0.30001787: resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -644,9 +759,17 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -656,6 +779,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -667,6 +793,9 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} @@ -676,6 +805,13 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -697,9 +833,6 @@ packages: debug: optional: true - fonteditor-core@file:vendor/fonteditor-core: - resolution: {directory: vendor/fonteditor-core, type: directory} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -709,6 +842,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-entities@2.3.3: resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} @@ -716,6 +853,9 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} @@ -727,6 +867,15 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + jsdom@29.0.2: + resolution: {integrity: sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -822,12 +971,19 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lru-cache@11.3.3: + resolution: {integrity: sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + merge-anything@5.1.7: resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} engines: {node: '>=12.13'} @@ -853,12 +1009,18 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + parenthesis@3.1.8: resolution: {integrity: sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==} parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -898,10 +1060,18 @@ packages: resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} engines: {node: ^10 || ^12 || >=14} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -916,6 +1086,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -930,6 +1104,9 @@ packages: resolution: {integrity: sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q==} engines: {node: '>=10'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + skia-canvas@3.0.8: resolution: {integrity: sha512-FSYKxp8Ng2vOeeOBiyPhnn6ui6FirPJXMyjk4PKl8N/OWzVrkMawUgY9zubIWHMdYtyWFn0gfX3QlRwg6HBmdg==} @@ -949,6 +1126,12 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + string-split-by@1.0.0: resolution: {integrity: sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==} @@ -957,6 +1140,9 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -964,13 +1150,39 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + engines: {node: '>=18'} + tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tldts-core@7.0.28: + resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==} + + tldts@7.0.28: + resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==} + hasBin: true + + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -1011,6 +1223,10 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici@7.24.7: + resolution: {integrity: sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==} + engines: {node: '>=20.18.1'} + undici@8.0.2: resolution: {integrity: sha512-B9MeU5wuFhkFAuNeA19K2GDFcQXZxq33fL0nRy2Aq30wdufZbyyvxW3/ChaeipXVfy/wUweZyzovQGk39+9k2w==} engines: {node: '>=22.19.0'} @@ -1096,15 +1312,100 @@ packages: vite: optional: true + vitest@4.1.3: + resolution: {integrity: sha512-DBc4Tx0MPNsqb9isoyOq00lHftVx/KIU44QOm2q59npZyLUkENn8TMFsuzuO+4U2FUa9rgbbPt3udrP25GcjXw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.3 + '@vitest/browser-preview': 4.1.3 + '@vitest/browser-webdriverio': 4.1.3 + '@vitest/coverage-istanbul': 4.1.3 + '@vitest/coverage-v8': 4.1.3 + '@vitest/ui': 4.1.3 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + web-streams-polyfill@4.2.0: resolution: {integrity: sha512-0rYDzGOh9EZpig92umN5g5D/9A1Kff7k0/mzPSSCY8jEQeYkgRMoY7LhbXtUCWzLCMX0TUE9aoHkjFNB7D9pfA==} engines: {node: '>= 8'} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} snapshots: + '@asamuzakjp/css-color@5.1.8': + dependencies: + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@7.0.8': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/nwsapi@2.3.9': {} + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -1216,6 +1517,34 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.2(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + '@emnapi/core@1.9.1': dependencies: '@emnapi/wasi-threads': 1.2.0 @@ -1310,6 +1639,8 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true + '@exodus/bytes@1.15.0': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1464,6 +1795,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.60.1': optional: true + '@standard-schema/spec@1.1.0': {} + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -1490,13 +1823,61 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + '@types/estree@1.0.8': {} '@types/node@25.5.2': dependencies: undici-types: 7.18.2 - '@xmldom/xmldom@0.8.12': {} + '@vitest/expect@4.1.3': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.3 + '@vitest/utils': 4.1.3 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.3(vite@8.0.7(@types/node@25.5.2)(esbuild@0.27.7))': + dependencies: + '@vitest/spy': 4.1.3 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.7(@types/node@25.5.2)(esbuild@0.27.7) + + '@vitest/pretty-format@4.1.3': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.3': + dependencies: + '@vitest/utils': 4.1.3 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.3': + dependencies: + '@vitest/pretty-format': 4.1.3 + '@vitest/utils': 4.1.3 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.3': {} + + '@vitest/utils@4.1.3': + dependencies: + '@vitest/pretty-format': 4.1.3 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + '@xmldom/xmldom@0.9.9': {} acorn@8.16.0: {} @@ -1504,6 +1885,8 @@ snapshots: any-promise@1.3.0: {} + assertion-error@2.0.1: {} + babel-plugin-jsx-dom-expressions@0.40.6(@babel/core@7.29.0): dependencies: '@babel/core': 7.29.0 @@ -1522,6 +1905,10 @@ snapshots: baseline-browser-mapping@2.10.16: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + browserslist@4.28.2: dependencies: baseline-browser-mapping: 2.10.16 @@ -1539,6 +1926,8 @@ snapshots: caniuse-lite@1.0.30001787: {} + chai@6.2.2: {} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -1551,18 +1940,34 @@ snapshots: convert-source-map@2.0.0: {} + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + csstype@3.2.3: {} + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + debug@4.4.3: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + detect-libc@2.1.2: {} electron-to-chromium@1.5.333: {} entities@6.0.1: {} + es-module-lexer@2.0.0: {} + esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 @@ -1594,6 +1999,12 @@ snapshots: escalade@3.2.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.3.0: {} + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -1606,15 +2017,17 @@ snapshots: follow-redirects@1.15.11: {} - fonteditor-core@file:vendor/fonteditor-core: - dependencies: - '@xmldom/xmldom': 0.8.12 - fsevents@2.3.3: optional: true gensync@1.0.0-beta.2: {} + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.0 + transitivePeerDependencies: + - '@noble/hashes' + html-entities@2.3.3: {} https-proxy-agent@7.0.6: @@ -1624,12 +2037,40 @@ snapshots: transitivePeerDependencies: - supports-color + is-potential-custom-element-name@1.0.1: {} + is-what@4.1.16: {} joycon@3.1.1: {} js-tokens@4.0.0: {} + jsdom@29.0.2: + dependencies: + '@asamuzakjp/css-color': 5.1.8 + '@asamuzakjp/dom-selector': 7.0.8 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.2(css-tree@3.2.1) + '@exodus/bytes': 1.15.0 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.3.3 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.24.7 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + jsesc@3.1.0: {} json5@2.2.3: {} @@ -1689,6 +2130,8 @@ snapshots: load-tsconfig@0.2.5: {} + lru-cache@11.3.3: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -1697,6 +2140,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + mdn-data@2.27.1: {} + merge-anything@5.1.7: dependencies: is-what: 4.1.16 @@ -1722,12 +2167,18 @@ snapshots: object-assign@4.1.1: {} + obug@2.1.1: {} + parenthesis@3.1.8: {} parse5@7.3.0: dependencies: entities: 6.0.1 + parse5@8.0.0: + dependencies: + entities: 6.0.1 + pathe@2.0.3: {} picocolors@1.1.1: {} @@ -1754,8 +2205,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + punycode@2.3.1: {} + readdirp@4.1.2: {} + require-from-string@2.0.2: {} + resolve-from@5.0.0: {} rolldown@1.0.0-rc.13: @@ -1810,6 +2265,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.1 fsevents: 2.3.3 + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + semver@6.3.1: {} seroval-plugins@1.5.2(seroval@1.5.2): @@ -1818,6 +2277,8 @@ snapshots: seroval@1.5.2: {} + siginfo@2.0.0: {} + skia-canvas@3.0.8: dependencies: detect-libc: 2.1.2 @@ -1847,6 +2308,10 @@ snapshots: source-map@0.7.6: {} + stackback@0.0.2: {} + + std-env@4.0.0: {} + string-split-by@1.0.0: dependencies: parenthesis: 3.1.8 @@ -1861,6 +2326,8 @@ snapshots: tinyglobby: 0.2.16 ts-interface-checker: 0.1.13 + symbol-tree@3.2.4: {} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -1869,13 +2336,33 @@ snapshots: dependencies: any-promise: 1.3.0 + tinybench@2.9.0: {} + tinyexec@0.3.2: {} + tinyexec@1.1.1: {} + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyrainbow@3.1.0: {} + + tldts-core@7.0.28: {} + + tldts@7.0.28: + dependencies: + tldts-core: 7.0.28 + + tough-cookie@6.0.1: + dependencies: + tldts: 7.0.28 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} ts-interface-checker@0.1.13: {} @@ -1917,6 +2404,8 @@ snapshots: undici-types@7.18.2: {} + undici@7.24.7: {} + undici@8.0.2: {} update-browserslist-db@1.2.3(browserslist@4.28.2): @@ -1960,6 +2449,59 @@ snapshots: optionalDependencies: vite: 8.0.7(@types/node@25.5.2)(esbuild@0.27.7) + vitest@4.1.3(@types/node@25.5.2)(jsdom@29.0.2)(vite@8.0.7(@types/node@25.5.2)(esbuild@0.27.7)): + dependencies: + '@vitest/expect': 4.1.3 + '@vitest/mocker': 4.1.3(vite@8.0.7(@types/node@25.5.2)(esbuild@0.27.7)) + '@vitest/pretty-format': 4.1.3 + '@vitest/runner': 4.1.3 + '@vitest/snapshot': 4.1.3 + '@vitest/spy': 4.1.3 + '@vitest/utils': 4.1.3 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.1.1 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.7(@types/node@25.5.2)(esbuild@0.27.7) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.5.2 + jsdom: 29.0.2 + transitivePeerDependencies: + - msw + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + web-streams-polyfill@4.2.0: {} + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.0 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + yallist@3.1.1: {} diff --git a/task.md b/task.md index 1942c1b..fa96270 100644 --- a/task.md +++ b/task.md @@ -1,3 +1,11 @@ -/loop 持续优化字体子集化性能,可以大胆放开手脚的去做,但是优化完一定要通过基准测试。中途不要切换到其他模式,比如计划模式也不要询问我,你直接做就行了,请你持续的去优化,不要去询问我,不要去中断,好吧 +/loop 持续优化字体子集化性能,可以大胆放开手脚的去做,但是优化完一定要通过`pnpx tsx ./基准测试.test.ts`。中途不要切换到其他模式,比如计划模式也不要询问我,你直接做就行了,请你持续的去优化,不要去询问我,不要去中断,好吧 -啊,你每次优化能不能把基准测试保存在本地目录下,这样我方便查看。你的文档中应该在每个重大节点更新基准测试结果,这样我能方便看到你使用了哪些优化方法,得到了什么样的优化效果。 \ No newline at end of file +啊,你每次优化能不能把基准测试结果文档保存在本地目录下,这样我方便查看。你的文档中应该在每个重大节点更新基准测试结果,这样我能方便看到你使用了哪些优化方法,得到了什么样的优化效果。 + + + +=== 字体裁剪基准测试 === + + 8个汉字: avg=23.6ms min=18.4ms max=37.2ms 输出=16,508 bytes ssim=1.0000 + 拉丁+数字: avg=16.4ms min=13.7ms max=18.2ms 输出=1,272 bytes ssim=1.0000 + 千字文前段: avg=59.4ms min=47.3ms max=76.5ms 输出=161,344 bytes ssim=1.0000 diff --git a/vendor/fonteditor-core/lib/graphics/reducePathFlat.js b/vendor/fonteditor-core/lib/graphics/reducePathFlat.js new file mode 100644 index 0000000..8148c10 --- /dev/null +++ b/vendor/fonteditor-core/lib/graphics/reducePathFlat.js @@ -0,0 +1,82 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = reducePathFlat; +/** + * @file 缩减path大小(扁平格式专用),去除冗余节点 + * @author mengke01(kekee000@gmail.com) + */ + +/** + * 缩减glyf,去除冗余节点(扁平格式 [x, y, onCurve, ...]) + * 懒分配:首个点被移除前不分配 reduced 数组,大多数 contour 无冗余点可直接返回 + */ +function reducePathFlat(contour) { + if (!contour.length) { + return contour; + } + var len = contour.length; + var l = len / 3; + /** 懒分配:仅在首个被保留的点出现时才创建 reduced 数组 */ + var reduced = null; + var ri = 0; + var removed = 0; + // 段1: i=0(首点,prev 是尾点) + var px = contour[0], py = contour[1], po = contour[2]; + var prevX = contour[(l - 1) * 3], prevY = contour[(l - 1) * 3 + 1], prevO = contour[(l - 1) * 3 + 2]; + var nextX = contour[3], nextY = contour[4], nextO = contour[5]; + + var dx = px - nextX; + var dy = py - nextY; + if ((po && nextO || !po && !nextO) && dx * dx + dy * dy <= 1) { removed++; } + else { + var cross = (nextY - py) * (prevX - px) - (prevY - py) * (nextX - px); + if (prevO && nextO && cross > -0.001 && cross < 0.001) { removed++; } + else { + reduced = new Array(len); + reduced[ri++] = px; reduced[ri++] = py; reduced[ri++] = po; + } + } + // 段2: i=1..l-2(中间点,prev/next 简单偏移) + for (var i = 1; i < l - 1; i++) { + var pi = i * 3; + px = contour[pi]; py = contour[pi + 1]; po = contour[pi + 2]; + prevX = contour[pi - 3]; prevY = contour[pi - 2]; prevO = contour[pi - 1]; + nextX = contour[pi + 3]; nextY = contour[pi + 4]; nextO = contour[pi + 5]; + + dx = px - nextX; + dy = py - nextY; + if ((po && nextO || !po && !nextO) && dx * dx + dy * dy <= 1) { removed++; continue; } + cross = (nextY - py) * (prevX - px) - (prevY - py) * (nextX - px); + if (prevO && nextO && cross > -0.001 && cross < 0.001) { removed++; continue; } + + if (!reduced) reduced = new Array(len); + reduced[ri++] = px; reduced[ri++] = py; reduced[ri++] = po; + } + // 段3: i=l-1(尾点,next 是首点) + if (l > 1) { + var pi = (l - 1) * 3; + px = contour[pi]; py = contour[pi + 1]; po = contour[pi + 2]; + prevX = contour[pi - 3]; prevY = contour[pi - 2]; prevO = contour[pi - 1]; + nextX = contour[0]; nextY = contour[1]; nextO = contour[2]; + + dx = px - nextX; + dy = py - nextY; + if ((po && nextO || !po && !nextO) && dx * dx + dy * dy <= 1) { removed++; } + else { + cross = (nextY - py) * (prevX - px) - (prevY - py) * (nextX - px); + if (prevO && nextO && cross > -0.001 && cross < 0.001) { removed++; } + else { + if (!reduced) reduced = new Array(len); + reduced[ri++] = px; reduced[ri++] = py; reduced[ri++] = po; + } + } + } + // 没有任何缩减,直接返回原数组避免拷贝 + if (!reduced) return contour; + // 截断到实际大小 + reduced.length = ri; + return reduced; +} diff --git a/vendor/fonteditor-core/src/common/DOMParser.js b/vendor/fonteditor-core/src/common/DOMParser.js deleted file mode 100644 index ef9fc73..0000000 --- a/vendor/fonteditor-core/src/common/DOMParser.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @file DOM解析器,兼容node端和浏览器端 - * @author mengke01(kekee000@gmail.com) - */ - -/* eslint-disable no-undef */ -export default typeof window !== 'undefined' && window.DOMParser - ? window.DOMParser - : require('@xmldom/xmldom').DOMParser; diff --git a/vendor/fonteditor-core/src/common/I18n.js b/vendor/fonteditor-core/src/common/I18n.js deleted file mode 100644 index 2e9b00f..0000000 --- a/vendor/fonteditor-core/src/common/I18n.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file 用于国际化的字符串管理类 - * @author mengke01(kekee000@gmail.com) - */ - -function appendLanguage(store, languageList) { - languageList.forEach(item => { - const language = item[0]; - store[language] = Object.assign(store[language] || {}, item[1]); - }); - return store; -} - -/** - * 管理国际化字符,根据lang切换语言版本 - * - * @class I18n - * @param {Array} languageList 当前支持的语言列表 - * @param {string=} defaultLanguage 默认语言 - * languageList = [ - * 'en-us', // 语言名称 - * langObject // 语言字符串列表 - * ] - */ -export default class I18n { - constructor(languageList, defaultLanguage) { - this.store = appendLanguage({}, languageList); - this.setLanguage( - defaultLanguage - || typeof navigator !== 'undefined' && navigator.language && navigator.language.toLowerCase() - || 'en-us' - ); - } - - /** - * 设置语言 - * - * @param {string} language 语言 - * @return {this} - */ - setLanguage(language) { - if (!this.store[language]) { - language = 'en-us'; - } - this.lang = this.store[this.language = language]; - return this; - } - - /** - * 添加一个语言字符串 - * - * @param {string} language 语言 - * @param {Object} langObject 语言对象 - * @return {this} - */ - addLanguage(language, langObject) { - appendLanguage(this.store, [[language, langObject]]); - return this; - } - - /** - * 获取当前语言字符串 - * - * @param {string} path 语言路径 - * @return {string} 语言字符串 - */ - get(path) { - const ref = path.split('.'); - let refObject = this.lang; - let level; - while (refObject != null && (level = ref.shift())) { - refObject = refObject[level]; - } - return refObject != null ? refObject : ''; - } -} diff --git a/vendor/fonteditor-core/src/common/ajaxFile.js b/vendor/fonteditor-core/src/common/ajaxFile.js deleted file mode 100644 index e203bb8..0000000 --- a/vendor/fonteditor-core/src/common/ajaxFile.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file ajax获取文本数据 - * @author mengke01(kekee000@gmail.com) - */ - - -/** - * ajax获取数据 - * - * @param {Object} options 参数选项 - * @param {string=} options.type 类型 - * @param {string=} options.method method - * @param {Function=} options.onSuccess 成功回调 - * @param {Function=} options.onError 失败回调 - * @param {Object=} options.params 参数集合 - */ -export default function ajaxFile(options) { - const xhr = new XMLHttpRequest(); - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - const status = xhr.status; - if (status >= 200 && status < 300 || status === 304) { - if (options.onSuccess) { - if (options.type === 'binary') { - const buffer = xhr.responseBlob || xhr.response; - options.onSuccess(buffer); - } - else if (options.type === 'xml') { - options.onSuccess(xhr.responseXML); - } - else if (options.type === 'json') { - options.onSuccess(JSON.parse(xhr.responseText)); - } - else { - options.onSuccess(xhr.responseText); - } - } - - } - else if (options.onError) { - options.onError(xhr, xhr.status); - } - } - }; - - const method = (options.method || 'GET').toUpperCase(); - let params = null; - if (options.params) { - - let str = []; - Object.keys(options.params).forEach(key => { - str.push(key + '=' + encodeURIComponent(options.params[key])); - }); - str = str.join('&'); - if (method === 'GET') { - options.url += (options.url.indexOf('?') === -1 ? '?' : '&') + str; - } - else { - params = str; - } - } - - xhr.open(method, options.url, true); - - if (options.type === 'binary') { - xhr.responseType = 'arraybuffer'; - } - xhr.send(params); -} - -export function loadFile(url, type = 'binary') { - return new Promise((resolve, reject) => { - ajaxFile({ - type, - url, - onSuccess(buffer) { - resolve(buffer); - }, - onError(e) { - reject(e); - } - }); - }); -} diff --git a/vendor/fonteditor-core/src/common/lang.js b/vendor/fonteditor-core/src/common/lang.js deleted file mode 100644 index 41ed273..0000000 --- a/vendor/fonteditor-core/src/common/lang.js +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @file 语言相关函数 - * @author mengke01(kekee000@gmail.com) - */ - - -export function isArray(obj) { - return obj != null && toString.call(obj).slice(8, -1) === 'Array'; -} - -export function isObject(obj) { - return obj != null && toString.call(obj).slice(8, -1) === 'Object'; -} - -export function isString(obj) { - return obj != null && toString.call(obj).slice(8, -1) === 'String'; -} - -export function isFunction(obj) { - return obj != null && toString.call(obj).slice(8, -1) === 'Function'; -} - -export function isDate(obj) { - return obj != null && toString.call(obj).slice(8, -1) === 'Date'; -} - -export function isEmptyObject(object) { - for (const name in object) { - // eslint-disable-next-line no-prototype-builtins - if (object.hasOwnProperty(name)) { - return false; - } - } - return true; -} - -/** - * 为函数提前绑定前置参数(柯里化) - * - * @see http://en.wikipedia.org/wiki/Currying - * @param {Function} fn 要绑定的函数 - * @param {...Array} cargs cargs - * @return {Function} - */ -export function curry(fn, ...cargs) { - return function (...rargs) { - const args = cargs.concat(rargs); - // eslint-disable-next-line no-invalid-this - return fn.apply(this, args); - }; -} - - -/** - * 方法静态化, 反绑定、延迟绑定 - * - * @param {Function} method 待静态化的方法 - * @return {Function} 静态化包装后方法 - */ -export function generic(method) { - return function (...fargs) { - return Function.call.apply(method, fargs); - }; -} - - -/** - * 设置覆盖相关的属性值 - * - * @param {Object} thisObj 覆盖对象 - * @param {Object} thatObj 值对象 - * @param {Array.} fields 字段 - * @return {Object} thisObj - */ -export function overwrite(thisObj, thatObj, fields) { - - if (!thatObj) { - return thisObj; - } - - // 这里`fields`未指定则仅overwrite自身可枚举的字段,指定`fields`则不做限制 - fields = fields || Object.keys(thatObj); - fields.forEach(field => { - // 拷贝对象 - if ( - thisObj[field] && typeof thisObj[field] === 'object' - && thatObj[field] && typeof thatObj[field] === 'object' - ) { - overwrite(thisObj[field], thatObj[field]); - } - else { - thisObj[field] = thatObj[field]; - } - }); - - return thisObj; -} - -/** - * 深复制对象,仅复制数据 - * - * @param {Object} source 源数据 - * @return {Object} 复制的数据 - */ -export function clone(source) { - if (!source || typeof source !== 'object') { - return source; - } - - let cloned = source; - - if (isArray(source)) { - cloned = source.slice().map(clone); - } - else if (isObject(source) && 'isPrototypeOf' in source) { - cloned = {}; - for (const key of Object.keys(source)) { - cloned[key] = clone(source[key]); - } - } - - return cloned; -} - - -// Returns a function, that, when invoked, will only be triggered at most once -// during a given window of time. -// @see underscore.js -export function throttle(func, wait) { - let context; - let args; - let timeout; - let result; - let previous = 0; - const later = function () { - previous = new Date(); - timeout = null; - result = func.apply(context, args); - }; - - return function (...args) { - const now = new Date(); - const remaining = wait - (now - previous); - // eslint-disable-next-line no-invalid-this - context = this; - if (remaining <= 0) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - } - else if (!timeout) { - timeout = setTimeout(later, remaining); - } - return result; - }; -} - -// Returns a function, that, as long as it continues to be invoked, will not -// be triggered. The function will be called after it stops being called for -// N milliseconds. If `immediate` is passed, trigger the function on the -// leading edge, instead of the trailing. -// @see underscore.js -export function debounce(func, wait, immediate) { - let timeout; - let result; - - return function (...args) { - // eslint-disable-next-line no-invalid-this - const context = this; - const later = function () { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - } - }; - - const callNow = immediate && !timeout; - - clearTimeout(timeout); - timeout = setTimeout(later, wait); - - if (callNow) { - result = func.apply(context, args); - } - - return result; - }; -} - -/** - * 判断两个对象的字段是否相等 - * - * @param {Object} thisObj 要比较的对象 - * @param {Object} thatObj 参考对象 - * @param {Array} fields 指定字段 - * @return {boolean} 是否相等 - */ -export function equals(thisObj, thatObj, fields) { - - if (thisObj === thatObj) { - return true; - } - - if (thisObj == null && thatObj == null) { - return true; - } - - if (thisObj == null && thatObj != null || thisObj != null && thatObj == null) { - return false; - } - - // 这里`fields`未指定则仅overwrite自身可枚举的字段,指定`fields`则不做限制 - fields = fields || (typeof thisObj === 'object' - ? Object.keys(thisObj) - : []); - - if (!fields.length) { - return thisObj === thatObj; - } - - let equal = true; - for (let i = 0, l = fields.length, field; equal && i < l; i++) { - field = fields[i]; - - if ( - thisObj[field] && typeof thisObj[field] === 'object' - && thatObj[field] && typeof thatObj[field] === 'object' - ) { - equal = equal && equals(thisObj[field], thatObj[field]); - } - else { - equal = equal && (thisObj[field] === thatObj[field]); - } - } - - return equal; -} diff --git a/vendor/fonteditor-core/src/common/string.js b/vendor/fonteditor-core/src/common/string.js deleted file mode 100644 index 87573ea..0000000 --- a/vendor/fonteditor-core/src/common/string.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file 字符串相关的函数 - * @author mengke01(kekee000@gmail.com) - */ - -export default { - - /** - * HTML解码字符串 - * - * @param {string} source 源字符串 - * @return {string} - */ - decodeHTML(source) { - - const str = String(source) - .replace(/"/g, '"') - .replace(/</g, '<') - .replace(/>/g, '>') - .replace(/&/g, '&'); - - // 处理转义的中文和实体字符 - return str.replace(/&#([\d]+);/g, ($0, $1) => String.fromCodePoint(parseInt($1, 10))); - }, - - /** - * HTML编码字符串 - * - * @param {string} source 源字符串 - * @return {string} - */ - encodeHTML(source) { - return String(source) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - }, - - /** - * 获取string字节长度 - * - * @param {string} source 源字符串 - * @return {number} 长度 - */ - getLength(source) { - // eslint-disable-next-line no-control-regex - return String(source).replace(/[^\x00-\xff]/g, '11').length; - }, - - /** - * 字符串格式化,支持如 ${xxx.xxx} 的语法 - * - * @param {string} source 模板字符串 - * @param {Object} data 数据 - * @return {string} 格式化后字符串 - */ - format(source, data) { - return source.replace(/\$\{([\w.]+)\}/g, ($0, $1) => { - const ref = $1.split('.'); - let refObject = data; - let level; - - while (refObject != null && (level = ref.shift())) { - refObject = refObject[level]; - } - - return refObject != null ? refObject : ''; - }); - }, - - /** - * 使用指定字符填充字符串,默认`0` - * - * @param {string} str 字符串 - * @param {number} size 填充到的大小 - * @param {string=} ch 填充字符 - * @return {string} 字符串 - */ - pad(str, size, ch) { - str = String(str); - if (str.length > size) { - return str.slice(str.length - size); - } - return new Array(size - str.length + 1).join(ch || '0') + str; - }, - - /** - * 获取字符串哈希编码 - * - * @param {string} str 字符串 - * @return {number} 哈希值 - */ - hashcode(str) { - if (!str) { - return 0; - } - - let hash = 0; - for (let i = 0, l = str.length; i < l; i++) { - hash = 0x7FFFFFFFF & (hash * 31 + str.charCodeAt(i)); - } - return hash; - } -}; diff --git a/vendor/fonteditor-core/src/graphics/computeBoundingBox.js b/vendor/fonteditor-core/src/graphics/computeBoundingBox.js deleted file mode 100644 index 96ff164..0000000 --- a/vendor/fonteditor-core/src/graphics/computeBoundingBox.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * @file 计算曲线包围盒 - * @author mengke01(kekee000@gmail.com) - * - * modify from: - * zrender - * https://github.com/ecomfe/zrender/blob/master/src/tool/computeBoundingBox.js - */ -import pathIterator from './pathIterator'; - -/** - * 计算包围盒 - * - * @param {Array} points 点集 - * @return {Object} bounding box - */ -function computeBoundingBox(points) { - - if (points.length === 0) { - return false; - } - - let left = points[0].x; - let right = points[0].x; - let top = points[0].y; - let bottom = points[0].y; - - for (let i = 1; i < points.length; i++) { - const p = points[i]; - - if (p.x < left) { - left = p.x; - } - - if (p.x > right) { - right = p.x; - } - - if (p.y < top) { - top = p.y; - } - - if (p.y > bottom) { - bottom = p.y; - } - } - - return { - x: left, - y: top, - width: right - left, - height: bottom - top - }; -} - -/** - * 计算二阶贝塞尔曲线的包围盒 - * http://pissang.net/blog/?p=91 - * - * @param {Object} p0 p0 - * @param {Object} p1 p1 - * @param {Object} p2 p2 - * @return {Object} bound对象 - */ -function computeQuadraticBezierBoundingBox(p0, p1, p2) { - // Find extremities, where derivative in x dim or y dim is zero - let tmp = (p0.x + p2.x - 2 * p1.x); - // p1 is center of p0 and p2 in x dim - let t1; - if (tmp === 0) { - t1 = 0.5; - } - else { - t1 = (p0.x - p1.x) / tmp; - } - - tmp = (p0.y + p2.y - 2 * p1.y); - // p1 is center of p0 and p2 in y dim - let t2; - if (tmp === 0) { - t2 = 0.5; - } - else { - t2 = (p0.y - p1.y) / tmp; - } - - t1 = Math.max(Math.min(t1, 1), 0); - t2 = Math.max(Math.min(t2, 1), 0); - - const ct1 = 1 - t1; - const ct2 = 1 - t2; - - const x1 = ct1 * ct1 * p0.x + 2 * ct1 * t1 * p1.x + t1 * t1 * p2.x; - const y1 = ct1 * ct1 * p0.y + 2 * ct1 * t1 * p1.y + t1 * t1 * p2.y; - - const x2 = ct2 * ct2 * p0.x + 2 * ct2 * t2 * p1.x + t2 * t2 * p2.x; - const y2 = ct2 * ct2 * p0.y + 2 * ct2 * t2 * p1.y + t2 * t2 * p2.y; - - return computeBoundingBox( - [ - p0, - p2, - { - x: x1, - y: y1 - }, - { - x: x2, - y: y2 - } - ] - ); -} - -/** - * 计算曲线包围盒 - * - * @private - * @param {...Array} args 坐标点集, 支持多个path - * @return {Object} {x, y, width, height} - */ -function computePathBoundingBox(...args) { - - const points = []; - const iterator = function (c, p0, p1, p2) { - if (c === 'L') { - points.push(p0); - points.push(p1); - } - else if (c === 'Q') { - const bound = computeQuadraticBezierBoundingBox(p0, p1, p2); - - points.push(bound); - points.push({ - x: bound.x + bound.width, - y: bound.y + bound.height - }); - } - }; - - if (args.length === 1) { - pathIterator(args[0], (c, p0, p1, p2) => { - if (c === 'L') { - points.push(p0); - points.push(p1); - } - else if (c === 'Q') { - const bound = computeQuadraticBezierBoundingBox(p0, p1, p2); - - points.push(bound); - points.push({ - x: bound.x + bound.width, - y: bound.y + bound.height - }); - } - }); - } - else { - for (let i = 0, l = args.length; i < l; i++) { - pathIterator(args[i], iterator); - } - } - - return computeBoundingBox(points); -} - - -/** - * 计算曲线点边界 - * - * @private - * @param {...Array} args path对象, 支持多个path - * @return {Object} {x, y, width, height} - */ -export function computePathBox(...args) { - let points = []; - if (args.length === 1) { - points = args[0]; - } - else { - for (let i = 0, l = args.length; i < l; i++) { - Array.prototype.splice.apply(points, [points.length, 0].concat(args[i])); - } - } - return computeBoundingBox(points); -} - -export const computeBounding = computeBoundingBox; -export const quadraticBezier = computeQuadraticBezierBoundingBox; -export const computePath = computePathBoundingBox; diff --git a/vendor/fonteditor-core/src/graphics/getArc.js b/vendor/fonteditor-core/src/graphics/getArc.js deleted file mode 100644 index 4f5da22..0000000 --- a/vendor/fonteditor-core/src/graphics/getArc.js +++ /dev/null @@ -1,247 +0,0 @@ -/** - * @file 使用插值法获取椭圆弧度,以支持svg arc命令 - * @author mengke01(kekee000@gmail.com) - * - * modify from: - * https://github.com/fontello/svgpath/blob/master/lib/a2c.js - * references: - * http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes - */ - -import bezierCubic2Q2 from '../math/bezierCubic2Q2'; - - -const TAU = Math.PI * 2; - -function vectorAngle(ux, uy, vx, vy) { - // Calculate an angle between two vectors - const sign = (ux * vy - uy * vx < 0) ? -1 : 1; - const umag = Math.sqrt(ux * ux + uy * uy); - const vmag = Math.sqrt(ux * ux + uy * uy); - const dot = ux * vx + uy * vy; - let div = dot / (umag * vmag); - - if (div > 1 || div < -1) { - // rounding errors, e.g. -1.0000000000000002 can screw up this - div = Math.max(div, -1); - div = Math.min(div, 1); - } - - return sign * Math.acos(div); -} - -function correctRadii(midx, midy, rx, ry) { - // Correction of out-of-range radii - rx = Math.abs(rx); - ry = Math.abs(ry); - - const Λ = (midx * midx) / (rx * rx) + (midy * midy) / (ry * ry); - if (Λ > 1) { - rx *= Math.sqrt(Λ); - ry *= Math.sqrt(Λ); - } - - return [rx, ry]; -} - - -function getArcCenter(x1, y1, x2, y2, fa, fs, rx, ry, sin_φ, cos_φ) { - // Convert from endpoint to center parameterization, - // see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - - // Step 1. - // - // Moving an ellipse so origin will be the middlepoint between our two - // points. After that, rotate it to line up ellipse axes with coordinate - // axes. - // - const x1p = cos_φ * (x1 - x2) / 2 + sin_φ * (y1 - y2) / 2; - const y1p = -sin_φ * (x1 - x2) / 2 + cos_φ * (y1 - y2) / 2; - - const rx_sq = rx * rx; - const ry_sq = ry * ry; - const x1p_sq = x1p * x1p; - const y1p_sq = y1p * y1p; - - // Step 2. - // - // Compute coordinates of the centre of this ellipse (cx', cy') - // in the new coordinate system. - // - let radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq); - - if (radicant < 0) { - // due to rounding errors it might be e.g. -1.3877787807814457e-17 - radicant = 0; - } - - radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq); - radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1); - - const cxp = radicant * rx / ry * y1p; - const cyp = radicant * -ry / rx * x1p; - - // Step 3. - // - // Transform back to get centre coordinates (cx, cy) in the original - // coordinate system. - // - const cx = cos_φ * cxp - sin_φ * cyp + (x1 + x2) / 2; - const cy = sin_φ * cxp + cos_φ * cyp + (y1 + y2) / 2; - - // Step 4. - // - // Compute angles (θ1, Δθ). - // - const v1x = (x1p - cxp) / rx; - const v1y = (y1p - cyp) / ry; - const v2x = (-x1p - cxp) / rx; - const v2y = (-y1p - cyp) / ry; - - const θ1 = vectorAngle(1, 0, v1x, v1y); - let Δθ = vectorAngle(v1x, v1y, v2x, v2y); - - if (fs === 0 && Δθ > 0) { - Δθ -= TAU; - } - if (fs === 1 && Δθ < 0) { - Δθ += TAU; - } - - return [cx, cy, θ1, Δθ]; -} - -function approximateUnitArc(θ1, Δθ) { - // Approximate one unit arc segment with bézier curves, - // see http://math.stackexchange.com/questions/873224/ - // calculate-control-points-of-cubic-bezier-curve-approximating-a-part-of-a-circle - const α = 4 / 3 * Math.tan(Δθ / 4); - - const x1 = Math.cos(θ1); - const y1 = Math.sin(θ1); - const x2 = Math.cos(θ1 + Δθ); - const y2 = Math.sin(θ1 + Δθ); - - return [x1, y1, x1 - y1 * α, y1 + x1 * α, x2 + y2 * α, y2 - x2 * α, x2, y2]; -} - - -function a2c(x1, y1, x2, y2, fa, fs, rx, ry, φ) { - const sin_φ = Math.sin(φ * TAU / 360); - const cos_φ = Math.cos(φ * TAU / 360); - - // Make sure radii are valid - // - const x1p = cos_φ * (x1 - x2) / 2 + sin_φ * (y1 - y2) / 2; - const y1p = -sin_φ * (x1 - x2) / 2 + cos_φ * (y1 - y2) / 2; - - if (x1p === 0 && y1p === 0) { - // we're asked to draw line to itself - return []; - } - - if (rx === 0 || ry === 0) { - // one of the radii is zero - return []; - } - - const radii = correctRadii(x1p, y1p, rx, ry); - rx = radii[0]; - ry = radii[1]; - - // Get center parameters (cx, cy, θ1, Δθ) - // - const cc = getArcCenter(x1, y1, x2, y2, fa, fs, rx, ry, sin_φ, cos_φ); - - const result = []; - let θ1 = cc[2]; - let Δθ = cc[3]; - - // Split an arc to multiple segments, so each segment - // will be less than τ/4 (= 90°) - // - const segments = Math.max(Math.ceil(Math.abs(Δθ) / (TAU / 4)), 1); - Δθ /= segments; - - for (let i = 0; i < segments; i++) { - result.push(approximateUnitArc(θ1, Δθ)); - θ1 += Δθ; - } - - // We have a bezier approximation of a unit circle, - // now need to transform back to the original ellipse - // - return result.map(curve => { - for (let i = 0; i < curve.length; i += 2) { - let x = curve[i + 0]; - let y = curve[i + 1]; - - // scale - x *= rx; - y *= ry; - - // rotate - const xp = cos_φ * x - sin_φ * y; - const yp = sin_φ * x + cos_φ * y; - - // translate - curve[i + 0] = xp + cc[0]; - curve[i + 1] = yp + cc[1]; - } - - return curve; - }); -} - -/** - * 获取椭圆弧度 - * - * @param {number} rx 椭圆长半轴 - * @param {number} ry 椭圆短半轴 - * @param {number} angle 旋转角度 - * @param {number} largeArc 是否大圆弧 - * @param {number} sweep 是否延伸圆弧 - * @param {Object} p0 分割点1 - * @param {Object} p1 分割点2 - * @return {Array} 分割后的路径 - */ -export default function getArc(rx, ry, angle, largeArc, sweep, p0, p1) { - const result = a2c(p0.x, p0.y, p1.x, p1.y, largeArc, sweep, rx, ry, angle); - const path = []; - - if (result.length) { - path.push({ - x: result[0][0], - y: result[0][1], - onCurve: true - }); - - // 将三次曲线转换成二次曲线 - result.forEach(c => { - const q2Array = bezierCubic2Q2({ - x: c[0], - y: c[1] - }, { - x: c[2], - y: c[3] - }, { - x: c[4], - y: c[5] - }, { - x: c[6], - y: c[7] - }); - - q2Array[0][2].onCurve = true; - path.push(q2Array[0][1]); - path.push(q2Array[0][2]); - if (q2Array[1]) { - q2Array[1][2].onCurve = true; - path.push(q2Array[1][1]); - path.push(q2Array[1][2]); - } - }); - } - - return path; -} diff --git a/vendor/fonteditor-core/src/graphics/matrix.js b/vendor/fonteditor-core/src/graphics/matrix.js deleted file mode 100644 index a0533f4..0000000 --- a/vendor/fonteditor-core/src/graphics/matrix.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file matrix变换操作 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 仿射矩阵相乘 - * - * @param {Array=} matrix1 矩阵1 - * @param {Array=} matrix2 矩阵2 - * @return {Array} 新矩阵 - */ -export function mul(matrix1 = [1, 0, 0, 1], matrix2 = [1, 0, 0, 1]) { - // 旋转变换 4 个参数 - if (matrix1.length === 4) { - return [ - matrix1[0] * matrix2[0] + matrix1[2] * matrix2[1], - matrix1[1] * matrix2[0] + matrix1[3] * matrix2[1], - matrix1[0] * matrix2[2] + matrix1[2] * matrix2[3], - matrix1[1] * matrix2[2] + matrix1[3] * matrix2[3] - ]; - } - // 旋转位移变换, 6 个参数 - - return [ - matrix1[0] * matrix2[0] + matrix1[2] * matrix2[1], - matrix1[1] * matrix2[0] + matrix1[3] * matrix2[1], - matrix1[0] * matrix2[2] + matrix1[2] * matrix2[3], - matrix1[1] * matrix2[2] + matrix1[3] * matrix2[3], - - matrix1[0] * matrix2[4] + matrix1[2] * matrix2[5] + matrix1[4], - matrix1[1] * matrix2[4] + matrix1[3] * matrix2[5] + matrix1[5] - ]; -} - -/** - * 多个仿射矩阵相乘 - * - * @param {...Array} matrixs matrix array - * @return {Array} 新矩阵 - */ -export function multiply(...matrixs) { - let result = matrixs[0]; - for (let i = 1, matrix; (matrix = matrixs[i]); i++) { - result = mul(result, matrix); - } - - return result; -} diff --git a/vendor/fonteditor-core/src/graphics/path/circle.js b/vendor/fonteditor-core/src/graphics/path/circle.js deleted file mode 100644 index ef2b502..0000000 --- a/vendor/fonteditor-core/src/graphics/path/circle.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file 圆路径集合,逆时针 - * @author mengke01(kekee000@gmail.com) - */ - -export default [ - { - x: 582, - y: 0 - }, - { - x: 758, - y: 75 - }, - { - x: 890, - y: 208 - }, - { - x: 965, - y: 384 - }, - { - x: 965, - y: 583 - }, - { - x: 890, - y: 760 - }, - { - x: 758, - y: 891 - }, - { - x: 582, - y: 966 - }, - { - x: 383, - y: 966 - }, - { - x: 207, - y: 891 - }, - { - x: 75, - y: 760 - }, - { - x: 0, - y: 583 - }, - { - x: 0, - y: 384 - }, - { - x: 75, - y: 208 - }, - { - x: 207, - y: 75 - }, - { - x: 383, - y: 0 - } -]; diff --git a/vendor/fonteditor-core/src/graphics/pathAdjust.js b/vendor/fonteditor-core/src/graphics/pathAdjust.js deleted file mode 100644 index 4146149..0000000 --- a/vendor/fonteditor-core/src/graphics/pathAdjust.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file 调整路径缩放和平移 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 对path坐标进行调整 - * - * @param {Object} contour 坐标点 - * @param {number} scaleX x缩放比例 - * @param {number} scaleY y缩放比例 - * @param {number} offsetX x偏移 - * @param {number} offsetY y偏移 - * - * @return {Object} contour 坐标点 - */ -export default function pathAdjust(contour, scaleX, scaleY, offsetX, offsetY) { - scaleX = scaleX === undefined ? 1 : scaleX; - scaleY = scaleY === undefined ? 1 : scaleY; - const x = offsetX || 0; - const y = offsetY || 0; - let p; - for (let i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - p.x = scaleX * (p.x + x); - p.y = scaleY * (p.y + y); - } - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathCeil.js b/vendor/fonteditor-core/src/graphics/pathCeil.js deleted file mode 100644 index 080a500..0000000 --- a/vendor/fonteditor-core/src/graphics/pathCeil.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @file 对路径进行四舍五入 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 对path坐标进行调整 - * - * @param {Array} contour 轮廓点数组 - * @param {number} point 四舍五入的点数 - * @return {Object} contour 坐标点 - */ -export default function pathCeil(contour, point) { - let p; - for (let i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - if (!point) { - p.x = Math.round(p.x); - p.y = Math.round(p.y); - } - else { - p.x = Number(p.x.toFixed(point)); - p.y = Number(p.y.toFixed(point)); - } - } - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathIterator.js b/vendor/fonteditor-core/src/graphics/pathIterator.js deleted file mode 100644 index 6e7bd44..0000000 --- a/vendor/fonteditor-core/src/graphics/pathIterator.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file 遍历路径的路径集合,包括segment和 bezier curve - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 遍历路径的路径集合 - * - * @param {Array} contour 坐标点集 - * @param {Function} callBack 回调函数,参数集合:command, p0, p1, p2, i - * p0, p1, p2 直线或者贝塞尔曲线参数 - * i 当前遍历的点 - * 其中command = L 或者 Q,表示直线或者贝塞尔曲线 - */ -export default function pathIterator(contour, callBack) { - - let curPoint; - let prevPoint; - let nextPoint; - let cursorPoint; // cursorPoint 为当前单个绘制命令的起点 - - for (let i = 0, l = contour.length; i < l; i++) { - curPoint = contour[i]; - prevPoint = i === 0 ? contour[l - 1] : contour[i - 1]; - nextPoint = i === l - 1 ? contour[0] : contour[i + 1]; - - // 起始坐标 - if (i === 0) { - if (curPoint.onCurve) { - cursorPoint = curPoint; - } - else if (prevPoint.onCurve) { - cursorPoint = prevPoint; - } - else { - cursorPoint = { - x: (prevPoint.x + curPoint.x) / 2, - y: (prevPoint.y + curPoint.y) / 2 - }; - } - - } - - // 直线 - if (curPoint.onCurve && nextPoint.onCurve) { - if (false === callBack('L', curPoint, nextPoint, 0, i)) { - break; - } - cursorPoint = nextPoint; - } - else if (!curPoint.onCurve) { - - if (nextPoint.onCurve) { - if (false === callBack('Q', cursorPoint, curPoint, nextPoint, i)) { - break; - } - cursorPoint = nextPoint; - } - else { - const last = { - x: (curPoint.x + nextPoint.x) / 2, - y: (curPoint.y + nextPoint.y) / 2 - }; - if (false === callBack('Q', cursorPoint, curPoint, last, i)) { - break; - } - cursorPoint = last; - } - } - } -} diff --git a/vendor/fonteditor-core/src/graphics/pathRotate.js b/vendor/fonteditor-core/src/graphics/pathRotate.js deleted file mode 100644 index 0e69bb4..0000000 --- a/vendor/fonteditor-core/src/graphics/pathRotate.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file 路径旋转 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 对path坐标进行调整 - * - * @param {Object} contour 坐标点 - * @param {number} angle 角度 - * @param {number} centerX x偏移 - * @param {number} centerY y偏移 - * - * @return {Object} contour 坐标点 - */ -export default function pathRotate(contour, angle, centerX, centerY) { - angle = angle === undefined ? 0 : angle; - const x = centerX || 0; - const y = centerY || 0; - const cos = Math.cos(angle); - const sin = Math.sin(angle); - let px; - let py; - let p; - - // x1=cos(angle)*x-sin(angle)*y; - // y1=cos(angle)*y+sin(angle)*x; - for (let i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - px = cos * (p.x - x) - sin * (p.y - y); - py = cos * (p.y - y) + sin * (p.x - x); - p.x = px + x; - p.y = py + y; - } - - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathSkew.js b/vendor/fonteditor-core/src/graphics/pathSkew.js deleted file mode 100644 index 343ce3e..0000000 --- a/vendor/fonteditor-core/src/graphics/pathSkew.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file path倾斜变换 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * path倾斜变换 - * - * @param {Object} contour 坐标点 - * @param {number} angle 角度 - * @param {number} offsetX x偏移 - * @param {number} offsetY y偏移 - * - * @return {Object} contour 坐标点 - */ -export default function pathSkew(contour, angle, offsetX, offsetY) { - angle = angle === undefined ? 0 : angle; - const x = offsetX || 0; - const tan = Math.tan(angle); - let p; - let i; - let l; - - // x 平移 - if (x === 0) { - for (i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - p.x += tan * (p.y - offsetY); - } - } - // y平移 - else { - for (i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - p.y += tan * (p.x - offsetX); - } - } - - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathSkewX.js b/vendor/fonteditor-core/src/graphics/pathSkewX.js deleted file mode 100644 index 3b91eca..0000000 --- a/vendor/fonteditor-core/src/graphics/pathSkewX.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file 按X轴平移变换, 变换中心为图像中心点 - * @author mengke01(kekee000@gmail.com) - */ -import {computePath} from './computeBoundingBox'; - -/** - * path倾斜变换 - * - * @param {Object} contour 坐标点 - * @param {number} angle 角度 - * - * @return {Object} contour 坐标点 - */ -export default function pathSkewX(contour, angle) { - angle = angle === undefined ? 0 : angle; - const y = computePath(contour).y; - const tan = Math.tan(angle); - let p; - // x 平移 - for (let i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - p.x += tan * (p.y - y); - } - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathSkewY.js b/vendor/fonteditor-core/src/graphics/pathSkewY.js deleted file mode 100644 index 10b915d..0000000 --- a/vendor/fonteditor-core/src/graphics/pathSkewY.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file 按Y轴平移变换, 变换中心为图像中心点 - * @author mengke01(kekee000@gmail.com) - */ -import {computePath} from './computeBoundingBox'; - -/** - * path倾斜变换 - * - * @param {Object} contour 坐标点 - * @param {number} angle 角度 - * - * @return {Object} contour 坐标点 - */ -export default function pathSkewY(contour, angle) { - angle = angle === undefined ? 0 : angle; - const x = computePath(contour).x; - const tan = Math.tan(angle); - let p; - // y 平移 - for (let i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - p.y += tan * (p.x - x); - } - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathTransform.js b/vendor/fonteditor-core/src/graphics/pathTransform.js deleted file mode 100644 index 621937b..0000000 --- a/vendor/fonteditor-core/src/graphics/pathTransform.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file 对轮廓进行transform变换 - * @author mengke01(kekee000@gmail.com) - * - * 参考资料: - * http://blog.csdn.net/henren555/article/details/9699449 - * - * |X| |a c e| |x| - * |Y| = |b d f| * |y| - * |1| |0 0 1| |1| - * - * X = x * a + y * c + e - * Y = x * b + y * d + f - */ - -/** - * 图形仿射矩阵变换 - * - * @param {Array.} contour 轮廓点 - * @param {number} a m11 - * @param {number} b m12 - * @param {number} c m21 - * @param {number} d m22 - * @param {number} e dx - * @param {number} f dy - * @return {Array.} contour 轮廓点 - */ -export default function transform(contour, a, b, c, d, e, f) { - let x; - let y; - let p; - for (let i = 0, l = contour.length; i < l; i++) { - p = contour[i]; - x = p.x; - y = p.y; - p.x = x * a + y * c + e; - p.y = x * b + y * d + f; - } - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/pathUtil.js b/vendor/fonteditor-core/src/graphics/pathUtil.js deleted file mode 100644 index d2431da..0000000 --- a/vendor/fonteditor-core/src/graphics/pathUtil.js +++ /dev/null @@ -1,185 +0,0 @@ -/** - * @file 路径相关的函数集合 - * @author mengke01(kekee000@gmail.com) - */ - -import {getPointHash} from './util'; - -/** - * 对路径进行插值,补全省略的点 - * - * @param {Array} path 路径 - * @return {Array} 路径 - */ -export function interpolate(path) { - const newPath = []; - for (let i = 0, l = path.length; i < l; i++) { - const next = i === l - 1 ? 0 : i + 1; - newPath.push(path[i]); - // 插值 - if (!path[i].onCurve && !path[next].onCurve) { - newPath.push({ - x: (path[i].x + path[next].x) / 2, - y: (path[i].y + path[next].y) / 2, - onCurve: true - }); - } - } - - return newPath; -} - - -/** - * 去除路径中的插值点 - * - * @param {Array} path 路径 - * @return {Array} 路径 - */ -export function deInterpolate(path) { - const newPath = []; - - for (let i = 0, l = path.length; i < l; i++) { - const next = i === l - 1 ? 0 : i + 1; - const prev = i === 0 ? l - 1 : i - 1; - // 插值 - if ( - !path[prev].onCurve && path[i].onCurve && !path[next].onCurve - && Math.abs(2 * path[i].x - path[prev].x - path[next].x) < 0.001 - && Math.abs(2 * path[i].y - path[prev].y - path[next].y) < 0.001 - ) { - continue; - } - - newPath.push(path[i]); - } - - return newPath; -} - - -/** - * 判断路径的方向是否顺时针 - * - * see: - * http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/clockwise.htm - * - * @param {Array} path 路径 - * @return {number} 0 无方向 1 clockwise, -1 counter clockwise - */ -export function isClockWise(path) { - - if (path.length < 3) { - return 0; - } - - let zCount = 0; - for (let i = 0, l = path.length; i < l; i++) { - const cur = path[i]; - const prev = i === 0 ? path[l - 1] : path[i - 1]; - const next = i === l - 1 ? path[0] : path[i + 1]; - const z = (cur.x - prev.x) * (next.y - cur.y) - - (cur.y - prev.y) * (next.x - cur.x); - - if (z < 0) { - zCount--; - } - else if (z > 0) { - zCount++; - } - } - - return zCount === 0 - ? 0 - : zCount < 0 ? 1 : -1; -} - -/** - * 获取路径哈希 - * - * @param {Array} path 路径数组 - * @return {number} 哈希值 - */ -export function getPathHash(path) { - let hash = 0; - const seed = 131; - - path.forEach(p => { - hash = 0x7FFFFFFF & (hash * seed + getPointHash(p) + (p.onCurve ? 1 : 0)); - }); - - return hash; -} - - -/** - * 移除重复点 - * - * @param {Array} points 点集合 - * @return {Array} 移除后点集合 - */ -export function removeOverlapPoints(points) { - const hash = {}; - const ret = []; - for (let i = 0, l = points.length; i < l; i++) { - const hashcode = points[i].x * 31 + points[i].y; - if (!hash[hashcode]) { - ret.push(points[i]); - hash[hashcode] = 1; - } - } - return ret; -} - -/** - * 对path进行双向链表连接 - * - * @param {Array} path 轮廓数组 - * @return {Array} path - */ -export function makeLink(path) { - for (let i = 0, l = path.length; i < l; i++) { - const cur = path[i]; - const prev = i === 0 ? path[l - 1] : path[i - 1]; - const next = i === l - 1 ? path[0] : path[i + 1]; - cur.index = i; - cur.next = next; - cur.prev = prev; - } - - return path; -} - -/** - * 对path进行缩放 - * - * @param {Array} path 轮廓数组 - * @param {number} ratio 缩放大小 - * - * @return {Array} path - */ -export function scale(path, ratio) { - for (let i = 0, l = path.length; i < l; i++) { - const cur = path[i]; - cur.x *= ratio; - cur.y *= ratio; - } - - return path; -} - - -export function clone(path) { - return path ? path.map(p => { - const newP = { - x: p.x, - y: p.y - }; - - if (p.onCurve) { - newP.onCurve = true; - } - - return newP; - }) : path; -} diff --git a/vendor/fonteditor-core/src/graphics/pathsUtil.js b/vendor/fonteditor-core/src/graphics/pathsUtil.js deleted file mode 100644 index c32a0bd..0000000 --- a/vendor/fonteditor-core/src/graphics/pathsUtil.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file 路径组变化函数 - * @author mengke01(kekee000@gmail.com) - */ - -import {computePath} from './computeBoundingBox'; -import pathAdjust from './pathAdjust'; -import pathRotate from './pathRotate'; - -/** - * 翻转路径 - * - * @param {Array} paths 路径数组 - * @param {number} xScale x翻转 - * @param {number} yScale y翻转 - * @return {Array} 变换后的路径 - */ -function mirrorPaths(paths, xScale, yScale) { - const {x, y, width, height} = computePath(...paths); - - if (xScale === -1) { - paths.forEach(p => { - pathAdjust(p, -1, 1, -x, 0); - pathAdjust(p, 1, 1, x + width, 0); - p.reverse(); - }); - - } - - if (yScale === -1) { - paths.forEach(p => { - pathAdjust(p, 1, -1, 0, -y); - pathAdjust(p, 1, 1, 0, y + height); - p.reverse(); - }); - } - - return paths; -} - - - -export default { - - /** - * 旋转路径 - * - * @param {Array} paths 路径数组 - * @param {number} angle 弧度 - * @return {Array} 变换后的路径 - */ - rotate(paths, angle) { - if (!angle) { - return paths; - } - - const bound = computePath(...paths); - - const cx = bound.x + (bound.width) / 2; - const cy = bound.y + (bound.height) / 2; - - paths.forEach(p => { - pathRotate(p, angle, cx, cy); - }); - - return paths; - }, - - /** - * 路径组变换 - * - * @param {Array} paths 路径数组 - * @param {number} x x 方向缩放 - * @param {number} y y 方向缩放 - * @return {Array} 变换后的路径 - */ - move(paths, x, y) { - const bound = computePath(...paths); - paths.forEach(path => { - pathAdjust(path, 1, 1, x - bound.x, y - bound.y); - }); - - return paths; - }, - - mirror(paths) { - return mirrorPaths(paths, -1, 1); - }, - - flip(paths) { - return mirrorPaths(paths, 1, -1); - } -}; diff --git a/vendor/fonteditor-core/src/graphics/reducePath.js b/vendor/fonteditor-core/src/graphics/reducePath.js deleted file mode 100644 index 7e16b70..0000000 --- a/vendor/fonteditor-core/src/graphics/reducePath.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file 缩减path大小,去除冗余节点 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 判断点是否多余的点 - * - * @param {Object} prev 上一个 - * @param {Object} p 当前 - * @param {Object} next 下一个 - * @return {boolean} - */ -function redundant(prev, p, next) { - - // 是否重合的点, 只有两个点同在曲线上或者同不在曲线上移出 - if ( - (p.onCurve && next.onCurve || !p.onCurve && !next.onCurve) - && Math.pow(p.x - next.x, 2) + Math.pow(p.y - next.y, 2) <= 1 - ) { - return true; - } - - // 三点同线 检查直线点 - if ( - (p.onCurve && prev.onCurve && next.onCurve) - && Math.abs((next.y - p.y) * (prev.x - p.x) - (prev.y - p.y) * (next.x - p.x)) <= 0.001 - ) { - return true; - } - - // 三点同线 检查控制点 - if ( - (!p.onCurve && prev.onCurve && next.onCurve) - && Math.abs((next.y - p.y) * (prev.x - p.x) - (prev.y - p.y) * (next.x - p.x)) <= 0.001 - ) { - return true; - } - - return false; -} - -/** - * 缩减glyf,去除冗余节点 - * - * @param {Array} contour 路径对象 - * @return {Array} 路径对象 - */ -export default function reducePath(contour) { - - if (!contour.length) { - return contour; - } - - let prev; - let next; - let p; - for (let i = contour.length - 1, last = i; i >= 0; i--) { - - // 这里注意逆序 - p = contour[i]; - next = i === last ? contour[0] : contour[i + 1]; - prev = i === 0 ? contour[last] : contour[i - 1]; - - if (redundant(prev, p, next)) { - contour.splice(i, 1); - last--; - continue; - } - } - - return contour; -} diff --git a/vendor/fonteditor-core/src/graphics/util.js b/vendor/fonteditor-core/src/graphics/util.js deleted file mode 100644 index fe2d32e..0000000 --- a/vendor/fonteditor-core/src/graphics/util.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @file grahpics点相关工具箱 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 将点进行误差舍入 - * - * @param {Object} p 点对象 - * @return {Object} 点 - */ -export function ceilPoint(p) { - let t = p.x; - - // 处理形如 4.99999 = 5, 5.00001 = 5的情况 - if (Math.abs(Math.round(t) - t) < 0.00002) { - p.x = Math.round(t); - } - else { - p.x = Math.round(p.x * 100000) / 100000; - } - - t = p.y; - if (Math.abs(Math.round(t) - t) < 0.00005) { - p.y = Math.round(t); - } - else { - p.y = Math.round(p.y * 100000) / 100000; - } - - return p; -} - -/** - * 将数值进行误差舍入 - * - * @param {Object} x 数值 - * @return {number} 点 - */ -export function ceil(x) { - if (Math.abs(Math.round(x) - x) < 0.00002) { - return Math.round(x); - } - - return Math.round(x * 100000) / 100000; -} - -/** - * 判断点是否在bounding box内部 - * - * @param {Object} bound bounding box对象 - * @param {Object} p 点对象 - * @param {boolean=} fixed 是否四舍五入 - * @return {boolean} 是否 - */ -export function isPointInBound(bound, p, fixed) { - - if (fixed) { - return ceil(p.x) <= ceil(bound.x + bound.width) - && ceil(p.x) >= ceil(bound.x) - && ceil(p.y) <= ceil(bound.y + bound.height) - && ceil(p.y) >= ceil(bound.y); - } - - return p.x <= bound.x + bound.width - && p.x >= bound.x - && p.y <= bound.y + bound.height - && p.y >= bound.y; -} - -/** - * 判断点是否重合 - * - * @param {Object} p0 p0 - * @param {Object} p1 p1 - * @return {boolean} 是否 - */ -export function isPointOverlap(p0, p1) { - return ceil(p0.x) === ceil(p1.x) && ceil(p0.y) === ceil(p1.y); -} - - -/** - * 获取点的hash值 - * - * @param {Object} p p - * @param {Object} p1 p1 - * @return {number} - */ -export function getPointHash(p) { - return Math.floor(7 * Math.floor(p.x * 10) + 131 * Math.floor(p.y * 100)); -} diff --git a/vendor/fonteditor-core/src/main.esm.js b/vendor/fonteditor-core/src/main.esm.js deleted file mode 100644 index b357e34..0000000 --- a/vendor/fonteditor-core/src/main.esm.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file 主函数 - * @author mengke01(kekee000@gmail.com) - */ - -import {Font, createFont} from './ttf/font'; -import TTF from './ttf/ttf'; -import TTFReader from './ttf/ttfreader'; -import TTFWriter from './ttf/ttfwriter'; -import ttf2eot from './ttf/ttf2eot'; -import eot2ttf from './ttf/eot2ttf'; -import ttf2woff from './ttf/ttf2woff'; -import woff2ttf from './ttf/woff2ttf'; -import ttf2svg from './ttf/ttf2svg'; -import svg2ttfobject from './ttf/svg2ttfobject'; -import Reader from './ttf/reader'; -import Writer from './ttf/writer'; -import OTFReader from './ttf/otfreader'; -import otf2ttfobject from './ttf/otf2ttfobject'; -import ttf2base64 from './ttf/ttf2base64'; -import ttf2icon from './ttf/ttf2icon'; -import ttftowoff2 from './ttf/ttftowoff2'; -import woff2tottf from './ttf/woff2tottf'; -import woff2 from '../woff2/index'; -import bufferUtil from './nodejs/buffer'; - -export { - createFont, - Font, - TTF, - TTFReader, - TTFWriter, - ttf2eot, - eot2ttf, - ttf2woff, - woff2ttf, - ttf2svg, - svg2ttfobject, - Reader, - Writer, - OTFReader, - otf2ttfobject, - ttf2base64, - ttf2icon, - ttftowoff2, - woff2tottf, - woff2, -}; - -export const toArrayBuffer = bufferUtil.toArrayBuffer; -export const toBuffer = bufferUtil.toBuffer; - -export default { - createFont, - Font, - TTF, - TTFReader, - TTFWriter, - ttf2eot, - eot2ttf, - ttf2woff, - woff2ttf, - ttf2svg, - svg2ttfobject, - Reader, - Writer, - OTFReader, - otf2ttfobject, - ttf2base64, - ttf2icon, - ttftowoff2, - woff2tottf, - woff2, - toArrayBuffer: bufferUtil.toArrayBuffer, - toBuffer: bufferUtil.toBuffer, -}; \ No newline at end of file diff --git a/vendor/fonteditor-core/src/main.js b/vendor/fonteditor-core/src/main.js deleted file mode 100644 index d0693db..0000000 --- a/vendor/fonteditor-core/src/main.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file 主函数 - * @author mengke01(kekee000@gmail.com) - */ - -import {Font, createFont} from './ttf/font'; -import TTF from './ttf/ttf'; -import TTFReader from './ttf/ttfreader'; -import TTFWriter from './ttf/ttfwriter'; -import ttf2eot from './ttf/ttf2eot'; -import eot2ttf from './ttf/eot2ttf'; -import ttf2woff from './ttf/ttf2woff'; -import woff2ttf from './ttf/woff2ttf'; -import ttf2svg from './ttf/ttf2svg'; -import svg2ttfobject from './ttf/svg2ttfobject'; -import Reader from './ttf/reader'; -import Writer from './ttf/writer'; -import OTFReader from './ttf/otfreader'; -import otf2ttfobject from './ttf/otf2ttfobject'; -import ttf2base64 from './ttf/ttf2base64'; -import ttf2icon from './ttf/ttf2icon'; -import ttftowoff2 from './ttf/ttftowoff2'; -import woff2tottf from './ttf/woff2tottf'; -import woff2 from '../woff2/index'; -import bufferUtil from './nodejs/buffer'; - -const modules = { - createFont, - Font, - TTF, - TTFReader, - TTFWriter, - ttf2eot, - eot2ttf, - ttf2woff, - woff2ttf, - ttf2svg, - svg2ttfobject, - Reader, - Writer, - OTFReader, - otf2ttfobject, - ttf2base64, - ttf2icon, - ttftowoff2, - woff2tottf, - woff2, - toArrayBuffer: bufferUtil.toArrayBuffer, - toBuffer: bufferUtil.toBuffer, -}; - -// Export named exports for ESM -export { Font, woff2, createFont }; - -// Export default object -export default modules; - -if (typeof exports !== 'undefined') { - // eslint-disable-next-line import/no-commonjs - module.exports = modules; -} \ No newline at end of file diff --git a/vendor/fonteditor-core/src/math/bezierCubic2Q2.js b/vendor/fonteditor-core/src/math/bezierCubic2Q2.js deleted file mode 100644 index 22dd66f..0000000 --- a/vendor/fonteditor-core/src/math/bezierCubic2Q2.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file 三次贝塞尔转二次贝塞尔 - * @author mengke01(kekee000@gmail.com) - * - * references: - * https://github.com/search?utf8=%E2%9C%93&q=svg2ttf - * http://www.caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html - * - */ - -function toQuad(p1, c1, c2, p2) { - // Quad control point is (3*c2 - p2 + 3*c1 - p1)/4 - const x = (3 * c2.x - p2.x + 3 * c1.x - p1.x) / 4; - const y = (3 * c2.y - p2.y + 3 * c1.y - p1.y) / 4; - return [ - p1, - {x, y}, - p2 - ]; -} - - -/** - * 三次贝塞尔转二次贝塞尔 - * - * @param {Object} p1 开始点 - * @param {Object} c1 控制点1 - * @param {Object} c2 控制点2 - * @param {Object} p2 结束点 - * @return {Array} 二次贝塞尔控制点 - */ -export default function bezierCubic2Q2(p1, c1, c2, p2) { - - // 判断极端情况,控制点和起止点一样 - if (p1.x === c1.x && p1.y === c1.y && c2.x === p2.x && c2.y === p2.y) { - return [ - [ - p1, - { - x: (p1.x + p2.x) / 2, - y: (p1.y + p2.y) / 2 - }, - p2 - ] - ]; - } - - const mx = p2.x - 3 * c2.x + 3 * c1.x - p1.x; - const my = p2.y - 3 * c2.y + 3 * c1.y - p1.y; - - // control points near - if (mx * mx + my * my <= 4) { - return [ - toQuad(p1, c1, c2, p2) - ]; - } - - // Split to 2 qubic beziers by midpoints - // (p2 + 3*c2 + 3*c1 + p1)/8 - const mp = { - x: (p2.x + 3 * c2.x + 3 * c1.x + p1.x) / 8, - y: (p2.y + 3 * c2.y + 3 * c1.y + p1.y) / 8 - }; - - return [ - toQuad( - p1, - { - x: (p1.x + c1.x) / 2, - y: (p1.y + c1.y) / 2 - - }, - { - x: (p1.x + 2 * c1.x + c2.x) / 4, - y: (p1.y + 2 * c1.y + c2.y) / 4 - }, - mp - ), - toQuad( - mp, - { - x: (p2.x + c1.x + 2 * c2.x) / 4, - y: (p2.y + c1.y + 2 * c2.y) / 4 - - }, - { - x: (p2.x + c2.x) / 2, - y: (p2.y + c2.y) / 2 - }, - p2 - ) - ]; -} diff --git a/vendor/fonteditor-core/src/nodejs/buffer.js b/vendor/fonteditor-core/src/nodejs/buffer.js deleted file mode 100644 index 75eaa00..0000000 --- a/vendor/fonteditor-core/src/nodejs/buffer.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file Buffer和ArrayBuffer转换 - * @author mengke01(kekee000@gmail.com) - */ - -/* eslint-disable no-undef */ -export default { - - /** - * Buffer转换成ArrayBuffer - * - * @param {Buffer} buffer 缓冲数组 - * @return {ArrayBuffer} - */ - toArrayBuffer(buffer) { - const length = buffer.length; - const view = new DataView(new ArrayBuffer(length), 0, length); - for (let i = 0, l = length; i < l; i++) { - view.setUint8(i, buffer[i], false); - } - return view.buffer; - }, - - /** - * ArrayBuffer转换成Buffer - * - * @param {ArrayBuffer} arrayBuffer 缓冲数组 - * @return {Buffer} - */ - toBuffer(arrayBuffer) { - if (Array.isArray(arrayBuffer)) { - return Buffer.from(arrayBuffer); - } - - const length = arrayBuffer.byteLength; - const view = new DataView(arrayBuffer, 0, length); - const buffer = Buffer.alloc(length); - for (let i = 0, l = length; i < l; i++) { - buffer[i] = view.getUint8(i, false); - } - return buffer; - } -}; diff --git a/vendor/fonteditor-core/src/ttf/data/default.js b/vendor/fonteditor-core/src/ttf/data/default.js deleted file mode 100644 index 1c7ceee..0000000 --- a/vendor/fonteditor-core/src/ttf/data/default.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @file 默认的ttf字体配置 - * @author mengke01(kekee000@gmail.com) - */ - -export default { - // 默认的字体编码 - fontId: 'fonteditor', - - // 默认的名字集合 - name: { - // 默认的字体家族 - fontFamily: 'fonteditor', - fontSubFamily: 'Medium', - uniqueSubFamily: 'FontEditor 1.0 : fonteditor', - version: 'Version 1.0; FontEditor (v1.0)', - postScriptName: 'fonteditor' - } -}; diff --git a/vendor/fonteditor-core/src/ttf/data/empty.js b/vendor/fonteditor-core/src/ttf/data/empty.js deleted file mode 100644 index 9a2e8ab..0000000 --- a/vendor/fonteditor-core/src/ttf/data/empty.js +++ /dev/null @@ -1,181 +0,0 @@ -/** - * @file 空的ttf格式json对象 - * @author mengke01(kekee000@gmail.com) - */ - -/* eslint-disable */ -export default { - "version": 1, - "numTables": 10, - "searchRange": 128, - "entrySelector": 3, - "rangeShift": 64, - "head": { - "version": 1, - "fontRevision": 1, - "checkSumAdjustment": 0, - "magickNumber": 1594834165, - "flags": 11, - "unitsPerEm": 1024, - "created": 1428940800000, - "modified": 1428940800000, - "xMin": 34, - "yMin": 0, - "xMax": 306, - "yMax": 682, - "macStyle": 0, - "lowestRecPPEM": 8, - "fontDirectionHint": 2, - "indexToLocFormat": 0, - "glyphDataFormat": 0 - }, - "glyf": [{ - "contours": [ - [{ - "x": 34, - "y": 0, - "onCurve": true - }, { - "x": 34, - "y": 682, - "onCurve": true - }, { - "x": 306, - "y": 682, - "onCurve": true - }, { - "x": 306, - "y": 0, - "onCurve": true - }], - [{ - "x": 68, - "y": 34, - "onCurve": true - }, { - "x": 272, - "y": 34, - "onCurve": true - }, { - "x": 272, - "y": 648, - "onCurve": true - }, { - "x": 68, - "y": 648, - "onCurve": true - }] - ], - "xMin": 34, - "yMin": 0, - "xMax": 306, - "yMax": 682, - "advanceWidth": 374, - "leftSideBearing": 34, - "name": ".notdef" - }], - "cmap": {}, - "name": { - "fontFamily": "fonteditor", - "fontSubFamily": "Medium", - "uniqueSubFamily": "FontEditor 1.0 : fonteditor", - "version": "Version 1.0 ; FontEditor (v0.0.1)", - "postScriptName": "fonteditor", - "fullName": "fonteditor" - }, - "hhea": { - "version": 1, - "ascent": 812, - "descent": -212, - "lineGap": 92, - "advanceWidthMax": 374, - "minLeftSideBearing": 34, - "minRightSideBearing": 68, - "xMaxExtent": 306, - "caretSlopeRise": 1, - "caretSlopeRun": 0, - "caretOffset": 0, - "reserved0": 0, - "reserved1": 0, - "reserved2": 0, - "reserved3": 0, - "metricDataFormat": 0, - "numOfLongHorMetrics": 1 - }, - "post": { - "italicAngle": 0, - "postoints": 65411, - "underlinePosition": 50, - "underlineThickness": 0, - "isFixedPitch": 0, - "minMemType42": 0, - "maxMemType42": 0, - "minMemType1": 0, - "maxMemType1": 1, - "format": 2 - }, - "maxp": { - "version": 1.0, - "numGlyphs": 0, - "maxPoints": 0, - "maxContours": 0, - "maxCompositePoints": 0, - "maxCompositeContours": 0, - "maxZones": 0, - "maxTwilightPoints": 0, - "maxStorage": 0, - "maxFunctionDefs": 0, - "maxStackElements": 0, - "maxSizeOfInstructions": 0, - "maxComponentElements": 0, - "maxComponentDepth": 0 - }, - "OS/2": { - "version": 4, - "xAvgCharWidth": 1031, - "usWeightClass": 400, - "usWidthClass": 5, - "fsType": 0, - "ySubscriptXSize": 665, - "ySubscriptYSize": 716, - "ySubscriptXOffset": 0, - "ySubscriptYOffset": 143, - "ySuperscriptXSize": 665, - "ySuperscriptYSize": 716, - "ySuperscriptXOffset": 0, - "ySuperscriptYOffset": 491, - "yStrikeoutSize": 51, - "yStrikeoutPosition": 265, - "sFamilyClass": 0, - "bFamilyType": 2, - "bSerifStyle": 0, - "bWeight": 6, - "bProportion": 3, - "bContrast": 0, - "bStrokeVariation": 0, - "bArmStyle": 0, - "bLetterform": 0, - "bMidline": 0, - "bXHeight": 0, - "ulUnicodeRange1": 1, - "ulUnicodeRange2": 268435456, - "ulUnicodeRange3": 0, - "ulUnicodeRange4": 0, - "achVendID": "PfEd", - "fsSelection": 192, - "usFirstCharIndex": 65535, - "usLastCharIndex": -1, - "sTypoAscender": 812, - "sTypoDescender": -212, - "sTypoLineGap": 92, - "usWinAscent": 812, - "usWinDescent": 212, - "ulCodePageRange1": 1, - "ulCodePageRange2": 0, - "sxHeight": 792, - "sCapHeight": 0, - "usDefaultChar": 0, - "usBreakChar": 32, - "usMaxContext": 1 - } -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/componentFlag.js b/vendor/fonteditor-core/src/ttf/enum/componentFlag.js deleted file mode 100644 index 1490659..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/componentFlag.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @file 复合图元标记位 - * @author mengke01(kekee000@gmail.com) - * - * 复合图元标记位 - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html - */ - -export default { - ARG_1_AND_2_ARE_WORDS: 0x01, - ARGS_ARE_XY_VALUES: 0x02, - ROUND_XY_TO_GRID: 0x04, - WE_HAVE_A_SCALE: 0x08, - RESERVED: 0x10, - MORE_COMPONENTS: 0x20, - WE_HAVE_AN_X_AND_Y_SCALE: 0x40, - WE_HAVE_A_TWO_BY_TWO: 0x80, - WE_HAVE_INSTRUCTIONS: 0x100, - USE_MY_METRICS: 0x200, - OVERLAP_COMPOUND: 0x400, - SCALED_COMPONENT_OFFSET: 0x800, - UNSCALED_COMPONENT_OFFSET: 0x1000 -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/encoding.js b/vendor/fonteditor-core/src/ttf/enum/encoding.js deleted file mode 100644 index 726cf6e..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/encoding.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file Unicode Platform-specific Encoding Identifiers - * @author mengke01(kekee000@gmail.com) - */ -// mac encoding id -export const mac = { - 'Default': 0, // default use - 'Version1.1': 1, - 'ISO10646': 2, - 'UnicodeBMP': 3, - 'UnicodenonBMP': 4, - 'UnicodeVariationSequences': 5, - 'FullUnicodecoverage': 6 -}; - -// windows encoding id -export const win = { - Symbol: 0, - UCS2: 1, // default use - ShiftJIS: 2, - PRC: 3, - BigFive: 4, - Johab: 5, - UCS4: 6 -}; - diff --git a/vendor/fonteditor-core/src/ttf/enum/glyFlag.js b/vendor/fonteditor-core/src/ttf/enum/glyFlag.js deleted file mode 100644 index cf785fb..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/glyFlag.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @file 轮廓标记位 - * @author mengke01(kekee000@gmail.com) - * - * see: - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html - */ - -export default { - ONCURVE: 0x01, // on curve ,off curve - XSHORT: 0x02, // x-Short Vector - YSHORT: 0x04, // y-Short Vector - REPEAT: 0x08, // next byte is flag repeat count - XSAME: 0x10, // This x is same (Positive x-Short vector) - YSAME: 0x20, // This y is same (Positive y-Short vector) - Reserved1: 0x40, - Reserved2: 0x80 -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/nameId.js b/vendor/fonteditor-core/src/ttf/enum/nameId.js deleted file mode 100644 index 37a4235..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/nameId.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file ttf `name`编码表 - * @author mengke01(kekee000@gmail.com) - */ - -const nameId = { - 0: 'copyright', - 1: 'fontFamily', - 2: 'fontSubFamily', - 3: 'uniqueSubFamily', - 4: 'fullName', - 5: 'version', - 6: 'postScriptName', - 7: 'tradeMark', - 8: 'manufacturer', - 9: 'designer', - 10: 'description', - 11: 'urlOfFontVendor', - 12: 'urlOfFontDesigner', - 13: 'licence', - 14: 'urlOfLicence', - 16: 'preferredFamily', - 17: 'preferredSubFamily', - 18: 'compatibleFull', - 19: 'sampleText' -}; - -// 反转names -const nameIdHash = {}; -Object.keys(nameId).forEach(id => { - nameIdHash[nameId[id]] = +id; -}); - -nameId.names = nameIdHash; - -export default nameId; diff --git a/vendor/fonteditor-core/src/ttf/enum/panose.js b/vendor/fonteditor-core/src/ttf/enum/panose.js deleted file mode 100644 index f67027a..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/panose.js +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @file 字体外观分类器 - * @author mengke01(kekee000@gmail.com) - * - * @see: - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html - */ - -export default { - - bFamilyType: [ - 'Any', - 'No Fit', - 'Text and Display', - 'Script', - 'Decorative', - 'Pictorial' - ], - - bSerifStyle: [ - 'Any', - 'No Fit', - 'Cove', - 'Obtuse Cove', - 'Square Cove', - 'Obtuse Square Cove', - 'Square', - 'Thin', - 'Bone', - 'Exaggerated', - 'Triangle', - 'Normal Sans', - 'Obtuse Sans', - 'Perp Sans', - 'Flared', - 'Rounded' - ], - - bWeight: [ - 'Any', - 'No Fit', - 'Very Light', - 'Light', - 'Thin', - 'Book', - 'Medium', - 'Demi', - 'Bold', - 'Heavy', - 'Black', - 'Nord' - ], - - bProportion: [ - 'Any', - 'No Fit', - 'Old Style', - 'Modern', - 'Even Width', - 'Expanded', - 'Condensed', - 'Very Expanded', - 'Very Condensed', - 'Monospaced' - ], - - bContrast: [ - 'Any', - 'No Fit', - 'None', - 'Very Low', - 'Low', - 'Medium Low', - 'Medium', - 'Medium High', - 'High', - 'Very High' - ], - - bStrokeVariation: [ - 'Any', - 'No Fit', - 'Gradual/Diagonal', - 'Gradual/Transitional', - 'Gradual/Vertical', - 'Gradual/Horizontal', - 'Rapid/Vertical', - 'Rapid/Horizontal', - 'Instant/Vertical' - ], - - bArmStyle: [ - 'Any', - 'No Fit', - 'Straight Arms/Horizontal', - 'Straight Arms/Wedge', - 'Straight Arms/Vertical', - 'Straight Arms/Single Serif', - 'Straight Arms/Double Serif', - 'Non-Straight Arms/Horizontal', - 'Non-Straight Arms/Wedge', - 'Non-Straight Arms/Vertical', - 'Non-Straight Arms/Single Serif', - 'Non-Straight Arms/Double Serif' - ], - - - bLetterform: [ - 'Any', - 'No Fit', - 'Normal/Contact', - 'Normal/Weighted', - 'Normal/Boxed', - 'Normal/Flattened', - 'Normal/Rounded', - 'Normal/Off Center', - 'Normal/Square', - 'Oblique/Contact', - 'Oblique/Weighted', - 'Oblique/Boxed', - 'Oblique/Flattened', - 'Oblique/Rounded', - 'Oblique/Off Center', - 'Oblique/Square' - ], - - bMidline: [ - 'Any', - 'No Fit', - 'Standard/Trimmed', - 'Standard/Pointed', - 'Standard/Serifed', - 'High/Trimmed', - 'High/Pointed', - 'High/Serifed', - 'Constant/Trimmed', - 'Constant/Pointed', - 'Constant/Serifed', - 'Low/Trimmed', - 'Low/Pointed', - 'Low/Serifed' - ], - - bXHeight: [ - 'Any', - 'No Fit', - 'Constant/Small', - 'Constant/Standard', - 'Constant/Large', - 'Ducking/Small', - 'Ducking/Standard', - 'Ducking/Large' - ] -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/platform.js b/vendor/fonteditor-core/src/ttf/enum/platform.js deleted file mode 100644 index 92f8b0b..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/platform.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @file 字体所属平台 - * @author mengke01(kekee000@gmail.com) - */ - -export default{ - Unicode: 0, - Macintosh: 1, // mac - reserved: 2, - Microsoft: 3 // win -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/postName.js b/vendor/fonteditor-core/src/ttf/enum/postName.js deleted file mode 100644 index 4a7e288..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/postName.js +++ /dev/null @@ -1,268 +0,0 @@ -/** - * @file Mac glyf命名表 - * @author mengke01(kekee000@gmail.com) - * - * see: - * http://www.microsoft.com/typography/otspec/WGL4.htm - */ - -export default { - 0: '.notdef', - 1: '.null', - 2: 'nonmarkingreturn', - 3: 'space', - 4: 'exclam', - 5: 'quotedbl', - 6: 'numbersign', - 7: 'dollar', - 8: 'percent', - 9: 'ampersand', - 10: 'quotesingle', - 11: 'parenleft', - 12: 'parenright', - 13: 'asterisk', - 14: 'plus', - 15: 'comma', - 16: 'hyphen', - 17: 'period', - 18: 'slash', - 19: 'zero', - 20: 'one', - 21: 'two', - 22: 'three', - 23: 'four', - 24: 'five', - 25: 'six', - 26: 'seven', - 27: 'eight', - 28: 'nine', - 29: 'colon', - 30: 'semicolon', - 31: 'less', - 32: 'equal', - 33: 'greater', - 34: 'question', - 35: 'at', - 36: 'A', - 37: 'B', - 38: 'C', - 39: 'D', - 40: 'E', - 41: 'F', - 42: 'G', - 43: 'H', - 44: 'I', - 45: 'J', - 46: 'K', - 47: 'L', - 48: 'M', - 49: 'N', - 50: 'O', - 51: 'P', - 52: 'Q', - 53: 'R', - 54: 'S', - 55: 'T', - 56: 'U', - 57: 'V', - 58: 'W', - 59: 'X', - 60: 'Y', - 61: 'Z', - 62: 'bracketleft', - 63: 'backslash', - 64: 'bracketright', - 65: 'asciicircum', - 66: 'underscore', - 67: 'grave', - 68: 'a', - 69: 'b', - 70: 'c', - 71: 'd', - 72: 'e', - 73: 'f', - 74: 'g', - 75: 'h', - 76: 'i', - 77: 'j', - 78: 'k', - 79: 'l', - 80: 'm', - 81: 'n', - 82: 'o', - 83: 'p', - 84: 'q', - 85: 'r', - 86: 's', - 87: 't', - 88: 'u', - 89: 'v', - 90: 'w', - 91: 'x', - 92: 'y', - 93: 'z', - 94: 'braceleft', - 95: 'bar', - 96: 'braceright', - 97: 'asciitilde', - 98: 'Adieresis', - 99: 'Aring', - 100: 'Ccedilla', - 101: 'Eacute', - 102: 'Ntilde', - 103: 'Odieresis', - 104: 'Udieresis', - 105: 'aacute', - 106: 'agrave', - 107: 'acircumflex', - 108: 'adieresis', - 109: 'atilde', - 110: 'aring', - 111: 'ccedilla', - 112: 'eacute', - 113: 'egrave', - 114: 'ecircumflex', - 115: 'edieresis', - 116: 'iacute', - 117: 'igrave', - 118: 'icircumflex', - 119: 'idieresis', - 120: 'ntilde', - 121: 'oacute', - 122: 'ograve', - 123: 'ocircumflex', - 124: 'odieresis', - 125: 'otilde', - 126: 'uacute', - 127: 'ugrave', - 128: 'ucircumflex', - 129: 'udieresis', - 130: 'dagger', - 131: 'degree', - 132: 'cent', - 133: 'sterling', - 134: 'section', - 135: 'bullet', - 136: 'paragraph', - 137: 'germandbls', - 138: 'registered', - 139: 'copyright', - 140: 'trademark', - 141: 'acute', - 142: 'dieresis', - 143: 'notequal', - 144: 'AE', - 145: 'Oslash', - 146: 'infinity', - 147: 'plusminus', - 148: 'lessequal', - 149: 'greaterequal', - 150: 'yen', - 151: 'mu', - 152: 'partialdiff', - 153: 'summation', - 154: 'product', - 155: 'pi', - 156: 'integral', - 157: 'ordfeminine', - 158: 'ordmasculine', - 159: 'Omega', - 160: 'ae', - 161: 'oslash', - 162: 'questiondown', - 163: 'exclamdown', - 164: 'logicalnot', - 165: 'radical', - 166: 'florin', - 167: 'approxequal', - 168: 'Delta', - 169: 'guillemotleft', - 170: 'guillemotright', - 171: 'ellipsis', - 172: 'nonbreakingspace', - 173: 'Agrave', - 174: 'Atilde', - 175: 'Otilde', - 176: 'OE', - 177: 'oe', - 178: 'endash', - 179: 'emdash', - 180: 'quotedblleft', - 181: 'quotedblright', - 182: 'quoteleft', - 183: 'quoteright', - 184: 'divide', - 185: 'lozenge', - 186: 'ydieresis', - 187: 'Ydieresis', - 188: 'fraction', - 189: 'currency', - 190: 'guilsinglleft', - 191: 'guilsinglright', - 192: 'fi', - 193: 'fl', - 194: 'daggerdbl', - 195: 'periodcentered', - 196: 'quotesinglbase', - 197: 'quotedblbase', - 198: 'perthousand', - 199: 'Acircumflex', - 200: 'Ecircumflex', - 201: 'Aacute', - 202: 'Edieresis', - 203: 'Egrave', - 204: 'Iacute', - 205: 'Icircumflex', - 206: 'Idieresis', - 207: 'Igrave', - 208: 'Oacute', - 209: 'Ocircumflex', - 210: 'apple', - 211: 'Ograve', - 212: 'Uacute', - 213: 'Ucircumflex', - 214: 'Ugrave', - 215: 'dotlessi', - 216: 'circumflex', - 217: 'tilde', - 218: 'macron', - 219: 'breve', - 220: 'dotaccent', - 221: 'ring', - 222: 'cedilla', - 223: 'hungarumlaut', - 224: 'ogonek', - 225: 'caron', - 226: 'Lslash', - 227: 'lslash', - 228: 'Scaron', - 229: 'scaron', - 230: 'Zcaron', - 231: 'zcaron', - 232: 'brokenbar', - 233: 'Eth', - 234: 'eth', - 235: 'Yacute', - 236: 'yacute', - 237: 'Thorn', - 238: 'thorn', - 239: 'minus', - 240: 'multiply', - 241: 'onesuperior', - 242: 'twosuperior', - 243: 'threesuperior', - 244: 'onehalf', - 245: 'onequarter', - 246: 'threequarters', - 247: 'franc', - 248: 'Gbreve', - 249: 'gbreve', - 250: 'Idotaccent', - 251: 'Scedilla', - 252: 'scedilla', - 253: 'Cacute', - 254: 'cacute', - 255: 'Ccaron', - 256: 'ccaron', - 257: 'dcroat' -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/unicodeName.js b/vendor/fonteditor-core/src/ttf/enum/unicodeName.js deleted file mode 100644 index 7146639..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/unicodeName.js +++ /dev/null @@ -1,298 +0,0 @@ -/** - * @file unicode 编码与postName对照表 - * @author mengke01(kekee000@gmail.com) - * - * see: - * http://www.microsoft.com/typography/otspec/WGL4.htm - */ - -export default { - 0: 1, - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 1, - 7: 1, - 8: 1, - 9: 2, - 10: 1, - 11: 1, - 12: 1, - 13: 2, - 14: 1, - 15: 1, - 16: 1, - 17: 1, - 18: 1, - 19: 1, - 20: 1, - 21: 1, - 22: 1, - 23: 1, - 24: 1, - 25: 1, - 26: 1, - 27: 1, - 28: 1, - 29: 1, - 30: 1, - 31: 1, - 32: 3, - 33: 4, - 34: 5, - 35: 6, - 36: 7, - 37: 8, - 38: 9, - 39: 10, - 40: 11, - 41: 12, - 42: 13, - 43: 14, - 44: 15, - 45: 16, - 46: 17, - 47: 18, - 48: 19, - 49: 20, - 50: 21, - 51: 22, - 52: 23, - 53: 24, - 54: 25, - 55: 26, - 56: 27, - 57: 28, - 58: 29, - 59: 30, - 60: 31, - 61: 32, - 62: 33, - 63: 34, - 64: 35, - 65: 36, - 66: 37, - 67: 38, - 68: 39, - 69: 40, - 70: 41, - 71: 42, - 72: 43, - 73: 44, - 74: 45, - 75: 46, - 76: 47, - 77: 48, - 78: 49, - 79: 50, - 80: 51, - 81: 52, - 82: 53, - 83: 54, - 84: 55, - 85: 56, - 86: 57, - 87: 58, - 88: 59, - 89: 60, - 90: 61, - 91: 62, - 92: 63, - 93: 64, - 94: 65, - 95: 66, - 96: 67, - 97: 68, - 98: 69, - 99: 70, - 100: 71, - 101: 72, - 102: 73, - 103: 74, - 104: 75, - 105: 76, - 106: 77, - 107: 78, - 108: 79, - 109: 80, - 110: 81, - 111: 82, - 112: 83, - 113: 84, - 114: 85, - 115: 86, - 116: 87, - 117: 88, - 118: 89, - 119: 90, - 120: 91, - 121: 92, - 122: 93, - 123: 94, - 124: 95, - 125: 96, - 126: 97, - 160: 172, - 161: 163, - 162: 132, - 163: 133, - 164: 189, - 165: 150, - 166: 232, - 167: 134, - 168: 142, - 169: 139, - 170: 157, - 171: 169, - 172: 164, - 174: 138, - 175: 218, - 176: 131, - 177: 147, - 178: 242, - 179: 243, - 180: 141, - 181: 151, - 182: 136, - 184: 222, - 185: 241, - 186: 158, - 187: 170, - 188: 245, - 189: 244, - 190: 246, - 191: 162, - 192: 173, - 193: 201, - 194: 199, - 195: 174, - 196: 98, - 197: 99, - 198: 144, - 199: 100, - 200: 203, - 201: 101, - 202: 200, - 203: 202, - 204: 207, - 205: 204, - 206: 205, - 207: 206, - 208: 233, - 209: 102, - 210: 211, - 211: 208, - 212: 209, - 213: 175, - 214: 103, - 215: 240, - 216: 145, - 217: 214, - 218: 212, - 219: 213, - 220: 104, - 221: 235, - 222: 237, - 223: 137, - 224: 106, - 225: 105, - 226: 107, - 227: 109, - 228: 108, - 229: 110, - 230: 160, - 231: 111, - 232: 113, - 233: 112, - 234: 114, - 235: 115, - 236: 117, - 237: 116, - 238: 118, - 239: 119, - 240: 234, - 241: 120, - 242: 122, - 243: 121, - 244: 123, - 245: 125, - 246: 124, - 247: 184, - 248: 161, - 249: 127, - 250: 126, - 251: 128, - 252: 129, - 253: 236, - 254: 238, - 255: 186, - 262: 253, - 263: 254, - 268: 255, - 269: 256, - 273: 257, - 286: 248, - 287: 249, - 304: 250, - 305: 215, - 321: 226, - 322: 227, - 338: 176, - 339: 177, - 350: 251, - 351: 252, - 352: 228, - 353: 229, - 376: 187, - 381: 230, - 382: 231, - 402: 166, - 710: 216, - 711: 225, - 728: 219, - 729: 220, - 730: 221, - 731: 224, - 733: 223, - 960: 155, - 8211: 178, - 8212: 179, - 8216: 182, - 8217: 183, - 8218: 196, - 8220: 180, - 8221: 181, - 8222: 197, - 8224: 130, - 8225: 194, - 8226: 135, - 8230: 171, - 8240: 198, - 8249: 190, - 8250: 191, - 8355: 247, - 8482: 140, - 8486: 159, - 8706: 152, - 8710: 168, - 8719: 154, - 8721: 153, - 8722: 239, - 8725: 188, - 8729: 195, - 8730: 165, - 8734: 146, - 8747: 156, - 8776: 167, - 8800: 143, - 8804: 148, - 8805: 149, - 9674: 185, - 61441: 192, - 61442: 193, - 64257: 192, - 64258: 193, - 65535: 0 // 0xFFFF指向.notdef -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/weightClass.js b/vendor/fonteditor-core/src/ttf/enum/weightClass.js deleted file mode 100644 index 5e992aa..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/weightClass.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file 字体粗细度量 - * @author mengke01(kekee000@gmail.com) - */ - -export default { - 100: 'Ultra-light', - 200: 'Extra-light', - 300: 'Light', - 400: 'Semi-light', - 500: 'Medium (normal)', - 600: 'Semi-bold', - 700: 'Bold', - 800: 'Extra-Bold', - 900: 'Ultra-bold' -}; diff --git a/vendor/fonteditor-core/src/ttf/enum/widthClass.js b/vendor/fonteditor-core/src/ttf/enum/widthClass.js deleted file mode 100644 index be26633..0000000 --- a/vendor/fonteditor-core/src/ttf/enum/widthClass.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file 字体宽度度量 - * @author mengke01(kekee000@gmail.com) - */ - -export default { - 1: 'Ultra-condensed', - 2: 'Extra-condensed', - 3: 'Condensed', - 4: 'Semi-condensed', - 5: 'Medium (normal)', - 6: 'Semi-expanded', - 7: 'Expanded', - 8: 'Extra-expanded', - 9: 'Ultra-expanded' -}; diff --git a/vendor/fonteditor-core/src/ttf/eot2base64.js b/vendor/fonteditor-core/src/ttf/eot2base64.js deleted file mode 100644 index 2115aac..0000000 --- a/vendor/fonteditor-core/src/ttf/eot2base64.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @file eot数组转base64编码 - * @author mengke01(kekee000@gmail.com) - */ -import bytes2base64 from './util/bytes2base64'; - -/** - * eot数组转base64编码 - * - * @param {Array} arrayBuffer ArrayBuffer对象 - * @return {string} base64编码 - */ -export default function eot2base64(arrayBuffer) { - return 'data:font/eot;charset=utf-8;base64,' + bytes2base64(arrayBuffer); -} diff --git a/vendor/fonteditor-core/src/ttf/eot2ttf.js b/vendor/fonteditor-core/src/ttf/eot2ttf.js deleted file mode 100644 index 0f3ee5f..0000000 --- a/vendor/fonteditor-core/src/ttf/eot2ttf.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file eot转ttf - * @author mengke01(kekee000@gmail.com) - */ - -import Reader from './reader'; -import Writer from './writer'; -import error from './error'; - -/** - * eot格式转换成ttf字体格式 - * - * @param {ArrayBuffer} eotBuffer eot缓冲数组 - * @param {Object} options 选项 - * - * @return {ArrayBuffer} ttf格式byte流 - */ -// eslint-disable-next-line no-unused-vars -export default function eot2ttf(eotBuffer, options = {}) { - // 这里用小尾方式读取 - const eotReader = new Reader(eotBuffer, 0, eotBuffer.byteLength, true); - - // check magic number - const magicNumber = eotReader.readUint16(34); - if (magicNumber !== 0x504C) { - error.raise(10110); - } - - // check version - const version = eotReader.readUint32(8); - if (version !== 0x20001 && version !== 0x10000 && version !== 0x20002) { - error.raise(10110); - } - - const eotSize = eotBuffer.byteLength || eotBuffer.length; - const fontSize = eotReader.readUint32(4); - - let fontOffset = 82; - const familyNameSize = eotReader.readUint16(fontOffset); - fontOffset += 4 + familyNameSize; - - const styleNameSize = eotReader.readUint16(fontOffset); - fontOffset += 4 + styleNameSize; - - const versionNameSize = eotReader.readUint16(fontOffset); - fontOffset += 4 + versionNameSize; - - const fullNameSize = eotReader.readUint16(fontOffset); - fontOffset += 2 + fullNameSize; - - // version 0x20001 - if (version === 0x20001 || version === 0x20002) { - const rootStringSize = eotReader.readUint16(fontOffset + 2); - fontOffset += 4 + rootStringSize; - } - - // version 0x20002 - if (version === 0x20002) { - fontOffset += 10; - const signatureSize = eotReader.readUint16(fontOffset); - fontOffset += 2 + signatureSize; - fontOffset += 4; - const eudcFontSize = eotReader.readUint32(fontOffset); - fontOffset += 4 + eudcFontSize; - } - - if (fontOffset + fontSize > eotSize) { - error.raise(10001); - } - - // support slice - if (eotBuffer.slice) { - return eotBuffer.slice(fontOffset, fontOffset + fontSize); - } - - // not support ArrayBuffer.slice eg. IE10 - const bytes = eotReader.readBytes(fontOffset, fontSize); - return new Writer(new ArrayBuffer(fontSize)).writeBytes(bytes).getBuffer(); -} diff --git a/vendor/fonteditor-core/src/ttf/error.js b/vendor/fonteditor-core/src/ttf/error.js deleted file mode 100644 index c12066d..0000000 --- a/vendor/fonteditor-core/src/ttf/error.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file ttf 相关错误号定义 - * @author mengke01(kekee000@gmail.com) - */ - -import string from '../common/string'; -import i18n from './i18n'; - -export default { - - /** - * 抛出一个异常 - * - * @param {Object} e 异常号或者异常对象 - * @param {...Array} fargs args 参数 - * - * 例如: - * e = 1001 - * e = { - * number: 1001, - * data: 错误数据 - * } - */ - raise(e, ...fargs) { - let number; - let data; - if (typeof e === 'object') { - number = e.number || 0; - data = e.data; - } - else { - number = e; - } - - let message = i18n.lang[number]; - if (fargs.length > 0) { - const args = typeof fargs[0] === 'object' - ? fargs[0] - : fargs; - message = string.format(message, args); - } - - const event = new Error(message); - event.number = number; - if (data) { - event.data = data; - } - - throw event; - } -}; - - diff --git a/vendor/fonteditor-core/src/ttf/font.js b/vendor/fonteditor-core/src/ttf/font.js deleted file mode 100644 index 625cfa6..0000000 --- a/vendor/fonteditor-core/src/ttf/font.js +++ /dev/null @@ -1,361 +0,0 @@ -/** - * @file 字体管理对象,处理字体相关的读取、查询、转换 - * - * @author mengke01(kekee000@gmail.com) - */ - -import bufferTool from '../nodejs/buffer'; - -import getEmptyttfObject from './getEmptyttfObject'; -import TTF from './ttf'; - -import woff2ttf from './woff2ttf'; -import otf2ttfobject from './otf2ttfobject'; -import eot2ttf from './eot2ttf'; -import svg2ttfobject from './svg2ttfobject'; -import TTFReader from './ttfreader'; - -import TTFWriter from './ttfwriter'; -import ttf2eot from './ttf2eot'; -import ttf2woff from './ttf2woff'; -import ttf2svg from './ttf2svg'; -import ttf2symbol from './ttf2symbol'; -import ttftowoff2 from './ttftowoff2'; -import woff2tottf from './woff2tottf'; - -import ttf2base64 from './ttf2base64'; -import eot2base64 from './eot2base64'; -import woff2base64 from './woff2base64'; -import svg2base64 from './svg2base64'; -import bytes2base64 from './util/bytes2base64'; -import woff2tobase64 from './woff2tobase64'; - -import optimizettf from './util/optimizettf'; - -// 必须是nodejs环境下的Buffer对象才能触发buffer转换 -const SUPPORT_BUFFER = - typeof process === 'object' && - typeof process.versions === 'object' && - typeof process.versions.node !== 'undefined' && - typeof Buffer === 'function'; - -class Font { - /** - * 字体对象构造函数 - * - * @param {ArrayBuffer|Buffer|string|Document} buffer 字体数据 - * @param {Object} options 读取参数 - */ - constructor(buffer, options = { type: 'ttf' }) { - // 字形对象 - if (typeof buffer === 'object' && buffer.glyf) { - this.set(buffer); - } - // buffer - else if (buffer) { - this.read(buffer, options); - } - // 空 - else { - this.readEmpty(); - } - } - - /** - * Create a Font instance - * - * @param {ArrayBuffer|Buffer|string|Document} buffer 字体数据 - * @param {Object} options 读取参数 - * @return {Font} - */ - static create(buffer, options) { - return new Font(buffer, options); - } - - /** - * 设置一个空的 ttfObject 对象 - * - * @return {Font} - */ - readEmpty() { - this.data = getEmptyttfObject(); - return this; - } - - /** - * 读取字体数据 - * - * @param {ArrayBuffer|Buffer|string|Document} buffer 字体数据 - * @param {Object} options 读取参数 - * @param {string} options.type 字体类型 - * - * ttf, woff , eot 读取配置 - * @param {boolean} options.hinting 是否保留 hinting 信息 - * @param {boolean} options.kerning 是否保留 kerning 信息 - * @param {boolean} options.compound2simple 复合字形转简单字形 - * - * woff 读取配置 - * @param {Function} options.inflate 解压相关函数 - * - * svg 读取配置 - * @param {boolean} options.combinePath 是否合并成单个字形,仅限于普通svg导入 - * @return {Font} - */ - read(buffer, options) { - // nodejs buffer - if (SUPPORT_BUFFER) { - if (buffer instanceof Buffer) { - buffer = bufferTool.toArrayBuffer(buffer); - } - } - - if (options.type === 'ttf') { - this.data = new TTFReader(options).read(buffer); - } else if (options.type === 'otf') { - this.data = otf2ttfobject(buffer, options); - } else if (options.type === 'eot') { - buffer = eot2ttf(buffer, options); - this.data = new TTFReader(options).read(buffer); - } else if (options.type === 'woff') { - buffer = woff2ttf(buffer, options); - this.data = new TTFReader(options).read(buffer); - } else if (options.type === 'woff2') { - buffer = woff2tottf(buffer, options); - this.data = new TTFReader(options).read(buffer); - } else if (options.type === 'svg') { - this.data = svg2ttfobject(buffer, options); - } else { - throw new Error('not support font type' + options.type); - } - - this.type = options.type; - return this; - } - - /** - * 写入字体数据 - * - * @param {Object} options 写入参数 - * @param {string} options.type 字体类型, 默认 ttf - * @param {boolean} options.toBuffer nodejs 环境中返回 Buffer 对象, 默认 true - * - * ttf 字体参数 - * @param {boolean} options.hinting 是否保留 hinting 信息 - * @param {boolean} options.kerning 是否保留 kerning 信息 - * svg,woff 字体参数 - * @param {Object} options.metadata 字体相关的信息 - * - * woff 字体参数 - * @param {Function} options.deflate 压缩相关函数 - * @return {Buffer|ArrayBuffer|string} - */ - write(options = {}) { - if (!options.type) { - options.type = this.type; - } - - let buffer = null; - if (options.type === 'ttf') { - buffer = new TTFWriter(options).write(this.data); - } else if (options.type === 'eot') { - buffer = new TTFWriter(options).write(this.data); - buffer = ttf2eot(buffer, options); - } else if (options.type === 'woff') { - buffer = new TTFWriter(options).write(this.data); - buffer = ttf2woff(buffer, options); - } else if (options.type === 'woff2') { - buffer = new TTFWriter(options).write(this.data); - buffer = ttftowoff2(buffer, options); - } else if (options.type === 'svg') { - buffer = ttf2svg(this.data, options); - } else if (options.type === 'symbol') { - buffer = ttf2symbol(this.data, options); - } else { - throw new Error('not support font type' + options.type); - } - - if (SUPPORT_BUFFER) { - if (false !== options.toBuffer && buffer instanceof ArrayBuffer) { - buffer = bufferTool.toBuffer(buffer); - } - } - - return buffer; - } - - /** - * 转换成 base64编码 - * - * @param {Object} options 写入参数 - * @param {string} options.type 字体类型, 默认 ttf - * 其他 options参数, 参考 write - * @see write - * - * @param {ArrayBuffer=} buffer 如果提供了buffer数据则使用 buffer数据, 否则转换现有的 font - * @return {string} - */ - toBase64(options, buffer) { - if (!options.type) { - options.type = this.type; - } - - if (buffer) { - if (SUPPORT_BUFFER) { - if (buffer instanceof Buffer) { - buffer = bufferTool.toArrayBuffer(buffer); - } - } - } else { - options.toBuffer = false; - buffer = this.write(options); - } - - let base64Str; - if (options.type === 'ttf') { - base64Str = ttf2base64(buffer); - } else if (options.type === 'eot') { - base64Str = eot2base64(buffer); - } else if (options.type === 'woff') { - base64Str = woff2base64(buffer); - } else if (options.type === 'woff2') { - base64Str = woff2tobase64(buffer); - } else if (options.type === 'svg') { - base64Str = svg2base64(buffer); - } else if (options.type === 'symbol') { - base64Str = svg2base64(buffer, 'image/svg+xml'); - } else { - throw new Error('not support font type' + options.type); - } - - return base64Str; - } - - /** - * 设置 font 对象 - * - * @param {Object} data font的ttfObject对象 - * @return {this} - */ - set(data) { - this.data = data; - return this; - } - - /** - * 获取 font 数据 - * - * @return {Object} ttfObject 对象 - */ - get() { - return this.data; - } - - /** - * 对字形数据进行优化 - * - * @param {Object} out 输出结果 - * @param {boolean|Object} out.result `true` 或者有问题的地方 - * @return {Font} - */ - optimize(out) { - const result = optimizettf(this.data); - if (out) { - out.result = result; - } - return this; - } - - /** - * 将字体中的复合字形转为简单字形 - * - * @return {this} - */ - compound2simple() { - const ttfHelper = this.getHelper(); - ttfHelper.compound2simple(); - this.data = ttfHelper.get(); - return this; - } - - /** - * 对字形按照unicode编码排序 - * - * @return {this} - */ - sort() { - const ttfHelper = this.getHelper(); - ttfHelper.sortGlyf(); - this.data = ttfHelper.get(); - return this; - } - - /** - * 查找相关字形 - * - * @param {Object} condition 查询条件 - * @param {Array|number} condition.unicode unicode编码列表或者单个unicode编码 - * @param {string} condition.name glyf名字,例如`uniE001`, `uniE` - * @param {Function} condition.filter 自定义过滤器 - * @example - * condition.filter(glyf) { - * return glyf.name === 'logo'; - * } - * @return {Array} glyf字形列表 - */ - find(condition) { - const ttfHelper = this.getHelper(); - const indexList = ttfHelper.findGlyf(condition); - return indexList.length ? ttfHelper.getGlyf(indexList) : indexList; - } - - /** - * 合并 font 到当前的 font - * - * @param {Object} font Font 对象 - * @param {Object} options 参数选项 - * @param {boolean} options.scale 是否自动缩放 - * @param {boolean} options.adjustGlyf 是否调整字形以适应边界 - * (和 options.scale 参数互斥) - * - * @return {Font} - */ - merge(font, options) { - const ttfHelper = this.getHelper(); - ttfHelper.mergeGlyf(font.get(), options); - this.data = ttfHelper.get(); - return this; - } - - /** - * 获取 TTF helper 实例 - */ - getHelper() { - return new TTF(this.data); - } -} - -/** - * base64序列化buffer 数据 - * - * @param {ArrayBuffer|Buffer|string} buffer 字体数据 - * @return {Font} - */ -Font.toBase64 = function (buffer) { - if (typeof buffer === 'string') { - // node 环境中没有 btoa 函数 - if (typeof btoa === 'undefined') { - return Buffer.from(buffer, 'binary').toString('base64'); - } - - return btoa(buffer); - } - return bytes2base64(buffer); -}; - -function createFont(buffer, options) { - return new Font(buffer, options); -} - -export {Font, createFont}; - -export default Font; \ No newline at end of file diff --git a/vendor/fonteditor-core/src/ttf/getEmptyttfObject.js b/vendor/fonteditor-core/src/ttf/getEmptyttfObject.js deleted file mode 100644 index c99c930..0000000 --- a/vendor/fonteditor-core/src/ttf/getEmptyttfObject.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file 获取空的ttf对象 - * @author mengke01(kekee000@gmail.com) - */ - -import {clone} from '../common/lang'; -import emptyttf from './data/empty'; -import config from './data/default'; - - -export default function getEmpty() { - const ttf = clone(emptyttf); - Object.assign(ttf.name, config.name); - ttf.head.created = ttf.head.modified = Date.now(); - return ttf; -} diff --git a/vendor/fonteditor-core/src/ttf/i18n.js b/vendor/fonteditor-core/src/ttf/i18n.js deleted file mode 100644 index 34e1959..0000000 --- a/vendor/fonteditor-core/src/ttf/i18n.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file 语言字符串管理 - * @author mengke01(kekee000@gmail.com) - */ - -import I18n from '../common/I18n'; - -const zh = { - // error define - 10001: '超出读取范围:${0}, ${1}', - 10002: '超出写入范围:${0}, ${1}', - 10003: '未知数据类型:${0}, ${1}', - 10004: '不支持svg解析', - - 10101: '错误的ttf文件', - 10102: '错误的woff文件', - 10103: '错误的svg文件', - 10104: '读取ttf文件错误', - 10105: '读取woff文件错误', - 10106: '读取svg文件错误', - 10107: '写入ttf文件错误', - 10108: '写入woff文件错误', - 10109: '写入svg文件错误', - 10112: '写入svg symbol 错误', - - 10110: '读取eot文件错误', - 10111: '读取eot字体错误', - - 10200: '重复的unicode代码点,字形序号:${0}', - 10201: 'ttf字形轮廓数据为空', - 10202: '不支持标志位:ARGS_ARE_XY_VALUES', - 10203: '未找到表:${0}', - 10204: '读取ttf表错误', - 10205: '未找到解压函数', - - 10301: '错误的otf文件', - 10302: '读取otf表错误', - 10303: 'otf字形轮廓数据为空' -}; - - -const en = { - // error define - 10001: 'Reading index out of range: ${0}, ${1}', - 10002: 'Writing index out of range: ${0}, ${1}', - 10003: 'Unknown datatype: ${0}, ${1}', - 10004: 'No svg parser', - - 10101: 'ttf file damaged', - 10102: 'woff file damaged', - 10103: 'svg file damaged', - 10104: 'Read ttf error', - 10105: 'Read woff error', - 10106: 'Read svg error', - 10107: 'Write ttf error', - 10108: 'Write woff error', - 10109: 'Write svg error', - 10112: 'Write svg symbol error', - - 10110: 'Read eot error', - 10111: 'Write eot error', - - 10200: 'Repeat unicode, glyph index: ${0}', - 10201: 'ttf `glyph` data is empty', - 10202: 'Not support compound glyph flag: ARGS_ARE_XY_VALUES', - 10203: 'No ttf table: ${0}', - 10204: 'Read ttf table data error', - 10205: 'No zip deflate function', - - 10301: 'otf file damaged', - 10302: 'Read otf table error', - 10303: 'otf `glyph` data is empty' -}; - - -export default new I18n( - [ - ['zh-cn', zh], - ['en-us', en] - ], - typeof window !== 'undefined' ? window.language : 'en-us' -); diff --git a/vendor/fonteditor-core/src/ttf/otf2base64.js b/vendor/fonteditor-core/src/ttf/otf2base64.js deleted file mode 100644 index 2c61363..0000000 --- a/vendor/fonteditor-core/src/ttf/otf2base64.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file otf转bse64字体 - * @author mengke01(kekee000@gmail.com) - */ - -import bytes2base64 from './util/bytes2base64'; - -/** - * ttf 二进制转base64编码 - * - * @param {Array} arrayBuffer ArrayBuffer对象 - * @return {string} base64编码 - */ -export default function ttf2base64(arrayBuffer) { - return 'data:font/otf;charset=utf-8;base64,' + bytes2base64(arrayBuffer); -} diff --git a/vendor/fonteditor-core/src/ttf/otf2ttfobject.js b/vendor/fonteditor-core/src/ttf/otf2ttfobject.js deleted file mode 100644 index c7c08c7..0000000 --- a/vendor/fonteditor-core/src/ttf/otf2ttfobject.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file otf格式转ttf格式对象 - * @author mengke01(kekee000@gmail.com) - */ - -import error from './error'; -import OTFReader from './otfreader'; -import otfContours2ttfContours from './util/otfContours2ttfContours'; -import {computePathBox} from '../graphics/computeBoundingBox'; - -/** - * otf格式转ttf格式对象 - * - * @param {ArrayBuffer|otfObject} otfBuffer 原始数据或者解析后的otf数据 - * @param {Object} options 参数 - * @return {Object} ttfObject对象 - */ -export default function otf2ttfobject(otfBuffer, options) { - let otfObject; - if (otfBuffer instanceof ArrayBuffer) { - const otfReader = new OTFReader(options); - otfObject = otfReader.read(otfBuffer); - otfReader.dispose(); - } - else if (otfBuffer.head && otfBuffer.glyf && otfBuffer.cmap) { - otfObject = otfBuffer; - } - else { - error.raise(10111); - } - - // 转换otf轮廓 - otfObject.glyf.forEach((g) => { - g.contours = otfContours2ttfContours(g.contours); - const box = computePathBox(...g.contours); - if (box) { - g.xMin = box.x; - g.xMax = box.x + box.width; - g.yMin = box.y; - g.yMax = box.y + box.height; - g.leftSideBearing = g.xMin; - } - else { - g.xMin = 0; - g.xMax = 0; - g.yMin = 0; - g.yMax = 0; - g.leftSideBearing = 0; - } - }); - - otfObject.version = 0x1; - - // 修改maxp相关配置 - otfObject.maxp.version = 1.0; - otfObject.maxp.maxZones = otfObject.maxp.maxTwilightPoints ? 2 : 1; - - delete otfObject.CFF; - delete otfObject.VORG; - - return otfObject; -} diff --git a/vendor/fonteditor-core/src/ttf/otfreader.js b/vendor/fonteditor-core/src/ttf/otfreader.js deleted file mode 100644 index d07fc37..0000000 --- a/vendor/fonteditor-core/src/ttf/otfreader.js +++ /dev/null @@ -1,171 +0,0 @@ -/** - * @file otf字体读取 - * @author mengke01(kekee000@gmail.com) - */ - -import Directory from './table/directory'; -import supportTables from './table/support-otf'; -import Reader from './reader'; -import error from './error'; - -export default class OTFReader { - - /** - * OTF读取函数 - * - * @param {Object} options 写入参数 - * @constructor - */ - constructor(options = {}) { - options.subset = options.subset || []; - this.options = options; - } - - /** - * 初始化 - * - * @param {ArrayBuffer} buffer buffer对象 - * @return {Object} ttf对象 - */ - readBuffer(buffer) { - - const reader = new Reader(buffer, 0, buffer.byteLength, false); - const font = {}; - - // version - font.version = reader.readString(0, 4); - - if (font.version !== 'OTTO') { - error.raise(10301); - } - - // num tables - font.numTables = reader.readUint16(); - - if (font.numTables <= 0 || font.numTables > 100) { - error.raise(10302); - } - - // searchRange - font.searchRange = reader.readUint16(); - - // entrySelector - font.entrySelector = reader.readUint16(); - - // rangeShift - font.rangeShift = reader.readUint16(); - - font.tables = new Directory(reader.offset).read(reader, font); - - if (!font.tables.head || !font.tables.cmap || !font.tables.CFF) { - error.raise(10302); - } - - font.readOptions = this.options; - - // 读取支持的表数据 - Object.keys(supportTables).forEach((tableName) => { - if (font.tables[tableName]) { - const offset = font.tables[tableName].offset; - font[tableName] = new supportTables[tableName](offset).read(reader, font); - } - }); - - if (!font.CFF.glyf) { - error.raise(10303); - } - - reader.dispose(); - - return font; - } - - /** - * 关联glyf相关的信息 - * - * @param {Object} font font对象 - */ - resolveGlyf(font) { - - const codes = font.cmap; - let glyf = font.CFF.glyf; - const subsetMap = font.readOptions.subset ? font.subsetMap : null; // 当前ttf的子集列表 - // unicode - Object.keys(codes).forEach((c) => { - const i = codes[c]; - if (subsetMap && !subsetMap[i]) { - return; - } - if (!glyf[i].unicode) { - glyf[i].unicode = []; - } - glyf[i].unicode.push(+c); - }); - - // leftSideBearing - font.hmtx.forEach((item, i) => { - if (subsetMap && !subsetMap[i]) { - return; - } - glyf[i].advanceWidth = glyf[i].advanceWidth || item.advanceWidth || 0; - glyf[i].leftSideBearing = item.leftSideBearing; - }); - - // 设置了subsetMap之后需要选取subset中的字形 - if (subsetMap) { - const subGlyf = []; - Object.keys(subsetMap).forEach((i) => { - subGlyf.push(glyf[+i]); - }); - glyf = subGlyf; - } - - font.glyf = glyf; - } - - /** - * 清除非必须的表 - * - * @param {Object} font font对象 - */ - cleanTables(font) { - delete font.readOptions; - delete font.tables; - delete font.hmtx; - delete font.post.glyphNameIndex; - delete font.post.names; - delete font.subsetMap; - - // 删除无用的表 - const cff = font.CFF; - delete cff.glyf; - delete cff.charset; - delete cff.encoding; - delete cff.gsubrs; - delete cff.gsubrsBias; - delete cff.subrs; - delete cff.subrsBias; - } - - /** - * 获取解析后的ttf文档 - * - * @param {ArrayBuffer} buffer buffer对象 - * - * @return {Object} ttf文档 - */ - read(buffer) { - this.font = this.readBuffer(buffer); - this.resolveGlyf(this.font); - this.cleanTables(this.font); - return this.font; - } - - /** - * 注销 - */ - dispose() { - delete this.font; - delete this.options; - } -} diff --git a/vendor/fonteditor-core/src/ttf/reader.js b/vendor/fonteditor-core/src/ttf/reader.js deleted file mode 100644 index 5ff4f4f..0000000 --- a/vendor/fonteditor-core/src/ttf/reader.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @file 数据读取器 - * @author mengke01(kekee000@gmail.com) - * - * thanks to: - * ynakajima/ttf.js - * https://github.com/ynakajima/ttf.js - */ - -import {curry} from '../common/lang'; -import error from './error'; - -// 检查数组支持情况 -if (typeof ArrayBuffer === 'undefined' || typeof DataView === 'undefined') { - throw new Error('not support ArrayBuffer and DataView'); -} - -// 数据类型 -const dataType = { - Int8: 1, - Int16: 2, - Int32: 4, - Uint8: 1, - Uint16: 2, - Uint32: 4, - Float32: 4, - Float64: 8 -}; - -export default class Reader { - - /** - * 读取器 - * - * @constructor - * @param {Array.} buffer 缓冲数组 - * @param {number} offset 起始偏移 - * @param {number} length 数组长度 - * @param {boolean} littleEndian 是否小尾 - */ - constructor(buffer, offset, length, littleEndian) { - - const bufferLength = buffer.byteLength || buffer.length; - - this.offset = offset || 0; - this.length = length || (bufferLength - this.offset); - this.littleEndian = littleEndian || false; - - this.view = new DataView(buffer, this.offset, this.length); - } - - /** - * 读取指定的数据类型 - * - * @param {string} type 数据类型 - * @param {number=} offset 位移 - * @param {boolean=} littleEndian 是否小尾 - * @return {number} 返回值 - */ - read(type, offset, littleEndian) { - - // 使用当前位移 - if (undefined === offset) { - offset = this.offset; - } - - // 使用小尾 - if (undefined === littleEndian) { - littleEndian = this.littleEndian; - } - - // 扩展方法 - if (undefined === dataType[type]) { - return this['read' + type](offset, littleEndian); - } - - const size = dataType[type]; - this.offset = offset + size; - return this.view['get' + type](offset, littleEndian); - } - - /** - * 获取指定的字节数组 - * - * @param {number} offset 偏移 - * @param {number} length 字节长度 - * @return {Array} 字节数组 - */ - readBytes(offset, length = null) { - - if (length == null) { - length = offset; - offset = this.offset; - } - - if (length < 0 || offset + length > this.length) { - error.raise(10001, this.length, offset + length); - } - - const buffer = []; - for (let i = 0; i < length; ++i) { - buffer.push(this.view.getUint8(offset + i)); - } - - this.offset = offset + length; - return buffer; - } - - /** - * 读取一个string - * - * @param {number} offset 偏移 - * @param {number} length 长度 - * @return {string} 字符串 - */ - readString(offset, length = null) { - - if (length == null) { - length = offset; - offset = this.offset; - } - - if (length < 0 || offset + length > this.length) { - error.raise(10001, this.length, offset + length); - } - - let value = ''; - for (let i = 0; i < length; ++i) { - const c = this.readUint8(offset + i); - value += String.fromCharCode(c); - } - - this.offset = offset + length; - - return value; - } - - /** - * 读取一个字符 - * - * @param {number} offset 偏移 - * @return {string} 字符串 - */ - readChar(offset) { - return this.readString(offset, 1); - } - - /** - * 读取一个uint24整形 - * - * @param {number} offset 偏移 - * @return {number} - */ - readUint24(offset) { - const [i, j, k] = this.readBytes(offset || this.offset, 3); - return (i << 16) + (j << 8) + k; - } - - /** - * 读取fixed类型 - * - * @param {number} offset 偏移 - * @return {number} float - */ - readFixed(offset) { - if (undefined === offset) { - offset = this.offset; - } - const val = this.readInt32(offset, false) / 65536.0; - return Math.ceil(val * 100000) / 100000; - } - - /** - * 读取长日期 - * - * @param {number} offset 偏移 - * @return {Date} Date对象 - */ - readLongDateTime(offset) { - if (undefined === offset) { - offset = this.offset; - } - - // new Date(1970, 1, 1).getTime() - new Date(1904, 1, 1).getTime(); - const delta = -2077545600000; - const time = this.readUint32(offset + 4, false); - const date = new Date(); - date.setTime(time * 1000 + delta); - return date; - } - - /** - * 跳转到指定偏移 - * - * @param {number} offset 偏移 - * @return {Object} this - */ - seek(offset) { - if (undefined === offset) { - this.offset = 0; - } - - if (offset < 0 || offset > this.length) { - error.raise(10001, this.length, offset); - } - - this.offset = offset; - - return this; - } - - /** - * 注销 - */ - dispose() { - delete this.view; - } -} - -// 直接支持的数据类型 -Object.keys(dataType).forEach((type) => { - Reader.prototype['read' + type] = curry(Reader.prototype.read, type); -}); diff --git a/vendor/fonteditor-core/src/ttf/svg/contoursTransform.js b/vendor/fonteditor-core/src/ttf/svg/contoursTransform.js deleted file mode 100644 index 232bfcf..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/contoursTransform.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file 根据transform参数变换轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import {mul, multiply} from '../../graphics/matrix'; -import pathTransform from '../../graphics/pathTransform'; - -/** - * 根据transform参数变换轮廓 - * - * @param {Array} contours 轮廓集合 - * @param {Array} transforms 变换指令集合 - * transforms = [{ - * name: 'scale' - * params: [3,4] - * }] - * - * @return {Array} 变换后的轮廓数组 - */ -export default function contoursTransform(contours, transforms) { - if (!contours || !contours.length || !transforms || !transforms.length) { - return contours; - } - - let matrix = [1, 0, 0, 1, 0, 0]; - for (let i = 0, l = transforms.length; i < l; i++) { - const transform = transforms[i]; - const params = transform.params; - let radian = null; - switch (transform.name) { - case 'translate': - matrix = mul(matrix, [1, 0, 0, 1, params[0], params[1]]); - break; - case 'scale': - matrix = mul(matrix, [params[0], 0, 0, params[1], 0, 0]); - break; - case 'matrix': - matrix = mul(matrix, - [params[0], params[1], params[2], params[3], params[4], params[5]]); - break; - case 'rotate': - radian = params[0] * Math.PI / 180; - if (params.length > 1) { - - matrix = multiply( - matrix, - [1, 0, 0, 1, -params[1], -params[2]], - [Math.cos(radian), Math.sin(radian), -Math.sin(radian), Math.cos(radian), 0, 0], - [1, 0, 0, 1, params[1], params[2]] - ); - } - else { - matrix = mul( - matrix, [Math.cos(radian), Math.sin(radian), -Math.sin(radian), Math.cos(radian), 0, 0]); - } - break; - case 'skewX': - matrix = mul(matrix, - [1, 0, Math.tan(params[0] * Math.PI / 180), 1, 0, 0]); - break; - case 'skewY': - matrix = mul(matrix, - [1, Math.tan(params[0] * Math.PI / 180), 0, 1, 0, 0]); - break; - } - } - - contours.forEach(p => { - pathTransform(p, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); - }); - - return contours; -} diff --git a/vendor/fonteditor-core/src/ttf/svg/oval2contour.js b/vendor/fonteditor-core/src/ttf/svg/oval2contour.js deleted file mode 100644 index cec8039..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/oval2contour.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file 椭圆转换成轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import {computePath} from '../../graphics/computeBoundingBox'; -import pathAdjust from '../../graphics/pathAdjust'; -import circlePath from '../../graphics/path/circle'; -import {clone} from '../../common/lang'; - -/** - * 椭圆转换成轮廓 - * - * @param {number} cx 椭圆中心点x - * @param {number} cy 椭圆中心点y - * @param {number} rx 椭圆x轴半径 - * @param {number} ry 椭圆y周半径 - * @return {Array} 轮廓数组 - */ -export default function oval2contour(cx, cy, rx, ry) { - - if (undefined === ry) { - ry = rx; - } - - const bound = computePath(circlePath); - const scaleX = (+rx) * 2 / bound.width; - const scaleY = (+ry) * 2 / bound.height; - const centerX = bound.width * scaleX / 2; - const centerY = bound.height * scaleY / 2; - const contour = clone(circlePath); - pathAdjust(contour, scaleX, scaleY); - pathAdjust(contour, 1, 1, +cx - centerX, +cy - centerY); - - return contour; -} diff --git a/vendor/fonteditor-core/src/ttf/svg/parseParams.js b/vendor/fonteditor-core/src/ttf/svg/parseParams.js deleted file mode 100644 index d101e00..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/parseParams.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file 解析参数数组 - * @author mengke01(kekee000@gmail.com) - */ - -const SEGMENT_REGEX = /-?\d+(?:\.\d+)?(?:e[-+]?\d+)?\b/g; - -/** - * 获取参数值 - * - * @param {string} d 参数 - * @return {number} 参数值 - */ -function getSegment(d) { - return +d.trim(); -} - -/** - * 解析参数数组 - * - * @param {string} str 参数字符串 - * @return {Array} 参数数组 - */ -export default function (str) { - if (!str) { - return []; - } - const matchs = str.match(SEGMENT_REGEX); - return matchs ? matchs.map(getSegment) : []; -} diff --git a/vendor/fonteditor-core/src/ttf/svg/parseTransform.js b/vendor/fonteditor-core/src/ttf/svg/parseTransform.js deleted file mode 100644 index 11e8fb2..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/parseTransform.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file 解析transform参数 - * @author mengke01(kekee000@gmail.com) - */ - -import parseParams from './parseParams'; -const TRANSFORM_REGEX = /(\w+)\s*\(([\d-.,\s]*)\)/g; - -/** - * 解析transform参数 - * - * @param {string} str 参数字符串 - * @return {Array} transform数组, 格式如下: - * [ - * { - * name: 'scale', - * params: [] - * } - * ] - */ -export default function parseTransform(str) { - - if (!str) { - return false; - } - - TRANSFORM_REGEX.lastIndex = 0; - const transforms = []; - let match; - - while ((match = TRANSFORM_REGEX.exec(str))) { - transforms.push({ - name: match[1], - params: parseParams(match[2]) - }); - } - - return transforms; -} diff --git a/vendor/fonteditor-core/src/ttf/svg/path2contours.js b/vendor/fonteditor-core/src/ttf/svg/path2contours.js deleted file mode 100644 index c084fc3..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/path2contours.js +++ /dev/null @@ -1,529 +0,0 @@ -/** - * @file svg path转换为轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import bezierCubic2Q2 from '../../math/bezierCubic2Q2'; -import getArc from '../../graphics/getArc'; -import parseParams from './parseParams'; - -/** - * 三次贝塞尔曲线,转二次贝塞尔曲线 - * - * @param {Array} cubicList 三次曲线数组 - * @param {Array} contour 当前解析后的轮廓数组 - * @return {Array} 当前解析后的轮廓数组 - */ -function cubic2Points(cubicList, contour) { - - let i; - let l; - const q2List = []; - - cubicList.forEach(c => { - const list = bezierCubic2Q2(c[0], c[1], c[2], c[3]); - for (i = 0, l = list.length; i < l; i++) { - q2List.push(list[i]); - } - }); - - let q2; - let prevq2; - for (i = 0, l = q2List.length; i < l; i++) { - q2 = q2List[i]; - if (i === 0) { - contour.push({ - x: q2[1].x, - y: q2[1].y - }); - contour.push({ - x: q2[2].x, - y: q2[2].y, - onCurve: true - }); - } - else { - prevq2 = q2List[i - 1]; - // 检查是否存在切线点 - if ( - prevq2[1].x + q2[1].x === 2 * q2[0].x - && prevq2[1].y + q2[1].y === 2 * q2[0].y - ) { - contour.pop(); - } - contour.push({ - x: q2[1].x, - y: q2[1].y - }); - contour.push({ - x: q2[2].x, - y: q2[2].y, - onCurve: true - }); - } - } - - contour.push({ - x: q2[2].x, - y: q2[2].y, - onCurve: true - }); - - return contour; -} - - -/** - * svg 命令数组转轮廓 - * - * @param {Array} segments svg 命令数组 - * @return {Array} 轮廓数组 - */ -function segments2Contours(segments) { - - // 解析segments - const contours = []; - let contour = []; - let prevX = 0; - let prevY = 0; - let segment; - let args; - let cmd; - let relative; - let q; - let ql; - let px; - let py; - let cubicList; - let p1; - let p2; - let c1; - let c2; - let prevCubicC1; // 三次贝塞尔曲线前一个控制点,用于绘制`s`命令 - - for (let i = 0, l = segments.length; i < l; i++) { - segment = segments[i]; - cmd = segment.cmd; - relative = segment.relative; - args = segment.args; - - if (args && !args.length && cmd !== 'Z') { - console.warn('`' + cmd + '` command args empty!'); - continue; - } - - if (cmd === 'Z') { - contours.push(contour); - contour = []; - } - else if (cmd === 'M' || cmd === 'L') { - if (args.length % 2) { - throw new Error('`M` command error:' + args.join(',')); - } - - // 这里可能会连续绘制,最后一个是终点 - if (relative) { - px = prevX; - py = prevY; - } - else { - px = 0; - py = 0; - } - - for (q = 0, ql = args.length; q < ql; q += 2) { - - if (relative) { - px += args[q]; - py += args[q + 1]; - } - else { - px = args[q]; - py = args[q + 1]; - } - - contour.push({ - x: px, - y: py, - onCurve: true - }); - } - - prevX = px; - prevY = py; - } - else if (cmd === 'H') { - if (relative) { - prevX += args[0]; - } - else { - prevX = args[0]; - } - - contour.push({ - x: prevX, - y: prevY, - onCurve: true - }); - } - else if (cmd === 'V') { - if (relative) { - prevY += args[0]; - } - else { - prevY = args[0]; - } - - contour.push({ - x: prevX, - y: prevY, - onCurve: true - }); - } - // 二次贝塞尔 - else if (cmd === 'Q') { - // 这里可能会连续绘制,最后一个是终点 - if (relative) { - px = prevX; - py = prevY; - } - else { - px = 0; - py = 0; - } - - for (q = 0, ql = args.length; q < ql; q += 4) { - - contour.push({ - x: px + args[q], - y: py + args[q + 1] - }); - contour.push({ - x: px + args[q + 2], - y: py + args[q + 3], - onCurve: true - }); - - if (relative) { - px += args[q + 2]; - py += args[q + 3]; - } - else { - px = 0; - py = 0; - } - } - - if (relative) { - prevX = px; - prevY = py; - } - else { - prevX = args[ql - 2]; - prevY = args[ql - 1]; - } - } - // 二次贝塞尔平滑 - else if (cmd === 'T') { - // 这里需要移除上一个曲线的终点 - let last = contour.pop(); - let pc = contour[contour.length - 1]; - if (!pc) { - pc = last; - } - - contour.push(pc = { - x: 2 * last.x - pc.x, - y: 2 * last.y - pc.y - }); - - px = prevX; - py = prevY; - - for (q = 0, ql = args.length - 2; q < ql; q += 2) { - - if (relative) { - px += args[q]; - py += args[q + 1]; - } - else { - px = args[q]; - py = args[q + 1]; - } - - last = { - x: px, - y: py - }; - - contour.push(pc = { - x: 2 * last.x - pc.x, - y: 2 * last.y - pc.y - }); - } - - if (relative) { - prevX = px + args[ql]; - prevY = py + args[ql + 1]; - } - else { - prevX = args[ql]; - prevY = args[ql + 1]; - } - - contour.push({ - x: prevX, - y: prevY, - onCurve: true - }); - - } - // 三次贝塞尔 - else if (cmd === 'C') { - if (args.length % 6) { - throw new Error('`C` command params error:' + args.join(',')); - } - - // 这里可能会连续绘制,最后一个是终点 - cubicList = []; - - if (relative) { - px = prevX; - py = prevY; - } - else { - px = 0; - py = 0; - } - - p1 = { - x: prevX, - y: prevY - }; - - for (q = 0, ql = args.length; q < ql; q += 6) { - - c1 = { - x: px + args[q], - y: py + args[q + 1] - }; - - c2 = { - x: px + args[q + 2], - y: py + args[q + 3] - }; - - p2 = { - x: px + args[q + 4], - y: py + args[q + 5] - }; - - cubicList.push([p1, c1, c2, p2]); - - p1 = p2; - - if (relative) { - px += args[q + 4]; - py += args[q + 5]; - } - else { - px = 0; - py = 0; - } - } - - if (relative) { - prevX = px; - prevY = py; - } - else { - prevX = args[ql - 2]; - prevY = args[ql - 1]; - } - - cubic2Points(cubicList, contour); - prevCubicC1 = cubicList[cubicList.length - 1][2]; - } - // 三次贝塞尔平滑 - else if (cmd === 'S') { - if (args.length % 4) { - throw new Error('`S` command params error:' + args.join(',')); - } - - // 这里可能会连续绘制,最后一个是终点 - cubicList = []; - - if (relative) { - px = prevX; - py = prevY; - } - else { - px = 0; - py = 0; - } - - // 这里需要移除上一个曲线的终点 - p1 = contour.pop(); - if (!prevCubicC1) { - prevCubicC1 = p1; - } - - c1 = { - x: 2 * p1.x - prevCubicC1.x, - y: 2 * p1.y - prevCubicC1.y - }; - - for (q = 0, ql = args.length; q < ql; q += 4) { - - c2 = { - x: px + args[q], - y: py + args[q + 1] - }; - - p2 = { - x: px + args[q + 2], - y: py + args[q + 3] - }; - - cubicList.push([p1, c1, c2, p2]); - - p1 = p2; - - c1 = { - x: 2 * p1.x - c2.x, - y: 2 * p1.y - c2.y - }; - - if (relative) { - px += args[q + 2]; - py += args[q + 3]; - } - else { - px = 0; - py = 0; - } - } - - if (relative) { - prevX = px; - prevY = py; - } - else { - prevX = args[ql - 2]; - prevY = args[ql - 1]; - } - - cubic2Points(cubicList, contour); - prevCubicC1 = cubicList[cubicList.length - 1][2]; - } - // 求弧度, rx, ry, angle, largeArc, sweep, ex, ey - else if (cmd === 'A') { - if (args.length % 7) { - throw new Error('arc command params error:' + args.join(',')); - } - - for (q = 0, ql = args.length; q < ql; q += 7) { - let ex = args[q + 5]; - let ey = args[q + 6]; - - if (relative) { - ex = prevX + ex; - ey = prevY + ey; - } - - const path = getArc( - args[q], args[q + 1], - args[q + 2], args[q + 3], args[q + 4], - {x: prevX, y: prevY}, - {x: ex, y: ey} - ); - - if (path && path.length > 1) { - for (let r = 1, rl = path.length; r < rl; r++) { - contour.push(path[r]); - } - } - prevX = ex; - prevY = ey; - } - } - } - - return contours; -} - -/** - * svg path转轮廓 - * - * @param {string} path svg的path字符串 - * @return {Array} 转换后的轮廓 - */ -export default function path2contours(path) { - - if (!path || !path.length) { - return null; - } - - path = path.trim(); - - // 修正头部不为`m`的情况 - if (path[0] !== 'M' && path[0] !== 'm') { - path = 'M 0 0' + path; - } - - // 修复中间没有结束符`z`的情况 - path = path.replace(/(\d+)\s*(m|$)/gi, '$1z$2'); - - // 获取segments - const segments = []; - let cmd; - let relative = false; - let lastIndex; - let args; - - for (let i = 0, l = path.length; i < l; i++) { - const c = path[i].toUpperCase(); - const r = c !== path[i]; - - switch (c) { - case 'M': - /* jshint -W086 */ - if (i === 0) { - cmd = c; - lastIndex = 1; - break; - } - // eslint-disable-next-line no-fallthrough - case 'Q': - case 'T': - case 'C': - case 'S': - case 'H': - case 'V': - case 'L': - case 'A': - case 'Z': - if (cmd === 'Z') { - segments.push({cmd: 'Z'}); - } - else { - args = path.slice(lastIndex, i); - segments.push({ - cmd, - relative, - args: parseParams(args) - }); - } - - cmd = c; - relative = r; - lastIndex = i + 1; - break; - - } - } - - segments.push({cmd: 'Z'}); - - return segments2Contours(segments); -} diff --git a/vendor/fonteditor-core/src/ttf/svg/polygon2contour.js b/vendor/fonteditor-core/src/ttf/svg/polygon2contour.js deleted file mode 100644 index 1882388..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/polygon2contour.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file 多边形转换成轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import parseParams from './parseParams'; - -/** - * 多边形转换成轮廓 - * - * @param {Array} points 多边形点集合 - * @return {Array} contours - */ -export default function polygon2contour(points) { - - if (!points || !points.length) { - return null; - } - - const contours = []; - const segments = parseParams(points); - for (let i = 0, l = segments.length; i < l; i += 2) { - contours.push({ - x: segments[i], - y: segments[i + 1], - onCurve: true - }); - } - - return contours; -} diff --git a/vendor/fonteditor-core/src/ttf/svg/rect2contour.js b/vendor/fonteditor-core/src/ttf/svg/rect2contour.js deleted file mode 100644 index 00a72be..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/rect2contour.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file 矩形转换成轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 矩形转换成轮廓 - * - * @param {number} x 左上角x - * @param {number} y 左上角y - * @param {number} width 宽度 - * @param {number} height 高度 - * @return {Array} 轮廓数组 - */ -export default function rect2contour(x, y, width, height) { - x = +x; - y = +y; - width = +width; - height = +height; - - return [ - { - x, - y, - onCurve: true - }, - { - x: x + width, - y, - onCurve: true - }, - { - x: x + width, - y: y + height, - onCurve: true - }, - { - x, - y: y + height, - onCurve: true - } - ]; -} diff --git a/vendor/fonteditor-core/src/ttf/svg/svgnode2contours.js b/vendor/fonteditor-core/src/ttf/svg/svgnode2contours.js deleted file mode 100644 index 17614dc..0000000 --- a/vendor/fonteditor-core/src/ttf/svg/svgnode2contours.js +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @file svg节点转字形轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import path2contours from './path2contours'; -import oval2contour from './oval2contour'; -import polygon2contour from './polygon2contour'; -import rect2contour from './rect2contour'; -import parseTransform from './parseTransform'; -import contoursTransform from './contoursTransform'; - -// 支持的解析器集合 -const support = { - - path: { - parse: path2contours, // 解析器 - params: ['d'], // 参数列表 - contours: true // 是否是多个轮廓 - }, - - circle: { - parse: oval2contour, - params: ['cx', 'cy', 'r'] - }, - - ellipse: { - parse: oval2contour, - params: ['cx', 'cy', 'rx', 'ry'] - }, - - rect: { - parse: rect2contour, - params: ['x', 'y', 'width', 'height'] - }, - - polygon: { - parse: polygon2contour, - params: ['points'] - }, - - polyline: { - parse: polygon2contour, - params: ['points'] - } -}; - -/** - * svg节点转字形轮廓 - * - * @param {Array} xmlNodes xml节点集合 - * @return {Array|false} 轮廓数组 - */ -export default function svgnode2contours(xmlNodes) { - let i; - let length; - let j; - let jlength; - let segment; // 当前指令 - const parsedSegments = []; // 解析后的指令 - - if (xmlNodes.length) { - for (i = 0, length = xmlNodes.length; i < length; i++) { - const node = xmlNodes[i]; - const name = node.tagName; - if (support[name]) { - const supportParams = support[name].params; - const params = []; - for (j = 0, jlength = supportParams.length; j < jlength; j++) { - params.push(node.getAttribute(supportParams[j])); - } - - segment = { - name, - params, - transform: parseTransform(node.getAttribute('transform')) - }; - - if (node.parentNode) { - let curNode = node.parentNode; - const transforms = segment.transform || []; - let transAttr; - const iterator = function (t) { - transforms.unshift(t); - }; - while (curNode !== null && curNode.tagName !== 'svg') { - transAttr = curNode.getAttribute('transform'); - if (transAttr) { - parseTransform(transAttr).reverse().forEach(iterator); - } - curNode = curNode.parentNode; - } - - segment.transform = transforms.length ? transforms : null; - } - parsedSegments.push(segment); - } - } - } - - if (parsedSegments.length) { - const result = []; - for (i = 0, length = parsedSegments.length; i < length; i++) { - segment = parsedSegments[i]; - const parser = support[segment.name]; - const contour = parser.parse.apply(null, segment.params); - if (contour && contour.length) { - let contours = parser.contours ? contour : [contour]; - - // 如果有变换则应用变换规则 - if (segment.transform) { - contours = contoursTransform(contours, segment.transform); - } - - for (j = 0, jlength = contours.length; j < jlength; j++) { - result.push(contours[j]); - } - } - } - return result; - } - - return false; -} diff --git a/vendor/fonteditor-core/src/ttf/svg2base64.js b/vendor/fonteditor-core/src/ttf/svg2base64.js deleted file mode 100644 index 4c5f8ae..0000000 --- a/vendor/fonteditor-core/src/ttf/svg2base64.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @file svg字符串转base64编码 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * svg字符串转base64编码 - * - * @param {string} svg svg对象 - * @param {string} scheme 头部 - * @return {string} base64编码 - */ -export default function svg2base64(svg, scheme = 'font/svg') { - if (typeof btoa === 'undefined') { - return 'data:' + scheme + ';charset=utf-8;base64,' - + Buffer.from(svg, 'binary').toString('base64'); - } - return 'data:' + scheme + ';charset=utf-8;base64,' + btoa(svg); -} diff --git a/vendor/fonteditor-core/src/ttf/svg2ttfobject.js b/vendor/fonteditor-core/src/ttf/svg2ttfobject.js deleted file mode 100644 index 2b693f8..0000000 --- a/vendor/fonteditor-core/src/ttf/svg2ttfobject.js +++ /dev/null @@ -1,431 +0,0 @@ -/** - * @file svg格式转ttfObject格式 - * @author mengke01(kekee000@gmail.com) - */ - -import string from '../common/string'; -import DOMParser from '../common/DOMParser'; -import path2contours from './svg/path2contours'; -import svgnode2contours from './svg/svgnode2contours'; -import {computePathBox} from '../graphics/computeBoundingBox'; -import pathsUtil from '../graphics/pathsUtil'; -import glyfAdjust from './util/glyfAdjust'; -import error from './error'; -import getEmptyttfObject from './getEmptyttfObject'; -import reduceGlyf from './util/reduceGlyf'; - -/** - * 加载xml字符串 - * - * @param {string} xml xml字符串 - * @return {Document} - */ -function loadXML(xml) { - if (DOMParser) { - try { - const domParser = new DOMParser(); - const xmlDoc = domParser.parseFromString(xml, 'text/xml'); - return xmlDoc; - } - catch (exp) { - error.raise(10103); - } - } - error.raise(10004); -} - -/** - * 对xml文本进行处理 - * - * @param {string} svg svg文本 - * @return {string} 处理后文本 - */ -function resolveSVG(svg) { - // 去除xmlns,防止xmlns导致svg解析错误 - svg = svg.replace(/\s+xmlns(?::[\w-]+)?=("|')[^"']*\1/g, ' ') - .replace(/\s][\s\S]+?\/defs>/g, (text) => { - if (text.indexOf('') >= 0) { - return text; - } - return ''; - }) - .replace(/\s][\s\S]+?\/use>/g, ''); - return svg; -} - -/** - * 获取空的ttf格式对象 - * - * @return {Object} ttfObject对象 - */ -function getEmptyTTF() { - const ttf = getEmptyttfObject(); - ttf.head.unitsPerEm = 0; // 去除unitsPerEm以便于重新计算 - ttf.from = 'svgfont'; - return ttf; -} - -/** - * 获取空的对象,用来作为ttf的容器 - * - * @return {Object} ttfObject对象 - */ -function getEmptyObject() { - return { - 'from': 'svg', - 'OS/2': {}, - 'name': {}, - 'hhea': {}, - 'head': {}, - 'post': {}, - 'glyf': [] - }; -} - -/** - * 根据边界获取unitsPerEm - * - * @param {number} xMin x最小值 - * @param {number} xMax x最大值 - * @param {number} yMin y最小值 - * @param {number} yMax y最大值 - * @return {number} - */ -function getUnitsPerEm(xMin, xMax, yMin, yMax) { - const seed = Math.ceil(Math.min(yMax - yMin, xMax - xMin)); - - if (!seed) { - return 1024; - } - - if (seed <= 128) { - return seed; - } - - // 获取合适的unitsPerEm - let unitsPerEm = 128; - while (unitsPerEm < 16384) { - - if (seed <= 1.2 * unitsPerEm) { - return unitsPerEm; - } - - unitsPerEm <<= 1; - } - - return 1024; -} - -/** - * 对ttfObject进行处理,去除小数 - * - * @param {Object} ttf ttfObject - * @return {Object} ttfObject - */ -function resolve(ttf) { - - - // 如果是svg格式字体,则去小数 - // 由于svg格式导入时候会出现字形重复问题,这里进行优化 - if (ttf.from === 'svgfont' && ttf.head.unitsPerEm > 128) { - ttf.glyf.forEach((g) => { - if (g.contours) { - glyfAdjust(g); - reduceGlyf(g); - } - }); - } - // 否则重新计算字形大小,缩放到1024的em - else { - let xMin = 16384; - let xMax = -16384; - let yMin = 16384; - let yMax = -16384; - - ttf.glyf.forEach((g) => { - if (g.contours) { - const bound = computePathBox(...g.contours); - if (bound) { - xMin = Math.min(xMin, bound.x); - xMax = Math.max(xMax, bound.x + bound.width); - yMin = Math.min(yMin, bound.y); - yMax = Math.max(yMax, bound.y + bound.height); - } - } - }); - - const unitsPerEm = getUnitsPerEm(xMin, xMax, yMin, yMax); - const scale = 1024 / unitsPerEm; - - ttf.glyf.forEach((g) => { - glyfAdjust(g, scale, scale); - reduceGlyf(g); - }); - ttf.head.unitsPerEm = 1024; - } - - return ttf; -} - -/** - * 解析字体信息相关节点 - * - * @param {Document} xmlDoc XML文档对象 - * @param {Object} ttf ttf对象 - * @return {Object} ttf对象 - */ -function parseFont(xmlDoc, ttf) { - - const metaNode = xmlDoc.getElementsByTagName('metadata')[0]; - const fontNode = xmlDoc.getElementsByTagName('font')[0]; - const fontFaceNode = xmlDoc.getElementsByTagName('font-face')[0]; - - if (metaNode && metaNode.textContent) { - ttf.metadata = string.decodeHTML(metaNode.textContent.trim()); - } - - // 解析font,如果有font节点说明是svg格式字体文件 - if (fontNode) { - ttf.id = fontNode.getAttribute('id') || ''; - ttf.hhea.advanceWidthMax = +(fontNode.getAttribute('horiz-adv-x') || 0); - ttf.from = 'svgfont'; - } - - if (fontFaceNode) { - const OS2 = ttf['OS/2']; - ttf.name.fontFamily = fontFaceNode.getAttribute('font-family') || ''; - OS2.usWeightClass = +(fontFaceNode.getAttribute('font-weight') || 0); - ttf.head.unitsPerEm = +(fontFaceNode.getAttribute('units-per-em') || 0); - - // 解析panose, eg: 2 0 6 3 0 0 0 0 0 0 - const panose = (fontFaceNode.getAttribute('panose-1') || '').split(' '); - [ - 'bFamilyType', 'bSerifStyle', 'bWeight', 'bProportion', 'bContrast', - 'bStrokeVariation', 'bArmStyle', 'bLetterform', 'bMidline', 'bXHeight' - ].forEach((name, i) => { - OS2[name] = +(panose[i] || 0); - }); - - ttf.hhea.ascent = +(fontFaceNode.getAttribute('ascent') || 0); - ttf.hhea.descent = +(fontFaceNode.getAttribute('descent') || 0); - OS2.bXHeight = +(fontFaceNode.getAttribute('x-height') || 0); - - // 解析bounding - const box = (fontFaceNode.getAttribute('bbox') || '').split(' '); - ['xMin', 'yMin', 'xMax', 'yMax'].forEach((name, i) => { - ttf.head[name] = +(box[i] || ''); - }); - - ttf.post.underlineThickness = +(fontFaceNode.getAttribute('underline-thickness') || 0); - ttf.post.underlinePosition = +(fontFaceNode.getAttribute('underline-position') || 0); - - // unicode range - const unicodeRange = fontFaceNode.getAttribute('unicode-range'); - if (unicodeRange) { - unicodeRange.replace(/u\+([0-9A-Z]+)(-[0-9A-Z]+)?/i, ($0, a, b) => { - OS2.usFirstCharIndex = Number('0x' + a); - OS2.usLastCharIndex = b ? Number('0x' + b.slice(1)) : 0xFFFFFFFF; - }); - } - } - - return ttf; -} - -/** - * 解析字体信息相关节点 - * - * @param {Document} xmlDoc XML文档对象 - * @param {Object} ttf ttf对象 - * @return {Object} ttf对象 - */ -function parseGlyf(xmlDoc, ttf) { - - const missingNode = xmlDoc.getElementsByTagName('missing-glyph')[0]; - - // 解析glyf - let d; - let unicode; - if (missingNode) { - - const missing = { - name: '.notdef' - }; - - if (missingNode.getAttribute('horiz-adv-x')) { - missing.advanceWidth = +missingNode.getAttribute('horiz-adv-x'); - } - - if ((d = missingNode.getAttribute('d'))) { - missing.contours = path2contours(d); - } - - // 去除默认的空字形 - if (ttf.glyf[0] && ttf.glyf[0].name === '.notdef') { - ttf.glyf.splice(0, 1); - } - - ttf.glyf.unshift(missing); - } - - const glyfNodes = xmlDoc.getElementsByTagName('glyph'); - - if (glyfNodes.length) { - - - for (let i = 0, l = glyfNodes.length; i < l; i++) { - - const node = glyfNodes[i]; - const glyf = { - name: node.getAttribute('glyph-name') || node.getAttribute('name') || '' - }; - - if (node.getAttribute('horiz-adv-x')) { - glyf.advanceWidth = +node.getAttribute('horiz-adv-x'); - } - - if ((unicode = node.getAttribute('unicode'))) { - const nextUnicode = []; - let totalCodePoints = 0; - for (let ui = 0; ui < unicode.length; ui++) { - const ucp = unicode.codePointAt(ui); - nextUnicode.push(ucp); - ui = ucp > 0xffff ? ui + 1 : ui; - totalCodePoints += 1; - } - if (totalCodePoints === 1) { - // TTF can't handle ligatures - glyf.unicode = nextUnicode; - - if ((d = node.getAttribute('d'))) { - glyf.contours = path2contours(d); - } - ttf.glyf.push(glyf); - - } - } - - } - } - - return ttf; -} - - -/** - * 解析字体信息相关节点 - * - * @param {Document} xmlDoc XML文档对象 - * @param {Object} ttf ttf对象 - */ -function parsePath(xmlDoc, ttf) { - - // 单个path组成一个glfy字形 - let contours; - let glyf; - let node; - const pathNodes = xmlDoc.getElementsByTagName('path'); - - if (pathNodes.length) { - for (let i = 0, l = pathNodes.length; i < l; i++) { - node = pathNodes[i]; - glyf = { - name: node.getAttribute('name') || '' - }; - contours = svgnode2contours([node]); - glyf.contours = contours; - ttf.glyf.push(glyf); - } - } - - // 其他svg指令组成一个glyf字形 - contours = svgnode2contours( - Array.prototype.slice.call(xmlDoc.getElementsByTagName('*')).filter((node) => node.tagName !== 'path') - ); - if (contours) { - glyf = { - name: '' - }; - - glyf.contours = contours; - ttf.glyf.push(glyf); - } -} - -/** - * 解析xml文档 - * - * @param {Document} xmlDoc XML文档对象 - * @param {Object} options 导入选项 - * - * @return {Object} 解析后对象 - */ -function parseXML(xmlDoc, options) { - - if (!xmlDoc.getElementsByTagName('svg').length) { - error.raise(10106); - } - - let ttf; - - // 如果是svg字体格式,则解析glyf,否则解析path - if (xmlDoc.getElementsByTagName('font')[0]) { - ttf = getEmptyTTF(); - parseFont(xmlDoc, ttf); - parseGlyf(xmlDoc, ttf); - } - else { - ttf = getEmptyObject(); - parsePath(xmlDoc, ttf); - } - - if (!ttf.glyf.length) { - error.raise(10201); - } - - if (ttf.from === 'svg') { - const glyf = ttf.glyf; - let i; - let l; - // 合并导入的字形为单个字形 - if (options.combinePath) { - const combined = []; - for (i = 0, l = glyf.length; i < l; i++) { - const contours = glyf[i].contours; - for (let index = 0, length = contours.length; index < length; index++) { - combined.push(contours[index]); - } - } - - glyf[0].contours = combined; - glyf.splice(1); - } - - // 对字形进行反转 - for (i = 0, l = glyf.length; i < l; i++) { - // 这里为了使ai等工具里面的字形方便导入,对svg做了反向处理 - glyf[i].contours = pathsUtil.flip(glyf[i].contours); - } - } - - return ttf; -} - -/** - * svg格式转ttfObject格式 - * - * @param {string|Document} svg svg格式 - * @param {Object=} options 导入选项 - * @param {boolean} options.combinePath 是否合并成单个字形,仅限于普通svg导入 - * @return {Object} ttfObject - */ -export default function svg2ttfObject(svg, options = {combinePath: false}) { - let xmlDoc = svg; - if (typeof svg === 'string') { - svg = resolveSVG(svg); - xmlDoc = loadXML(svg); - } - - const ttf = parseXML(xmlDoc, options); - return resolve(ttf); -} diff --git a/vendor/fonteditor-core/src/ttf/table/CFF.js b/vendor/fonteditor-core/src/ttf/table/CFF.js deleted file mode 100644 index 3433ee2..0000000 --- a/vendor/fonteditor-core/src/ttf/table/CFF.js +++ /dev/null @@ -1,259 +0,0 @@ -/** - * @file cff表 - * @author mengke01(kekee000@gmail.com) - * - * reference: - * http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf - * - * modify from: - * https://github.com/nodebox/opentype.js/blob/master/src/tables/cff.js - */ - -import table from './table'; -import string from '../util/string'; -import encoding from './cff/encoding'; -import cffStandardStrings from './cff/cffStandardStrings'; -import parseCFFDict from './cff/parseCFFDict'; -import parseCFFGlyph from './cff/parseCFFGlyph'; -import parseCFFCharset from './cff/parseCFFCharset'; -import parseCFFEncoding from './cff/parseCFFEncoding'; -import Reader from '../reader'; - -/** - * 获取cff偏移 - * - * @param {Reader} reader 读取器 - * @param {number} offSize 偏移大小 - * @param {number} offset 起始偏移 - * @return {number} 偏移 - */ -function getOffset(reader, offSize) { - let v = 0; - for (let i = 0; i < offSize; i++) { - v <<= 8; - v += reader.readUint8(); - } - return v; -} - -/** - * 解析cff表头部 - * - * @param {Reader} reader 读取器 - * @return {Object} 头部字段 - */ -function parseCFFHead(reader) { - const head = {}; - head.startOffset = reader.offset; - head.endOffset = head.startOffset + 4; - head.formatMajor = reader.readUint8(); - head.formatMinor = reader.readUint8(); - head.size = reader.readUint8(); - head.offsetSize = reader.readUint8(); - return head; -} - -/** - * 解析`CFF`表索引 - * - * @param {Reader} reader 读取器 - * @param {number} offset 偏移 - * @param {Funciton} conversionFn 转换函数 - * @return {Object} 表对象 - */ -function parseCFFIndex(reader, offset, conversionFn) { - if (offset) { - reader.seek(offset); - } - const start = reader.offset; - const offsets = []; - const objects = []; - const count = reader.readUint16(); - let i; - let l; - if (count !== 0) { - const offsetSize = reader.readUint8(); - for (i = 0, l = count + 1; i < l; i++) { - offsets.push(getOffset(reader, offsetSize)); - } - - for (i = 0, l = count; i < l; i++) { - let value = reader.readBytes(offsets[i + 1] - offsets[i]); - if (conversionFn) { - value = conversionFn(value); - } - objects.push(value); - } - } - - return { - objects, - startOffset: start, - endOffset: reader.offset - }; -} - -// Subroutines are encoded using the negative half of the number space. -// See type 2 chapter 4.7 "Subroutine operators". -function calcCFFSubroutineBias(subrs) { - let bias; - if (subrs.length < 1240) { - bias = 107; - } - else if (subrs.length < 33900) { - bias = 1131; - } - else { - bias = 32768; - } - - return bias; -} - - -export default table.create( - 'cff', - [], - { - read(reader, font) { - - const offset = this.offset; - reader.seek(offset); - - const head = parseCFFHead(reader); - const nameIndex = parseCFFIndex(reader, head.endOffset, string.getString); - const topDictIndex = parseCFFIndex(reader, nameIndex.endOffset); - const stringIndex = parseCFFIndex(reader, topDictIndex.endOffset, string.getString); - const globalSubrIndex = parseCFFIndex(reader, stringIndex.endOffset); - - const cff = { - head - }; - - // 全局子glyf数据 - cff.gsubrs = globalSubrIndex.objects; - cff.gsubrsBias = calcCFFSubroutineBias(globalSubrIndex.objects); - - // 顶级字典数据 - const dictReader = new Reader(new Uint8Array(topDictIndex.objects[0]).buffer); - const topDict = parseCFFDict.parseTopDict( - dictReader, - 0, - dictReader.length, - stringIndex.objects - ); - cff.topDict = topDict; - - // 私有字典数据 - const privateDictLength = topDict.private[0]; - let privateDict = {}; - let privateDictOffset; - if (privateDictLength) { - privateDictOffset = offset + topDict.private[1]; - privateDict = parseCFFDict.parsePrivateDict( - reader, - privateDictOffset, - privateDictLength, - stringIndex.objects - ); - cff.defaultWidthX = privateDict.defaultWidthX; - cff.nominalWidthX = privateDict.nominalWidthX; - } - else { - cff.defaultWidthX = 0; - cff.nominalWidthX = 0; - } - - // 私有子glyf数据 - if (privateDict.subrs) { - const subrOffset = privateDictOffset + privateDict.subrs; - const subrIndex = parseCFFIndex(reader, subrOffset); - cff.subrs = subrIndex.objects; - cff.subrsBias = calcCFFSubroutineBias(cff.subrs); - } - else { - cff.subrs = []; - cff.subrsBias = 0; - } - cff.privateDict = privateDict; - - // 解析glyf数据和名字 - const charStringsIndex = parseCFFIndex(reader, offset + topDict.charStrings); - const nGlyphs = charStringsIndex.objects.length; - - if (topDict.charset < 3) { - // @author: fr33z00 - // See end of chapter 13 (p22) of #5176.CFF.pdf : - // Still more optimization is possible by - // observing that many fonts adopt one of 3 common charsets. In - // these cases the operand to the charset operator in the Top DICT - // specifies a predefined charset id, in place of an offset, as shown in table 22 - cff.charset = cffStandardStrings; - } - else { - cff.charset = parseCFFCharset(reader, offset + topDict.charset, nGlyphs, stringIndex.objects); - } - - // Standard encoding - if (topDict.encoding === 0) { - cff.encoding = encoding.standardEncoding; - } - // Expert encoding - else if (topDict.encoding === 1) { - cff.encoding = encoding.expertEncoding; - } - else { - cff.encoding = parseCFFEncoding(reader, offset + topDict.encoding); - } - - cff.glyf = []; - - // only parse subset glyphs - const subset = font.readOptions.subset; - if (subset && subset.length > 0) { - - // subset map - const subsetMap = { - 0: true // 设置.notdef - }; - const codes = font.cmap; - - // unicode to index - Object.keys(codes).forEach((c) => { - if (subset.indexOf(+c) > -1) { - const i = codes[c]; - subsetMap[i] = true; - } - }); - font.subsetMap = subsetMap; - - Object.keys(subsetMap).forEach((i) => { - i = +i; - const glyf = parseCFFGlyph(charStringsIndex.objects[i], cff, i); - glyf.name = cff.charset[i]; - cff.glyf[i] = glyf; - }); - } - // parse all - else { - for (let i = 0, l = nGlyphs; i < l; i++) { - const glyf = parseCFFGlyph(charStringsIndex.objects[i], cff, i); - glyf.name = cff.charset[i]; - cff.glyf.push(glyf); - } - } - - return cff; - }, - - // eslint-disable-next-line no-unused-vars - write(writer, font) { - throw new Error('not support write cff table'); - }, - - // eslint-disable-next-line no-unused-vars - size(font) { - throw new Error('not support get cff table size'); - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/GPOS.js b/vendor/fonteditor-core/src/ttf/table/GPOS.js deleted file mode 100644 index 9e19e9d..0000000 --- a/vendor/fonteditor-core/src/ttf/table/GPOS.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file GPOS - * @author fr33z00(https://github.com/fr33z00) - * - * @reference: https://learn.microsoft.com/en-us/typography/opentype/spec/gpos - */ - -import table from './table'; - -export default table.create( - 'GPOS', - [], - { - - read(reader, ttf) { - const length = ttf.tables.GPOS.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.GPOS) { - writer.writeBytes(ttf.GPOS, ttf.GPOS.length); - } - }, - - size(ttf) { - return ttf.GPOS ? ttf.GPOS.length : 0; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/OS2.js b/vendor/fonteditor-core/src/ttf/table/OS2.js deleted file mode 100644 index 688a299..0000000 --- a/vendor/fonteditor-core/src/ttf/table/OS2.js +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file OS/2表 - * @author mengke01(kekee000@gmail.com) - * - * http://www.microsoft.com/typography/otspec/os2.htm - */ - -import table from './table'; -import struct from './struct'; - -export default table.create( - 'OS/2', - [ - ['version', struct.Uint16], - - ['xAvgCharWidth', struct.Int16], - ['usWeightClass', struct.Uint16], - ['usWidthClass', struct.Uint16], - - ['fsType', struct.Uint16], - - ['ySubscriptXSize', struct.Uint16], - ['ySubscriptYSize', struct.Uint16], - ['ySubscriptXOffset', struct.Uint16], - ['ySubscriptYOffset', struct.Uint16], - - ['ySuperscriptXSize', struct.Uint16], - ['ySuperscriptYSize', struct.Uint16], - ['ySuperscriptXOffset', struct.Uint16], - ['ySuperscriptYOffset', struct.Uint16], - - ['yStrikeoutSize', struct.Uint16], - ['yStrikeoutPosition', struct.Uint16], - - ['sFamilyClass', struct.Uint16], - - // Panose - ['bFamilyType', struct.Uint8], - ['bSerifStyle', struct.Uint8], - ['bWeight', struct.Uint8], - ['bProportion', struct.Uint8], - ['bContrast', struct.Uint8], - ['bStrokeVariation', struct.Uint8], - ['bArmStyle', struct.Uint8], - ['bLetterform', struct.Uint8], - ['bMidline', struct.Uint8], - ['bXHeight', struct.Uint8], - - // unicode range - ['ulUnicodeRange1', struct.Uint32], - ['ulUnicodeRange2', struct.Uint32], - ['ulUnicodeRange3', struct.Uint32], - ['ulUnicodeRange4', struct.Uint32], - - // char 4 - ['achVendID', struct.String, 4], - - ['fsSelection', struct.Uint16], - ['usFirstCharIndex', struct.Uint16], - ['usLastCharIndex', struct.Uint16], - - ['sTypoAscender', struct.Int16], - ['sTypoDescender', struct.Int16], - ['sTypoLineGap', struct.Int16], - - ['usWinAscent', struct.Uint16], - ['usWinDescent', struct.Uint16], - // version 0 above 39 - - ['ulCodePageRange1', struct.Uint32], - ['ulCodePageRange2', struct.Uint32], - // version 1 above 41 - - ['sxHeight', struct.Int16], - ['sCapHeight', struct.Int16], - - ['usDefaultChar', struct.Uint16], - ['usBreakChar', struct.Uint16], - ['usMaxContext', struct.Uint16] - // version 2,3,4 above 46 - ], - { - - read(reader, ttf) { - const format = reader.readUint16(this.offset); - let struct = this.struct; - - // format2 - if (format === 0) { - struct = struct.slice(0, 39); - } - else if (format === 1) { - struct = struct.slice(0, 41); - } - - const OS2Head = table.create('os2head', struct); - const tbl = new OS2Head(this.offset).read(reader, ttf); - - // 补齐其他version的字段 - const os2Fields = { - ulCodePageRange1: 1, - ulCodePageRange2: 0, - sxHeight: 0, - sCapHeight: 0, - usDefaultChar: 0, - usBreakChar: 32, - usMaxContext: 0 - }; - - return Object.assign(os2Fields, tbl); - }, - - size(ttf) { - - // 更新其他表的统计信息 - // header - let xMin = 16384; - let yMin = 16384; - let xMax = -16384; - let yMax = -16384; - - // hhea - let advanceWidthMax = -1; - let minLeftSideBearing = 16384; - let minRightSideBearing = 16384; - let xMaxExtent = -16384; - - // os2 count - let xAvgCharWidth = 0; - let usFirstCharIndex = 0x10FFFF; - let usLastCharIndex = -1; - - // maxp - let maxPoints = 0; - let maxContours = 0; - let maxCompositePoints = 0; - let maxCompositeContours = 0; - let maxSizeOfInstructions = 0; - let maxComponentElements = 0; - - let glyfNotEmpty = 0; // 非空glyf - const hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false; - - // 计算instructions和functiondefs - if (hinting) { - - if (ttf.cvt) { - maxSizeOfInstructions = Math.max(maxSizeOfInstructions, ttf.cvt.length); - } - - if (ttf.prep) { - maxSizeOfInstructions = Math.max(maxSizeOfInstructions, ttf.prep.length); - } - - if (ttf.fpgm) { - maxSizeOfInstructions = Math.max(maxSizeOfInstructions, ttf.fpgm.length); - } - - } - - - ttf.glyf.forEach((glyf) => { - - // 统计control point信息 - if (glyf.compound) { - let compositeContours = 0; - let compositePoints = 0; - glyf.glyfs.forEach((g) => { - const cglyf = ttf.glyf[g.glyphIndex]; - if (!cglyf) { - return; - } - compositeContours += cglyf.contours ? cglyf.contours.length : 0; - if (cglyf.contours && cglyf.contours.length) { - cglyf.contours.forEach((contour) => { - compositePoints += contour.length; - }); - } - }); - maxComponentElements = Math.max(maxComponentElements, glyf.glyfs.length); - maxCompositePoints = Math.max(maxCompositePoints, compositePoints); - maxCompositeContours = Math.max(maxCompositeContours, compositeContours); - } - // 简单图元 - else if (glyf.contours && glyf.contours.length) { - maxContours = Math.max(maxContours, glyf.contours.length); - - let points = 0; - glyf.contours.forEach((contour) => { - points += contour.length; - }); - maxPoints = Math.max(maxPoints, points); - } - - if (hinting && glyf.instructions) { - maxSizeOfInstructions = Math.max(maxSizeOfInstructions, glyf.instructions.length); - } - - // 统计边界信息 - if (null != glyf.xMin && glyf.xMin < xMin) { - xMin = glyf.xMin; - } - - if (null != glyf.yMin && glyf.yMin < yMin) { - yMin = glyf.yMin; - } - - if (null != glyf.xMax && glyf.xMax > xMax) { - xMax = glyf.xMax; - } - - if (null != glyf.yMax && glyf.yMax > yMax) { - yMax = glyf.yMax; - } - - advanceWidthMax = Math.max(advanceWidthMax, glyf.advanceWidth); - minLeftSideBearing = Math.min(minLeftSideBearing, glyf.leftSideBearing); - if (null != glyf.xMax) { - minRightSideBearing = Math.min(minRightSideBearing, glyf.advanceWidth - glyf.xMax); - xMaxExtent = Math.max(xMaxExtent, glyf.xMax); - } - if (null != glyf.advanceWidth) { - xAvgCharWidth += glyf.advanceWidth; - glyfNotEmpty++; - } - - let unicodes = glyf.unicode; - - if (typeof glyf.unicode === 'number') { - unicodes = [glyf.unicode]; - } - - if (Array.isArray(unicodes)) { - unicodes.forEach((unicode) => { - if (unicode !== 0xFFFF) { - usFirstCharIndex = Math.min(usFirstCharIndex, unicode); - usLastCharIndex = Math.max(usLastCharIndex, unicode); - } - }); - } - }); - - // 重新设置version 4 - ttf['OS/2'].version = 0x4; - ttf['OS/2'].achVendID = (ttf['OS/2'].achVendID + ' ').slice(0, 4); - ttf['OS/2'].xAvgCharWidth = xAvgCharWidth / (glyfNotEmpty || 1); - ttf['OS/2'].ulUnicodeRange2 = 268435456; - ttf['OS/2'].usFirstCharIndex = usFirstCharIndex; - ttf['OS/2'].usLastCharIndex = usLastCharIndex; - - // rewrite hhea - ttf.hhea.version = ttf.hhea.version || 0x1; - ttf.hhea.advanceWidthMax = advanceWidthMax; - ttf.hhea.minLeftSideBearing = minLeftSideBearing; - ttf.hhea.minRightSideBearing = minRightSideBearing; - ttf.hhea.xMaxExtent = xMaxExtent; - - // rewrite head - ttf.head.version = ttf.head.version || 0x1; - ttf.head.lowestRecPPEM = ttf.head.lowestRecPPEM || 0x8; - ttf.head.xMin = xMin; - ttf.head.yMin = yMin; - ttf.head.xMax = xMax; - ttf.head.yMax = yMax; - - // head rewrite - if (ttf.support.head) { - const {xMin, yMin, xMax, yMax} = ttf.support.head; - if (xMin != null) { - ttf.head.xMin = xMin; - } - if (yMin != null) { - ttf.head.yMin = yMin; - } - if (xMax != null) { - ttf.head.xMax = xMax; - } - if (yMax != null) { - ttf.head.yMax = yMax; - } - - } - // hhea rewrite - if (ttf.support.hhea) { - const {advanceWidthMax, xMaxExtent, minLeftSideBearing, minRightSideBearing} = ttf.support.hhea; - if (advanceWidthMax != null) { - ttf.hhea.advanceWidthMax = advanceWidthMax; - } - if (xMaxExtent != null) { - ttf.hhea.xMaxExtent = xMaxExtent; - } - if (minLeftSideBearing != null) { - ttf.hhea.minLeftSideBearing = minLeftSideBearing; - } - if (minRightSideBearing != null) { - ttf.hhea.minRightSideBearing = minRightSideBearing; - } - } - // 这里根据存储的maxp来设置新的maxp,避免重复计算maxp - ttf.maxp = ttf.maxp || {}; - ttf.support.maxp = { - version: 1.0, - numGlyphs: ttf.glyf.length, - maxPoints, - maxContours, - maxCompositePoints, - maxCompositeContours, - maxZones: ttf.maxp.maxZones || 0, - maxTwilightPoints: ttf.maxp.maxTwilightPoints || 0, - maxStorage: ttf.maxp.maxStorage || 0, - maxFunctionDefs: ttf.maxp.maxFunctionDefs || 0, - maxStackElements: ttf.maxp.maxStackElements || 0, - maxSizeOfInstructions, - maxComponentElements, - maxComponentDepth: maxComponentElements ? 1 : 0 - }; - - return table.size.call(this, ttf); - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/cff/cffStandardStrings.js b/vendor/fonteditor-core/src/ttf/table/cff/cffStandardStrings.js deleted file mode 100644 index a76c716..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/cffStandardStrings.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file cffStandardStrings.js - * @author mengke01(kekee000@gmail.com) - */ -const cffStandardStrings = [ - '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', - 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', - 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', - 'question', 'at', 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', - 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', - 'asciitilde', 'exclamdown', 'cent', 'sterling', - 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', - 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', - 'daggerdbl', 'periodcentered', 'paragraph', - 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', - 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', - 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', - 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', - 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', - 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', - 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', - 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', - 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', - 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', - 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', - 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', - 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', - 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', - 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff', 'onedotenleader', - 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', - 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', - 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', - 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', - 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', - 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', - 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', - 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', - 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', - 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', - 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', - 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', - 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', - 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', - 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', - 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', - 'sevensuperior', 'eightsuperior', 'ninesuperior', - 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', - 'fourinferior', 'fiveinferior', 'sixinferior', - 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', - 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', - 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', - 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', - 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', - 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', - 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', - 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', - 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', - 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', - '001.001', '001.002', '001.003', 'Black', 'Bold', - 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold' -]; - -export default cffStandardStrings; diff --git a/vendor/fonteditor-core/src/ttf/table/cff/encoding.js b/vendor/fonteditor-core/src/ttf/table/cff/encoding.js deleted file mode 100644 index ab31f8a..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/encoding.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file cff名字设置 - * @author mengke01(kekee000@gmail.com) - */ - - -const cffStandardEncoding = [ - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', - 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', - 'period', 'slash', 'zero', 'one', 'two', - 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', - 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', - 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', - 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', - 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', - 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', - 'guillemotright', 'ellipsis', 'perthousand', '', - 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', - 'macron', 'breve', 'dotaccent', 'dieresis', '', - 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', - 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - 'AE', '', 'ordfeminine', '', '', '', - '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', - 'lslash', 'oslash', 'oe', 'germandbls' -]; - -const cffExpertEncoding = [ - '', '', '', '', '', '', '', '', '', '', '', '', '', '', - '', '', '', '', '', '', '', '', '', '', '', '', '', '', - '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', - 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', - 'parenrightsuperior', 'twodotenleader', 'onedotenleader', - 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', - 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', - 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', - 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', - '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', - 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', - 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', - 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', - 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', - 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', - 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', - 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', - '', '', '', '', '', '', '', - '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', - 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', - 'Macronsmall', '', '', 'figuredash', 'hypheninferior', - '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', - 'questiondownsmall', 'oneeighth', 'threeeighths', - 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', - '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', - 'sixsuperior', 'sevensuperior', 'eightsuperior', - 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', - 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', - 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', - 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', - 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', - 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', - 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', - 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', - 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', - 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall' -]; - - - -export default { - standardEncoding: cffStandardEncoding, - expertEncoding: cffExpertEncoding -}; diff --git a/vendor/fonteditor-core/src/ttf/table/cff/getCFFString.js b/vendor/fonteditor-core/src/ttf/table/cff/getCFFString.js deleted file mode 100644 index 0f53950..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/getCFFString.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file 获取cff字符串 - * @author mengke01(kekee000@gmail.com) - */ - -import cffStandardStrings from './cffStandardStrings'; - -/** - * 根据索引获取cff字符串 - * - * @param {Object} strings 标准cff字符串索引 - * @param {number} index 索引号 - * @return {number} 字符串索引 - */ -export default function getCFFString(strings, index) { - if (index <= 390) { - index = cffStandardStrings[index]; - } - // Strings below index 392 are standard CFF strings and are not encoded in the font. - else { - index = strings[index - 391]; - } - - return index; -} diff --git a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFCharset.js b/vendor/fonteditor-core/src/ttf/table/cff/parseCFFCharset.js deleted file mode 100644 index 1ff8a6d..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFCharset.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file 解析cff字符集 - * @author mengke01(kekee000@gmail.com) - */ - -import getCFFString from './getCFFString'; - -/** - * 解析cff字形名称 - * See Adobe TN #5176 chapter 13, "Charsets". - * - * @param {Reader} reader 读取器 - * @param {number} start 起始偏移 - * @param {number} nGlyphs 字形个数 - * @param {Object} strings cff字符串字典 - * @return {Array} 字符集 - */ -export default function parseCFFCharset(reader, start, nGlyphs, strings) { - if (start) { - reader.seek(start); - } - - let i; - let sid; - let count; - // The .notdef glyph is not included, so subtract 1. - nGlyphs -= 1; - const charset = ['.notdef']; - - const format = reader.readUint8(); - if (format === 0) { - for (i = 0; i < nGlyphs; i += 1) { - sid = reader.readUint16(); - charset.push(getCFFString(strings, sid)); - } - } - else if (format === 1) { - while (charset.length <= nGlyphs) { - sid = reader.readUint16(); - count = reader.readUint8(); - for (i = 0; i <= count; i += 1) { - charset.push(getCFFString(strings, sid)); - sid += 1; - } - } - } - else if (format === 2) { - while (charset.length <= nGlyphs) { - sid = reader.readUint16(); - count = reader.readUint16(); - for (i = 0; i <= count; i += 1) { - charset.push(getCFFString(strings, sid)); - sid += 1; - } - } - } - else { - throw new Error('Unknown charset format ' + format); - } - - return charset; -} diff --git a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFDict.js b/vendor/fonteditor-core/src/ttf/table/cff/parseCFFDict.js deleted file mode 100644 index 98f076b..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFDict.js +++ /dev/null @@ -1,350 +0,0 @@ -/** - * @file 解析cffdict数据 - * @author mengke01(kekee000@gmail.com) - */ - -import getCFFString from './getCFFString'; - -const TOP_DICT_META = [ - { - name: 'version', - op: 0, - type: 'SID' - }, - { - name: 'notice', - op: 1, - type: 'SID' - }, - { - name: 'copyright', - op: 1200, - type: 'SID' - }, - { - name: 'fullName', - op: 2, - type: 'SID' - }, - { - name: 'familyName', - op: 3, - type: 'SID' - }, - { - name: 'weight', - op: 4, - type: 'SID' - }, - { - name: 'isFixedPitch', - op: 1201, - type: 'number', - value: 0 - }, - { - name: 'italicAngle', - op: 1202, - type: 'number', - value: 0 - }, - { - name: 'underlinePosition', - op: 1203, - type: 'number', - value: -100 - }, - { - name: 'underlineThickness', - op: 1204, - type: 'number', - value: 50 - }, - { - name: 'paintType', - op: 1205, - type: 'number', - value: 0 - }, - { - name: 'charstringType', - op: 1206, - type: 'number', - value: 2 - }, - { - name: 'fontMatrix', - op: 1207, - type: ['real', 'real', 'real', 'real', 'real', 'real'], - value: [0.001, 0, 0, 0.001, 0, 0] - }, - { - name: 'uniqueId', - op: 13, - type: 'number' - }, - { - name: 'fontBBox', - op: 5, - type: ['number', 'number', 'number', 'number'], - value: [0, 0, 0, 0] - }, - { - name: 'strokeWidth', - op: 1208, - type: 'number', - value: 0 - }, - { - name: 'xuid', - op: 14, - type: [], - value: null - }, - { - name: 'charset', - op: 15, - type: 'offset', - value: 0 - }, - { - name: 'encoding', - op: 16, - type: 'offset', - value: 0 - }, - { - name: 'charStrings', - op: 17, - type: 'offset', - value: 0 - }, - { - name: 'private', - op: 18, - type: ['number', 'offset'], - value: [0, 0] - } -]; - -const PRIVATE_DICT_META = [ - { - name: 'subrs', - op: 19, - type: 'offset', - value: 0 - }, - { - name: 'defaultWidthX', - op: 20, - type: 'number', - value: 0 - }, - { - name: 'nominalWidthX', - op: 21, - type: 'number', - value: 0 - } -]; - -function entriesToObject(entries) { - const hash = {}; - - for (let i = 0, l = entries.length; i < l; i++) { - const key = entries[i][0]; - if (undefined !== hash[key]) { - console.warn('dict already has key:' + key); - continue; - } - - const values = entries[i][1]; - hash[key] = values.length === 1 ? values[0] : values; - } - - return hash; -} - - -/* eslint-disable no-constant-condition */ -function parseFloatOperand(reader) { - let s = ''; - const eof = 15; - const lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-']; - - while (true) { - const b = reader.readUint8(); - const n1 = b >> 4; - const n2 = b & 15; - - if (n1 === eof) { - break; - } - - s += lookup[n1]; - - if (n2 === eof) { - break; - } - - s += lookup[n2]; - } - - return parseFloat(s); -} -/* eslint-enable no-constant-condition */ - -/** - * 解析cff字典数据 - * - * @param {Reader} reader 读取器 - * @param {number} b0 操作码 - * @return {number} 数据 - */ -function parseOperand(reader, b0) { - let b1; - let b2; - let b3; - let b4; - if (b0 === 28) { - b1 = reader.readUint8(); - b2 = reader.readUint8(); - return b1 << 8 | b2; - } - - if (b0 === 29) { - b1 = reader.readUint8(); - b2 = reader.readUint8(); - b3 = reader.readUint8(); - b4 = reader.readUint8(); - return b1 << 24 | b2 << 16 | b3 << 8 | b4; - } - - if (b0 === 30) { - return parseFloatOperand(reader); - } - - if (b0 >= 32 && b0 <= 246) { - return b0 - 139; - } - - if (b0 >= 247 && b0 <= 250) { - b1 = reader.readUint8(); - return (b0 - 247) * 256 + b1 + 108; - } - - if (b0 >= 251 && b0 <= 254) { - b1 = reader.readUint8(); - return -(b0 - 251) * 256 - b1 - 108; - } - - throw new Error('invalid b0 ' + b0 + ',at:' + reader.offset); -} - - - -/** - * 解析字典值 - * - * @param {Object} dict 字典数据 - * @param {Array} meta 元数据 - * @param {Object} strings cff字符串字典 - * @return {Object} 解析后数据 - */ -function interpretDict(dict, meta, strings) { - const newDict = {}; - - // Because we also want to include missing values, we start out from the meta list - // and lookup values in the dict. - for (let i = 0, l = meta.length; i < l; i++) { - const m = meta[i]; - let value = dict[m.op]; - if (value === undefined) { - value = m.value !== undefined ? m.value : null; - } - - if (m.type === 'SID') { - value = getCFFString(strings, value); - } - - newDict[m.name] = value; - } - - return newDict; -} - - -/** - * 解析cff dict字典 - * - * @param {Reader} reader 读取器 - * @param {number} offset 起始偏移 - * @param {number} length 大小 - * @return {Object} 配置 - */ -function parseCFFDict(reader, offset, length) { - if (null != offset) { - reader.seek(offset); - } - - const entries = []; - let operands = []; - const lastOffset = reader.offset + (null != length ? length : reader.length); - - while (reader.offset < lastOffset) { - let op = reader.readUint8(); - - // The first byte for each dict item distinguishes between operator (key) and operand (value). - // Values <= 21 are operators. - if (op <= 21) { - // Two-byte operators have an initial escape byte of 12. - if (op === 12) { - op = 1200 + reader.readUint8(); - } - - entries.push([op, operands]); - operands = []; - } - else { - // Since the operands (values) come before the operators (keys), we store all operands in a list - // until we encounter an operator. - operands.push(parseOperand(reader, op)); - } - } - - return entriesToObject(entries); -} - -/** - * 解析cff top字典 - * - * @param {Reader} reader 读取器 - * @param {number} start 开始offset - * @param {number} length 大小 - * @param {Object} strings 字符串集合 - * @return {Object} 字典数据 - */ -function parseTopDict(reader, start, length, strings) { - const dict = parseCFFDict(reader, start || 0, length || reader.length); - return interpretDict(dict, TOP_DICT_META, strings); -} - -/** - * 解析cff私有字典 - * - * @param {Reader} reader 读取器 - * @param {number} start 开始offset - * @param {number} length 大小 - * @param {Object} strings 字符串集合 - * @return {Object} 字典数据 - */ -function parsePrivateDict(reader, start, length, strings) { - const dict = parseCFFDict(reader, start || 0, length || reader.length); - return interpretDict(dict, PRIVATE_DICT_META, strings); -} - - -export default { - parseTopDict, - parsePrivateDict -}; diff --git a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFEncoding.js b/vendor/fonteditor-core/src/ttf/table/cff/parseCFFEncoding.js deleted file mode 100644 index e714ae2..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFEncoding.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file 解析cff编码 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 解析cff encoding数据 - * See Adobe TN #5176 chapter 12, "Encodings". - * - * @param {Reader} reader 读取器 - * @param {number=} start 偏移 - * @return {Object} 编码表 - */ -export default function parseCFFEncoding(reader, start) { - if (null != start) { - reader.seek(start); - } - - let i; - let code; - const encoding = {}; - const format = reader.readUint8(); - - if (format === 0) { - const nCodes = reader.readUint8(); - for (i = 0; i < nCodes; i += 1) { - code = reader.readUint8(); - encoding[code] = i; - } - } - else if (format === 1) { - const nRanges = reader.readUint8(); - code = 1; - for (i = 0; i < nRanges; i += 1) { - const first = reader.readUint8(); - const nLeft = reader.readUint8(); - for (let j = first; j <= first + nLeft; j += 1) { - encoding[j] = code; - code += 1; - } - } - } - else { - console.warn('unknown encoding format:' + format); - } - - return encoding; -} diff --git a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFGlyph.js b/vendor/fonteditor-core/src/ttf/table/cff/parseCFFGlyph.js deleted file mode 100644 index 32b486e..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cff/parseCFFGlyph.js +++ /dev/null @@ -1,489 +0,0 @@ -/** - * @file 解析cff字形 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 解析cff字形,返回直线和三次bezier曲线点数组 - * - * @param {Array} code 操作码 - * @param {Object} font 相关联的font对象 - * @param {number} index glyf索引 - * @return {Object} glyf对象 - */ -export default function parseCFFCharstring(code, font, index) { - let c1x; - let c1y; - let c2x; - let c2y; - const contours = []; - let contour = []; - const stack = []; - const glyfs = []; - let nStems = 0; - let haveWidth = false; - let width = font.defaultWidthX; - let open = false; - let x = 0; - let y = 0; - - function lineTo(x, y) { - contour.push({ - onCurve: true, - x, - y - }); - } - - function curveTo(c1x, c1y, c2x, c2y, x, y) { - contour.push({ - x: c1x, - y: c1y - }); - contour.push({ - x: c2x, - y: c2y - }); - contour.push({ - onCurve: true, - x, - y - }); - } - - function newContour(x, y) { - if (open) { - contours.push(contour); - } - - contour = []; - lineTo(x, y); - open = true; - } - - function parseStems() { - // The number of stem operators on the stack is always even. - // If the value is uneven, that means a width is specified. - const hasWidthArg = stack.length % 2 !== 0; - if (hasWidthArg && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - } - - nStems += stack.length >> 1; - stack.length = 0; - haveWidth = true; - } - - function parse(code) { - let b1; - let b2; - let b3; - let b4; - let codeIndex; - let subrCode; - let jpx; - let jpy; - let c3x; - let c3y; - let c4x; - let c4y; - - let i = 0; - while (i < code.length) { - let v = code[i]; - i += 1; - switch (v) { - case 1: // hstem - parseStems(); - break; - case 3: // vstem - parseStems(); - break; - case 4: // vmoveto - if (stack.length > 1 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - y += stack.pop(); - newContour(x, y); - break; - case 5: // rlineto - while (stack.length > 0) { - x += stack.shift(); - y += stack.shift(); - lineTo(x, y); - } - - break; - case 6: // hlineto - while (stack.length > 0) { - x += stack.shift(); - lineTo(x, y); - if (stack.length === 0) { - break; - } - - y += stack.shift(); - lineTo(x, y); - } - - break; - case 7: // vlineto - while (stack.length > 0) { - y += stack.shift(); - lineTo(x, y); - if (stack.length === 0) { - break; - } - - x += stack.shift(); - lineTo(x, y); - } - - break; - case 8: // rrcurveto - while (stack.length > 0) { - c1x = x + stack.shift(); - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + stack.shift(); - curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 10: // callsubr - codeIndex = stack.pop() + font.subrsBias; - subrCode = font.subrs[codeIndex]; - if (subrCode) { - parse(subrCode); - } - - break; - case 11: // return - return; - case 12: // flex operators - v = code[i]; - i += 1; - switch (v) { - case 35: // flex - // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |- - c1x = x + stack.shift(); // dx1 - c1y = y + stack.shift(); // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y + stack.shift(); // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = jpy + stack.shift(); // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = c3y + stack.shift(); // dy5 - x = c4x + stack.shift(); // dx6 - y = c4y + stack.shift(); // dy6 - stack.shift(); // flex depth - curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - curveTo(c3x, c3y, c4x, c4y, x, y); - break; - case 34: // hflex - // |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |- - c1x = x + stack.shift(); // dx1 - c1y = y; // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y; // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = c2y; // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = y; // dy5 - x = c4x + stack.shift(); // dx6 - curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - curveTo(c3x, c3y, c4x, c4y, x, y); - break; - case 36: // hflex1 - // |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |- - c1x = x + stack.shift(); // dx1 - c1y = y + stack.shift(); // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y; // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = c2y; // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = c3y + stack.shift(); // dy5 - x = c4x + stack.shift(); // dx6 - curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - curveTo(c3x, c3y, c4x, c4y, x, y); - break; - case 37: // flex1 - // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |- - c1x = x + stack.shift(); // dx1 - c1y = y + stack.shift(); // dy1 - c2x = c1x + stack.shift(); // dx2 - c2y = c1y + stack.shift(); // dy2 - jpx = c2x + stack.shift(); // dx3 - jpy = c2y + stack.shift(); // dy3 - c3x = jpx + stack.shift(); // dx4 - c3y = jpy + stack.shift(); // dy4 - c4x = c3x + stack.shift(); // dx5 - c4y = c3y + stack.shift(); // dy5 - if (Math.abs(c4x - x) > Math.abs(c4y - y)) { - x = c4x + stack.shift(); - } - else { - y = c4y + stack.shift(); - } - - curveTo(c1x, c1y, c2x, c2y, jpx, jpy); - curveTo(c3x, c3y, c4x, c4y, x, y); - break; - default: - console.warn('Glyph ' + index + ': unknown operator ' + (1200 + v)); - stack.length = 0; - } - break; - case 14: // endchar - if (stack.length === 1 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - else if (stack.length === 4) { - glyfs[1] = { - glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]), - transform: {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} - }; - glyfs[0] = { - glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]), - transform: {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} - }; - glyfs[1].transform.f = stack.pop(); - glyfs[1].transform.e = stack.pop(); - } - else if (stack.length === 5) { - if (!haveWidth) { - width = stack.shift() + font.nominalWidthX; - } - haveWidth = true; - glyfs[1] = { - glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]), - transform: {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} - }; - glyfs[0] = { - glyphIndex: font.charset.indexOf(font.encoding[stack.pop()]), - transform: {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} - }; - glyfs[1].transform.f = stack.pop(); - glyfs[1].transform.e = stack.pop(); - } - - if (open) { - contours.push(contour); - open = false; - } - - break; - case 18: // hstemhm - parseStems(); - break; - case 19: // hintmask - case 20: // cntrmask - parseStems(); - i += (nStems + 7) >> 3; - break; - case 21: // rmoveto - if (stack.length > 2 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - y += stack.pop(); - x += stack.pop(); - newContour(x, y); - break; - case 22: // hmoveto - if (stack.length > 1 && !haveWidth) { - width = stack.shift() + font.nominalWidthX; - haveWidth = true; - } - - x += stack.pop(); - newContour(x, y); - break; - case 23: // vstemhm - parseStems(); - break; - case 24: // rcurveline - while (stack.length > 2) { - c1x = x + stack.shift(); - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + stack.shift(); - curveTo(c1x, c1y, c2x, c2y, x, y); - } - - x += stack.shift(); - y += stack.shift(); - lineTo(x, y); - break; - case 25: // rlinecurve - while (stack.length > 6) { - x += stack.shift(); - y += stack.shift(); - lineTo(x, y); - } - - c1x = x + stack.shift(); - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + stack.shift(); - curveTo(c1x, c1y, c2x, c2y, x, y); - break; - case 26: // vvcurveto - if (stack.length % 2) { - x += stack.shift(); - } - - while (stack.length > 0) { - c1x = x; - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x; - y = c2y + stack.shift(); - curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 27: // hhcurveto - if (stack.length % 2) { - y += stack.shift(); - } - - while (stack.length > 0) { - c1x = x + stack.shift(); - c1y = y; - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y; - curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 28: // shortint - b1 = code[i]; - b2 = code[i + 1]; - stack.push(((b1 << 24) | (b2 << 16)) >> 16); - i += 2; - break; - case 29: // callgsubr - codeIndex = stack.pop() + font.gsubrsBias; - subrCode = font.gsubrs[codeIndex]; - if (subrCode) { - parse(subrCode); - } - - break; - case 30: // vhcurveto - while (stack.length > 0) { - c1x = x; - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + (stack.length === 1 ? stack.shift() : 0); - curveTo(c1x, c1y, c2x, c2y, x, y); - if (stack.length === 0) { - break; - } - - c1x = x + stack.shift(); - c1y = y; - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - y = c2y + stack.shift(); - x = c2x + (stack.length === 1 ? stack.shift() : 0); - curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - case 31: // hvcurveto - while (stack.length > 0) { - c1x = x + stack.shift(); - c1y = y; - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - y = c2y + stack.shift(); - x = c2x + (stack.length === 1 ? stack.shift() : 0); - curveTo(c1x, c1y, c2x, c2y, x, y); - if (stack.length === 0) { - break; - } - - c1x = x; - c1y = y + stack.shift(); - c2x = c1x + stack.shift(); - c2y = c1y + stack.shift(); - x = c2x + stack.shift(); - y = c2y + (stack.length === 1 ? stack.shift() : 0); - curveTo(c1x, c1y, c2x, c2y, x, y); - } - - break; - default: - if (v < 32) { - console.warn('Glyph ' + index + ': unknown operator ' + v); - } - else if (v < 247) { - stack.push(v - 139); - } - else if (v < 251) { - b1 = code[i]; - i += 1; - stack.push((v - 247) * 256 + b1 + 108); - } - else if (v < 255) { - b1 = code[i]; - i += 1; - stack.push(-(v - 251) * 256 - b1 - 108); - } - else { - b1 = code[i]; - b2 = code[i + 1]; - b3 = code[i + 2]; - b4 = code[i + 3]; - i += 4; - stack.push(((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65536); - } - } - } - } - - parse(code); - - const glyf = { - - // 移除重复的起点和终点 - contours: contours.map(contour => { - const last = contour.length - 1; - if (contour[0].x === contour[last].x && contour[0].y === contour[last].y) { - contour.splice(last, 1); - } - return contour; - }), - - advanceWidth: width - }; - if (glyfs.length) { - glyf.compound = true; - glyf.glyfs = glyfs; - } - return glyf; -} diff --git a/vendor/fonteditor-core/src/ttf/table/cmap.js b/vendor/fonteditor-core/src/ttf/table/cmap.js deleted file mode 100644 index b5b2ed3..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cmap.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @file cmap 表 - * @author mengke01(kekee000@gmail.com) - * - * @see - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html - */ - -import table from './table'; -import parse from './cmap/parse'; -import write from './cmap/write'; -import sizeof from './cmap/sizeof'; - -export default table.create( - 'cmap', - [], - { - write, - read: parse, - size: sizeof - } -); - diff --git a/vendor/fonteditor-core/src/ttf/table/cmap/parse.js b/vendor/fonteditor-core/src/ttf/table/cmap/parse.js deleted file mode 100644 index 921cdea..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cmap/parse.js +++ /dev/null @@ -1,253 +0,0 @@ -/** - * @file 解析cmap表 - * @author mengke01(kekee000@gmail.com) - */ - -import readWindowsAllCodes from '../../util/readWindowsAllCodes'; - -/** - * 读取cmap子表 - * - * @param {Reader} reader Reader对象 - * @param {Object} ttf ttf对象 - * @param {Object} subTable 子表对象 - * @param {number} cmapOffset 子表的偏移 - */ -function readSubTable(reader, ttf, subTable, cmapOffset) { - let i; - let l; - let glyphIdArray; - const startOffset = cmapOffset + subTable.offset; - let glyphCount; - subTable.format = reader.readUint16(startOffset); - - // 0~256 紧凑排列 - if (subTable.format === 0) { - const format0 = subTable; - // 跳过format字段 - format0.length = reader.readUint16(); - format0.language = reader.readUint16(); - glyphIdArray = []; - for (i = 0, l = format0.length - 6; i < l; i++) { - glyphIdArray.push(reader.readUint8()); - } - format0.glyphIdArray = glyphIdArray; - } - else if (subTable.format === 2) { - const format2 = subTable; - // 跳过format字段 - format2.length = reader.readUint16(); - format2.language = reader.readUint16(); - - const subHeadKeys = []; - let maxSubHeadKey = 0;// 最大索引 - let maxPos = -1; // 最大位置 - for (let i = 0, l = 256; i < l; i++) { - subHeadKeys[i] = reader.readUint16() / 8; - if (subHeadKeys[i] > maxSubHeadKey) { - maxSubHeadKey = subHeadKeys[i]; - maxPos = i; - } - } - - const subHeads = []; - for (i = 0; i <= maxSubHeadKey; i++) { - subHeads[i] = { - firstCode: reader.readUint16(), - entryCount: reader.readUint16(), - idDelta: reader.readUint16(), - idRangeOffset: (reader.readUint16() - (maxSubHeadKey - i) * 8 - 2) / 2 - }; - } - - glyphCount = (startOffset + format2.length - reader.offset) / 2; - const glyphs = []; - for (i = 0; i < glyphCount; i++) { - glyphs[i] = reader.readUint16(); - } - - format2.subHeadKeys = subHeadKeys; - format2.maxPos = maxPos; - format2.subHeads = subHeads; - format2.glyphs = glyphs; - - } - // 双字节编码,非紧凑排列 - else if (subTable.format === 4) { - const format4 = subTable; - // 跳过format字段 - format4.length = reader.readUint16(); - format4.language = reader.readUint16(); - format4.segCountX2 = reader.readUint16(); - format4.searchRange = reader.readUint16(); - format4.entrySelector = reader.readUint16(); - format4.rangeShift = reader.readUint16(); - - const segCount = format4.segCountX2 / 2; - - // end code - const endCode = []; - for (i = 0; i < segCount; ++i) { - endCode.push(reader.readUint16()); - } - format4.endCode = endCode; - - format4.reservedPad = reader.readUint16(); - - // start code - const startCode = []; - for (i = 0; i < segCount; ++i) { - startCode.push(reader.readUint16()); - } - format4.startCode = startCode; - - // idDelta - const idDelta = []; - for (i = 0; i < segCount; ++i) { - idDelta.push(reader.readUint16()); - } - format4.idDelta = idDelta; - - - format4.idRangeOffsetOffset = reader.offset; - - // idRangeOffset - const idRangeOffset = []; - for (i = 0; i < segCount; ++i) { - idRangeOffset.push(reader.readUint16()); - } - format4.idRangeOffset = idRangeOffset; - - // 总长度 - glyphIdArray起始偏移/2 - glyphCount = (format4.length - (reader.offset - startOffset)) / 2; - - // 记录array offset - format4.glyphIdArrayOffset = reader.offset; - - // glyphIdArray - glyphIdArray = []; - for (i = 0; i < glyphCount; ++i) { - glyphIdArray.push(reader.readUint16()); - } - - format4.glyphIdArray = glyphIdArray; - } - - else if (subTable.format === 6) { - const format6 = subTable; - - format6.length = reader.readUint16(); - format6.language = reader.readUint16(); - format6.firstCode = reader.readUint16(); - format6.entryCount = reader.readUint16(); - - // 记录array offset - format6.glyphIdArrayOffset = reader.offset; - - const glyphIndexArray = []; - const entryCount = format6.entryCount; - // 读取字符分组 - for (i = 0; i < entryCount; ++i) { - glyphIndexArray.push(reader.readUint16()); - } - format6.glyphIdArray = glyphIndexArray; - - } - // defines segments for sparse representation in 4-byte character space - else if (subTable.format === 12) { - const format12 = subTable; - - format12.reserved = reader.readUint16(); - format12.length = reader.readUint32(); - format12.language = reader.readUint32(); - format12.nGroups = reader.readUint32(); - - const groups = []; - const nGroups = format12.nGroups; - // 读取字符分组 - for (i = 0; i < nGroups; ++i) { - const group = {}; - group.start = reader.readUint32(); - group.end = reader.readUint32(); - group.startId = reader.readUint32(); - groups.push(group); - } - format12.groups = groups; - } - // format 14 - else if (subTable.format === 14) { - const format14 = subTable; - format14.length = reader.readUint32(); - const numVarSelectorRecords = reader.readUint32(); - const groups = []; - let offset = reader.offset; - for (let i = 0; i < numVarSelectorRecords; i++) { - const varSelector = reader.readUint24(offset); - const defaultUVSOffset = reader.readUint32(offset + 3); - const nonDefaultUVSOffset = reader.readUint32(offset + 7); - offset += 11; - - if (defaultUVSOffset) { - const numUnicodeValueRanges = reader.readUint32(startOffset + defaultUVSOffset); - for (let j = 0; j < numUnicodeValueRanges; j++) { - const startUnicode = reader.readUint24(); - const additionalCount = reader.readUint8(); - groups.push({ - start: startUnicode, - end: startUnicode + additionalCount, - varSelector - }); - } - } - if (nonDefaultUVSOffset) { - const numUVSMappings = reader.readUint32(startOffset + nonDefaultUVSOffset); - for (let j = 0; j < numUVSMappings; j++) { - const unicode = reader.readUint24(); - const glyphId = reader.readUint16(); - groups.push({ - unicode, - glyphId, - varSelector - }); - } - } - } - format14.groups = groups; - } - else { - console.warn('not support cmap format:' + subTable.format); - } -} - - -export default function parse(reader, ttf) { - const tcmap = {}; - // eslint-disable-next-line no-invalid-this - const cmapOffset = this.offset; - - reader.seek(cmapOffset); - - tcmap.version = reader.readUint16(); // 编码方式 - const numberSubtables = tcmap.numberSubtables = reader.readUint16(); // 表个数 - - - const subTables = tcmap.tables = []; // 名字表 - let offset = reader.offset; - - // 使用offset读取,以便于查找 - for (let i = 0, l = numberSubtables; i < l; i++) { - const subTable = {}; - subTable.platformID = reader.readUint16(offset); - subTable.encodingID = reader.readUint16(offset + 2); - subTable.offset = reader.readUint32(offset + 4); - - readSubTable(reader, ttf, subTable, cmapOffset); - subTables.push(subTable); - - offset += 8; - } - - const cmap = readWindowsAllCodes(subTables, ttf); - - return cmap; -} diff --git a/vendor/fonteditor-core/src/ttf/table/cmap/sizeof.js b/vendor/fonteditor-core/src/ttf/table/cmap/sizeof.js deleted file mode 100644 index 5146eec..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cmap/sizeof.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file 获取cmap表的大小 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 获取format4 delta值 - * Delta is saved in signed int in cmap format 4 subtable, - * but can be in -0xFFFF..0 interval. - * -0x10000..-0x7FFF values are stored with offset. - * - * @param {number} delta delta值 - * @return {number} delta值 - */ -function encodeDelta(delta) { - return delta > 0x7FFF - ? delta - 0x10000 - : (delta < -0x7FFF ? delta + 0x10000 : delta); -} - -/** - * 根据bound获取glyf segment - * - * @param {Array} glyfUnicodes glyf编码集合 - * @param {number} bound 编码范围 - * @return {Array} 码表 - */ -function getSegments(glyfUnicodes, bound) { - - let prevGlyph = null; - const result = []; - let segment = {}; - - glyfUnicodes.forEach((glyph) => { - - if (bound === undefined || glyph.unicode <= bound) { - // 初始化编码头部,这里unicode和graph id 都必须连续 - if (prevGlyph === null - || glyph.unicode !== prevGlyph.unicode + 1 - || glyph.id !== prevGlyph.id + 1 - ) { - if (prevGlyph !== null) { - segment.end = prevGlyph.unicode; - result.push(segment); - segment = { - start: glyph.unicode, - startId: glyph.id, - delta: encodeDelta(glyph.id - glyph.unicode) - }; - } - else { - segment.start = glyph.unicode; - segment.startId = glyph.id; - segment.delta = encodeDelta(glyph.id - glyph.unicode); - } - } - - prevGlyph = glyph; - } - }); - - // need to finish the last segment - if (prevGlyph !== null) { - segment.end = prevGlyph.unicode; - result.push(segment); - } - - // 返回编码范围 - return result; -} - -/** - * 获取format0编码集合 - * - * @param {Array} glyfUnicodes glyf编码集合 - * @return {Array} 码表 - */ -function getFormat0Segment(glyfUnicodes) { - const unicodes = []; - glyfUnicodes.forEach((u) => { - if (u.unicode !== undefined && u.unicode < 256) { - unicodes.push([u.unicode, u.id]); - } - }); - - // 按编码排序 - unicodes.sort((a, b) => a[0] - b[0]); - - return unicodes; -} - -/** - * 对cmap数据进行预处理,获取大小 - * - * @param {Object} ttf ttf对象 - * @return {number} 大小 - */ -export default function sizeof(ttf) { - ttf.support.cmap = {}; - let glyfUnicodes = []; - ttf.glyf.forEach((glyph, index) => { - - let unicodes = glyph.unicode; - - if (typeof glyph.unicode === 'number') { - unicodes = [glyph.unicode]; - } - - if (unicodes && unicodes.length) { - unicodes.forEach((unicode) => { - glyfUnicodes.push({ - unicode, - id: unicode !== 0xFFFF ? index : 0 - }); - }); - } - - }); - - glyfUnicodes = glyfUnicodes.sort((a, b) => a.unicode - b.unicode); - - ttf.support.cmap.unicodes = glyfUnicodes; - - const unicodes2Bytes = glyfUnicodes; - - ttf.support.cmap.format4Segments = getSegments(unicodes2Bytes, 0xFFFF); - ttf.support.cmap.format4Size = 24 - + ttf.support.cmap.format4Segments.length * 8; - - ttf.support.cmap.format0Segments = getFormat0Segment(glyfUnicodes); - ttf.support.cmap.format0Size = 262; - - // we need subtable 12 only if found unicodes with > 2 bytes. - const hasGLyphsOver2Bytes = unicodes2Bytes.some((glyph) => glyph.unicode > 0xFFFF); - - if (hasGLyphsOver2Bytes) { - ttf.support.cmap.hasGLyphsOver2Bytes = hasGLyphsOver2Bytes; - - const unicodes4Bytes = glyfUnicodes; - - ttf.support.cmap.format12Segments = getSegments(unicodes4Bytes); - ttf.support.cmap.format12Size = 16 - + ttf.support.cmap.format12Segments.length * 12; - } - - const size = 4 + (hasGLyphsOver2Bytes ? 32 : 24) // cmap header - + ttf.support.cmap.format0Size // format 0 - + ttf.support.cmap.format4Size // format 4 - + (hasGLyphsOver2Bytes ? ttf.support.cmap.format12Size : 0); // format 12 - - return size; -} - diff --git a/vendor/fonteditor-core/src/ttf/table/cmap/write.js b/vendor/fonteditor-core/src/ttf/table/cmap/write.js deleted file mode 100644 index 01bff0a..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cmap/write.js +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @file 写cmap表 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 创建`子表0` - * - * @param {Writer} writer 写对象 - * @param {Array} unicodes unicodes列表 - * @return {Writer} - */ -function writeSubTable0(writer, unicodes) { - - writer.writeUint16(0); // format - writer.writeUint16(262); // length - writer.writeUint16(0); // language - - // Array of unicodes 0..255 - let i = -1; - let unicode; - while ((unicode = unicodes.shift())) { - while (++i < unicode[0]) { - writer.writeUint8(0); - } - - writer.writeUint8(unicode[1]); - i = unicode[0]; - } - - while (++i < 256) { - writer.writeUint8(0); - } - - return writer; -} - - -/** - * 创建`子表4` - * - * @param {Writer} writer 写对象 - * @param {Array} segments 分块编码列表 - * @return {Writer} - */ -function writeSubTable4(writer, segments) { - - writer.writeUint16(4); // format - writer.writeUint16(24 + segments.length * 8); // length - writer.writeUint16(0); // language - - const segCount = segments.length + 1; - const maxExponent = Math.floor(Math.log(segCount) / Math.LN2); - const searchRange = 2 * Math.pow(2, maxExponent); - - writer.writeUint16(segCount * 2); // segCountX2 - writer.writeUint16(searchRange); // searchRange - writer.writeUint16(maxExponent); // entrySelector - writer.writeUint16(2 * segCount - searchRange); // rangeShift - - // end list - segments.forEach((segment) => { - writer.writeUint16(segment.end); - }); - writer.writeUint16(0xFFFF); // end code - writer.writeUint16(0); // reservedPad - - - // start list - segments.forEach((segment) => { - writer.writeUint16(segment.start); - }); - writer.writeUint16(0xFFFF); // start code - - // id delta - segments.forEach((segment) => { - writer.writeUint16(segment.delta); - }); - writer.writeUint16(1); - - // Array of range offsets, it doesn't matter when deltas present - for (let i = 0, l = segments.length; i < l; i++) { - writer.writeUint16(0); - } - writer.writeUint16(0); // rangeOffsetArray should be finished with 0 - - return writer; -} - -/** - * 创建`子表12` - * - * @param {Writer} writer 写对象 - * @param {Array} segments 分块编码列表 - * @return {Writer} - */ -function writeSubTable12(writer, segments) { - - writer.writeUint16(12); // format - writer.writeUint16(0); // reserved - writer.writeUint32(16 + segments.length * 12); // length - writer.writeUint32(0); // language - writer.writeUint32(segments.length); // nGroups - - segments.forEach((segment) => { - writer.writeUint32(segment.start); - writer.writeUint32(segment.end); - writer.writeUint32(segment.startId); - }); - - return writer; -} - -/** - * 写subtableheader - * - * @param {Writer} writer Writer对象 - * @param {number} platform 平台 - * @param {number} encoding 编码 - * @param {number} offset 偏移 - * @return {Writer} - */ -function writeSubTableHeader(writer, platform, encoding, offset) { - writer.writeUint16(platform); // platform - writer.writeUint16(encoding); // encoding - writer.writeUint32(offset); // offset - return writer; -} - - -/** - * 写cmap表数据 - * - * @param {Object} writer 写入器 - * @param {Object} ttf ttf对象 - * @return {Object} 写入器 - */ -export default function write(writer, ttf) { - const hasGLyphsOver2Bytes = ttf.support.cmap.hasGLyphsOver2Bytes; - - // write table header. - writer.writeUint16(0); // version - writer.writeUint16(hasGLyphsOver2Bytes ? 4 : 3); // count - - // header size - const subTableOffset = 4 + (hasGLyphsOver2Bytes ? 32 : 24); - const format4Size = ttf.support.cmap.format4Size; - const format0Size = ttf.support.cmap.format0Size; - - // subtable 4, unicode - writeSubTableHeader(writer, 0, 3, subTableOffset); - - // subtable 0, mac standard - writeSubTableHeader(writer, 1, 0, subTableOffset + format4Size); - - // subtable 4, windows standard - writeSubTableHeader(writer, 3, 1, subTableOffset); - - if (hasGLyphsOver2Bytes) { - writeSubTableHeader(writer, 3, 10, subTableOffset + format4Size + format0Size); - } - - // write tables, order of table seem to be magic, it is taken from TTX tool - writeSubTable4(writer, ttf.support.cmap.format4Segments); - writeSubTable0(writer, ttf.support.cmap.format0Segments); - - if (hasGLyphsOver2Bytes) { - writeSubTable12(writer, ttf.support.cmap.format12Segments); - } - - return writer; -} diff --git a/vendor/fonteditor-core/src/ttf/table/cvt.js b/vendor/fonteditor-core/src/ttf/table/cvt.js deleted file mode 100644 index e011ae2..0000000 --- a/vendor/fonteditor-core/src/ttf/table/cvt.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file cvt表 - * @author mengke01(kekee000@gmail.com) - * - * @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cvt.html - */ - -import table from './table'; - -export default table.create( - 'cvt', - [], - { - - read(reader, ttf) { - const length = ttf.tables.cvt.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.cvt) { - writer.writeBytes(ttf.cvt, ttf.cvt.length); - } - }, - - size(ttf) { - return ttf.cvt ? ttf.cvt.length : 0; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/directory.js b/vendor/fonteditor-core/src/ttf/table/directory.js deleted file mode 100644 index 9c45fcb..0000000 --- a/vendor/fonteditor-core/src/ttf/table/directory.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file directory 表, 读取和写入ttf表索引 - * @author mengke01(kekee000@gmail.com) - * - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html - */ - -import table from './table'; - -export default table.create( - 'directory', - [], - { - read(reader, ttf) { - const tables = {}; - const numTables = ttf.numTables; - const offset = this.offset; - - for (let i = offset, l = numTables * 16; i < l; i += 16) { - const name = reader.readString(i, 4).trim(); - - tables[name] = { - name, - checkSum: reader.readUint32(i + 4), - offset: reader.readUint32(i + 8), - length: reader.readUint32(i + 12) - }; - } - - return tables; - }, - - write(writer, ttf) { - - const tables = ttf.support.tables; - for (let i = 0, l = tables.length; i < l; i++) { - writer.writeString((tables[i].name + ' ').slice(0, 4)); - writer.writeUint32(tables[i].checkSum); - writer.writeUint32(tables[i].offset); - writer.writeUint32(tables[i].length); - } - - return writer; - }, - - size(ttf) { - return ttf.numTables * 16; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/fpgm.js b/vendor/fonteditor-core/src/ttf/table/fpgm.js deleted file mode 100644 index aab5e68..0000000 --- a/vendor/fonteditor-core/src/ttf/table/fpgm.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file fpgm 表 - * @author mengke01(kekee000@gmail.com) - * - * reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fpgm.html - */ - -import table from './table'; - -export default table.create( - 'fpgm', - [], - { - - read(reader, ttf) { - const length = ttf.tables.fpgm.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.fpgm) { - writer.writeBytes(ttf.fpgm, ttf.fpgm.length); - } - }, - - size(ttf) { - return ttf.fpgm ? ttf.fpgm.length : 0; - } - } -); - diff --git a/vendor/fonteditor-core/src/ttf/table/gasp.js b/vendor/fonteditor-core/src/ttf/table/gasp.js deleted file mode 100644 index fa33eb1..0000000 --- a/vendor/fonteditor-core/src/ttf/table/gasp.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file gasp 表 - * 对于需要hinting的字号需要这个表,否则会导致错误 - * @author mengke01(kekee000@gmail.com) - * reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gasp.html - */ - -import table from './table'; - -export default table.create( - 'gasp', - [], - { - - read(reader, ttf) { - const length = ttf.tables.gasp.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.gasp) { - writer.writeBytes(ttf.gasp, ttf.gasp.length); - } - }, - - size(ttf) { - return ttf.gasp ? ttf.gasp.length : 0; - } - } -); - diff --git a/vendor/fonteditor-core/src/ttf/table/glyf.js b/vendor/fonteditor-core/src/ttf/table/glyf.js deleted file mode 100644 index 0d16a50..0000000 --- a/vendor/fonteditor-core/src/ttf/table/glyf.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @file glyf表 - * @author mengke01(kekee000@gmail.com) - * - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html - */ - -import table from './table'; -import parse from './glyf/parse'; -import write from './glyf/write'; -import sizeof from './glyf/sizeof'; -import {isEmptyObject} from '../../common/lang'; - -export default table.create( - 'glyf', - [], - { - - read(reader, ttf) { - const startOffset = this.offset; - const loca = ttf.loca; - const numGlyphs = ttf.maxp.numGlyphs; - const glyphs = []; - - reader.seek(startOffset); - - // subset - const subset = ttf.readOptions.subset; - - if (subset && subset.length > 0) { - const subsetMap = { - 0: true // 设置.notdef - }; - subsetMap[0] = true; - // subset map - const cmap = ttf.cmap; - - // unicode to index - Object.keys(cmap).forEach((c) => { - if (subset.indexOf(+c) > -1) { - const i = cmap[c]; - subsetMap[i] = true; - } - }); - ttf.subsetMap = subsetMap; - const parsedGlyfMap = {}; - // 循环解析subset相关的glyf,包括复合字形相关的字形 - const travelsParse = function travels(subsetMap) { - const newSubsetMap = {}; - Object.keys(subsetMap).forEach((i) => { - const index = +i; - parsedGlyfMap[index] = true; - // 当前的和下一个一样,或者最后一个无轮廓 - if (loca[index] === loca[index + 1]) { - glyphs[index] = { - contours: [] - }; - } - else { - glyphs[index] = parse(reader, ttf, startOffset + loca[index]); - } - - if (glyphs[index].compound) { - glyphs[index].glyfs.forEach((g) => { - if (!parsedGlyfMap[g.glyphIndex]) { - newSubsetMap[g.glyphIndex] = true; - } - }); - } - }); - - if (!isEmptyObject(newSubsetMap)) { - travels(newSubsetMap); - } - }; - - travelsParse(subsetMap); - return glyphs; - } - - // 解析字体轮廓, 前n-1个 - let i; - let l; - for (i = 0, l = numGlyphs - 1; i < l; i++) { - // 当前的和下一个一样,或者最后一个无轮廓 - if (loca[i] === loca[i + 1]) { - glyphs[i] = { - contours: [] - }; - } - else { - glyphs[i] = parse(reader, ttf, startOffset + loca[i]); - } - } - - // 最后一个轮廓 - if ((ttf.tables.glyf.length - loca[i]) < 5) { - glyphs[i] = { - contours: [] - }; - } - else { - glyphs[i] = parse(reader, ttf, startOffset + loca[i]); - } - - return glyphs; - }, - - write, - size: sizeof - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/glyf/parse.js b/vendor/fonteditor-core/src/ttf/table/glyf/parse.js deleted file mode 100644 index 2deb650..0000000 --- a/vendor/fonteditor-core/src/ttf/table/glyf/parse.js +++ /dev/null @@ -1,308 +0,0 @@ -/** - * @file 解析glyf轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import glyFlag from '../../enum/glyFlag'; -import componentFlag from '../../enum/componentFlag'; - -const MAX_INSTRUCTION_LENGTH = 5000; // 设置instructions阈值防止读取错误 -const MAX_NUMBER_OF_COORDINATES = 20000; // 设置坐标最大个数阈值,防止glyf读取错误 - -/** - * 读取简单字形 - * - * @param {Reader} reader Reader对象 - * @param {Object} glyf 空glyf - * @return {Object} 解析后的glyf - */ -function parseSimpleGlyf(reader, glyf) { - const offset = reader.offset; - - // 轮廓点个数 - const numberOfCoordinates = glyf.endPtsOfContours[ - glyf.endPtsOfContours.length - 1 - ] + 1; - - // 判断坐标是否超过最大个数 - if (numberOfCoordinates > MAX_NUMBER_OF_COORDINATES) { - console.warn('error read glyf coordinates:' + offset); - return glyf; - } - - // 获取flag标志 - let i; - let length; - const flags = []; - let flag; - - i = 0; - while (i < numberOfCoordinates) { - flag = reader.readUint8(); - flags.push(flag); - i++; - - // 标志位3重复flag - if ((flag & glyFlag.REPEAT) && i < numberOfCoordinates) { - // 重复个数 - const repeat = reader.readUint8(); - for (let j = 0; j < repeat; j++) { - flags.push(flag); - i++; - } - } - } - - // 坐标集合 - const coordinates = []; - const xCoordinates = []; - let prevX = 0; - let x; - - for (i = 0, length = flags.length; i < length; ++i) { - x = 0; - flag = flags[i]; - - // 标志位1 - // If set, the corresponding y-coordinate is 1 byte long, not 2 - if (flag & glyFlag.XSHORT) { - x = reader.readUint8(); - - // 标志位5 - x = (flag & glyFlag.XSAME) ? x : -1 * x; - } - // 与上一值一致 - else if (flag & glyFlag.XSAME) { - x = 0; - } - // 新值 - else { - x = reader.readInt16(); - } - - prevX += x; - xCoordinates[i] = prevX; - coordinates[i] = { - x: prevX, - y: 0 - }; - if (flag & glyFlag.ONCURVE) { - coordinates[i].onCurve = true; - } - } - - const yCoordinates = []; - let prevY = 0; - let y; - - for (i = 0, length = flags.length; i < length; i++) { - y = 0; - flag = flags[i]; - - if (flag & glyFlag.YSHORT) { - y = reader.readUint8(); - y = (flag & glyFlag.YSAME) ? y : -1 * y; - } - else if (flag & glyFlag.YSAME) { - y = 0; - } - else { - y = reader.readInt16(); - } - - prevY += y; - yCoordinates[i] = prevY; - if (coordinates[i]) { - coordinates[i].y = prevY; - } - } - - // 计算轮廓集合 - if (coordinates.length) { - const endPtsOfContours = glyf.endPtsOfContours; - const contours = []; - contours.push(coordinates.slice(0, endPtsOfContours[0] + 1)); - - for (i = 1, length = endPtsOfContours.length; i < length; i++) { - contours.push(coordinates.slice(endPtsOfContours[i - 1] + 1, endPtsOfContours[i] + 1)); - } - - glyf.contours = contours; - } - - return glyf; -} - -/** - * 读取复合字形 - * - * @param {Reader} reader Reader对象 - * @param {Object} glyf glyf对象 - * @return {Object} glyf对象 - */ -function parseCompoundGlyf(reader, glyf) { - glyf.compound = true; - glyf.glyfs = []; - - let flags; - let g; - - // 读取复杂字形 - do { - flags = reader.readUint16(); - g = {}; - g.flags = flags; - g.glyphIndex = reader.readUint16(); - - let arg1 = 0; - let arg2 = 0; - let scaleX = 16384; - let scaleY = 16384; - let scale01 = 0; - let scale10 = 0; - - if (componentFlag.ARG_1_AND_2_ARE_WORDS & flags) { - arg1 = reader.readInt16(); - arg2 = reader.readInt16(); - - } - else { - arg1 = reader.readInt8(); - arg2 = reader.readInt8(); - } - - if (componentFlag.ROUND_XY_TO_GRID & flags) { - arg1 = Math.round(arg1); - arg2 = Math.round(arg2); - } - - if (componentFlag.WE_HAVE_A_SCALE & flags) { - scaleX = reader.readInt16(); - scaleY = scaleX; - } - else if (componentFlag.WE_HAVE_AN_X_AND_Y_SCALE & flags) { - scaleX = reader.readInt16(); - scaleY = reader.readInt16(); - } - else if (componentFlag.WE_HAVE_A_TWO_BY_TWO & flags) { - scaleX = reader.readInt16(); - scale01 = reader.readInt16(); - scale10 = reader.readInt16(); - scaleY = reader.readInt16(); - } - - if (componentFlag.ARGS_ARE_XY_VALUES & flags) { - g.useMyMetrics = !!flags & componentFlag.USE_MY_METRICS; - g.overlapCompound = !!flags & componentFlag.OVERLAP_COMPOUND; - - g.transform = { - a: Math.round(10000 * scaleX / 16384) / 10000, - b: Math.round(10000 * scale01 / 16384) / 10000, - c: Math.round(10000 * scale10 / 16384) / 10000, - d: Math.round(10000 * scaleY / 16384) / 10000, - e: arg1, - f: arg2 - }; - } - else { - g.points = [arg1, arg2]; - g.transform = { - a: Math.round(10000 * scaleX / 16384) / 10000, - b: Math.round(10000 * scale01 / 16384) / 10000, - c: Math.round(10000 * scale10 / 16384) / 10000, - d: Math.round(10000 * scaleY / 16384) / 10000, - e: 0, - f: 0 - }; - } - - glyf.glyfs.push(g); - - } while (componentFlag.MORE_COMPONENTS & flags); - - if (componentFlag.WE_HAVE_INSTRUCTIONS & flags) { - const length = reader.readUint16(); - if (length < MAX_INSTRUCTION_LENGTH) { - const instructions = []; - for (let i = 0; i < length; ++i) { - instructions.push(reader.readUint8()); - } - glyf.instructions = instructions; - } - else { - console.warn(length); - } - } - - return glyf; -} - - - -/** - * 解析glyf轮廓 - * - * @param {Reader} reader 读取器 - * @param {Object} ttf ttf对象 - * @param {number=} offset 偏移 - * @return {Object} glyf对象 - */ -export default function parseGlyf(reader, ttf, offset) { - - if (null != offset) { - reader.seek(offset); - } - - const glyf = {}; - let i; - let length; - let instructions; - - // 边界值 - const numberOfContours = reader.readInt16(); - glyf.xMin = reader.readInt16(); - glyf.yMin = reader.readInt16(); - glyf.xMax = reader.readInt16(); - glyf.yMax = reader.readInt16(); - - // 读取简单字形 - if (numberOfContours >= 0) { - // endPtsOfConturs - glyf.endPtsOfContours = []; - if (numberOfContours > 0) { - for (i = 0; i < numberOfContours; i++) { - glyf.endPtsOfContours.push(reader.readUint16()); - } - } - else { - delete glyf.xMin; - delete glyf.yMin; - delete glyf.xMax; - delete glyf.yMax; - } - - // instructions - length = reader.readUint16(); - if (length) { - // range错误 - if (length < MAX_INSTRUCTION_LENGTH) { - instructions = []; - for (i = 0; i < length; ++i) { - instructions.push(reader.readUint8()); - } - glyf.instructions = instructions; - } - else { - console.warn(length); - } - } - - parseSimpleGlyf(reader, glyf); - delete glyf.endPtsOfContours; - } - else { - parseCompoundGlyf(reader, glyf); - } - - return glyf; -} diff --git a/vendor/fonteditor-core/src/ttf/table/glyf/sizeof.js b/vendor/fonteditor-core/src/ttf/table/glyf/sizeof.js deleted file mode 100644 index 30dd0b9..0000000 --- a/vendor/fonteditor-core/src/ttf/table/glyf/sizeof.js +++ /dev/null @@ -1,257 +0,0 @@ -/** - * @file 获取glyf的大小,同时对glyf写入进行预处理 - * @author mengke01(kekee000@gmail.com) - */ - -import glyFlag from '../../enum/glyFlag'; - -/** - * 获取glyf的大小 - * - * @param {Object} glyf glyf对象 - * @param {Object} glyfSupport glyf相关统计 - * @param {boolean} hinting 是否保留hints - * @param {boolean} writeZeroContoursGlyfData 是否写空轮廓 glyph - * @return {number} size大小 - */ -function sizeofSimple(glyf, glyfSupport, hinting, writeZeroContoursGlyfData) { - if (!writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) { - return 0; - } - - // fixed header + endPtsOfContours - let result = 12 - + (glyf.contours || []).length * 2 - + (glyfSupport.flags || []).length; - - (glyfSupport.xCoord || []).forEach((x) => { - result += 0 <= x && x <= 0xFF ? 1 : 2; - }); - - (glyfSupport.yCoord || []).forEach((y) => { - result += 0 <= y && y <= 0xFF ? 1 : 2; - }); - - return result + (hinting && glyf.instructions ? glyf.instructions.length : 0); -} - -/** - * 复合图元size - * - * @param {Object} glyf glyf对象 - * @param {boolean} hinting 是否保留hints, compound 图元暂时不做hinting - * @return {number} size大小 - */ -// eslint-disable-next-line no-unused-vars -function sizeofCompound(glyf, hinting) { - let size = 10; - let transform; - glyf.glyfs.forEach((g) => { - transform = g.transform; - // flags + glyfIndex - size += 4; - - // a, b, c, d, e - // xy values or points - if (transform.e < 0 || transform.e > 0x7F || transform.f < 0 || transform.f > 0x7F) { - size += 4; - } - else { - size += 2; - } - - // 01 , 10 - if (transform.b || transform.c) { - size += 8; - } - // scale - else if (transform.a !== 1 || transform.d !== 1) { - size += transform.a === transform.d ? 2 : 4; - } - - }); - - return size; -} - -/** - * 获取flags - * - * @param {Object} glyf glyf对象 - * @param {Object} glyfSupport glyf相关统计 - * @return {Array} - */ -function getFlags(glyf, glyfSupport) { - - if (!glyf.contours || 0 === glyf.contours.length) { - return glyfSupport; - } - - const flags = []; - const xCoord = []; - const yCoord = []; - - const contours = glyf.contours; - let contour; - let prev; - let first = true; - - for (let j = 0, cl = contours.length; j < cl; j++) { - contour = contours[j]; - - for (let i = 0, l = contour.length; i < l; i++) { - - const point = contour[i]; - if (first) { - xCoord.push(point.x); - yCoord.push(point.y); - first = false; - } - else { - xCoord.push(point.x - prev.x); - yCoord.push(point.y - prev.y); - } - flags.push(point.onCurve ? glyFlag.ONCURVE : 0); - prev = point; - } - } - - // compress - const flagsC = []; - const xCoordC = []; - const yCoordC = []; - let x; - let y; - let prevFlag; - let repeatPoint = -1; - - flags.forEach((flag, index) => { - - x = xCoord[index]; - y = yCoord[index]; - - // 第一个 - if (index === 0) { - - if (-0xFF <= x && x <= 0xFF) { - flag += glyFlag.XSHORT; - if (x >= 0) { - flag += glyFlag.XSAME; - } - - x = Math.abs(x); - } - - if (-0xFF <= y && y <= 0xFF) { - flag += glyFlag.YSHORT; - if (y >= 0) { - flag += glyFlag.YSAME; - } - - y = Math.abs(y); - } - - flagsC.push(prevFlag = flag); - xCoordC.push(x); - yCoordC.push(y); - } - // 后续 - else { - - if (x === 0) { - flag += glyFlag.XSAME; - } - else { - if (-0xFF <= x && x <= 0xFF) { - flag += glyFlag.XSHORT; - if (x > 0) { - flag += glyFlag.XSAME; - } - - x = Math.abs(x); - } - - xCoordC.push(x); - } - - if (y === 0) { - flag += glyFlag.YSAME; - } - else { - if (-0xFF <= y && y <= 0xFF) { - flag += glyFlag.YSHORT; - if (y > 0) { - flag += glyFlag.YSAME; - } - y = Math.abs(y); - } - yCoordC.push(y); - } - - // repeat - if (flag === prevFlag) { - // 记录重复个数 - if (-1 === repeatPoint) { - repeatPoint = flagsC.length - 1; - flagsC[repeatPoint] |= glyFlag.REPEAT; - flagsC.push(1); - } - else { - ++flagsC[repeatPoint + 1]; - } - } - else { - repeatPoint = -1; - flagsC.push(prevFlag = flag); - } - } - - }); - - glyfSupport.flags = flagsC; - glyfSupport.xCoord = xCoordC; - glyfSupport.yCoord = yCoordC; - - return glyfSupport; -} - -/** - * 对glyf数据进行预处理,获取大小 - * - * @param {Object} ttf ttf对象 - * @return {number} 大小 - */ -export default function sizeof(ttf) { - ttf.support.glyf = []; - let tableSize = 0; - const hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false; - const writeZeroContoursGlyfData = ttf.writeOptions ? ttf.writeOptions.writeZeroContoursGlyfData : false; - ttf.glyf.forEach((glyf) => { - let glyfSupport = {}; - glyfSupport = glyf.compound ? glyfSupport : getFlags(glyf, glyfSupport); - - const glyfSize = glyf.compound - ? sizeofCompound(glyf, hinting) - : sizeofSimple(glyf, glyfSupport, hinting, writeZeroContoursGlyfData); - let size = glyfSize; - - // 4字节对齐 - if (size % 4) { - size += 4 - size % 4; - } - - glyfSupport.glyfSize = glyfSize; - glyfSupport.size = size; - - ttf.support.glyf.push(glyfSupport); - - tableSize += size; - }); - - ttf.support.glyf.tableSize = tableSize; - - // 写header的indexToLocFormat - ttf.head.indexToLocFormat = tableSize > 65536 ? 1 : 0; - - return ttf.support.glyf.tableSize; -} diff --git a/vendor/fonteditor-core/src/ttf/table/glyf/write.js b/vendor/fonteditor-core/src/ttf/table/glyf/write.js deleted file mode 100644 index c67b448..0000000 --- a/vendor/fonteditor-core/src/ttf/table/glyf/write.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * @file 写glyf数据 - * @author mengke01(kekee000@gmail.com) - */ - -import componentFlag from '../../enum/componentFlag'; - -/** - * 写glyf - * - * @param {Object} writer 写入器 - * @param {Object} ttf ttf对象 - * @return {Object} 写入器 - */ -export default function write(writer, ttf) { - const hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false; - const writeZeroContoursGlyfData = ttf.writeOptions ? ttf.writeOptions.writeZeroContoursGlyfData : false; - ttf.glyf.forEach((glyf, index) => { - // 非复合图元没有轮廓则不写 - if (!glyf.compound && !writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) { - return; - } - // header - writer.writeInt16(glyf.compound ? -1 : (glyf.contours || []).length); - writer.writeInt16(glyf.xMin); - writer.writeInt16(glyf.yMin); - writer.writeInt16(glyf.xMax); - writer.writeInt16(glyf.yMax); - - let i; - let l; - let flags; - - // 复合图元 - if (glyf.compound) { - - for (i = 0, l = glyf.glyfs.length; i < l; i++) { - const g = glyf.glyfs[i]; - - flags = g.points - ? 0 : (componentFlag.ARGS_ARE_XY_VALUES + componentFlag.ROUND_XY_TO_GRID); // xy values - - // more components - if (i < l - 1) { - flags += componentFlag.MORE_COMPONENTS; - } - - - // use my metrics - flags += g.useMyMetrics ? componentFlag.USE_MY_METRICS : 0; - // overlap compound - flags += g.overlapCompound ? componentFlag.OVERLAP_COMPOUND : 0; - - const transform = g.transform; - const a = transform.a; - const b = transform.b; - const c = transform.c; - const d = transform.d; - const e = g.points ? g.points[0] : transform.e; - const f = g.points ? g.points[1] : transform.f; - - // xy values or points - // int 8 放不下,则用int16放 - if (e < 0 || e > 0x7F || f < 0 || f > 0x7F) { - flags += componentFlag.ARG_1_AND_2_ARE_WORDS; - } - - if (b || c) { - flags += componentFlag.WE_HAVE_A_TWO_BY_TWO; - } - else if ((a !== 1 || d !== 1) && a === d) { - flags += componentFlag.WE_HAVE_A_SCALE; - } - else if (a !== 1 || d !== 1) { - flags += componentFlag.WE_HAVE_AN_X_AND_Y_SCALE; - } - - writer.writeUint16(flags); - writer.writeUint16(g.glyphIndex); - - if (componentFlag.ARG_1_AND_2_ARE_WORDS & flags) { - writer.writeInt16(e); - writer.writeInt16(f); - - } - else { - writer.writeUint8(e); - writer.writeUint8(f); - } - - if (componentFlag.WE_HAVE_A_SCALE & flags) { - writer.writeInt16(Math.round(a * 16384)); - } - else if (componentFlag.WE_HAVE_AN_X_AND_Y_SCALE & flags) { - writer.writeInt16(Math.round(a * 16384)); - writer.writeInt16(Math.round(d * 16384)); - } - else if (componentFlag.WE_HAVE_A_TWO_BY_TWO & flags) { - writer.writeInt16(Math.round(a * 16384)); - writer.writeInt16(Math.round(b * 16384)); - writer.writeInt16(Math.round(c * 16384)); - writer.writeInt16(Math.round(d * 16384)); - } - } - - } - else { - let endPtsOfContours = -1; - (glyf.contours || []).forEach((contour) => { - endPtsOfContours += contour.length; - writer.writeUint16(endPtsOfContours); - }); - - // instruction - if (hinting && glyf.instructions) { - const instructions = glyf.instructions; - writer.writeUint16(instructions.length); - for (i = 0, l = instructions.length; i < l; i++) { - writer.writeUint8(instructions[i]); - } - } - else { - writer.writeUint16(0); - } - - - // 获取暂存中的flags - flags = ttf.support.glyf[index].flags || []; - for (i = 0, l = flags.length; i < l; i++) { - writer.writeUint8(flags[i]); - } - - const xCoord = ttf.support.glyf[index].xCoord || []; - for (i = 0, l = xCoord.length; i < l; i++) { - if (0 <= xCoord[i] && xCoord[i] <= 0xFF) { - writer.writeUint8(xCoord[i]); - } - else { - writer.writeInt16(xCoord[i]); - } - } - - const yCoord = ttf.support.glyf[index].yCoord || []; - for (i = 0, l = yCoord.length; i < l; i++) { - if (0 <= yCoord[i] && yCoord[i] <= 0xFF) { - writer.writeUint8(yCoord[i]); - } - else { - writer.writeInt16(yCoord[i]); - } - } - } - - // 4字节对齐 - const glyfSize = ttf.support.glyf[index].glyfSize; - - if (glyfSize % 4) { - writer.writeEmpty(4 - glyfSize % 4); - } - }); - - return writer; -} diff --git a/vendor/fonteditor-core/src/ttf/table/head.js b/vendor/fonteditor-core/src/ttf/table/head.js deleted file mode 100644 index 794fcb9..0000000 --- a/vendor/fonteditor-core/src/ttf/table/head.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file head表 - * @author mengke01(kekee000@gmail.com) - */ - -import table from './table'; -import struct from './struct'; - -export default table.create( - 'head', - [ - ['version', struct.Fixed], - ['fontRevision', struct.Fixed], - ['checkSumAdjustment', struct.Uint32], - ['magickNumber', struct.Uint32], - ['flags', struct.Uint16], - ['unitsPerEm', struct.Uint16], - ['created', struct.LongDateTime], - ['modified', struct.LongDateTime], - ['xMin', struct.Int16], - ['yMin', struct.Int16], - ['xMax', struct.Int16], - ['yMax', struct.Int16], - ['macStyle', struct.Uint16], - ['lowestRecPPEM', struct.Uint16], - ['fontDirectionHint', struct.Int16], - ['indexToLocFormat', struct.Int16], - ['glyphDataFormat', struct.Int16] - ] -); diff --git a/vendor/fonteditor-core/src/ttf/table/hhea.js b/vendor/fonteditor-core/src/ttf/table/hhea.js deleted file mode 100644 index 73ea846..0000000 --- a/vendor/fonteditor-core/src/ttf/table/hhea.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file hhea 表 - * @author mengke01(kekee000@gmail.com) - * - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html - */ - -import table from './table'; -import struct from './struct'; -export default table.create( - 'hhea', - [ - ['version', struct.Fixed], - ['ascent', struct.Int16], - ['descent', struct.Int16], - ['lineGap', struct.Int16], - ['advanceWidthMax', struct.Uint16], - ['minLeftSideBearing', struct.Int16], - ['minRightSideBearing', struct.Int16], - ['xMaxExtent', struct.Int16], - ['caretSlopeRise', struct.Int16], - ['caretSlopeRun', struct.Int16], - ['caretOffset', struct.Int16], - ['reserved0', struct.Int16], - ['reserved1', struct.Int16], - ['reserved2', struct.Int16], - ['reserved3', struct.Int16], - ['metricDataFormat', struct.Int16], - ['numOfLongHorMetrics', struct.Uint16] - ] -); diff --git a/vendor/fonteditor-core/src/ttf/table/hmtx.js b/vendor/fonteditor-core/src/ttf/table/hmtx.js deleted file mode 100644 index 2846cfb..0000000 --- a/vendor/fonteditor-core/src/ttf/table/hmtx.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file hmtx 表 - * @author mengke01(kekee000@gmail.com) - * - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html - */ - -import table from './table'; - -export default table.create( - 'hmtx', - [], - { - - read(reader, ttf) { - const offset = this.offset; - reader.seek(offset); - - const numOfLongHorMetrics = ttf.hhea.numOfLongHorMetrics; - const hMetrics = []; - let i; - let hMetric; - for (i = 0; i < numOfLongHorMetrics; ++i) { - hMetric = {}; - hMetric.advanceWidth = reader.readUint16(); - hMetric.leftSideBearing = reader.readInt16(); - hMetrics.push(hMetric); - } - - // 最后一个宽度 - const advanceWidth = hMetrics[numOfLongHorMetrics - 1].advanceWidth; - const numOfLast = ttf.maxp.numGlyphs - numOfLongHorMetrics; - - // 获取后续的hmetrics - for (i = 0; i < numOfLast; ++i) { - hMetric = {}; - hMetric.advanceWidth = advanceWidth; - hMetric.leftSideBearing = reader.readInt16(); - hMetrics.push(hMetric); - } - - return hMetrics; - - }, - - write(writer, ttf) { - let i; - const numOfLongHorMetrics = ttf.hhea.numOfLongHorMetrics; - for (i = 0; i < numOfLongHorMetrics; ++i) { - writer.writeUint16(ttf.glyf[i].advanceWidth); - writer.writeInt16(ttf.glyf[i].leftSideBearing); - } - - // 最后一个宽度 - const numOfLast = ttf.glyf.length - numOfLongHorMetrics; - - for (i = 0; i < numOfLast; ++i) { - writer.writeInt16(ttf.glyf[numOfLongHorMetrics + i].leftSideBearing); - } - - return writer; - }, - - size(ttf) { - - // 计算同最后一个advanceWidth相等的元素个数 - let numOfLast = 0; - // 最后一个advanceWidth - const advanceWidth = ttf.glyf[ttf.glyf.length - 1].advanceWidth; - - for (let i = ttf.glyf.length - 2; i >= 0; i--) { - if (advanceWidth === ttf.glyf[i].advanceWidth) { - numOfLast++; - } - else { - break; - } - } - - ttf.hhea.numOfLongHorMetrics = ttf.glyf.length - numOfLast; - - return 4 * ttf.hhea.numOfLongHorMetrics + 2 * numOfLast; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/kern.js b/vendor/fonteditor-core/src/ttf/table/kern.js deleted file mode 100644 index 324a972..0000000 --- a/vendor/fonteditor-core/src/ttf/table/kern.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file kern - * @author fr33z00(https://github.com/fr33z00) - * - * @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html - */ - -import table from './table'; - -export default table.create( - 'kern', - [], - { - - read(reader, ttf) { - const length = ttf.tables.kern.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.kern) { - writer.writeBytes(ttf.kern, ttf.kern.length); - } - }, - - size(ttf) { - return ttf.kern ? ttf.kern.length : 0; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/kerx.js b/vendor/fonteditor-core/src/ttf/table/kerx.js deleted file mode 100644 index 6397787..0000000 --- a/vendor/fonteditor-core/src/ttf/table/kerx.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file kerx - * @author mengke01(kekee000@gmail.com) - * - * @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html - */ - -import table from './table'; - -export default table.create( - 'kerx', - [], - { - - read(reader, ttf) { - const length = ttf.tables.kerx.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.kerx) { - writer.writeBytes(ttf.kerx, ttf.kerx.length); - } - }, - - size(ttf) { - return ttf.kerx ? ttf.kerx.length : 0; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/loca.js b/vendor/fonteditor-core/src/ttf/table/loca.js deleted file mode 100644 index 46f2858..0000000 --- a/vendor/fonteditor-core/src/ttf/table/loca.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file loca表 - * @author mengke01(kekee000@gmail.com) - */ - -import table from './table'; -import struct from './struct'; - -export default table.create( - 'loca', - [], - { - - read(reader, ttf) { - let offset = this.offset; - const indexToLocFormat = ttf.head.indexToLocFormat; - // indexToLocFormat有2字节和4字节的区别 - const type = struct.names[(indexToLocFormat === 0) ? struct.Uint16 : struct.Uint32]; - const size = (indexToLocFormat === 0) ? 2 : 4; // 字节大小 - const sizeRatio = (indexToLocFormat === 0) ? 2 : 1; // 真实地址偏移 - const wordOffset = []; - - reader.seek(offset); - - const numGlyphs = ttf.maxp.numGlyphs; - for (let i = 0; i < numGlyphs; ++i) { - wordOffset.push(reader.read(type, offset, false) * sizeRatio); - offset += size; - } - - return wordOffset; - }, - - write(writer, ttf) { - const glyfSupport = ttf.support.glyf; - let offset = ttf.support.glyf.offset || 0; - const indexToLocFormat = ttf.head.indexToLocFormat; - const sizeRatio = (indexToLocFormat === 0) ? 0.5 : 1; - const numGlyphs = ttf.glyf.length; - - for (let i = 0; i < numGlyphs; ++i) { - if (indexToLocFormat) { - writer.writeUint32(offset); - } - else { - writer.writeUint16(offset); - } - offset += glyfSupport[i].size * sizeRatio; - } - - // write extra - if (indexToLocFormat) { - writer.writeUint32(offset); - } - else { - writer.writeUint16(offset); - } - - return writer; - }, - - size(ttf) { - const locaCount = ttf.glyf.length + 1; - return ttf.head.indexToLocFormat ? locaCount * 4 : locaCount * 2; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/maxp.js b/vendor/fonteditor-core/src/ttf/table/maxp.js deleted file mode 100644 index 87df1d7..0000000 --- a/vendor/fonteditor-core/src/ttf/table/maxp.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file maxp 表 - * @author mengke01(kekee000@gmail.com) - */ - -import table from './table'; -import struct from './struct'; - -export default table.create( - 'maxp', - [ - ['version', struct.Fixed], - ['numGlyphs', struct.Uint16], - ['maxPoints', struct.Uint16], - ['maxContours', struct.Uint16], - ['maxCompositePoints', struct.Uint16], - ['maxCompositeContours', struct.Uint16], - ['maxZones', struct.Uint16], - ['maxTwilightPoints', struct.Uint16], - ['maxStorage', struct.Uint16], - ['maxFunctionDefs', struct.Uint16], - ['maxInstructionDefs', struct.Uint16], - ['maxStackElements', struct.Uint16], - ['maxSizeOfInstructions', struct.Uint16], - ['maxComponentElements', struct.Uint16], - ['maxComponentDepth', struct.Int16] - ], - { - - write(writer, ttf) { - table.write.call(this, writer, ttf.support); - return writer; - }, - - size() { - return 32; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/name.js b/vendor/fonteditor-core/src/ttf/table/name.js deleted file mode 100644 index 7a18d57..0000000 --- a/vendor/fonteditor-core/src/ttf/table/name.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @file name表 - * @author mengke01(kekee000@gmail.com) - */ - -import table from './table'; -import nameIdTbl from '../enum/nameId'; -import string from '../util/string'; -import platformTbl from '../enum/platform'; -import {mac, win} from '../enum/encoding'; - -export default table.create( - 'name', - [], - { - - read(reader) { - let offset = this.offset; - reader.seek(offset); - - const nameTbl = {}; - nameTbl.format = reader.readUint16(); - nameTbl.count = reader.readUint16(); - nameTbl.stringOffset = reader.readUint16(); - - const nameRecordTbl = []; - const count = nameTbl.count; - let i; - let nameRecord; - - for (i = 0; i < count; ++i) { - nameRecord = {}; - nameRecord.platform = reader.readUint16(); - nameRecord.encoding = reader.readUint16(); - nameRecord.language = reader.readUint16(); - nameRecord.nameId = reader.readUint16(); - nameRecord.length = reader.readUint16(); - nameRecord.offset = reader.readUint16(); - nameRecordTbl.push(nameRecord); - } - - offset += nameTbl.stringOffset; - - // 读取字符名字 - for (i = 0; i < count; ++i) { - nameRecord = nameRecordTbl[i]; - nameRecord.name = reader.readBytes(offset + nameRecord.offset, nameRecord.length); - } - - const names = {}; - - // mac 下的english name - let platform = platformTbl.Macintosh; - let encoding = mac.Default; - let language = 0; - - // 如果有windows 下的 english,则用windows下的 name - if (nameRecordTbl.some((record) => record.platform === platformTbl.Microsoft - && record.encoding === win.UCS2 - && record.language === 1033)) { - platform = platformTbl.Microsoft; - encoding = win.UCS2; - language = 1033; - } - - for (i = 0; i < count; ++i) { - nameRecord = nameRecordTbl[i]; - if (nameRecord.platform === platform - && nameRecord.encoding === encoding - && nameRecord.language === language - && nameIdTbl[nameRecord.nameId]) { - names[nameIdTbl[nameRecord.nameId]] = language === 0 - ? string.getUTF8String(nameRecord.name) - : string.getUCS2String(nameRecord.name); - } - } - - return names; - }, - - write(writer, ttf) { - const nameRecordTbl = ttf.support.name; - - writer.writeUint16(0); // format - writer.writeUint16(nameRecordTbl.length); // count - writer.writeUint16(6 + nameRecordTbl.length * 12); // string offset - - // write name tbl header - let offset = 0; - nameRecordTbl.forEach((nameRecord) => { - writer.writeUint16(nameRecord.platform); - writer.writeUint16(nameRecord.encoding); - writer.writeUint16(nameRecord.language); - writer.writeUint16(nameRecord.nameId); - writer.writeUint16(nameRecord.name.length); - writer.writeUint16(offset); // offset - offset += nameRecord.name.length; - }); - - // write name tbl strings - nameRecordTbl.forEach((nameRecord) => { - writer.writeBytes(nameRecord.name); - }); - - return writer; - }, - - size(ttf) { - const names = ttf.name; - let nameRecordTbl = []; - - // 写入name信息 - // 这里为了简化书写,仅支持英文编码字符, - // 中文编码字符将被转化成url encode - let size = 6; - Object.keys(names).forEach((name) => { - const id = nameIdTbl.names[name]; - - const utf8Bytes = string.toUTF8Bytes(names[name]); - const usc2Bytes = string.toUCS2Bytes(names[name]); - - if (undefined !== id) { - // mac - nameRecordTbl.push({ - nameId: id, - platform: 1, - encoding: 0, - language: 0, - name: utf8Bytes - }); - - // windows - nameRecordTbl.push({ - nameId: id, - platform: 3, - encoding: 1, - language: 1033, - name: usc2Bytes - }); - - // 子表大小 - size += 12 * 2 + utf8Bytes.length + usc2Bytes.length; - } - }); - - const namingOrder = ['platform', 'encoding', 'language', 'nameId']; - nameRecordTbl = nameRecordTbl.sort((a, b) => { - let l = 0; - namingOrder.some(name => { - const o = a[name] - b[name]; - if (o) { - l = o; - return true; - } - return false; - }); - return l; - }); - - // 保存预处理信息 - ttf.support.name = nameRecordTbl; - - return size; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/post.js b/vendor/fonteditor-core/src/ttf/table/post.js deleted file mode 100644 index ad4d26d..0000000 --- a/vendor/fonteditor-core/src/ttf/table/post.js +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @file post 表 - * @author mengke01(kekee000@gmail.com) - * - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html - */ - -import table from './table'; -import struct from './struct'; -import string from '../util/string'; -import unicodeName from '../enum/unicodeName'; - -const Posthead = table.create( - 'posthead', - [ - ['format', struct.Fixed], - ['italicAngle', struct.Fixed], - ['underlinePosition', struct.Int16], - ['underlineThickness', struct.Int16], - ['isFixedPitch', struct.Uint32], - ['minMemType42', struct.Uint32], - ['maxMemType42', struct.Uint32], - ['minMemType1', struct.Uint32], - ['maxMemType1', struct.Uint32] - ] -); - -export default table.create( - 'post', - [], - { - - read(reader, ttf) { - const format = reader.readFixed(this.offset); - // 读取表头 - const tbl = new Posthead(this.offset).read(reader, ttf); - - // format2 - if (format === 2) { - const numberOfGlyphs = reader.readUint16(); - const glyphNameIndex = []; - - for (let i = 0; i < numberOfGlyphs; ++i) { - glyphNameIndex.push(reader.readUint16()); - } - - const pascalStringOffset = reader.offset; - const pascalStringLength = ttf.tables.post.length - (pascalStringOffset - this.offset); - const pascalStringBytes = reader.readBytes(reader.offset, pascalStringLength); - - tbl.nameIndex = glyphNameIndex; // 设置glyf名字索引 - tbl.names = string.getPascalString(pascalStringBytes); // glyf名字数组 - } - // deprecated - else if (format === 2.5) { - tbl.format = 3; - } - - return tbl; - }, - - write(writer, ttf) { - - - const post = ttf.post || { - format: 3 - }; - - // write header - writer.writeFixed(post.format); // format - writer.writeFixed(post.italicAngle || 0); // italicAngle - writer.writeInt16(post.underlinePosition || 0); // underlinePosition - writer.writeInt16(post.underlineThickness || 0); // underlineThickness - writer.writeUint32(post.isFixedPitch || 0); // isFixedPitch - writer.writeUint32(post.minMemType42 || 0); // minMemType42 - writer.writeUint32(post.maxMemType42 || 0); // maxMemType42 - writer.writeUint32(post.minMemType1 || 0); // minMemType1 - writer.writeUint32(post.maxMemType1 || 0); // maxMemType1 - - // version 3 不设置post信息 - if (post.format === 2) { - const numberOfGlyphs = ttf.glyf.length; - writer.writeUint16(numberOfGlyphs); // numberOfGlyphs - // write glyphNameIndex - const nameIndex = ttf.support.post.nameIndex; - for (let i = 0, l = nameIndex.length; i < l; i++) { - writer.writeUint16(nameIndex[i]); - } - - // write names - ttf.support.post.names.forEach((name) => { - writer.writeBytes(name); - }); - } - }, - - size(ttf) { - - const numberOfGlyphs = ttf.glyf.length; - ttf.post = ttf.post || {}; - ttf.post.format = ttf.post.format || 3; - ttf.post.maxMemType1 = numberOfGlyphs; - - // version 3 不设置post信息 - if (ttf.post.format === 3 || ttf.post.format === 1) { - return 32; - } - - // version 2 - let size = 34 + numberOfGlyphs * 2; // header + numberOfGlyphs + numberOfGlyphs * 2 - const glyphNames = []; - const nameIndexArr = []; - let nameIndex = 0; - - // 获取 name的大小 - for (let i = 0; i < numberOfGlyphs; i++) { - // .notdef - if (i === 0) { - nameIndexArr.push(0); - } - else { - const glyf = ttf.glyf[i]; - const unicode = glyf.unicode ? glyf.unicode[0] : 0; - const unicodeNameIndex = unicodeName[unicode]; - if (undefined !== unicodeNameIndex) { - nameIndexArr.push(unicodeNameIndex); - } - else { - // 这里需要注意,"" 有可能是"\3" length不为0,但是是空字符串 - const name = glyf.name; - if (!name || name.charCodeAt(0) < 32) { - nameIndexArr.push(258 + nameIndex++); - glyphNames.push([0]); - size++; - } - else { - nameIndexArr.push(258 + nameIndex++); - const bytes = string.toPascalStringBytes(name); // pascal string bytes - glyphNames.push(bytes); - size += bytes.length; - } - } - } - } - - ttf.support.post = { - nameIndex: nameIndexArr, - names: glyphNames - }; - - return size; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/prep.js b/vendor/fonteditor-core/src/ttf/table/prep.js deleted file mode 100644 index b4dc9e2..0000000 --- a/vendor/fonteditor-core/src/ttf/table/prep.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file prep表 - * @author mengke01(kekee000@gmail.com) - * - * @reference: http://www.microsoft.com/typography/otspec140/prep.htm - */ - -import table from './table'; - -export default table.create( - 'prep', - [], - { - - read(reader, ttf) { - const length = ttf.tables.prep.length; - return reader.readBytes(this.offset, length); - }, - - write(writer, ttf) { - if (ttf.prep) { - writer.writeBytes(ttf.prep, ttf.prep.length); - } - }, - - size(ttf) { - return ttf.prep ? ttf.prep.length : 0; - } - } -); diff --git a/vendor/fonteditor-core/src/ttf/table/struct.js b/vendor/fonteditor-core/src/ttf/table/struct.js deleted file mode 100644 index 4d46b51..0000000 --- a/vendor/fonteditor-core/src/ttf/table/struct.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file ttf基本数据结构 - * @author mengke01(kekee000@gmail.com) - * - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html - */ - -const struct = { - Int8: 1, - Uint8: 2, - Int16: 3, - Uint16: 4, - Int32: 5, - Uint32: 6, - Fixed: 7, // 32-bit signed fixed-point number (16.16) - FUnit: 8, // Smallest measurable distance in the em space - // 16-bit signed fixed number with the low 14 bits of fraction - F2Dot14: 11, - // The long internal format of a date in seconds since 12:00 midnight, - // January 1, 1904. It is represented as a signed 64-bit integer. - LongDateTime: 12, - - // extend data type - Char: 13, - String: 14, - Bytes: 15, - Uint24: 20 -}; - -// 反转名字查找 -const names = {}; -Object.keys(struct).forEach((key) => { - names[struct[key]] = key; -}); - -struct.names = names; - -export default struct; diff --git a/vendor/fonteditor-core/src/ttf/table/support-otf.js b/vendor/fonteditor-core/src/ttf/table/support-otf.js deleted file mode 100644 index e7d136c..0000000 --- a/vendor/fonteditor-core/src/ttf/table/support-otf.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file otf字体格式支持的表 - * @author mengke01(kekee000@gmail.com) - */ - -import head from './head'; -import maxp from './maxp'; -import cmap from './cmap'; -import name from './name'; -import hhea from './hhea'; -import hmtx from './hmtx'; -import post from './post'; -import OS2 from './OS2'; -import CFF from './CFF'; -import GPOS from './GPOS'; -import kern from './kern'; - -export default { - head, - maxp, - cmap, - name, - hhea, - hmtx, - post, - 'OS/2': OS2, - CFF, - GPOS, - kern -}; diff --git a/vendor/fonteditor-core/src/ttf/table/support.js b/vendor/fonteditor-core/src/ttf/table/support.js deleted file mode 100644 index 41f3a12..0000000 --- a/vendor/fonteditor-core/src/ttf/table/support.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file ttf读取和写入支持的表 - * @author mengke01(kekee000@gmail.com) - */ - -import head from './head'; -import maxp from './maxp'; -import loca from './loca'; -import cmap from './cmap'; -import glyf from './glyf'; -import name from './name'; -import hhea from './hhea'; -import hmtx from './hmtx'; -import post from './post'; -import OS2 from './OS2'; -import fpgm from './fpgm'; -import cvt from './cvt'; -import prep from './prep'; -import gasp from './gasp'; -import GPOS from './GPOS'; -import kern from './kern'; -import kerx from './kerx'; - -export default { - head, - maxp, - loca, - cmap, - glyf, - name, - hhea, - hmtx, - post, - 'OS/2': OS2, - fpgm, - cvt, - prep, - gasp, - GPOS, - kern, - kerx -}; diff --git a/vendor/fonteditor-core/src/ttf/table/table.js b/vendor/fonteditor-core/src/ttf/table/table.js deleted file mode 100644 index 26b8a77..0000000 --- a/vendor/fonteditor-core/src/ttf/table/table.js +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @file ttf表基类 - * @author mengke01(kekee000@gmail.com) - */ - -import struct from './struct'; -import error from '../error'; -/* eslint-disable no-invalid-this */ -/** - * 读取表结构 - * - * @param {Reader} reader reader对象 - * @return {Object} 当前对象 - */ -function read(reader) { - - const offset = this.offset; - - if (undefined !== offset) { - reader.seek(offset); - } - - const me = this; - - this.struct.forEach((item) => { - const name = item[0]; - const type = item[1]; - let typeName = null; - switch (type) { - case struct.Int8: - case struct.Uint8: - case struct.Int16: - case struct.Uint16: - case struct.Int32: - case struct.Uint32: - typeName = struct.names[type]; - me[name] = reader.read(typeName); - break; - - case struct.Fixed: - me[name] = reader.readFixed(); - break; - - case struct.LongDateTime: - me[name] = reader.readLongDateTime(); - break; - - case struct.Bytes: - me[name] = reader.readBytes(reader.offset, item[2] || 0); - break; - - case struct.Char: - me[name] = reader.readChar(); - break; - - case struct.String: - me[name] = reader.readString(reader.offset, item[2] || 0); - break; - - default: - error.raise(10003, name, type); - } - }); - - return this.valueOf(); -} - -/** - * 写表结构 - * - * @param {Object} writer writer对象 - * @param {Object} ttf 已解析的ttf对象 - * - * @return {Writer} 返回writer对象 - */ -function write(writer, ttf) { - const table = ttf[this.name]; - - if (!table) { - error.raise(10203, this.name); - } - - this.struct.forEach((item) => { - const name = item[0]; - const type = item[1]; - let typeName = null; - switch (type) { - case struct.Int8: - case struct.Uint8: - case struct.Int16: - case struct.Uint16: - case struct.Int32: - case struct.Uint32: - typeName = struct.names[type]; - writer.write(typeName, table[name]); - break; - - case struct.Fixed: - writer.writeFixed(table[name]); - break; - - case struct.LongDateTime: - writer.writeLongDateTime(table[name]); - break; - - case struct.Bytes: - writer.writeBytes(table[name], item[2] || 0); - break; - - case struct.Char: - writer.writeChar(table[name]); - break; - - case struct.String: - writer.writeString(table[name], item[2] || 0); - break; - - default: - error.raise(10003, name, type); - } - }); - - return writer; -} - -/** - * 获取ttf表的size大小 - * - * @param {string} name 表名 - * @return {number} 表大小 - */ -function size() { - - let sz = 0; - this.struct.forEach((item) => { - const type = item[1]; - switch (type) { - case struct.Int8: - case struct.Uint8: - sz += 1; - break; - - case struct.Int16: - case struct.Uint16: - sz += 2; - break; - - case struct.Int32: - case struct.Uint32: - case struct.Fixed: - sz += 4; - break; - - case struct.LongDateTime: - sz += 8; - break; - - case struct.Bytes: - sz += item[2] || 0; - break; - - case struct.Char: - sz += 1; - break; - - case struct.String: - sz += item[2] || 0; - break; - - default: - error.raise(10003, name, type); - } - }); - - return sz; -} - -/** - * 获取对象的值 - * - * @return {*} 当前对象的值 - */ -function valueOf() { - const val = {}; - const me = this; - this.struct.forEach(item => { - val[item[0]] = me[item[0]]; - }); - - return val; -} - -export default { - read, - write, - size, - valueOf, - - /** - * 创建一个表结构 - * - * @param {string} name 表名 - * @param {Array<[string, number]>} struct 表结构 - * @param {Object} proto 原型 - * @return {Function} 表构造函数 - */ - create(name, struct, proto) { - class Table { - constructor(offset) { - this.name = name; - this.struct = struct; - this.offset = offset; - } - } - - Table.prototype.read = read; - Table.prototype.write = write; - Table.prototype.size = size; - Table.prototype.valueOf = valueOf; - Object.assign(Table.prototype, proto); - return Table; - } -}; - diff --git a/vendor/fonteditor-core/src/ttf/ttf.js b/vendor/fonteditor-core/src/ttf/ttf.js deleted file mode 100644 index 4b75962..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf.js +++ /dev/null @@ -1,877 +0,0 @@ -/** - * @file ttf相关处理对象 - * @author mengke01(kekee000@gmail.com) - */ - -import {overwrite} from '../common/lang'; -import string from './util/string'; -import pathAdjust from '../graphics/pathAdjust'; -import pathCeil from '../graphics/pathCeil'; -import {computePath, computePathBox} from '../graphics/computeBoundingBox'; -import compound2simpleglyf from './util/compound2simpleglyf'; -import glyfAdjust from './util/glyfAdjust'; -import optimizettf from './util/optimizettf'; -import config from './data/default'; - -/** - * 缩放到EM框 - * - * @param {Array} glyfList glyf列表 - * @param {number} ascent 上升 - * @param {number} descent 下降 - * @param {number} adjustToEmPadding 顶部和底部留白 - * @return {Array} glyfList - */ -function adjustToEmBox(glyfList, ascent, descent, adjustToEmPadding) { - - glyfList.forEach((g) => { - - if (g.contours && g.contours.length) { - const rightSideBearing = g.advanceWidth - g.xMax; - const bound = computePath(...g.contours); - const scale = (ascent - descent - adjustToEmPadding) / bound.height; - const center = (ascent + descent) / 2; - const yOffset = center - (bound.y + bound.height / 2) * scale; - - g.contours.forEach((contour) => { - if (scale !== 1) { - pathAdjust(contour, scale, scale); - } - - pathAdjust(contour, 1, 1, 0, yOffset); - pathCeil(contour); - }); - - const box = computePathBox(...g.contours); - - g.xMin = box.x; - g.xMax = box.x + box.width; - g.yMin = box.y; - g.yMax = box.y + box.height; - - g.leftSideBearing = g.xMin; - g.advanceWidth = g.xMax + rightSideBearing; - - } - - }); - - return glyfList; -} - -/** - * 调整字形位置 - * - * @param {Array} glyfList 字形列表 - * @param {number=} leftSideBearing 左边距 - * @param {number=} rightSideBearing 右边距 - * @param {number=} verticalAlign 垂直对齐 - * - * @return {Array} 改变的列表 - */ -function adjustPos(glyfList, leftSideBearing, rightSideBearing, verticalAlign) { - - let changed = false; - - // 左边轴 - if (null != leftSideBearing) { - changed = true; - - glyfList.forEach((g) => { - if (g.leftSideBearing !== leftSideBearing) { - glyfAdjust(g, 1, 1, leftSideBearing - g.leftSideBearing); - } - }); - } - - // 右边轴 - if (null != rightSideBearing) { - changed = true; - - glyfList.forEach((g) => { - g.advanceWidth = g.xMax + rightSideBearing; - }); - } - - // 基线高度 - if (null != verticalAlign) { - changed = true; - - glyfList.forEach(g => { - if (g.contours && g.contours.length) { - const bound = computePath(...g.contours); - const offset = verticalAlign - bound.y; - glyfAdjust(g, 1, 1, 0, offset); - } - }); - } - - return changed ? glyfList : []; -} - - - -/** - * 合并两个ttfObject,此处仅合并简单字形 - * - * @param {Object} ttf ttfObject - * @param {Object} imported ttfObject - * @param {Object} options 参数选项 - * @param {boolean} options.scale 是否自动缩放,默认true - * @param {boolean} options.adjustGlyf 是否调整字形以适应边界 - * (与 options.scale 互斥) - * - * @return {Object} 合并后的ttfObject - */ -function merge(ttf, imported, options = {scale: true}) { - - const list = imported.glyf.filter((g) => - // 简单轮廓 - g.contours && g.contours.length - // 非预定义字形 - && g.name !== '.notdef' && g.name !== '.null' && g.name !== 'nonmarkingreturn' - ); - - // 调整字形以适应边界 - if (options.adjustGlyf) { - const ascent = ttf.hhea.ascent; - const descent = ttf.hhea.descent; - const adjustToEmPadding = 16; - adjustPos(list, 16, 16); - adjustToEmBox(list, ascent, descent, adjustToEmPadding); - - list.forEach((g) => { - ttf.glyf.push(g); - }); - } - // 根据unitsPerEm 进行缩放 - else if (options.scale) { - - let scale = 1; - - // 调整glyf对导入的轮廓进行缩放处理 - if (imported.head.unitsPerEm && imported.head.unitsPerEm !== ttf.head.unitsPerEm) { - scale = ttf.head.unitsPerEm / imported.head.unitsPerEm; - } - - list.forEach((g) => { - glyfAdjust(g, scale, scale); - ttf.glyf.push(g); - }); - } - - return list; -} - -export default class TTF { - - /** - * ttf读取函数 - * - * @constructor - * @param {Object} ttf ttf文件结构 - */ - constructor(ttf) { - this.ttf = ttf; - } - - /** - * 获取所有的字符信息 - * - * @return {Object} 字符信息 - */ - codes() { - return Object.keys(this.ttf.cmap); - } - - /** - * 根据编码获取字形索引 - * - * @param {string} c 字符或者字符编码 - * - * @return {?number} 返回glyf索引号 - */ - getGlyfIndexByCode(c) { - const charCode = typeof c === 'number' ? c : c.codePointAt(0); - const glyfIndex = this.ttf.cmap[charCode] || -1; - return glyfIndex; - } - - /** - * 根据索引获取字形 - * - * @param {number} glyfIndex glyf的索引 - * - * @return {?Object} 返回glyf对象 - */ - getGlyfByIndex(glyfIndex) { - const glyfList = this.ttf.glyf; - const glyf = glyfList[glyfIndex]; - return glyf; - } - - /** - * 根据编码获取字形 - * - * @param {string} c 字符或者字符编码 - * - * @return {?Object} 返回glyf对象 - */ - getGlyfByCode(c) { - const glyfIndex = this.getGlyfIndexByCode(c); - return this.getGlyfByIndex(glyfIndex); - } - - /** - * 设置ttf对象 - * - * @param {Object} ttf ttf对象 - * @return {this} - */ - set(ttf) { - this.ttf = ttf; - return this; - } - - /** - * 获取ttf对象 - * - * @return {ttfObject} ttf ttf对象 - */ - get() { - return this.ttf; - } - - /** - * 添加glyf - * - * @param {Object} glyf glyf对象 - * - * @return {number} 添加的glyf - */ - addGlyf(glyf) { - return this.insertGlyf(glyf); - } - - /** - * 插入glyf - * - * @param {Object} glyf glyf对象 - * @param {Object} insertIndex 插入的索引 - * @return {number} 添加的glyf - */ - insertGlyf(glyf, insertIndex) { - if (insertIndex >= 0 && insertIndex < this.ttf.glyf.length) { - this.ttf.glyf.splice(insertIndex, 0, glyf); - } - else { - this.ttf.glyf.push(glyf); - } - - return [glyf]; - } - - /** - * 合并两个ttfObject,此处仅合并简单字形 - * - * @param {Object} imported ttfObject - * @param {Object} options 参数选项 - * @param {boolean} options.scale 是否自动缩放 - * @param {boolean} options.adjustGlyf 是否调整字形以适应边界 - * (和 options.scale 参数互斥) - * - * @return {Array} 添加的glyf - */ - mergeGlyf(imported, options) { - const list = merge(this.ttf, imported, options); - return list; - } - - - /** - * 删除指定字形 - * - * @param {Array} indexList 索引列表 - * @return {Array} 删除的glyf - */ - removeGlyf(indexList) { - const glyf = this.ttf.glyf; - const removed = []; - for (let i = glyf.length - 1; i >= 0; i--) { - if (indexList.indexOf(i) >= 0) { - removed.push(glyf[i]); - glyf.splice(i, 1); - } - } - return removed; - } - - - /** - * 设置unicode代码 - * - * @param {string} unicode unicode代码 $E021, $22 - * @param {Array=} indexList 索引列表 - * @param {boolean} isGenerateName 是否生成name - * @return {Array} 改变的glyf - */ - setUnicode(unicode, indexList, isGenerateName) { - const glyf = this.ttf.glyf; - let list = []; - if (indexList && indexList.length) { - const first = indexList.indexOf(0); - if (first >= 0) { - indexList.splice(first, 1); - } - list = indexList.map((item) => glyf[item]); - } - else { - list = glyf.slice(1); - } - - // 需要选出 unicode >32 的glyf - if (list.length > 1) { - const less32 = function (u) { - return u < 33; - }; - list = list.filter((g) => !g.unicode || !g.unicode.some(less32)); - } - - if (list.length) { - unicode = Number('0x' + unicode.slice(1)); - list.forEach((g) => { - // 空格有可能会放入 nonmarkingreturn 因此不做编码 - if (unicode === 0xA0 || unicode === 0x3000) { - unicode++; - } - - g.unicode = [unicode]; - - if (isGenerateName) { - g.name = string.getUnicodeName(unicode); - } - unicode++; - }); - } - - return list; - } - - /** - * 生成字形名称 - * - * @param {Array=} indexList 索引列表 - * @return {Array} 改变的glyf - */ - genGlyfName(indexList) { - const glyf = this.ttf.glyf; - let list = []; - if (indexList && indexList.length) { - list = indexList.map((item) => glyf[item]); - } - else { - list = glyf; - } - - if (list.length) { - const first = this.ttf.glyf[0]; - - list.forEach((g) => { - if (g === first) { - g.name = '.notdef'; - } - else if (g.unicode && g.unicode.length) { - g.name = string.getUnicodeName(g.unicode[0]); - } - else { - g.name = '.notdef'; - } - }); - } - - return list; - } - - /** - * 清除字形名称 - * - * @param {Array=} indexList 索引列表 - * @return {Array} 改变的glyf - */ - clearGlyfName(indexList) { - const glyf = this.ttf.glyf; - let list = []; - if (indexList && indexList.length) { - list = indexList.map((item) => glyf[item]); - } - else { - list = glyf; - } - - if (list.length) { - - list.forEach((g) => { - delete g.name; - }); - } - - return list; - } - - /** - * 添加并体替换指定的glyf - * - * @param {Array} glyfList 添加的列表 - * @param {Array=} indexList 需要替换的索引列表 - * @return {Array} 改变的glyf - */ - appendGlyf(glyfList, indexList) { - const glyf = this.ttf.glyf; - const result = glyfList.slice(0); - - if (indexList && indexList.length) { - const l = Math.min(glyfList.length, indexList.length); - for (let i = 0; i < l; i++) { - glyf[indexList[i]] = glyfList[i]; - } - glyfList = glyfList.slice(l); - } - - if (glyfList.length) { - Array.prototype.splice.apply(glyf, [glyf.length, 0, ...glyfList]); - } - - return result; - } - - - /** - * 调整glyf位置 - * - * @param {Array=} indexList 索引列表 - * @param {Object} setting 选项 - * @param {number=} setting.leftSideBearing 左边距 - * @param {number=} setting.rightSideBearing 右边距 - * @param {number=} setting.verticalAlign 垂直对齐 - * @return {Array} 改变的glyf - */ - adjustGlyfPos(indexList, setting) { - - const glyfList = this.getGlyf(indexList); - return adjustPos( - glyfList, - setting.leftSideBearing, - setting.rightSideBearing, - setting.verticalAlign - ); - } - - - /** - * 调整glyf - * - * @param {Array=} indexList 索引列表 - * @param {Object} setting 选项 - * @param {boolean=} setting.reverse 字形反转操作 - * @param {boolean=} setting.mirror 字形镜像操作 - * @param {number=} setting.scale 字形缩放 - * @param {boolean=} setting.adjustToEmBox 是否调整字形到 em 框 - * @param {number=} setting.adjustToEmPadding 调整到 em 框的留白 - * @return {boolean} - */ - adjustGlyf(indexList, setting) { - - const glyfList = this.getGlyf(indexList); - let changed = false; - setting.adjustToEmBox = setting.ajdustToEmBox || setting.adjustToEmBox; - setting.adjustToEmPadding = setting.ajdustToEmPadding || setting.adjustToEmPadding; - - if (setting.reverse || setting.mirror) { - - changed = true; - - glyfList.forEach((g) => { - if (g.contours && g.contours.length) { - const offsetX = g.xMax + g.xMin; - const offsetY = g.yMax + g.yMin; - g.contours.forEach((contour) => { - pathAdjust(contour, setting.mirror ? -1 : 1, setting.reverse ? -1 : 1); - pathAdjust(contour, 1, 1, setting.mirror ? offsetX : 0, setting.reverse ? offsetY : 0); - }); - } - }); - } - - - if (setting.scale && setting.scale !== 1) { - - changed = true; - - const scale = setting.scale; - glyfList.forEach((g) => { - if (g.contours && g.contours.length) { - glyfAdjust(g, scale, scale); - } - }); - } - // 缩放到embox - else if (setting.adjustToEmBox) { - - changed = true; - const ascent = this.ttf.hhea.ascent; - const descent = this.ttf.hhea.descent; - const adjustToEmPadding = 2 * (setting.adjustToEmPadding || 0); - - adjustToEmBox(glyfList, ascent, descent, adjustToEmPadding); - } - - return changed ? glyfList : []; - } - - /** - * 获取glyf列表 - * - * @param {Array=} indexList 索引列表 - * @return {Array} glyflist - */ - getGlyf(indexList) { - const glyf = this.ttf.glyf; - if (indexList && indexList.length) { - return indexList.map((item) => glyf[item]); - } - - return glyf; - } - - - /** - * 查找相关字形 - * - * @param {Object} condition 查询条件 - * @param {Array|number} condition.unicode unicode编码列表或者单个unicode编码 - * @param {string} condition.name glyf名字,例如`uniE001`, `uniE` - * @param {Function} condition.filter 自定义过滤器 - * @example - * condition.filter = function (glyf) { - * return glyf.name === 'logo'; - * } - * @return {Array} glyf字形索引列表 - */ - findGlyf(condition) { - if (!condition) { - return []; - } - - - const filters = []; - - // 按unicode数组查找 - if (condition.unicode) { - const unicodeList = Array.isArray(condition.unicode) ? condition.unicode : [condition.unicode]; - const unicodeHash = {}; - unicodeList.forEach((unicode) => { - if (typeof unicode === 'string') { - unicode = Number('0x' + unicode.slice(1)); - } - unicodeHash[unicode] = true; - }); - - filters.push((glyf) => { - if (!glyf.unicode || !glyf.unicode.length) { - return false; - } - - for (let i = 0, l = glyf.unicode.length; i < l; i++) { - if (unicodeHash[glyf.unicode[i]]) { - return true; - } - } - }); - } - - // 按名字查找 - if (condition.name) { - const name = condition.name; - filters.push((glyf) => glyf.name && glyf.name.indexOf(name) === 0); - } - - // 按筛选函数查找 - if (typeof condition.filter === 'function') { - filters.push(condition.filter); - } - - const indexList = []; - this.ttf.glyf.forEach((glyf, index) => { - for (let filterIndex = 0, filter; (filter = filters[filterIndex++]);) { - if (true === filter(glyf)) { - indexList.push(index); - break; - } - } - }); - - return indexList; - } - - - /** - * 更新指定的glyf - * - * @param {Object} glyf glyfobject - * @param {string} index 需要替换的索引列表 - * @return {Array} 改变的glyf - */ - replaceGlyf(glyf, index) { - if (index >= 0 && index < this.ttf.glyf.length) { - this.ttf.glyf[index] = glyf; - return [glyf]; - } - return []; - } - - /** - * 设置glyf - * - * @param {Array} glyfList glyf列表 - * @return {Array} 设置的glyf列表 - */ - setGlyf(glyfList) { - delete this.glyf; - this.ttf.glyf = glyfList || []; - return this.ttf.glyf; - } - - /** - * 对字形按照unicode编码排序,此处不对复合字形进行排序,如果存在复合字形, 不进行排序 - * - * @param {Array} glyfList glyf列表 - * @return {Array} 设置的glyf列表 - */ - sortGlyf() { - const glyf = this.ttf.glyf; - if (glyf.length > 1) { - - // 如果存在复合字形则退出 - if (glyf.some((a) => a.compound)) { - return -2; - } - - const notdef = glyf.shift(); - // 按代码点排序, 首先将空字形排到最后,然后按照unicode第一个编码进行排序 - glyf.sort((a, b) => { - if ((!a.unicode || !a.unicode.length) && (!b.unicode || !b.unicode.length)) { - return 0; - } - else if ((!a.unicode || !a.unicode.length) && b.unicode) { - return 1; - } - else if (a.unicode && (!b.unicode || !b.unicode.length)) { - return -1; - } - return Math.min.apply(null, a.unicode) - Math.min.apply(null, b.unicode); - }); - - glyf.unshift(notdef); - return glyf; - } - - return -1; - } - - - - /** - * 设置名字 - * - * @param {string} name 名字字段 - * @return {Object} 名字对象 - */ - setName(name) { - - if (name) { - this.ttf.name.fontFamily = this.ttf.name.fullName = name.fontFamily || config.name.fontFamily; - this.ttf.name.fontSubFamily = name.fontSubFamily || config.name.fontSubFamily; - this.ttf.name.uniqueSubFamily = name.uniqueSubFamily || ''; - this.ttf.name.postScriptName = name.postScriptName || ''; - } - - return this.ttf.name; - } - - /** - * 设置head信息 - * - * @param {Object} head 头部信息 - * @return {Object} 头对象 - */ - setHead(head) { - if (head) { - // unitsperem - if (head.unitsPerEm && head.unitsPerEm >= 64 && head.unitsPerEm <= 16384) { - this.ttf.head.unitsPerEm = head.unitsPerEm; - } - - // lowestrecppem - if (head.lowestRecPPEM && head.lowestRecPPEM >= 8 && head.lowestRecPPEM <= 16384) { - this.ttf.head.lowestRecPPEM = head.lowestRecPPEM; - } - // created - if (head.created) { - this.ttf.head.created = head.created; - } - if (head.modified) { - this.ttf.head.modified = head.modified; - } - } - return this.ttf.head; - } - - /** - * 设置hhea信息 - * - * @param {Object} fields 字段值 - * @return {Object} 头对象 - */ - setHhea(fields) { - overwrite(this.ttf.hhea, fields, ['ascent', 'descent', 'lineGap']); - return this.ttf.hhea; - } - - /** - * 设置OS2信息 - * - * @param {Object} fields 字段值 - * @return {Object} 头对象 - */ - setOS2(fields) { - overwrite( - this.ttf['OS/2'], fields, - [ - 'usWinAscent', 'usWinDescent', - 'sTypoAscender', 'sTypoDescender', 'sTypoLineGap', - 'sxHeight', 'bXHeight', 'usWeightClass', 'usWidthClass', - 'yStrikeoutPosition', 'yStrikeoutSize', - 'achVendID', - // panose - 'bFamilyType', 'bSerifStyle', 'bWeight', 'bProportion', 'bContrast', - 'bStrokeVariation', 'bArmStyle', 'bLetterform', 'bMidline', 'bXHeight' - ] - ); - return this.ttf['OS/2']; - } - - /** - * 设置post信息 - * - * @param {Object} fields 字段值 - * @return {Object} 头对象 - */ - setPost(fields) { - overwrite( - this.ttf.post, fields, - [ - 'underlinePosition', 'underlineThickness' - ] - ); - return this.ttf.post; - } - - - /** - * 计算度量信息 - * - * @return {Object} 度量信息 - */ - calcMetrics() { - let ascent = -16384; - let descent = 16384; - const uX = 0x78; - const uH = 0x48; - let sxHeight; - let sCapHeight; - this.ttf.glyf.forEach((g) => { - - if (g.yMax > ascent) { - ascent = g.yMax; - } - - if (g.yMin < descent) { - descent = g.yMin; - } - - if (g.unicode) { - if (g.unicode.indexOf(uX) >= 0) { - sxHeight = g.yMax; - } - if (g.unicode.indexOf(uH) >= 0) { - sCapHeight = g.yMax; - } - } - }); - - ascent = Math.round(ascent); - descent = Math.round(descent); - - return { - - // 此处非必须自动设置 - ascent, - descent, - sTypoAscender: ascent, - sTypoDescender: descent, - - // 自动设置项目 - usWinAscent: ascent, - usWinDescent: -descent, - sxHeight: sxHeight || 0, - sCapHeight: sCapHeight || 0 - }; - } - - - /** - * 优化ttf字形信息 - * - * @return {Array} 改变的glyf - */ - optimize() { - return optimizettf(this.ttf); - } - - /** - * 复合字形转简单字形 - * - * @param {Array=} indexList 索引列表 - * @return {Array} 改变的glyf - */ - compound2simple(indexList) { - - const ttf = this.ttf; - if (ttf.maxp && !ttf.maxp.maxComponentElements) { - return []; - } - - let i; - let l; - // 全部的compound glyf - if (!indexList || !indexList.length) { - indexList = []; - for (i = 0, l = ttf.glyf.length; i < l; ++i) { - if (ttf.glyf[i].compound) { - indexList.push(i); - } - } - } - - const list = []; - for (i = 0, l = indexList.length; i < l; ++i) { - const glyfIndex = indexList[i]; - if (ttf.glyf[glyfIndex] && ttf.glyf[glyfIndex].compound) { - compound2simpleglyf(glyfIndex, ttf, true); - list.push(ttf.glyf[glyfIndex]); - } - } - - return list; - } -} diff --git a/vendor/fonteditor-core/src/ttf/ttf2base64.js b/vendor/fonteditor-core/src/ttf/ttf2base64.js deleted file mode 100644 index d4dc8cc..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf2base64.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file ttf数组转base64编码 - * @author mengke01(kekee000@gmail.com) - */ - -import bytes2base64 from './util/bytes2base64'; - -/** - * ttf数组转base64编码 - * - * @param {Array} arrayBuffer ArrayBuffer对象 - * @return {string} base64编码 - */ -export default function ttf2base64(arrayBuffer) { - return 'data:font/ttf;charset=utf-8;base64,' + bytes2base64(arrayBuffer); -} diff --git a/vendor/fonteditor-core/src/ttf/ttf2eot.js b/vendor/fonteditor-core/src/ttf/ttf2eot.js deleted file mode 100644 index f023323..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf2eot.js +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file ttf转eot - * @author mengke01(kekee000@gmail.com) - * - * reference: - * http://www.w3.org/Submission/EOT/ - * https://github.com/fontello/ttf2eot/blob/master/index.js - */ - -import Reader from './reader'; -import Writer from './writer'; -import string from './util/string'; -import error from './error'; -import table from './table/table'; -import struct from './table/struct'; -import NameTbl from './table/name'; - -const EotHead = table.create( - 'head', - [ - ['EOTSize', struct.Uint32], - ['FontDataSize', struct.Uint32], - ['Version', struct.Uint32], - ['Flags', struct.Uint32], - ['PANOSE', struct.Bytes, 10], - ['Charset', struct.Uint8], - ['Italic', struct.Uint8], - ['Weight', struct.Uint32], - ['fsType', struct.Uint16], - ['MagicNumber', struct.Uint16], - ['UnicodeRange', struct.Bytes, 16], - ['CodePageRange', struct.Bytes, 8], - ['CheckSumAdjustment', struct.Uint32], - ['Reserved', struct.Bytes, 16], - ['Padding1', struct.Uint16] - ] -); - -/** - * ttf格式转换成eot字体格式 - * - * @param {ArrayBuffer} ttfBuffer ttf缓冲数组 - * @param {Object} options 选项 - * @return {ArrayBuffer} eot格式byte流 - */ -// eslint-disable-next-line no-unused-vars -export default function ttf2eot(ttfBuffer, options = {}) { - // 构造eot头部 - const eotHead = new EotHead(); - const eotHeaderSize = eotHead.size(); - const eot = {}; - eot.head = eotHead.read(new Reader(new ArrayBuffer(eotHeaderSize))); - - // set fields - eot.head.FontDataSize = ttfBuffer.byteLength || ttfBuffer.length; - eot.head.Version = 0x20001; - eot.head.Flags = 0; - eot.head.Charset = 0x1; - eot.head.MagicNumber = 0x504C; - eot.head.Padding1 = 0; - - const ttfReader = new Reader(ttfBuffer); - // 读取ttf表个数 - const numTables = ttfReader.readUint16(4); - - if (numTables <= 0 || numTables > 100) { - error.raise(10101); - } - - // 读取ttf表索引信息 - ttfReader.seek(12); - // 需要读取3个表内容,设置3个byte - let tblReaded = 0; - for (let i = 0; i < numTables && tblReaded !== 0x7; ++i) { - - const tableEntry = { - tag: ttfReader.readString(ttfReader.offset, 4), - checkSum: ttfReader.readUint32(), - offset: ttfReader.readUint32(), - length: ttfReader.readUint32() - }; - - const entryOffset = ttfReader.offset; - - if (tableEntry.tag === 'head') { - eot.head.CheckSumAdjustment = ttfReader.readUint32(tableEntry.offset + 8); - tblReaded += 0x1; - } - else if (tableEntry.tag === 'OS/2') { - eot.head.PANOSE = ttfReader.readBytes(tableEntry.offset + 32, 10); - eot.head.Italic = ttfReader.readUint16(tableEntry.offset + 62); - eot.head.Weight = ttfReader.readUint16(tableEntry.offset + 4); - eot.head.fsType = ttfReader.readUint16(tableEntry.offset + 8); - eot.head.UnicodeRange = ttfReader.readBytes(tableEntry.offset + 42, 16); - eot.head.CodePageRange = ttfReader.readBytes(tableEntry.offset + 78, 8); - tblReaded += 0x2; - } - - // 设置名字信息 - else if (tableEntry.tag === 'name') { - const names = new NameTbl(tableEntry.offset).read(ttfReader); - - eot.FamilyName = string.toUCS2Bytes(names.fontFamily || ''); - eot.FamilyNameSize = eot.FamilyName.length; - - eot.StyleName = string.toUCS2Bytes(names.fontStyle || ''); - eot.StyleNameSize = eot.StyleName.length; - - eot.VersionName = string.toUCS2Bytes(names.version || ''); - eot.VersionNameSize = eot.VersionName.length; - - eot.FullName = string.toUCS2Bytes(names.fullName || ''); - eot.FullNameSize = eot.FullName.length; - - tblReaded += 0x3; - } - - ttfReader.seek(entryOffset); - } - - // 计算size - eot.head.EOTSize = eotHeaderSize - + 4 + eot.FamilyNameSize - + 4 + eot.StyleNameSize - + 4 + eot.VersionNameSize - + 4 + eot.FullNameSize - + 2 - + eot.head.FontDataSize; - - // 这里用小尾方式写入 - const eotWriter = new Writer(new ArrayBuffer(eot.head.EOTSize), 0, eot.head.EOTSize, true); - - // write head - eotHead.write(eotWriter, eot); - - // write names - eotWriter.writeUint16(eot.FamilyNameSize); - eotWriter.writeBytes(eot.FamilyName, eot.FamilyNameSize); - eotWriter.writeUint16(0); - - eotWriter.writeUint16(eot.StyleNameSize); - eotWriter.writeBytes(eot.StyleName, eot.StyleNameSize); - eotWriter.writeUint16(0); - - eotWriter.writeUint16(eot.VersionNameSize); - eotWriter.writeBytes(eot.VersionName, eot.VersionNameSize); - eotWriter.writeUint16(0); - - eotWriter.writeUint16(eot.FullNameSize); - eotWriter.writeBytes(eot.FullName, eot.FullNameSize); - eotWriter.writeUint16(0); - - // write rootstring - eotWriter.writeUint16(0); - - eotWriter.writeBytes(ttfBuffer, eot.head.FontDataSize); - - return eotWriter.getBuffer(); -} diff --git a/vendor/fonteditor-core/src/ttf/ttf2icon.js b/vendor/fonteditor-core/src/ttf/ttf2icon.js deleted file mode 100644 index baf7568..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf2icon.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file ttf转icon - * @author mengke01(kekee000@gmail.com) - */ - -import TTFReader from './ttfreader'; -import error from './error'; -import config from './data/default'; -import {getSymbolId} from './ttf2symbol'; - -/** - * listUnicode - * - * @param {Array} unicode unicode - * @return {string} unicode string - */ -function listUnicode(unicode) { - return unicode.map((u) => '\\' + u.toString(16)).join(','); -} - -/** - * ttf数据结构转icon数据结构 - * - * @param {ttfObject} ttf ttfObject对象 - * @param {Object} options 选项 - * @param {Object} options.metadata 字体相关的信息 - * @param {Object} options.iconPrefix icon 前缀 - * @return {Object} icon obj - */ -function ttfobject2icon(ttf, options = {}) { - - const glyfList = []; - - // glyf 信息 - const filtered = ttf.glyf.filter((g) => g.name !== '.notdef' - && g.name !== '.null' - && g.name !== 'nonmarkingreturn' - && g.unicode && g.unicode.length); - - filtered.forEach((g, i) => { - glyfList.push({ - code: '&#x' + g.unicode[0].toString(16) + ';', - codeName: listUnicode(g.unicode), - name: g.name, - id: getSymbolId(g, i) - }); - }); - - return { - fontFamily: ttf.name.fontFamily || config.name.fontFamily, - iconPrefix: options.iconPrefix || 'icon', - glyfList - }; - -} - - -/** - * ttf格式转换成icon - * - * @param {ArrayBuffer|ttfObject} ttfBuffer ttf缓冲数组或者ttfObject对象 - * @param {Object} options 选项 - * @param {Object} options.metadata 字体相关的信息 - * - * @return {Object} icon object - */ -export default function ttf2icon(ttfBuffer, options = {}) { - // 读取ttf二进制流 - if (ttfBuffer instanceof ArrayBuffer) { - const reader = new TTFReader(); - const ttfObject = reader.read(ttfBuffer); - reader.dispose(); - - return ttfobject2icon(ttfObject, options); - } - // 读取ttfObject - else if (ttfBuffer.version && ttfBuffer.glyf) { - - return ttfobject2icon(ttfBuffer, options); - } - - error.raise(10101); -} diff --git a/vendor/fonteditor-core/src/ttf/ttf2svg.js b/vendor/fonteditor-core/src/ttf/ttf2svg.js deleted file mode 100644 index 8c0d91e..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf2svg.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * @file ttf转svg - * @author mengke01(kekee000@gmail.com) - * - * references: - * http://www.w3.org/TR/SVG11/fonts.html - */ - -import string from '../common/string'; -import utilString from './util/string'; -import TTFReader from './ttfreader'; -import contours2svg from './util/contours2svg'; -import unicode2xml from './util/unicode2xml'; -import error from './error'; -import config from './data/default'; - -// svg font id -const SVG_FONT_ID = config.fontId; - -// xml 模板 -/* eslint-disable no-multi-spaces */ -const XML_TPL = '' - + '' - + '' - + '' - + '${metadata}' - + '' - + '' - + '' - + '${glyphList}' - + '' - + ''; -/* eslint-enable no-multi-spaces */ -// glyph 模板 -const GLYPH_TPL = ''; - -/** - * ttf数据结构转svg - * - * @param {ttfObject} ttf ttfObject对象 - * @param {Object} options 选项 - * @param {string} options.metadata 字体相关的信息 - * @return {string} svg字符串 - */ -function ttfobject2svg(ttf, options) { - - const OS2 = ttf['OS/2']; - - // 用来填充xml的数据 - const xmlObject = { - id: ttf.name.uniqueSubFamily || SVG_FONT_ID, - metadata: string.encodeHTML(options.metadata || ''), - advanceWidth: ttf.hhea.advanceWidthMax, - fontFamily: ttf.name.fontFamily, - fontWeight: OS2.usWeightClass, - unitsPerEm: ttf.head.unitsPerEm, - panose: [ - OS2.bFamilyType, OS2.bSerifStyle, OS2.bWeight, OS2.bProportion, OS2.bContrast, - OS2.bStrokeVariation, OS2.bArmStyle, OS2.bLetterform, OS2.bMidline, OS2.bXHeight - ].join(' '), - ascent: ttf.hhea.ascent, - descent: ttf.hhea.descent, - xHeight: OS2.bXHeight, - bbox: [ttf.head.xMin, ttf.head.yMin, ttf.head.xMax, ttf.head.yMax].join(' '), - underlineThickness: ttf.post.underlineThickness, - underlinePosition: ttf.post.underlinePosition, - unicodeRange: 'U+' + string.pad(OS2.usFirstCharIndex.toString(16), 4) - + '-' + string.pad(OS2.usLastCharIndex.toString(16), 4) - }; - - // glyf 第一个为missing glyph - xmlObject.missing = {}; - xmlObject.missing.advanceWidth = ttf.glyf[0].advanceWidth || 0; - xmlObject.missing.d = ttf.glyf[0].contours && ttf.glyf[0].contours.length - ? 'd="' + contours2svg(ttf.glyf[0].contours) + '"' - : ''; - - // glyf 信息 - let glyphList = ''; - for (let i = 1, l = ttf.glyf.length; i < l; i++) { - const glyf = ttf.glyf[i]; - - // 筛选简单字形,并且有轮廓,有编码 - if (!glyf.compound && glyf.contours && glyf.unicode && glyf.unicode.length) { - const glyfObject = { - name: utilString.escape(glyf.name), - unicode: unicode2xml(glyf.unicode), - d: contours2svg(glyf.contours) - }; - glyphList += string.format(GLYPH_TPL, glyfObject); - } - } - xmlObject.glyphList = glyphList; - - return string.format(XML_TPL, xmlObject); -} - - -/** - * ttf格式转换成svg字体格式 - * - * @param {ArrayBuffer|ttfObject} ttfBuffer ttf缓冲数组或者ttfObject对象 - * @param {Object} options 选项 - * @param {Object} options.metadata 字体相关的信息 - * - * @return {string} svg字符串 - */ -export default function ttf2svg(ttfBuffer, options = {}) { - - // 读取ttf二进制流 - if (ttfBuffer instanceof ArrayBuffer) { - const reader = new TTFReader(); - const ttfObject = reader.read(ttfBuffer); - reader.dispose(); - - return ttfobject2svg(ttfObject, options); - } - // 读取ttfObject - else if (ttfBuffer.version && ttfBuffer.glyf) { - - return ttfobject2svg(ttfBuffer, options); - } - - error.raise(10109); -} diff --git a/vendor/fonteditor-core/src/ttf/ttf2symbol.js b/vendor/fonteditor-core/src/ttf/ttf2symbol.js deleted file mode 100644 index 500a4e2..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf2symbol.js +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file ttf 转 svg symbol - * @author mengke01(kekee000@gmail.com) - */ - -import string from '../common/string'; -import TTFReader from './ttfreader'; -import contours2svg from './util/contours2svg'; -import pathsUtil from '../graphics/pathsUtil'; -import error from './error'; - -// xml 模板 -const XML_TPL = '' - + '' - + '${symbolList}' - + ''; - -// symbol 模板 -const SYMBOL_TPL = '' - + '' - + '' - + ''; - - -/** - * 根据 glyf 获取 symbo 名称 - * 1. 有 `name` 属性则使用 name 属性 - * 2. 有 `unicode` 属性则取 unicode 第一个: 'uni' + unicode - * 3. 使用索引号作为 id: 'symbol' + index - * - * @param {Object} glyf glyf 对象 - * @param {number} index glyf 索引 - * @return {string} - */ -export function getSymbolId(glyf, index) { - if (glyf.name) { - return glyf.name; - } - - if (glyf.unicode && glyf.unicode.length) { - return 'uni-' + glyf.unicode[0]; - } - return 'symbol-' + index; -} - -/** - * ttf数据结构转svg - * - * @param {ttfObject} ttf ttfObject对象 - * @param {Object} options 选项 - * @param {Object} options.metadata 字体相关的信息 - * @return {string} svg字符串 - */ -// eslint-disable-next-line no-unused-vars -function ttfobject2symbol(ttf, options = {}) { - const xmlObject = {}; - const unitsPerEm = ttf.head.unitsPerEm; - const descent = ttf.hhea.descent; - // glyf 信息 - let symbolList = ''; - for (let i = 1, l = ttf.glyf.length; i < l; i++) { - const glyf = ttf.glyf[i]; - // 筛选简单字形,并且有轮廓,有编码 - if (!glyf.compound && glyf.contours) { - const contours = pathsUtil.flip(glyf.contours); - const glyfObject = { - descent, - unitsPerEm, - id: getSymbolId(glyf, i), - d: contours2svg(contours) - }; - symbolList += string.format(SYMBOL_TPL, glyfObject); - } - } - xmlObject.symbolList = symbolList; - return string.format(XML_TPL, xmlObject); -} - - -/** - * ttf格式转换成svg字体格式 - * - * @param {ArrayBuffer|ttfObject} ttfBuffer ttf缓冲数组或者ttfObject对象 - * @param {Object} options 选项 - * @param {Object} options.metadata 字体相关的信息 - * - * @return {string} svg字符串 - */ -export default function ttf2symbol(ttfBuffer, options = {}) { - - // 读取ttf二进制流 - if (ttfBuffer instanceof ArrayBuffer) { - const reader = new TTFReader(); - const ttfObject = reader.read(ttfBuffer); - reader.dispose(); - - return ttfobject2symbol(ttfObject, options); - } - // 读取ttfObject - else if (ttfBuffer.version && ttfBuffer.glyf) { - - return ttfobject2symbol(ttfBuffer, options); - } - - error.raise(10112); -} diff --git a/vendor/fonteditor-core/src/ttf/ttf2woff.js b/vendor/fonteditor-core/src/ttf/ttf2woff.js deleted file mode 100644 index b54b765..0000000 --- a/vendor/fonteditor-core/src/ttf/ttf2woff.js +++ /dev/null @@ -1,297 +0,0 @@ -/** - * @file ttf转换为woff - * @author mengke01(kekee000@gmail.com) - * - * woff format: - * http://www.w3.org/TR/2012/REC-WOFF-20121213/ - * - * references: - * https://github.com/fontello/ttf2woff - * https://github.com/nodeca/pako - */ -/* eslint-disable no-multi-spaces */ -import Reader from './reader'; -import Writer from './writer'; -import string from '../common/string'; -import utilString from './util/string'; -import error from './error'; -import config from './data/default'; - -/** - * metadata 转换成XML - * - * @param {Object} metadata metadata - * - * @example - * metadata json: - * - * { - * "uniqueid": "", - * "vendor": { - * "name": "", - * "url": "" - * }, - * "credit": [ - * { - * "name": "", - * "url": "", - * "role": "" - * } - * ], - * "description": "", - * "license": { - * "id": "", - * "url": "", - * "text": "" - * }, - * "copyright": "", - * "trademark": "", - * "licensee": "" - * } - * - * @return {string} xml字符串 - */ -function metadata2xml(metadata) { - let xml = '' - + '' - + ''; - - metadata.uniqueid = metadata.uniqueid || (config.fontId + '.' + Date.now()); - xml += ''; - - if (metadata.vendor) { - xml += ''; - } - - if (metadata.credit) { - xml += ''; - const credits = metadata.credit instanceof Array ? metadata.credit : [metadata.credit]; - - credits.forEach((credit) => { - xml += ''; - }); - - xml += ''; - } - - if (metadata.description) { - xml += '' - + string.encodeHTML(metadata.description) - + ''; - } - - if (metadata.license) { - xml += ''; - xml += string.encodeHTML(metadata.license.text); - xml += ''; - } - - if (metadata.copyright) { - xml += ''; - xml += string.encodeHTML(metadata.copyright); - xml += ''; - } - - if (metadata.trademark) { - xml += '' - + string.encodeHTML(metadata.trademark) - + ''; - } - - if (metadata.licensee) { - xml += ''; - } - - xml += ''; - - return xml; -} - - -/** - * ttf格式转换成woff字体格式 - * - * @param {ArrayBuffer} ttfBuffer ttf缓冲数组 - * @param {Object} options 选项 - * @param {Object} options.metadata 字体相关的信息 - * @param {Object} options.deflate 压缩相关函数 - * - * @return {ArrayBuffer} woff格式byte流 - */ -export default function ttf2woff(ttfBuffer, options = {}) { - - // woff 头部结构 - const woffHeader = { - signature: 0x774F4646, // for woff - flavor: 0x10000, // for ttf - length: 0, - numTables: 0, - reserved: 0, - totalSfntSize: 0, - majorVersion: 0, - minorVersion: 0, - metaOffset: 0, - metaLength: 0, - metaOrigLength: 0, - privOffset: 0, - privLength: 0 - }; - - const ttfReader = new Reader(ttfBuffer); - let tableEntries = []; - const numTables = ttfReader.readUint16(4); // 读取ttf表个数 - let tableEntry; - let deflatedData; - let i; - let l; - - if (numTables <= 0 || numTables > 100) { - error.raise(10101); - } - - // 读取ttf表索引信息 - ttfReader.seek(12); - - for (i = 0; i < numTables; ++i) { - - tableEntry = { - tag: ttfReader.readString(ttfReader.offset, 4), - checkSum: ttfReader.readUint32(), - offset: ttfReader.readUint32(), - length: ttfReader.readUint32() - }; - - const entryOffset = ttfReader.offset; - - if (tableEntry.tag === 'head') { - // 读取font revision - woffHeader.majorVersion = ttfReader.readUint16(tableEntry.offset + 4); - woffHeader.minorVersion = ttfReader.readUint16(tableEntry.offset + 6); - } - - // ttf 表数据 - const sfntData = ttfReader.readBytes(tableEntry.offset, tableEntry.length); - - // 对数据进行压缩 - if (options.deflate) { - deflatedData = options.deflate(sfntData); - - // 这里需要判断是否压缩后数据小于原始数据 - if (deflatedData.length < sfntData.length) { - tableEntry.data = deflatedData; - tableEntry.deflated = true; - } - else { - tableEntry.data = sfntData; - } - } - else { - tableEntry.data = sfntData; - } - - tableEntry.compLength = tableEntry.data.length; - tableEntries.push(tableEntry); - ttfReader.seek(entryOffset); - } - - if (!tableEntries.length) { - error.raise(10204); - } - - // 对table进行排序 - tableEntries = tableEntries.sort((a, b) => a.tag === b.tag ? 0 : a.tag < b.tag ? -1 : 1); - - // 计算offset和 woff size - let woffSize = 44 + 20 * numTables; // header size + table entries - let ttfSize = 12 + 16 * numTables; - - for (i = 0, l = tableEntries.length; i < l; ++i) { - tableEntry = tableEntries[i]; - tableEntry.offset = woffSize; - // 4字节对齐 - woffSize += tableEntry.compLength + (tableEntry.compLength % 4 ? 4 - tableEntry.compLength % 4 : 0); - ttfSize += tableEntry.length + (tableEntry.length % 4 ? 4 - tableEntry.length % 4 : 0); - } - - // 计算metaData - let metadata = null; - if (options.metadata) { - const xml = utilString.toUTF8Bytes(metadata2xml(options.metadata)); - - if (options.deflate) { - deflatedData = options.deflate(xml); - if (deflatedData.length < xml.length) { - metadata = deflatedData; - } - else { - metadata = xml; - } - } - else { - metadata = xml; - } - - woffHeader.metaLength = metadata.length; - woffHeader.metaOrigLength = xml.length; - woffHeader.metaOffset = woffSize; - // metadata header + length - woffSize += woffHeader.metaLength + (woffHeader.metaLength % 4 ? 4 - woffHeader.metaLength % 4 : 0); - } - - woffHeader.numTables = tableEntries.length; - woffHeader.length = woffSize; - woffHeader.totalSfntSize = ttfSize; - - // 写woff数据 - const woffWriter = new Writer(new ArrayBuffer(woffSize)); - - // 写woff头部 - woffWriter.writeUint32(woffHeader.signature); - woffWriter.writeUint32(woffHeader.flavor); - woffWriter.writeUint32(woffHeader.length); - woffWriter.writeUint16(woffHeader.numTables); - woffWriter.writeUint16(woffHeader.reserved); - woffWriter.writeUint32(woffHeader.totalSfntSize); - woffWriter.writeUint16(woffHeader.majorVersion); - woffWriter.writeUint16(woffHeader.minorVersion); - woffWriter.writeUint32(woffHeader.metaOffset); - woffWriter.writeUint32(woffHeader.metaLength); - woffWriter.writeUint32(woffHeader.metaOrigLength); - woffWriter.writeUint32(woffHeader.privOffset); - woffWriter.writeUint32(woffHeader.privLength); - - - // 写woff表索引 - for (i = 0, l = tableEntries.length; i < l; ++i) { - tableEntry = tableEntries[i]; - woffWriter.writeString(tableEntry.tag); - woffWriter.writeUint32(tableEntry.offset); - woffWriter.writeUint32(tableEntry.compLength); - woffWriter.writeUint32(tableEntry.length); - woffWriter.writeUint32(tableEntry.checkSum); - } - - // 写表数据 - for (i = 0, l = tableEntries.length; i < l; ++i) { - tableEntry = tableEntries[i]; - woffWriter.writeBytes(tableEntry.data); - - if (tableEntry.compLength % 4) { - woffWriter.writeEmpty(4 - tableEntry.compLength % 4); - } - } - - // 写metadata - if (metadata) { - woffWriter.writeBytes(metadata); - if (woffHeader.metaLength % 4) { - woffWriter.writeEmpty(4 - woffHeader.metaLength % 4); - } - } - - return woffWriter.getBuffer(); -} diff --git a/vendor/fonteditor-core/src/ttf/ttfreader.js b/vendor/fonteditor-core/src/ttf/ttfreader.js deleted file mode 100644 index 4b8ced5..0000000 --- a/vendor/fonteditor-core/src/ttf/ttfreader.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * @file ttf读取器 - * @author mengke01(kekee000@gmail.com) - * - * thanks to: - * ynakajima/ttf.js - * https://github.com/ynakajima/ttf.js - */ - -import Directory from './table/directory'; -import supportTables from './table/support'; -import Reader from './reader'; -import postName from './enum/postName'; -import error from './error'; -import compound2simpleglyf from './util/compound2simpleglyf'; - -export default class TTFReader { - - /** - * ttf读取器的构造函数 - * - * @param {Object} options 写入参数 - * @param {boolean} options.hinting 保留hinting信息 - * @param {boolean} options.compound2simple 复合字形转简单字形 - * @constructor - */ - constructor(options = {}) { - options.subset = options.subset || []; // 子集 - options.hinting = options.hinting || false; // 默认不保留 hints 信息 - options.kerning = options.kerning || false; // 默认不保留 kerning 信息 - options.compound2simple = options.compound2simple || false; // 复合字形转简单字形 - this.options = options; - } - - /** - * 初始化读取 - * - * @param {ArrayBuffer} buffer buffer对象 - * @return {Object} ttf对象 - */ - readBuffer(buffer) { - - const reader = new Reader(buffer, 0, buffer.byteLength, false); - - const ttf = {}; - - // version - ttf.version = reader.readFixed(0); - - if (ttf.version !== 0x1) { - error.raise(10101); - } - - // num tables - ttf.numTables = reader.readUint16(); - - if (ttf.numTables <= 0 || ttf.numTables > 100) { - error.raise(10101); - } - - // searchRange - ttf.searchRange = reader.readUint16(); - - // entrySelector - ttf.entrySelector = reader.readUint16(); - - // rangeShift - ttf.rangeShift = reader.readUint16(); - - ttf.tables = new Directory(reader.offset).read(reader, ttf); - - if (!ttf.tables.glyf || !ttf.tables.head || !ttf.tables.cmap || !ttf.tables.hmtx) { - error.raise(10204); - } - - ttf.readOptions = this.options; - - // 读取支持的表数据 - Object.keys(supportTables).forEach((tableName) => { - - if (ttf.tables[tableName]) { - const offset = ttf.tables[tableName].offset; - ttf[tableName] = new supportTables[tableName](offset).read(reader, ttf); - } - }); - - if (!ttf.glyf) { - error.raise(10201); - } - - reader.dispose(); - - return ttf; - } - - /** - * 关联glyf相关的信息 - * - * @param {Object} ttf ttf对象 - */ - resolveGlyf(ttf) { - const codes = ttf.cmap; - const glyf = ttf.glyf; - const subsetMap = ttf.readOptions.subset ? ttf.subsetMap : null; // 当前ttf的子集列表 - - // unicode - Object.keys(codes).forEach((c) => { - const i = codes[c]; - if (subsetMap && !subsetMap[i]) { - return; - } - if (!glyf[i].unicode) { - glyf[i].unicode = []; - } - glyf[i].unicode.push(+c); - }); - - // advanceWidth - ttf.hmtx.forEach((item, i) => { - if (subsetMap && !subsetMap[i]) { - return; - } - glyf[i].advanceWidth = item.advanceWidth; - glyf[i].leftSideBearing = item.leftSideBearing; - }); - - // format = 2 的post表会携带glyf name信息 - if (ttf.post && 2 === ttf.post.format) { - const nameIndex = ttf.post.nameIndex; - const names = ttf.post.names; - nameIndex.forEach((nameIndex, i) => { - if (subsetMap && !subsetMap[i]) { - return; - } - if (nameIndex <= 257) { - glyf[i].name = postName[nameIndex]; - } - else { - glyf[i].name = names[nameIndex - 258] || ''; - } - }); - } - - // 设置了subsetMap之后需要选取subset中的字形 - // 并且对复合字形转换成简单字形 - if (subsetMap) { - const subGlyf = []; - Object.keys(subsetMap).forEach((i) => { - i = +i; - if (glyf[i].compound) { - compound2simpleglyf(i, ttf, true); - } - subGlyf.push(glyf[i]); - }); - ttf.glyf = subGlyf; - // 转换之后不存在复合字形了 - ttf.maxp.maxComponentElements = 0; - ttf.maxp.maxComponentDepth = 0; - } - } - - /** - * 清除非必须的表 - * - * @param {Object} ttf ttf对象 - */ - cleanTables(ttf) { - delete ttf.readOptions; - delete ttf.tables; - delete ttf.hmtx; - delete ttf.loca; - if (ttf.post) { - delete ttf.post.nameIndex; - delete ttf.post.names; - } - - delete ttf.subsetMap; - - // 不携带hinting信息则删除hint相关表 - if (!this.options.hinting) { - delete ttf.fpgm; - delete ttf.cvt; - delete ttf.prep; - ttf.glyf.forEach((glyf) => { - delete glyf.instructions; - }); - } - - if (!this.options.hinting && !this.options.kerning) { - delete ttf.GPOS; - delete ttf.kern; - delete ttf.kerx; - } - - // 复合字形转简单字形 - if (this.options.compound2simple && ttf.maxp.maxComponentElements) { - ttf.glyf.forEach((glyf, index) => { - if (glyf.compound) { - compound2simpleglyf(index, ttf, true); - } - }); - ttf.maxp.maxComponentElements = 0; - ttf.maxp.maxComponentDepth = 0; - } - } - - /** - * 获取解析后的ttf文档 - * - * @param {ArrayBuffer} buffer buffer对象 - * @return {Object} ttf文档 - */ - read(buffer) { - this.ttf = this.readBuffer(buffer); - this.resolveGlyf(this.ttf); - this.cleanTables(this.ttf); - return this.ttf; - } - - /** - * 注销 - */ - dispose() { - delete this.ttf; - delete this.options; - } - -} diff --git a/vendor/fonteditor-core/src/ttf/ttftowoff2.js b/vendor/fonteditor-core/src/ttf/ttftowoff2.js deleted file mode 100644 index 799a923..0000000 --- a/vendor/fonteditor-core/src/ttf/ttftowoff2.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file ttf to woff2 - * @author mengke01(kekee000@gmail.com) - */ -import woff2 from '../../woff2/index'; - -/** - * ttf格式转换成woff2字体格式 - * - * @param {ArrayBuffer} ttfBuffer ttf缓冲数组 - * @param {Object} options 选项 - * - * @return {Promise.} woff格式byte流 - */ -// eslint-disable-next-line no-unused-vars -export default function ttftowoff2(ttfBuffer, options = {}) { - if (!woff2.isInited()) { - throw new Error('use woff2.init() to init woff2 module!'); - } - - const result = woff2.encode(ttfBuffer); - return result.buffer; -} - - -/** - * ttf格式转换成woff2字体格式 - * - * @param {ArrayBuffer} ttfBuffer ttf缓冲数组 - * @param {Object} options 选项 - * - * @return {Promise.} woff格式byte流 - */ -export function ttftowoff2async(ttfBuffer, options = {}) { - return woff2.init(options.wasmUrl).then(() => { - const result = woff2.encode(ttfBuffer); - return result.buffer; - }); -} diff --git a/vendor/fonteditor-core/src/ttf/ttfwriter.js b/vendor/fonteditor-core/src/ttf/ttfwriter.js deleted file mode 100644 index f2151e2..0000000 --- a/vendor/fonteditor-core/src/ttf/ttfwriter.js +++ /dev/null @@ -1,243 +0,0 @@ -/** - * @file ttf写入器 - * @author mengke01(kekee000@gmail.com) - */ - -import Writer from './writer'; -import Directory from './table/directory'; -import supportTables from './table/support'; -import checkSum from './util/checkSum'; -import error from './error'; - -// 支持写的表, 注意表顺序 -const SUPPORT_TABLES = [ - 'OS/2', - 'cmap', - 'glyf', - 'head', - 'hhea', - 'hmtx', - 'loca', - 'maxp', - 'name', - 'post' -]; - -export default class TTFWriter { - constructor(options = {}) { - this.options = { - writeZeroContoursGlyfData: options.writeZeroContoursGlyfData || false, // 不写入空 glyf 数据 - hinting: options.hinting || false, // 默认不保留hints信息 - kerning: options.kerning || false, // 默认不保留 kernings space 信息 - support: options.support // 自定义的导出表结构,可以自己修改某些表项目 - }; - } - - /** - * 处理ttf结构,以便于写 - * - * @param {ttfObject} ttf ttf数据结构 - */ - resolveTTF(ttf) { - - // 头部信息 - ttf.version = ttf.version || 0x1; - ttf.numTables = ttf.writeOptions.tables.length; - ttf.entrySelector = Math.floor(Math.log(ttf.numTables) / Math.LN2); - ttf.searchRange = Math.pow(2, ttf.entrySelector) * 16; - ttf.rangeShift = ttf.numTables * 16 - ttf.searchRange; - - // 重置校验码 - ttf.head.checkSumAdjustment = 0; - ttf.head.magickNumber = 0x5F0F3CF5; - - if (typeof ttf.head.created === 'string') { - ttf.head.created = /^\d+$/.test(ttf.head.created) - ? +ttf.head.created : Date.parse(ttf.head.created); - } - if (typeof ttf.head.modified === 'string') { - ttf.head.modified = /^\d+$/.test(ttf.head.modified) - ? +ttf.head.modified : Date.parse(ttf.head.modified); - } - // 重置日期 - if (!ttf.head.created) { - ttf.head.created = Date.now(); - } - if (!ttf.head.modified) { - ttf.head.modified = ttf.head.created; - } - - const checkUnicodeRepeat = {}; // 检查是否有重复代码点 - - // 将glyf的代码点按小到大排序 - ttf.glyf.forEach((glyf, index) => { - if (glyf.unicode) { - glyf.unicode = glyf.unicode.sort(); - - glyf.unicode.forEach((u) => { - if (checkUnicodeRepeat[u]) { - error.raise({ - number: 10200, - data: index - }, index); - } - else { - checkUnicodeRepeat[u] = true; - } - }); - - } - }); - } - - /** - * 写ttf文件 - * - * @param {ttfObject} ttf ttf数据结构 - * @return {ArrayBuffer} 字节流 - */ - dump(ttf) { - - // 用来做写入缓存的对象,用完后删掉 - ttf.support = Object.assign({}, this.options.support); - - // head + directory - let ttfSize = 12 + ttf.numTables * 16; - let ttfHeadOffset = 0; // 记录head的偏移 - - // 构造tables - ttf.support.tables = []; - ttf.writeOptions.tables.forEach((tableName) => { - const offset = ttfSize; - const TableClass = supportTables[tableName]; - const tableSize = new TableClass().size(ttf); // 原始的表大小 - let size = tableSize; // 对齐后的表大小 - - if (tableName === 'head') { - ttfHeadOffset = offset; - } - - // 4字节对齐 - if (size % 4) { - size += 4 - size % 4; - } - - ttf.support.tables.push({ - name: tableName, - checkSum: 0, - offset, - length: tableSize, - size - }); - - ttfSize += size; - }); - - const writer = new Writer(new ArrayBuffer(ttfSize)); - - // 写头部 - writer.writeFixed(ttf.version); - writer.writeUint16(ttf.numTables); - writer.writeUint16(ttf.searchRange); - writer.writeUint16(ttf.entrySelector); - writer.writeUint16(ttf.rangeShift); - - // 写表偏移 - new Directory().write(writer, ttf); - - // 写支持的表数据 - ttf.support.tables.forEach((table) => { - - const tableStart = writer.offset; - const TableClass = supportTables[table.name]; - new TableClass().write(writer, ttf); - - if (table.length % 4) { - // 对齐字节 - writer.writeEmpty(4 - table.length % 4); - } - - // 计算校验和 - table.checkSum = checkSum(writer.getBuffer(), tableStart, table.size); - - }); - - // 重新写入每个表校验和 - ttf.support.tables.forEach((table, index) => { - const offset = 12 + index * 16 + 4; - writer.writeUint32(table.checkSum, offset); - }); - - // 写入总校验和 - const ttfCheckSum = (0xB1B0AFBA - checkSum(writer.getBuffer()) + 0x100000000) % 0x100000000; - writer.writeUint32(ttfCheckSum, ttfHeadOffset + 8); - - delete ttf.writeOptions; - delete ttf.support; - - const buffer = writer.getBuffer(); - writer.dispose(); - - return buffer; - } - - /** - * 对ttf的表进行评估,标记需要处理的表 - * - * @param {Object} ttf ttf对象 - */ - prepareDump(ttf) { - - if (!ttf.glyf || ttf.glyf.length === 0) { - error.raise(10201); - } - - if (!ttf['OS/2'] || !ttf.head || !ttf.name) { - error.raise(10204); - } - - - const tables = SUPPORT_TABLES.slice(0); - ttf.writeOptions = {}; - // hinting tables direct copy - if (this.options.hinting) { - ['cvt', 'fpgm', 'prep', 'gasp', 'GPOS', 'kern', 'kerx'].forEach((table) => { - if (ttf[table]) { - tables.push(table); - } - }); - } - // copy kerning space table - if (this.options.kerning) { - ['GPOS', 'kern', 'kerx'].forEach((table) => { - if (ttf[table]) { - tables.push(table); - } - }); - } - ttf.writeOptions.writeZeroContoursGlyfData = !!this.options.writeZeroContoursGlyfData; - ttf.writeOptions.hinting = !!this.options.hinting; - ttf.writeOptions.kerning = !!this.options.kerning; - ttf.writeOptions.tables = tables.sort(); - } - - /** - * 写一个ttf字体结构 - * - * @param {Object} ttf ttf数据结构 - * @return {ArrayBuffer} 缓冲数组 - */ - write(ttf) { - this.prepareDump(ttf); - this.resolveTTF(ttf); - const buffer = this.dump(ttf); - return buffer; - } - - /** - * 注销 - */ - dispose() { - delete this.options; - } -} diff --git a/vendor/fonteditor-core/src/ttf/util/base642bytes.js b/vendor/fonteditor-core/src/ttf/util/base642bytes.js deleted file mode 100644 index 8720903..0000000 --- a/vendor/fonteditor-core/src/ttf/util/base642bytes.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @file base64字符串转数组 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * base64字符串转数组 - * - * @param {string} base64 base64字符串 - * @return {Array} 数组 - */ -export default function base642bytes(base64) { - const str = atob(base64); - const result = []; - for (let i = 0, l = str.length; i < l; i++) { - result.push(str[i].charCodeAt(0)); - } - return result; -} diff --git a/vendor/fonteditor-core/src/ttf/util/bytes2base64.js b/vendor/fonteditor-core/src/ttf/util/bytes2base64.js deleted file mode 100644 index 32bfa0c..0000000 --- a/vendor/fonteditor-core/src/ttf/util/bytes2base64.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file 二进制byte流转base64编码 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 二进制byte流转base64编码 - * - * @param {ArrayBuffer|Array} buffer ArrayBuffer对象 - * @return {string} base64编码 - */ -export default function bytes2base64(buffer) { - let str = ''; - let length; - let i; - // ArrayBuffer - if (buffer instanceof ArrayBuffer) { - length = buffer.byteLength; - const view = new DataView(buffer, 0, length); - for (i = 0; i < length; i++) { - str += String.fromCharCode(view.getUint8(i, false)); - } - } - // Array - else if (buffer.length) { - length = buffer.length; - for (i = 0; i < length; i++) { - str += String.fromCharCode(buffer[i]); - } - } - - if (!str) { - return ''; - } - return typeof btoa !== 'undefined' - ? btoa(str) - : Buffer.from(str, 'binary').toString('base64'); -} diff --git a/vendor/fonteditor-core/src/ttf/util/checkSum.js b/vendor/fonteditor-core/src/ttf/util/checkSum.js deleted file mode 100644 index a2ce0c1..0000000 --- a/vendor/fonteditor-core/src/ttf/util/checkSum.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file ttf table校验函数 - * @author mengke01(kekee000@gmail.com) - */ - -function checkSumArrayBuffer(buffer, offset = 0, length) { - length = length == null ? buffer.byteLength : length; - - if (offset + length > buffer.byteLength) { - throw new Error('check sum out of bound'); - } - - const nLongs = Math.floor(length / 4); - const view = new DataView(buffer, offset, length); - let sum = 0; - let i = 0; - - while (i < nLongs) { - sum += view.getUint32(4 * i++, false); - } - - let leftBytes = length - nLongs * 4; - if (leftBytes) { - offset = nLongs * 4; - while (leftBytes > 0) { - sum += view.getUint8(offset, false) << (leftBytes * 8); - offset++; - leftBytes--; - } - } - return sum % 0x100000000; -} - -function checkSumArray(buffer, offset = 0, length) { - length = length || buffer.length; - - if (offset + length > buffer.length) { - throw new Error('check sum out of bound'); - } - - const nLongs = Math.floor(length / 4); - let sum = 0; - let i = 0; - - while (i < nLongs) { - sum += (buffer[i++] << 24) - + (buffer[i++] << 16) - + (buffer[i++] << 8) - + buffer[i++]; - } - - let leftBytes = length - nLongs * 4; - if (leftBytes) { - offset = nLongs * 4; - while (leftBytes > 0) { - sum += buffer[offset] << (leftBytes * 8); - offset++; - leftBytes--; - } - } - return sum % 0x100000000; -} - - -/** - * table校验 - * - * @param {ArrayBuffer|Array} buffer 表数据 - * @param {number=} offset 偏移量 - * @param {number=} length 长度 - * - * @return {number} 校验和 - */ -export default function checkSum(buffer, offset, length) { - if (buffer instanceof ArrayBuffer) { - return checkSumArrayBuffer(buffer, offset, length); - } - else if (buffer instanceof Array) { - return checkSumArray(buffer, offset, length); - } - - throw new Error('not support checksum buffer type'); -} diff --git a/vendor/fonteditor-core/src/ttf/util/compound2simple.js b/vendor/fonteditor-core/src/ttf/util/compound2simple.js deleted file mode 100644 index a0967c1..0000000 --- a/vendor/fonteditor-core/src/ttf/util/compound2simple.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file 复合字形设置轮廓,转化为简单字形 - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 复合字形转简单字形 - * - * @param {Object} glyf glyf对象 - * @param {Array} contours 轮廓数组 - * @return {Object} 转换后对象 - */ -export default function compound2simple(glyf, contours) { - glyf.contours = contours; - delete glyf.compound; - delete glyf.glyfs; - // 这里hinting信息会失效,删除hinting信息 - delete glyf.instructions; - return glyf; -} diff --git a/vendor/fonteditor-core/src/ttf/util/compound2simpleglyf.js b/vendor/fonteditor-core/src/ttf/util/compound2simpleglyf.js deleted file mode 100644 index 1b7bd07..0000000 --- a/vendor/fonteditor-core/src/ttf/util/compound2simpleglyf.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file ttf复合字形转简单字形 - * @author mengke01(kekee000@gmail.com) - */ - - -import transformGlyfContours from './transformGlyfContours'; -import compound2simple from './compound2simple'; - -/** - * ttf复合字形转简单字形 - * - * @param {Object|number} glyf glyf对象或者glyf索引 - * @param {Object} ttf ttfObject对象 - * @param {boolean} recrusive 是否递归的进行转换,如果复合字形为嵌套字形,则转换每一个复合字形 - * @return {Object} 转换后的对象 - */ -export default function compound2simpleglyf(glyf, ttf, recrusive) { - - let glyfIndex; - // 兼容索引和对象传入 - if (typeof glyf === 'number') { - glyfIndex = glyf; - glyf = ttf.glyf[glyfIndex]; - } - else { - glyfIndex = ttf.glyf.indexOf(glyf); - if (-1 === glyfIndex) { - return glyf; - } - } - - if (!glyf.compound || !glyf.glyfs) { - return glyf; - } - - const contoursList = {}; - transformGlyfContours(glyf, ttf, contoursList, glyfIndex); - - if (recrusive) { - Object.keys(contoursList).forEach((index) => { - compound2simple(ttf.glyf[index], contoursList[index]); - }); - } - else { - compound2simple(glyf, contoursList[glyfIndex]); - } - - return glyf; -} diff --git a/vendor/fonteditor-core/src/ttf/util/contour2svg.js b/vendor/fonteditor-core/src/ttf/util/contour2svg.js deleted file mode 100644 index 43dd02f..0000000 --- a/vendor/fonteditor-core/src/ttf/util/contour2svg.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file 将ttf路径转换为svg路径`d` - * @author mengke01(kekee000@gmail.com) - */ - -/** - * 将路径转换为svg路径 - * - * @param {Array} contour 轮廓序列 - * @param {number} precision 精确度 - * @return {string} 路径 - */ -export default function contour2svg(contour, precision = 2) { - if (!contour.length) { - return ''; - } - - const ceil = function (number) { - return +(number).toFixed(precision); - }; - const pathArr = []; - let curPoint; - let prevPoint; - let nextPoint; - let x; // x相对坐标 - let y; // y相对坐标 - for (let i = 0, l = contour.length; i < l; i++) { - curPoint = contour[i]; - prevPoint = i === 0 ? contour[l - 1] : contour[i - 1]; - nextPoint = i === l - 1 ? contour[0] : contour[i + 1]; - - // 起始坐标 - if (i === 0) { - if (curPoint.onCurve) { - x = curPoint.x; - y = curPoint.y; - pathArr.push('M' + ceil(x) + ' ' + ceil(y)); - } - else if (prevPoint.onCurve) { - x = prevPoint.x; - y = prevPoint.y; - pathArr.push('M' + ceil(x) + ' ' + ceil(y)); - } - else { - x = (prevPoint.x + curPoint.x) / 2; - y = (prevPoint.y + curPoint.y) / 2; - pathArr.push('M' + ceil(x) + ' ' + ceil(y)); - } - } - - // 直线 - if (curPoint.onCurve && nextPoint.onCurve) { - pathArr.push('l' + ceil(nextPoint.x - x) - + ' ' + ceil(nextPoint.y - y)); - x = nextPoint.x; - y = nextPoint.y; - } - else if (!curPoint.onCurve) { - if (nextPoint.onCurve) { - pathArr.push('q' + ceil(curPoint.x - x) - + ' ' + ceil(curPoint.y - y) - + ' ' + ceil(nextPoint.x - x) - + ' ' + ceil(nextPoint.y - y)); - x = nextPoint.x; - y = nextPoint.y; - } - else { - const x1 = (curPoint.x + nextPoint.x) / 2; - const y1 = (curPoint.y + nextPoint.y) / 2; - pathArr.push('q' + ceil(curPoint.x - x) - + ' ' + ceil(curPoint.y - y) - + ' ' + ceil(x1 - x) - + ' ' + ceil(y1 - y)); - x = x1; - y = y1; - } - } - } - pathArr.push('Z'); - return pathArr.join(' '); -} diff --git a/vendor/fonteditor-core/src/ttf/util/contours2svg.js b/vendor/fonteditor-core/src/ttf/util/contours2svg.js deleted file mode 100644 index 7797c1b..0000000 --- a/vendor/fonteditor-core/src/ttf/util/contours2svg.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @file 将ttf字形转换为svg路径`d` - * @author mengke01(kekee000@gmail.com) - */ - -import contour2svg from './contour2svg'; - -/** - * contours轮廓转svgpath - * - * @param {Array} contours 轮廓list - * @param {number} precision 精确度 - * @return {string} path字符串 - */ -export default function contours2svg(contours, precision) { - - if (!contours.length) { - return ''; - } - - return contours.map((contour) => contour2svg(contour, precision)).join(''); -} diff --git a/vendor/fonteditor-core/src/ttf/util/glyf2svg.js b/vendor/fonteditor-core/src/ttf/util/glyf2svg.js deleted file mode 100644 index 4984ef0..0000000 --- a/vendor/fonteditor-core/src/ttf/util/glyf2svg.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file glyf转换svg,复合字形轮廓需要ttfObject支持 - * @author mengke01(kekee000@gmail.com) - * - * thanks to: - * ynakajima/ttf.js - * https://github.com/ynakajima/ttf.js - */ - -import contours2svg from './contours2svg'; -import transformGlyfContours from './transformGlyfContours'; - -/** - * glyf转换svg - * - * @param {Object} glyf 解析后的glyf结构 - * @param {Object} ttf ttf对象 - * @return {string} svg文本 - */ -export default function glyf2svg(glyf, ttf) { - - if (!glyf) { - return ''; - } - - const pathArray = []; - - if (!glyf.compound) { - if (glyf.contours && glyf.contours.length) { - pathArray.push(contours2svg(glyf.contours)); - } - - } - else { - const contours = transformGlyfContours(glyf, ttf); - if (contours && contours.length) { - pathArray.push(contours2svg(contours)); - } - } - - return pathArray.join(' '); -} diff --git a/vendor/fonteditor-core/src/ttf/util/glyfAdjust.js b/vendor/fonteditor-core/src/ttf/util/glyfAdjust.js deleted file mode 100644 index 6b19eab..0000000 --- a/vendor/fonteditor-core/src/ttf/util/glyfAdjust.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file glyf的缩放和平移调整 - * @author mengke01(kekee000@gmail.com) - */ - -import pathAdjust from '../../graphics/pathAdjust'; -import pathCeil from '../../graphics/pathCeil'; -import {computePathBox} from '../../graphics/computeBoundingBox'; - - -/** - * 简单字形的缩放和平移调整 - * - * @param {Object} g glyf对象 - * @param {number} scaleX x缩放比例 - * @param {number} scaleY y缩放比例 - * @param {number} offsetX x偏移 - * @param {number} offsetY y偏移 - * @param {boolan} useCeil 是否对字形设置取整,默认取整 - * - * @return {Object} 调整后的glyf对象 - */ -export default function glyfAdjust(g, scaleX = 1, scaleY = 1, offsetX = 0, offsetY = 0, useCeil = true) { - - if (g.contours && g.contours.length) { - if (scaleX !== 1 || scaleY !== 1) { - g.contours.forEach((contour) => { - pathAdjust(contour, scaleX, scaleY); - }); - } - - if (offsetX !== 0 || offsetY !== 0) { - g.contours.forEach((contour) => { - pathAdjust(contour, 1, 1, offsetX, offsetY); - }); - } - - if (false !== useCeil) { - g.contours.forEach((contour) => { - pathCeil(contour); - }); - } - } - - // 重新计算xmin,xmax,ymin,ymax - const advanceWidth = g.advanceWidth; - if ( - undefined === g.xMin - || undefined === g.yMax - || undefined === g.leftSideBearing - || undefined === g.advanceWidth - ) { - // 有的字形没有形状,需要特殊处理一下 - let bound; - if (g.contours && g.contours.length) { - // eslint-disable-next-line no-invalid-this - bound = computePathBox.apply(this, g.contours); - } - else { - bound = { - x: 0, - y: 0, - width: 0, - height: 0 - }; - } - - g.xMin = bound.x; - g.xMax = bound.x + bound.width; - g.yMin = bound.y; - g.yMax = bound.y + bound.height; - - g.leftSideBearing = g.xMin; - - // 如果设置了advanceWidth就是用默认的,否则为xMax + abs(xMin) - if (undefined !== advanceWidth) { - g.advanceWidth = Math.round(advanceWidth * scaleX + offsetX); - } - else { - g.advanceWidth = g.xMax + Math.abs(g.xMin); - } - } - else { - g.xMin = Math.round(g.xMin * scaleX + offsetX); - g.xMax = Math.round(g.xMax * scaleX + offsetX); - g.yMin = Math.round(g.yMin * scaleY + offsetY); - g.yMax = Math.round(g.yMax * scaleY + offsetY); - g.leftSideBearing = Math.round(g.leftSideBearing * scaleX + offsetX); - g.advanceWidth = Math.round(advanceWidth * scaleX + offsetX); - } - - return g; -} diff --git a/vendor/fonteditor-core/src/ttf/util/optimizettf.js b/vendor/fonteditor-core/src/ttf/util/optimizettf.js deleted file mode 100644 index 34d984a..0000000 --- a/vendor/fonteditor-core/src/ttf/util/optimizettf.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file 对ttf对象进行优化,查找错误,去除冗余点 - * @author mengke01(kekee000@gmail.com) - */ - -import reduceGlyf from './reduceGlyf'; -import pathCeil from '../../graphics/pathCeil'; - -/** - * 对ttf对象进行优化 - * - * @param {Object} ttf ttf对象 - * @return {true|Object} 错误信息 - */ -export default function optimizettf(ttf) { - - const checkUnicodeRepeat = {}; // 检查是否有重复代码点 - const repeatList = []; - - ttf.glyf.forEach((glyf, index) => { - if (glyf.unicode) { - glyf.unicode = glyf.unicode.sort(); - - // 将glyf的代码点按小到大排序 - glyf.unicode.sort((a, b) => a - b).forEach((u) => { - if (checkUnicodeRepeat[u]) { - repeatList.push(index); - } - else { - checkUnicodeRepeat[u] = true; - } - }); - - } - - if (!glyf.compound && glyf.contours) { - // 整数化 - glyf.contours.forEach((contour) => { - pathCeil(contour); - }); - // 缩减glyf - reduceGlyf(glyf); - } - - // 整数化 - glyf.xMin = Math.round(glyf.xMin || 0); - glyf.xMax = Math.round(glyf.xMax || 0); - glyf.yMin = Math.round(glyf.yMin || 0); - glyf.yMax = Math.round(glyf.yMax || 0); - glyf.leftSideBearing = Math.round(glyf.leftSideBearing || 0); - glyf.advanceWidth = Math.round(glyf.advanceWidth || 0); - }); - - // 过滤无轮廓字体,如果存在复合字形不进行过滤 - if (!ttf.glyf.some((a) => a.compound)) { - ttf.glyf = ttf.glyf.filter((glyf, index) => index === 0 || glyf.contours && glyf.contours.length); - } - - if (!repeatList.length) { - return true; - } - - return { - repeat: repeatList - }; -} diff --git a/vendor/fonteditor-core/src/ttf/util/otfContours2ttfContours.js b/vendor/fonteditor-core/src/ttf/util/otfContours2ttfContours.js deleted file mode 100644 index 36fce44..0000000 --- a/vendor/fonteditor-core/src/ttf/util/otfContours2ttfContours.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file otf轮廓转ttf轮廓 - * @author mengke01(kekee000@gmail.com) - */ - -import bezierCubic2Q2 from '../../math/bezierCubic2Q2'; -import pathCeil from '../../graphics/pathCeil'; - -/** - * 转换轮廓 - * - * @param {Array} otfContour otf轮廓 - * @return {Array} ttf轮廓 - */ -function transformContour(otfContour) { - const contour = []; - let prevPoint; - let curPoint; - let nextPoint; - let nextNextPoint; - - contour.push(prevPoint = otfContour[0]); - for (let i = 1, l = otfContour.length; i < l; i++) { - curPoint = otfContour[i]; - - if (curPoint.onCurve) { - contour.push(curPoint); - prevPoint = curPoint; - } - // 三次bezier曲线 - else { - nextPoint = otfContour[i + 1]; - nextNextPoint = i === l - 2 ? otfContour[0] : otfContour[i + 2]; - const bezierArray = bezierCubic2Q2(prevPoint, curPoint, nextPoint, nextNextPoint); - bezierArray[0][2].onCurve = true; - contour.push(bezierArray[0][1]); - contour.push(bezierArray[0][2]); - - // 第二个曲线 - if (bezierArray[1]) { - bezierArray[1][2].onCurve = true; - contour.push(bezierArray[1][1]); - contour.push(bezierArray[1][2]); - } - - prevPoint = nextNextPoint; - i += 2; - } - } - - return pathCeil(contour); -} - - -/** - * otf轮廓转ttf轮廓 - * - * @param {Array} otfContours otf轮廓数组 - * @return {Array} ttf轮廓 - */ -export default function otfContours2ttfContours(otfContours) { - if (!otfContours || !otfContours.length) { - return otfContours; - } - const contours = []; - for (let i = 0, l = otfContours.length; i < l; i++) { - - // 这里可能由于转换错误导致空轮廓,需要去除 - if (otfContours[i][0]) { - contours.push(transformContour(otfContours[i])); - } - } - - return contours; -} diff --git a/vendor/fonteditor-core/src/ttf/util/readWindowsAllCodes.js b/vendor/fonteditor-core/src/ttf/util/readWindowsAllCodes.js deleted file mode 100644 index 121a76e..0000000 --- a/vendor/fonteditor-core/src/ttf/util/readWindowsAllCodes.js +++ /dev/null @@ -1,165 +0,0 @@ -/* eslint-disable */ - -/** - * @file 读取windows支持的字符集 - * @author mengke01(kekee000@gmail.com) - * - * @see - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html - */ - -/** - * 读取ttf中windows字符表的字符 - * - * @param {Array} tables cmap表结构 - * @param {Object} ttf ttf对象 - * @return {Object} 字符字典索引,unicode => glyf index - */ -export default function readWindowsAllCodes(tables, ttf) { - - let codes = {}; - - // 读取windows unicode 编码段 - let format0 = tables.find(function (item) { - return item.format === 0; - }); - - // 读取windows unicode 编码段 - let format12 = tables.find(function (item) { - return item.platformID === 3 - && item.encodingID === 10 - && item.format === 12; - }); - - let format4 = tables.find(function (item) { - return item.platformID === 3 - && item.encodingID === 1 - && item.format === 4; - }); - - let format2 = tables.find(function (item) { - return item.platformID === 3 - && item.encodingID === 3 - && item.format === 2; - }); - - let format14 = tables.find(function (item) { - return item.platformID === 0 - && item.encodingID === 5 - && item.format === 14; - }); - - if (format0) { - for (let i = 0, l = format0.glyphIdArray.length; i < l; i++) { - if (format0.glyphIdArray[i]) { - codes[i] = format0.glyphIdArray[i]; - } - } - } - - // format 14 support - if (format14) { - for (let i = 0, l = format14.groups.length; i < l; i++) { - let {unicode, glyphId} = format14.groups[i]; - if (unicode) { - codes[unicode] = glyphId; - } - } - } - - // 读取format12表 - if (format12) { - for (let i = 0, l = format12.nGroups; i < l; i++) { - let group = format12.groups[i]; - let startId = group.startId; - let start = group.start; - let end = group.end; - for (;start <= end;) { - codes[start++] = startId++; - } - } - } - // 读取format4表 - else if (format4) { - let segCount = format4.segCountX2 / 2; - // graphIdArray 和idRangeOffset的偏移量 - let graphIdArrayIndexOffset = (format4.glyphIdArrayOffset - format4.idRangeOffsetOffset) / 2; - - for (let i = 0; i < segCount; ++i) { - // 读取单个字符 - for (let start = format4.startCode[i], end = format4.endCode[i]; start <= end; ++start) { - // range offset = 0 - if (format4.idRangeOffset[i] === 0) { - codes[start] = (start + format4.idDelta[i]) % 0x10000; - } - // rely on to glyphIndexArray - else { - let index = i + format4.idRangeOffset[i] / 2 - + (start - format4.startCode[i]) - - graphIdArrayIndexOffset; - - let graphId = format4.glyphIdArray[index]; - if (graphId !== 0) { - codes[start] = (graphId + format4.idDelta[i]) % 0x10000; - } - else { - codes[start] = 0; - } - - } - } - } - - delete codes[65535]; - } - // 读取format2表 - // see https://github.com/fontforge/fontforge/blob/master/fontforge/parsettf.c - else if (format2) { - let subHeadKeys = format2.subHeadKeys; - let subHeads = format2.subHeads; - let glyphs = format2.glyphs; - let numGlyphs = ttf.maxp.numGlyphs; - let index = 0; - - for (let i = 0; i < 256; i++) { - // 单字节编码 - if (subHeadKeys[i] === 0) { - if (i >= format2.maxPos) { - index = 0; - } - else if (i < subHeads[0].firstCode - || i >= subHeads[0].firstCode + subHeads[0].entryCount - || subHeads[0].idRangeOffset + (i - subHeads[0].firstCode) >= glyphs.length) { - index = 0; - } - else if ((index = glyphs[subHeads[0].idRangeOffset + (i - subHeads[0].firstCode)]) !== 0) { - index = index + subHeads[0].idDelta; - } - - // 单字节解码 - if (index !== 0 && index < numGlyphs) { - codes[i] = index; - } - } - else { - let k = subHeadKeys[i]; - for (let j = 0, entryCount = subHeads[k].entryCount; j < entryCount; j++) { - if (subHeads[k].idRangeOffset + j >= glyphs.length) { - index = 0; - } - else if ((index = glyphs[subHeads[k].idRangeOffset + j]) !== 0) { - index = index + subHeads[k].idDelta; - } - - if (index !== 0 && index < numGlyphs) { - let unicode = ((i << 8) | (j + subHeads[k].firstCode)) % 0xffff; - codes[unicode] = index; - } - - } - } - } - } - - return codes; -} diff --git a/vendor/fonteditor-core/src/ttf/util/reduceGlyf.js b/vendor/fonteditor-core/src/ttf/util/reduceGlyf.js deleted file mode 100644 index 9701cf3..0000000 --- a/vendor/fonteditor-core/src/ttf/util/reduceGlyf.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file 缩减glyf大小,去除冗余节点 - * @author mengke01(kekee000@gmail.com) - */ - -import reducePath from '../../graphics/reducePath'; - -/** - * 缩减glyf,去除冗余节点 - * - * @param {Object} glyf glyf对象 - * @return {Object} glyf对象 - */ -export default function reduceGlyf(glyf) { - - const contours = glyf.contours; - let contour; - for (let j = contours.length - 1; j >= 0; j--) { - contour = reducePath(contours[j]); - - // 空轮廓 - if (contour.length <= 2) { - contours.splice(j, 1); - continue; - } - } - - if (0 === glyf.contours.length) { - delete glyf.contours; - } - - return glyf; -} diff --git a/vendor/fonteditor-core/src/ttf/util/string.js b/vendor/fonteditor-core/src/ttf/util/string.js deleted file mode 100644 index d1a8ffc..0000000 --- a/vendor/fonteditor-core/src/ttf/util/string.js +++ /dev/null @@ -1,207 +0,0 @@ -/** - * @file ttf字符串相关函数 - * @author mengke01(kekee000@gmail.com) - * - * references: - * 1. svg2ttf @ github - */ - -import unicodeName from '../enum/unicodeName'; -import postName from '../enum/postName'; - -/** - * 将unicode编码转换成js内部编码, - * 有时候单子节的字符会编码成类似`\u0020`, 这里还原单字节 - * - * @param {string} str str字符串 - * @return {string} 转换后字符串 - */ -function stringify(str) { - if (!str) { - return str; - } - - let newStr = ''; - for (let i = 0, l = str.length, ch; i < l; i++) { - ch = str.charCodeAt(i); - if (ch === 0) { - continue; - } - newStr += String.fromCharCode(ch); - } - return newStr; -} - -export default { - - stringify, - - /** - * 将双字节编码字符转换成`\uxxxx`形式 - * - * @param {string} str str字符串 - * @return {string} 转换后字符串 - */ - escape(str) { - if (!str) { - return str; - } - return String(str).replace(/[\uff-\uffff]/g, c => escape(c).replace('%', '\\')); - }, - - /** - * bytes to string - * - * @param {Array} bytes 字节数组 - * @return {string} string - */ - getString(bytes) { - let s = ''; - for (let i = 0, l = bytes.length; i < l; i++) { - s += String.fromCharCode(bytes[i]); - } - return s; - }, - - /** - * 获取unicode的名字值 - * - * @param {number} unicode unicode - * @return {string} 名字 - */ - getUnicodeName(unicode) { - const unicodeNameIndex = unicodeName[unicode]; - if (undefined !== unicodeNameIndex) { - return postName[unicodeNameIndex]; - } - - return 'uni' + unicode.toString(16).toUpperCase(); - }, - - /** - * 转换成utf8的字节数组 - * - * @param {string} str 字符串 - * @return {Array.} 字节数组 - */ - toUTF8Bytes(str) { - str = stringify(str); - const byteArray = []; - for (let i = 0, l = str.length; i < l; i++) { - if (str.charCodeAt(i) <= 0x7F) { - byteArray.push(str.charCodeAt(i)); - } - else { - const codePoint = str.codePointAt(i); - if (codePoint > 0xffff) { - i++; - } - const h = encodeURIComponent(String.fromCodePoint(codePoint)).slice(1).split('%'); - for (let j = 0; j < h.length; j++) { - byteArray.push(parseInt(h[j], 16)); - } - } - } - return byteArray; - }, - - /** - * 转换成usc2的字节数组 - * - * @param {string} str 字符串 - * @return {Array.} 字节数组 - */ - toUCS2Bytes(str) { - str = stringify(str); - const byteArray = []; - - for (let i = 0, l = str.length, ch; i < l; i++) { - ch = str.charCodeAt(i); - byteArray.push(ch >> 8); - byteArray.push(ch & 0xFF); - } - - return byteArray; - }, - - - /** - * 获取pascal string 字节数组 - * - * @param {string} str 字符串 - * @return {Array.} byteArray byte数组 - */ - toPascalStringBytes(str) { - const bytes = []; - const length = str ? (str.length < 256 ? str.length : 255) : 0; - bytes.push(length); - - for (let i = 0, l = str.length; i < l; i++) { - const c = str.charCodeAt(i); - // non-ASCII characters are substituted with '*' - bytes.push(c < 128 ? c : 42); - } - - return bytes; - }, - - /** - * utf8字节转字符串 - * - * @param {Array} bytes 字节 - * @return {string} 字符串 - */ - getUTF8String(bytes) { - let str = ''; - for (let i = 0, l = bytes.length; i < l; i++) { - if (bytes[i] < 0x7F) { - str += String.fromCharCode(bytes[i]); - } - else { - str += '%' + (256 + bytes[i]).toString(16).slice(1); - } - } - - return unescape(str); - }, - - /** - * ucs2字节转字符串 - * - * @param {Array} bytes 字节 - * @return {string} 字符串 - */ - getUCS2String(bytes) { - let str = ''; - for (let i = 0, l = bytes.length; i < l; i += 2) { - str += String.fromCharCode((bytes[i] << 8) + bytes[i + 1]); - } - return str; - }, - - /** - * 读取 pascal string - * - * @param {Array.} byteArray byte数组 - * @return {Array.} 读取后的字符串数组 - */ - getPascalString(byteArray) { - const strArray = []; - let i = 0; - const l = byteArray.length; - - while (i < l) { - let strLength = byteArray[i++]; - let str = ''; - - while (strLength-- > 0 && i < l) { - str += String.fromCharCode(byteArray[i++]); - } - // 这里需要将unicode转换成js编码 - str = stringify(str); - strArray.push(str); - } - - return strArray; - } -}; diff --git a/vendor/fonteditor-core/src/ttf/util/transformGlyfContours.js b/vendor/fonteditor-core/src/ttf/util/transformGlyfContours.js deleted file mode 100644 index 943ed5f..0000000 --- a/vendor/fonteditor-core/src/ttf/util/transformGlyfContours.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file 转换复合字形的contours,以便于显示 - * @author mengke01(kekee000@gmail.com) - */ - -import pathCeil from '../../graphics/pathCeil'; -import pathTransform from '../../graphics/pathTransform'; -import {clone} from '../../common/lang'; - - -/** - * 转换复合字形轮廓,结果保存在contoursList中,并返回当前glyf的轮廓 - * - * @param {Object} glyf glyf对象 - * @param {Object} ttf ttfObject对象 - * @param {Object=} contoursList 保存转换中间生成的contours - * @param {number} glyfIndex glyf对象当前的index - * @return {Array} 转换后的轮廓 - */ -export default function transformGlyfContours(glyf, ttf, contoursList = {}, glyfIndex) { - - if (!glyf.glyfs) { - return glyf; - } - - const compoundContours = []; - glyf.glyfs.forEach(g => { - const glyph = ttf.glyf[g.glyphIndex]; - - if (!glyph || glyph === glyf) { - return; - } - - // 递归转换contours - if (glyph.compound && !contoursList[g.glyphIndex]) { - transformGlyfContours(glyph, ttf, contoursList, g.glyphIndex); - } - - // 这里需要进行matrix变换,需要复制一份 - const contours = clone(glyph.compound ? (contoursList[g.glyphIndex] || []) : glyph.contours); - const transform = g.transform; - for (let i = 0, l = contours.length; i < l; i++) { - pathTransform( - contours[i], - transform.a, - transform.b, - transform.c, - transform.d, - transform.e, - transform.f - ); - compoundContours.push(pathCeil(contours[i])); - } - }); - - // eslint-disable-next-line eqeqeq - if (null != glyfIndex) { - contoursList[glyfIndex] = compoundContours; - } - - return compoundContours; -} diff --git a/vendor/fonteditor-core/src/ttf/util/unicode2xml.js b/vendor/fonteditor-core/src/ttf/util/unicode2xml.js deleted file mode 100644 index 26b53e4..0000000 --- a/vendor/fonteditor-core/src/ttf/util/unicode2xml.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file unicode字符转xml字符编码 - * @author mengke01(kekee000@gmail.com) - */ -import string from '../../common/string'; - -/** - * unicode 转xml编码格式 - * - * @param {Array.} unicodeList unicode字符列表 - * @return {string} xml编码格式 - */ -export default function unicode2xml(unicodeList) { - if (typeof unicodeList === 'number') { - unicodeList = [unicodeList]; - } - return unicodeList.map(u => { - if (u < 0x20) { - return ''; - } - return u >= 0x20 && u <= 255 - ? string.encodeHTML(String.fromCharCode(u)) - : '&#x' + u.toString(16) + ';'; - }).join(''); -} diff --git a/vendor/fonteditor-core/src/ttf/woff2base64.js b/vendor/fonteditor-core/src/ttf/woff2base64.js deleted file mode 100644 index 9baddb5..0000000 --- a/vendor/fonteditor-core/src/ttf/woff2base64.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file woff数组转base64编码 - * @author mengke01(kekee000@gmail.com) - */ - -import bytes2base64 from './util/bytes2base64'; - -/** - * woff数组转base64编码 - * - * @param {Array} arrayBuffer ArrayBuffer对象 - * @return {string} base64编码 - */ -export default function woff2base64(arrayBuffer) { - return 'data:font/woff;charset=utf-8;base64,' + bytes2base64(arrayBuffer); -} diff --git a/vendor/fonteditor-core/src/ttf/woff2tobase64.js b/vendor/fonteditor-core/src/ttf/woff2tobase64.js deleted file mode 100644 index e76dd0d..0000000 --- a/vendor/fonteditor-core/src/ttf/woff2tobase64.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file woff2数组转base64编码 - * @author mengke01(kekee000@gmail.com) - */ - -import bytes2base64 from './util/bytes2base64'; - -/** - * woff数组转base64编码 - * - * @param {Array} arrayBuffer ArrayBuffer对象 - * @return {string} base64编码 - */ -export default function woff2tobase64(arrayBuffer) { - return 'data:font/woff2;charset=utf-8;base64,' + bytes2base64(arrayBuffer); -} diff --git a/vendor/fonteditor-core/src/ttf/woff2tottf.js b/vendor/fonteditor-core/src/ttf/woff2tottf.js deleted file mode 100644 index efc1044..0000000 --- a/vendor/fonteditor-core/src/ttf/woff2tottf.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file woff2 to ttf - * @author mengke01(kekee000@gmail.com) - */ -import woff2 from '../../woff2/index'; - - -/** - * ttf格式转换成woff2字体格式 - * - * @param {ArrayBuffer} woff2Buffer ttf缓冲数组 - * @param {Object} options 选项 - * - * @return {ArrayBuffer} woff格式byte流 - */ -// eslint-disable-next-line no-unused-vars -export default function woff2tottf(woff2Buffer, options = {}) { - if (!woff2.isInited()) { - throw new Error('use woff2.init() to init woff2 module!'); - } - const result = woff2.decode(woff2Buffer); - return result.buffer; -} - -/** - * ttf格式转换成woff2字体格式 - * - * @param {ArrayBuffer} woff2Buffer ttf缓冲数组 - * @param {Object} options 选项 - * - * @return {Promise.} woff格式byte流 - */ -export function woff2tottfasync(woff2Buffer, options = {}) { - return woff2.init(options.wasmUrl).then(() => { - const result = woff2.decode(woff2Buffer); - return result.buffer; - }); -} diff --git a/vendor/fonteditor-core/src/ttf/woff2ttf.js b/vendor/fonteditor-core/src/ttf/woff2ttf.js deleted file mode 100644 index a63aadf..0000000 --- a/vendor/fonteditor-core/src/ttf/woff2ttf.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @file woff转换ttf - * @author mengke01(kekee000@gmail.com) - */ - -import Reader from './reader'; -import Writer from './writer'; -import error from './error'; - -/** - * woff格式转换成ttf字体格式 - * - * @param {ArrayBuffer} woffBuffer woff缓冲数组 - * @param {Object} options 选项 - * @param {Object} options.inflate 解压相关函数 - * - * @return {ArrayBuffer} ttf格式byte流 - */ -export default function woff2ttf(woffBuffer, options = {}) { - const reader = new Reader(woffBuffer); - const signature = reader.readUint32(0); - const flavor = reader.readUint32(4); - - if (signature !== 0x774F4646 || (flavor !== 0x10000 && flavor !== 0x4f54544f)) { - reader.dispose(); - error.raise(10102); - } - - const numTables = reader.readUint16(12); - const ttfSize = reader.readUint32(16); - const tableEntries = []; - let tableEntry; - let i; - let l; - - // 读取woff表索引信息 - for (i = 0; i < numTables; ++i) { - reader.seek(44 + i * 20); - tableEntry = { - tag: reader.readString(reader.offset, 4), - offset: reader.readUint32(), - compLength: reader.readUint32(), - length: reader.readUint32(), - checkSum: reader.readUint32() - }; - - // ttf 表数据 - const deflateData = reader.readBytes(tableEntry.offset, tableEntry.compLength); - // 需要解压 - if (deflateData.length < tableEntry.length) { - - if (!options.inflate) { - reader.dispose(); - error.raise(10105); - } - - tableEntry.data = options.inflate(deflateData); - } - else { - tableEntry.data = deflateData; - } - - tableEntry.length = tableEntry.data.length; - tableEntries.push(tableEntry); - } - - - const writer = new Writer(new ArrayBuffer(ttfSize)); - // 写头部 - const entrySelector = Math.floor(Math.log(numTables) / Math.LN2); - const searchRange = Math.pow(2, entrySelector) * 16; - const rangeShift = numTables * 16 - searchRange; - - writer.writeUint32(flavor); - writer.writeUint16(numTables); - writer.writeUint16(searchRange); - writer.writeUint16(entrySelector); - writer.writeUint16(rangeShift); - - // 写ttf表索引 - let tblOffset = 12 + 16 * tableEntries.length; - for (i = 0, l = tableEntries.length; i < l; ++i) { - tableEntry = tableEntries[i]; - writer.writeString(tableEntry.tag); - writer.writeUint32(tableEntry.checkSum); - writer.writeUint32(tblOffset); - writer.writeUint32(tableEntry.length); - tblOffset += tableEntry.length - + (tableEntry.length % 4 ? 4 - tableEntry.length % 4 : 0); - } - - // 写ttf表数据 - for (i = 0, l = tableEntries.length; i < l; ++i) { - tableEntry = tableEntries[i]; - writer.writeBytes(tableEntry.data); - if (tableEntry.length % 4) { - writer.writeEmpty(4 - tableEntry.length % 4); - } - } - - return writer.getBuffer(); -} diff --git a/vendor/fonteditor-core/src/ttf/writer.js b/vendor/fonteditor-core/src/ttf/writer.js deleted file mode 100644 index 6b438a4..0000000 --- a/vendor/fonteditor-core/src/ttf/writer.js +++ /dev/null @@ -1,306 +0,0 @@ -/** - * @file 数据写入器 - * @author mengke01(kekee000@gmail.com) - */ - -import {curry} from '../common/lang'; -import error from './error'; - -// 检查数组支持情况 -if (typeof ArrayBuffer === 'undefined' || typeof DataView === 'undefined') { - throw new Error('not support ArrayBuffer and DataView'); -} - -// 数据类型 -const dataType = { - Int8: 1, - Int16: 2, - Int32: 4, - Uint8: 1, - Uint16: 2, - Uint32: 4, - Float32: 4, - Float64: 8 -}; - - -/** - * 读取器 - * - * @constructor - * @param {Array.} buffer 缓冲数组 - * @param {number} offset 起始偏移 - * @param {number=} length 数组长度 - * @param {boolean=} littleEndian 是否小尾 - */ -class Writer { - constructor(buffer, offset, length, littleEndian) { - const bufferLength = buffer.byteLength || buffer.length; - this.offset = offset || 0; - this.length = length || (bufferLength - this.offset); - this.littleEndian = littleEndian || false; - this.view = new DataView(buffer, this.offset, this.length); - } - - /** - * 读取指定的数据类型 - * - * @param {string} type 数据类型 - * @param {number} value value值 - * @param {number=} offset 位移 - * @param {boolean=} littleEndian 是否小尾 - * - * @return {this} - */ - write(type, value, offset, littleEndian) { - - // 使用当前位移 - if (undefined === offset) { - offset = this.offset; - } - - // 使用小尾 - if (undefined === littleEndian) { - littleEndian = this.littleEndian; - } - - // 扩展方法 - if (undefined === dataType[type]) { - return this['write' + type](value, offset, littleEndian); - } - - const size = dataType[type]; - this.offset = offset + size; - this.view['set' + type](offset, value, littleEndian); - return this; - } - - /** - * 写入指定的字节数组 - * - * @param {ArrayBuffer} value 写入值 - * @param {number=} length 数组长度 - * @param {number=} offset 起始偏移 - * @return {this} - */ - writeBytes(value, length, offset) { - - length = length || value.byteLength || value.length; - let i; - - if (!length) { - return this; - } - - if (undefined === offset) { - offset = this.offset; - } - - if (length < 0 || offset + length > this.length) { - error.raise(10002, this.length, offset + length); - } - - const littleEndian = this.littleEndian; - if (value instanceof ArrayBuffer) { - const view = new DataView(value, 0, length); - for (i = 0; i < length; ++i) { - this.view.setUint8(offset + i, view.getUint8(i, littleEndian), littleEndian); - } - } - else { - for (i = 0; i < length; ++i) { - this.view.setUint8(offset + i, value[i], littleEndian); - } - } - - this.offset = offset + length; - - return this; - } - - /** - * 写空数据 - * - * @param {number} length 长度 - * @param {number=} offset 起始偏移 - * @return {this} - */ - writeEmpty(length, offset) { - - if (length < 0) { - error.raise(10002, this.length, length); - } - - if (undefined === offset) { - offset = this.offset; - } - - const littleEndian = this.littleEndian; - for (let i = 0; i < length; ++i) { - this.view.setUint8(offset + i, 0, littleEndian); - } - - this.offset = offset + length; - - return this; - } - - /** - * 写入一个string - * - * @param {string} str 字符串 - * @param {number=} length 长度 - * @param {number=} offset 偏移 - * - * @return {this} - */ - writeString(str = '', length, offset) { - - if (undefined === offset) { - offset = this.offset; - } - - // eslint-disable-next-line no-control-regex - length = length || str.replace(/[^\x00-\xff]/g, '11').length; - - if (length < 0 || offset + length > this.length) { - error.raise(10002, this.length, offset + length); - } - - this.seek(offset); - - for (let i = 0, l = str.length, charCode; i < l; ++i) { - charCode = str.charCodeAt(i) || 0; - if (charCode > 127) { - // unicode编码可能会超出2字节, - // 写入与编码有关系,此处不做处理 - this.writeUint16(charCode); - } - else { - this.writeUint8(charCode); - } - } - - this.offset = offset + length; - - return this; - } - - /** - * 写入一个字符 - * - * @param {string} value 字符 - * @param {number=} offset 偏移 - * @return {this} - */ - writeChar(value, offset) { - return this.writeString(value, offset); - } - - /** - * 写入fixed类型 - * - * @param {number} value 写入值 - * @param {number=} offset 偏移 - * @return {number} float - */ - writeFixed(value, offset) { - if (undefined === offset) { - offset = this.offset; - } - this.writeInt32(Math.round(value * 65536), offset); - - return this; - } - - /** - * 写入长日期 - * - * @param {Date} value 日期对象 - * @param {number=} offset 偏移 - * - * @return {Date} Date对象 - */ - writeLongDateTime(value, offset) { - - if (undefined === offset) { - offset = this.offset; - } - - // new Date(1970, 1, 1).getTime() - new Date(1904, 1, 1).getTime(); - const delta = -2077545600000; - - if (typeof value === 'undefined') { - value = delta; - } - else if (typeof value.getTime === 'function') { - value = value.getTime(); - } - else if (/^\d+$/.test(value)) { - value = +value; - } - else { - value = Date.parse(value); - } - - const time = Math.round((value - delta) / 1000); - this.writeUint32(0, offset); - this.writeUint32(time, offset + 4); - - return this; - } - - /** - * 跳转到指定偏移 - * - * @param {number=} offset 偏移 - * @return {this} - */ - seek(offset) { - if (undefined === offset) { - this.offset = 0; - } - - if (offset < 0 || offset > this.length) { - error.raise(10002, this.length, offset); - } - - this._offset = this.offset; - this.offset = offset; - - return this; - } - - /** - * 跳转到写入头部位置 - * - * @return {this} - */ - head() { - this.offset = this._offset || 0; - return this; - } - - /** - * 获取缓存的byte数组 - * - * @return {ArrayBuffer} - */ - getBuffer() { - return this.view.buffer; - } - - /** - * 注销 - */ - dispose() { - delete this.view; - } -} - -// 直接支持的数据类型 -Object.keys(dataType).forEach(type => { - Writer.prototype['write' + type] = curry(Writer.prototype.write, type); -}); - -export default Writer; diff --git a/verify_font.ts b/verify_font.ts index 3c630bd..f719aaf 100644 --- a/verify_font.ts +++ b/verify_font.ts @@ -10,7 +10,7 @@ * 2. 渲染相似度对比(skia-canvas 渲染,SSIM 相似度阈值) */ import { readFile, writeFile, mkdir } from "node:fs/promises"; -import { Font } from "fonteditor-core"; +import { Font } from "./vendor/fonteditor-core/lib/ttf/font.js"; import { Canvas, FontLibrary } from "skia-canvas"; const isBaseline = process.argv[2] === "baseline"; @@ -96,15 +96,25 @@ function calculateSSIM(a: Uint8Array, b: Uint8Array): number { function extractFontData(font: any) { const d = font.data; const glyf = d.glyf.map((g: any, i: number) => { - const contourHeads = g.contours - ? g.contours.map((c: any[]) => - c.slice(0, 3).map((p: any) => [p.x, p.y, !!p.onCurve]) - ) - : []; + /** 兼容扁平格式 [x,y,onCurve,...] 和对象格式 [{x,y,onCurve},...] */ + const toPoints = (c: any[]) => { + if (!c || !c.length) return []; + if (typeof c[0] === "number") { + const pts: [number, number, boolean][] = []; + for (let k = 0; k < c.length; k += 3) pts.push([c[k], c[k + 1], !!c[k + 2]]); + return pts; + } + return c.slice(0, 3).map((p: any) => [p.x, p.y, !!p.onCurve] as [number, number, boolean]); + }; + const contourHeads = g.contours ? g.contours.map(toPoints) : []; + const pointCount = (c: any[]) => { + if (!c || !c.length) return 0; + return typeof c[0] === "number" ? c.length / 3 : c.length; + }; return { index: i, contours: g.contours?.length || 0, - pts: g.contours ? g.contours.reduce((s: number, c: any[]) => s + c.length, 0) : 0, + pts: g.contours ? g.contours.reduce((s: number, c: any[]) => s + pointCount(c), 0) : 0, compound: !!g.compound, unicode: g.unicode ? [...g.unicode].sort((a: number, b: number) => a - b) : [], advanceWidth: g.advanceWidth, diff --git a/基准测试.test.ts b/基准测试.test.ts index 64a4768..51e3bba 100644 --- a/基准测试.test.ts +++ b/基准测试.test.ts @@ -9,7 +9,7 @@ */ import { readFile, writeFile, mkdir } from "node:fs/promises"; import { performance } from "node:perf_hooks"; -import { Font } from "fonteditor-core"; +import { Font } from "./vendor/fonteditor-core/lib/ttf/font.js"; import { Canvas, FontLibrary } from "skia-canvas"; const FONT_PATH = "font/令东齐伋复刻体.ttf";