diff --git a/package-lock.json b/package-lock.json index 22dc508..b19d602 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@makeitaquote/utils": "^1.2.1", - "@napi-rs/canvas": ">=1.0.8 <1.0.12", + "@napi-rs/canvas": "^1.0.13", "@twemoji/parser": "^17.0.2", "budoux": "^0.9.1", "cleye": "^2.6.0", @@ -316,9 +316,9 @@ "license": "MIT AND CC-BY-4.0 AND Unicode-3.0" }, "node_modules/@napi-rs/canvas": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-1.0.8.tgz", - "integrity": "sha512-/SaLcvlqGWdm0HSCWMgHu7cjJiQXfP8/mOY+6dUyV9flQz7sPBBZ+ed2zYtoukojPmxOaL7bm+d/G4GeWWoN7g==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-1.0.13.tgz", + "integrity": "sha512-b87ugZpQ5ViwqVBkjervxpwa0GmJPsKHLBNoZN6GpjWeHzTbDUGryriq+2DYW2XbB+xCqSIINQysC0/I87nPbw==", "license": "MIT", "workspaces": [ "e2e/*" @@ -331,23 +331,23 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "1.0.8", - "@napi-rs/canvas-darwin-arm64": "1.0.8", - "@napi-rs/canvas-darwin-x64": "1.0.8", - "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.8", - "@napi-rs/canvas-linux-arm64-gnu": "1.0.8", - "@napi-rs/canvas-linux-arm64-musl": "1.0.8", - "@napi-rs/canvas-linux-riscv64-gnu": "1.0.8", - "@napi-rs/canvas-linux-x64-gnu": "1.0.8", - "@napi-rs/canvas-linux-x64-musl": "1.0.8", - "@napi-rs/canvas-win32-arm64-msvc": "1.0.8", - "@napi-rs/canvas-win32-x64-msvc": "1.0.8" + "@napi-rs/canvas-android-arm64": "1.0.13", + "@napi-rs/canvas-darwin-arm64": "1.0.13", + "@napi-rs/canvas-darwin-x64": "1.0.13", + "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.13", + "@napi-rs/canvas-linux-arm64-gnu": "1.0.13", + "@napi-rs/canvas-linux-arm64-musl": "1.0.13", + "@napi-rs/canvas-linux-riscv64-gnu": "1.0.13", + "@napi-rs/canvas-linux-x64-gnu": "1.0.13", + "@napi-rs/canvas-linux-x64-musl": "1.0.13", + "@napi-rs/canvas-win32-arm64-msvc": "1.0.13", + "@napi-rs/canvas-win32-x64-msvc": "1.0.13" } }, "node_modules/@napi-rs/canvas-android-arm64": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.8.tgz", - "integrity": "sha512-5+nkh8i3gt6lqS/d2jTZ1xAn6tdgtB4Lf1mW6T0Qm5/rXNwBuV1sAEyLEWan5o9gJPU/GuvHR3rvSeZ+FaGrbw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.13.tgz", + "integrity": "sha512-trn7AaDzQ+yeeA0ezhkC7cB1ZDPtp4UYk0EvB5F8qtYL9jEVWtVrU30WOpI52DszoTxaTsCgf5PP4ZVaOlOIHQ==", "cpu": [ "arm64" ], @@ -365,9 +365,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.8.tgz", - "integrity": "sha512-7jQ47gi+fZ7KJmfc/5rNyy1CYw/cu4kZ0KPIYbo9UUgSdW0bKQJpt+WihEor6s4Lyp7+xc3a+3HeyXmAEbbnPg==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.13.tgz", + "integrity": "sha512-6Y2djEetL8copxfNK6hg7oig/xqTwOchv19hBOm+zBNdKc/02Z3kjZN5wrLzv/l5O04/bAQS6I/AlQpwBlXgPg==", "cpu": [ "arm64" ], @@ -385,9 +385,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.8.tgz", - "integrity": "sha512-rRjDMZs9pIRKGxgijwezplKc1RnJsqUokrA9h88bbTkqQ+7ePj0ZN4ZnZDy8Vu0tXs7KRlI2tQLaK4mx9QlxHg==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.13.tgz", + "integrity": "sha512-OZoPwwu4TMMg8GTCFBrg8UFExwQTU/55i3uTC/izDat6PHE+ro9dimyQoOboFf91+NY7Pnn70ScR8f8I8+eZXw==", "cpu": [ "x64" ], @@ -405,9 +405,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.8.tgz", - "integrity": "sha512-jGcCd+8ra6Q61xKqZeiItujTpp9a9eRLcQ0jW6qYNku+WpupqOPFPY0SrsuSnXFviJwkpKYT9p7QrB4lsf3LNQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.13.tgz", + "integrity": "sha512-dZSYaKROuswU2eUWG5aBKndNVe68elo1YX93xtRax7q658tj8rYE+HwduovWJgs6qwv1r1/CLR60nDeBbyjvyg==", "cpu": [ "arm" ], @@ -425,12 +425,15 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.8.tgz", - "integrity": "sha512-od6I2Y7kU7i1SwZYG2EKW8rWz6JiedtPpko4WEe1DDsiikrfaotVBCRaUTM5/yeZKaZ92EatoAS+5xG+6uJlYA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.13.tgz", + "integrity": "sha512-W6FzYE8ADHI93In1vi80KBL6btDtAMuj50Ch5ptkWS8xuntyzbR4h5JDUmXoakxZn2yMInksudTEqVSWoFqFGg==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -445,12 +448,15 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.8.tgz", - "integrity": "sha512-yYkPbJDJiWj6N0gASA3CAvRypZmVpJnxU0DQg3aBhneLDQde9TPLKADsQkobNoJUtTT/lj46aWpzT48PDb3Qcg==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.13.tgz", + "integrity": "sha512-+6fQ+rR49hkAa4voh2stLIwQ+4t+gmoseM8Bc53/DlMXb73IKymDPWK9A/NtWeqTW4ijWppYuyuxS2hPI8tzNA==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -465,12 +471,15 @@ } }, "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.8.tgz", - "integrity": "sha512-PB00MSKAp4VwK/xwe6duKxRKmH8UH4GIl1pqHSbxng0jnU9Dr7FwaDypDiqwNFZ774N+8G7mJLGuLtg9NTcQsg==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.13.tgz", + "integrity": "sha512-17XEMO3t9RW/TtHtSFf2AkaSWuCWdzbPeidz7zrOFawHxoLSJCnpTI1hN5aUvrZNnkNNmt/vZVJCh0ryUaik3A==", "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -485,12 +494,15 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.8.tgz", - "integrity": "sha512-TWM2XWJoitLiIPCvgJh7SriC+L/T9qkYCVzC66AidsZy0QP1hkKzBzVwshCdcA3q6fIn3yE0ISbq4lMJSy8jFw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.13.tgz", + "integrity": "sha512-lc48IwknVHBsNzXn9Xs5OkUsRX38Ml3Z1aOybQ51mMEzZckm8+4A0qROlyYHEoBPzr1kL3IU8ZUAqDb7wtdX8w==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -505,12 +517,15 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.8.tgz", - "integrity": "sha512-hb20MxKXXb5IB7AAwN8UHz9WRsa2HmdZfjsDCzjElwJoeV1aotVEwFU4FrFQcYQVzsJQLeaCc/2Qdt/0Q72mMg==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.13.tgz", + "integrity": "sha512-bGY1r26S2bs8UNFJcPWcCSNdCFbKep5PATsvtgtC9A5u6SRgr2/jJE/RlhHL5m9ZpixNDhVkLY/5h16Kx5V9YA==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -525,9 +540,9 @@ } }, "node_modules/@napi-rs/canvas-win32-arm64-msvc": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.8.tgz", - "integrity": "sha512-WwPN08IXE4SkL+FhJyPz/iFnycMAUkbphFIT4cmKLlvbSU0Zfn1R7BGJ3Hqky1S89QUYc0Q4IOScXb/42Re9wQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.13.tgz", + "integrity": "sha512-2vRPBZoaIvJrUkDhZTE2Hn0YrnpJRCWVM3EJACoBKjuWI6WgPxGtUoRMsxRviCsyks8bKTSFdyw14CellnG2qA==", "cpu": [ "arm64" ], @@ -545,9 +560,9 @@ } }, "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.8.tgz", - "integrity": "sha512-XkrVqKb+pxyba7kjy2LJvABFVBTE0DNpEl7MrG4OYUmaWarrXH+t54z/Czj2YxCKtizYTV4mg6phNm3x24qjhQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.13.tgz", + "integrity": "sha512-DUlW3lZPz63kYsf8mxgyyZuevhlH0T3/BGP9l+NazhB0F1+gL6D4hqZdnhZpw24DlWmTpATDcyYSZlJOi+DdfQ==", "cpu": [ "x64" ], diff --git a/package.json b/package.json index 3d03d07..e455fc6 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ }, "dependencies": { "@makeitaquote/utils": "^1.2.1", - "@napi-rs/canvas": ">=1.0.8 <1.0.12", + "@napi-rs/canvas": "^1.0.13", "@twemoji/parser": "^17.0.2", "budoux": "^0.9.1", "cleye": "^2.6.0", diff --git a/src/render/layout.test.ts b/src/render/layout.test.ts index 54327c1..ec36640 100644 --- a/src/render/layout.test.ts +++ b/src/render/layout.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest' import { defineTheme } from '../theme/resolve' +import { createCanvas } from './canvasFactory' import { autoArea, computeLayout, cssFontFamily, fontString, gradientLine } from './layout' describe('computeLayout · side', () => { @@ -196,3 +197,21 @@ describe('cssFontFamily', () => { expect(cssFontFamily(' Noto Sans JP ,, sans-serif ')).toBe('"Noto Sans JP", sans-serif') }) }) + +describe('fontString on a real canvas', () => { + // A ctx.font value the parser rejects is silently ignored, so read it back: any family name a user or the catalogue can supply must stick. + it.each([ + 'M PLUS Rounded 1c, Noto Sans JP, sans-serif', + 'M PLUS 1p', + 'DotGothic16', + "O'Brien Sans", + '2nd Custom Font', + 'sans-serif', + ])('is accepted by ctx.font for %s', (family) => { + const ctx = createCanvas(1, 1).getContext('2d') + ctx.font = '7px serif' + ctx.font = fontString('bold', 32, family, true) + expect(ctx.font).not.toBe('7px serif') + expect(ctx.font).toContain('32px') + }) +}) diff --git a/src/render/textStyle.ts b/src/render/textStyle.ts index c47c5ac..40aea6d 100644 --- a/src/render/textStyle.ts +++ b/src/render/textStyle.ts @@ -24,7 +24,7 @@ export function resolvedWeight(base: FontWeight, bold: boolean | undefined): Fon /** * Families whose bold is faked, keyed by family name. * - * Variable fonts registered through `GlobalFonts` — including the Noto Sans JP this package downloads — expose only their default instance to Skia, so `ctx.font = 'bold …'` measures and draws identically to regular. Detected once per family by measuring both. + * A family registered with only its regular face — common for fonts registered at runtime — has no bold to switch to, so `ctx.font = 'bold …'` measures and draws identically to regular. Detected once per family by measuring both. (Variable fonts such as the Noto Sans JP this package downloads honour their weight axis since `@napi-rs/canvas` 1.0.12, so they detect as real bold.) */ const syntheticFamilies = new Map()