ntk 8.17.5 → 8.17.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/fontconfig.js +9 -6
- package/lib/text/fontsource.js +22 -12
- package/package.json +1 -1
package/lib/fontconfig.js
CHANGED
|
@@ -479,15 +479,18 @@ function slantRank(italic, [lo, hi]) {
|
|
|
479
479
|
// Weight, for `weight` asked: between 400 and 500, up to 500 ascending, then
|
|
480
480
|
// lighter descending, then past 500 ascending; below 400 lighter first, above
|
|
481
481
|
// 500 heavier first. A variable face's range holds every weight in it.
|
|
482
|
-
|
|
482
|
+
// `regular` and `medium` are 400 and 500 on the scale the weights are on —
|
|
483
|
+
// fontconfig's here, CSS's in StaticFontSource, where an OS/2 weight class can
|
|
484
|
+
// be anything up to 65535 and so each direction is a million past the last.
|
|
485
|
+
export function weightRank(weight, [lo, hi], regular = REGULAR, medium = MEDIUM) {
|
|
483
486
|
if (lo <= weight && hi >= weight) return 0;
|
|
484
487
|
const x = hi < weight ? hi : lo;
|
|
485
|
-
if (weight >=
|
|
486
|
-
if (x > weight && x <=
|
|
487
|
-
return x < weight ?
|
|
488
|
+
if (weight >= regular && weight <= medium) {
|
|
489
|
+
if (x > weight && x <= medium) return x - weight;
|
|
490
|
+
return x < weight ? 1e6 + weight - x : 2e6 + x - weight;
|
|
488
491
|
}
|
|
489
|
-
if (weight <
|
|
490
|
-
return x > weight ? x - weight :
|
|
492
|
+
if (weight < regular) return x < weight ? weight - x : 1e6 + x - weight;
|
|
493
|
+
return x > weight ? x - weight : 1e6 + weight - x;
|
|
491
494
|
}
|
|
492
495
|
|
|
493
496
|
/**
|
package/lib/text/fontsource.js
CHANGED
|
@@ -54,7 +54,8 @@ import {
|
|
|
54
54
|
noFontsError,
|
|
55
55
|
prewarmFaces,
|
|
56
56
|
prewarmPatterns,
|
|
57
|
-
supported
|
|
57
|
+
supported,
|
|
58
|
+
weightRank
|
|
58
59
|
} from '../fontconfig.js';
|
|
59
60
|
import Font from './font.js';
|
|
60
61
|
|
|
@@ -178,14 +179,16 @@ export class FontconfigFontSource {
|
|
|
178
179
|
* source.alias('sans-serif', 'DejaVu Sans');
|
|
179
180
|
* const app = await createClient({ fontSource: source });
|
|
180
181
|
*
|
|
181
|
-
* Matching mirrors
|
|
182
|
+
* Matching mirrors the system path: every added face is a fallback
|
|
182
183
|
* candidate; faces matching a requested family (in list order) rank first,
|
|
183
|
-
* then
|
|
184
|
-
*
|
|
184
|
+
* then within a family the style, then the weight CSS's font matching picks
|
|
185
|
+
* (CSS Fonts 4 §5.2) — as the fontconfig source does, so a family answers
|
|
186
|
+
* alike from either. Coverage checks use the real font tables, so
|
|
187
|
+
* per-codepoint fallback works exactly like the system path.
|
|
185
188
|
*/
|
|
186
189
|
export class StaticFontSource {
|
|
187
190
|
constructor() {
|
|
188
|
-
this._faces = []; // { font, family, weight, italic, candidate }
|
|
191
|
+
this._faces = []; // { font, family, weight: [lo, hi], italic, candidate }
|
|
189
192
|
this._aliases = new Map(); // 'sans-serif' -> 'dejavu sans'
|
|
190
193
|
this._n = 0;
|
|
191
194
|
/** files a font spec could not parse: [{ file, error }] */
|
|
@@ -196,7 +199,9 @@ export class StaticFontSource {
|
|
|
196
199
|
* Register a font.
|
|
197
200
|
* @param {Uint8Array|Buffer|Font} data font file bytes (or an open Font)
|
|
198
201
|
* @param {object} [opts] { family (alias for matching; defaults to the
|
|
199
|
-
* font's family name), weight, style, postscriptName (face of a .ttc) }
|
|
202
|
+
* font's family name), weight, style, postscriptName (face of a .ttc) }.
|
|
203
|
+
* A `weight` is the face's, as @font-face's descriptor is; without one a
|
|
204
|
+
* variable face holds every weight on its `wght` axis.
|
|
200
205
|
* @returns {Font}
|
|
201
206
|
*/
|
|
202
207
|
add(data, opts = {}) {
|
|
@@ -208,10 +213,12 @@ export class StaticFontSource {
|
|
|
208
213
|
postscriptName: opts.postscriptName
|
|
209
214
|
});
|
|
210
215
|
const detected = detectStyle(font);
|
|
216
|
+
const axis = font.variationAxes.wght;
|
|
217
|
+
const weight = opts.weight !== undefined ? numericWeight(opts.weight) : detected.weight;
|
|
211
218
|
this._faces.push({
|
|
212
219
|
font,
|
|
213
220
|
family: (opts.family || font.familyName || '').toLowerCase(),
|
|
214
|
-
weight: opts.weight
|
|
221
|
+
weight: axis && opts.weight === undefined ? [axis.min, axis.max] : [weight, weight],
|
|
215
222
|
italic:
|
|
216
223
|
opts.style !== undefined ? String(opts.style).includes('italic') : detected.italic,
|
|
217
224
|
candidate: null
|
|
@@ -234,8 +241,8 @@ export class StaticFontSource {
|
|
|
234
241
|
*
|
|
235
242
|
* This is not cosmetic. Every widget default in the toolkit is
|
|
236
243
|
* `sans-serif`, and `code`/`pre` ask for `monospace`; with no alias for
|
|
237
|
-
* them `matchSorted` ranks every face equally and breaks the tie on
|
|
238
|
-
*
|
|
244
|
+
* them `matchSorted` ranks every face equally and breaks the tie on style
|
|
245
|
+
* and weight and then insertion order, so `monospace` silently renders in a
|
|
239
246
|
* proportional face. Inference happens automatically for a source built
|
|
240
247
|
* from a font spec; a hand-built source calls this when it wants it.
|
|
241
248
|
*
|
|
@@ -278,16 +285,19 @@ export class StaticFontSource {
|
|
|
278
285
|
const weight = numericWeight(pattern.weight);
|
|
279
286
|
const italic = !!(pattern.style && String(pattern.style).includes('italic'));
|
|
280
287
|
|
|
288
|
+
// family, then style, then weight in CSS's order; the sort is stable, so
|
|
289
|
+
// faces alike in all three stay in the order they were added
|
|
281
290
|
const scored = this._faces.map((face) => {
|
|
282
291
|
let rank = families.indexOf(face.family);
|
|
283
292
|
if (rank === -1) rank = families.length; // non-matching faces trail
|
|
284
293
|
return {
|
|
285
294
|
face,
|
|
286
|
-
|
|
287
|
-
rank * 1e6 + (face.italic !== italic ? 1e4 : 0) + Math.abs(face.weight - weight)
|
|
295
|
+
ranks: [rank, face.italic !== italic ? 1 : 0, weightRank(weight, face.weight, 400, 500)]
|
|
288
296
|
};
|
|
289
297
|
});
|
|
290
|
-
scored.sort(
|
|
298
|
+
scored.sort(
|
|
299
|
+
(a, b) => a.ranks[0] - b.ranks[0] || a.ranks[1] - b.ranks[1] || a.ranks[2] - b.ranks[2]
|
|
300
|
+
);
|
|
291
301
|
return scored.map(({ face }) => {
|
|
292
302
|
if (!face.candidate) {
|
|
293
303
|
// the font's own family name, not the (lowercased, possibly aliased)
|