@turntrout/subfont 1.7.1 → 1.8.0
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/CLAUDE.md +39 -13
- package/README.md +24 -14
- package/lib/FontTracerPool.d.ts +1 -0
- package/lib/FontTracerPool.d.ts.map +1 -1
- package/lib/FontTracerPool.js +46 -24
- package/lib/FontTracerPool.js.map +1 -1
- package/lib/HeadlessBrowser.d.ts +18 -0
- package/lib/HeadlessBrowser.d.ts.map +1 -0
- package/lib/HeadlessBrowser.js +216 -210
- package/lib/HeadlessBrowser.js.map +1 -0
- package/lib/codepointMaps.d.ts +4 -0
- package/lib/codepointMaps.d.ts.map +1 -0
- package/lib/codepointMaps.js +99 -0
- package/lib/codepointMaps.js.map +1 -0
- package/lib/collectFeatureGlyphIds.d.ts +3 -0
- package/lib/collectFeatureGlyphIds.d.ts.map +1 -0
- package/lib/collectFeatureGlyphIds.js +124 -138
- package/lib/collectFeatureGlyphIds.js.map +1 -0
- package/lib/collectTextsByPage.d.ts +41 -0
- package/lib/collectTextsByPage.d.ts.map +1 -0
- package/lib/collectTextsByPage.js +726 -965
- package/lib/collectTextsByPage.js.map +1 -0
- package/lib/concurrencyLimit.d.ts +3 -0
- package/lib/concurrencyLimit.d.ts.map +1 -0
- package/lib/concurrencyLimit.js +12 -11
- package/lib/concurrencyLimit.js.map +1 -0
- package/lib/escapeJsStringLiteral.d.ts +3 -0
- package/lib/escapeJsStringLiteral.d.ts.map +1 -0
- package/lib/escapeJsStringLiteral.js +7 -6
- package/lib/escapeJsStringLiteral.js.map +1 -0
- package/lib/extractReferencedCustomPropertyNames.d.ts +3 -0
- package/lib/extractReferencedCustomPropertyNames.d.ts.map +1 -0
- package/lib/extractReferencedCustomPropertyNames.js +15 -16
- package/lib/extractReferencedCustomPropertyNames.js.map +1 -0
- package/lib/extractVisibleText.d.ts +7 -0
- package/lib/extractVisibleText.d.ts.map +1 -0
- package/lib/extractVisibleText.js +110 -119
- package/lib/extractVisibleText.js.map +1 -0
- package/lib/findCustomPropertyDefinitions.d.ts +8 -0
- package/lib/findCustomPropertyDefinitions.d.ts.map +1 -0
- package/lib/findCustomPropertyDefinitions.js +41 -48
- package/lib/findCustomPropertyDefinitions.js.map +1 -0
- package/lib/fontConverter.d.ts +2 -0
- package/lib/fontConverter.d.ts.map +1 -0
- package/lib/fontConverter.js +40 -21
- package/lib/fontConverter.js.map +1 -0
- package/lib/fontConverterWorker.d.ts +2 -0
- package/lib/fontConverterWorker.d.ts.map +1 -0
- package/lib/fontConverterWorker.js +52 -15
- package/lib/fontConverterWorker.js.map +1 -0
- package/lib/fontFaceHelpers.d.ts +64 -0
- package/lib/fontFaceHelpers.d.ts.map +1 -0
- package/lib/fontFaceHelpers.js +237 -249
- package/lib/fontFaceHelpers.js.map +1 -0
- package/lib/fontFeatureHelpers.d.ts +30 -0
- package/lib/fontFeatureHelpers.d.ts.map +1 -0
- package/lib/fontFeatureHelpers.js +277 -212
- package/lib/fontFeatureHelpers.js.map +1 -0
- package/lib/fontTracerWorker.d.ts +11 -0
- package/lib/fontTracerWorker.d.ts.map +1 -0
- package/lib/fontTracerWorker.js +94 -60
- package/lib/fontTracerWorker.js.map +1 -0
- package/lib/gatherStylesheetsWithPredicates.d.ts +26 -0
- package/lib/gatherStylesheetsWithPredicates.d.ts.map +1 -0
- package/lib/gatherStylesheetsWithPredicates.js +75 -84
- package/lib/gatherStylesheetsWithPredicates.js.map +1 -0
- package/lib/getCssRulesByProperty.d.ts +29 -0
- package/lib/getCssRulesByProperty.d.ts.map +1 -0
- package/lib/getCssRulesByProperty.js +316 -316
- package/lib/getCssRulesByProperty.js.map +1 -0
- package/lib/getFontInfo.d.ts +11 -0
- package/lib/getFontInfo.d.ts.map +1 -0
- package/lib/getFontInfo.js +31 -33
- package/lib/getFontInfo.js.map +1 -0
- package/lib/initialValueByProp.d.ts +3 -0
- package/lib/initialValueByProp.d.ts.map +1 -0
- package/lib/initialValueByProp.js +20 -17
- package/lib/initialValueByProp.js.map +1 -0
- package/lib/injectSubsetDefinitions.d.ts +3 -0
- package/lib/injectSubsetDefinitions.d.ts.map +1 -0
- package/lib/injectSubsetDefinitions.js +55 -59
- package/lib/injectSubsetDefinitions.js.map +1 -0
- package/lib/normalizeFontPropertyValue.d.ts +3 -0
- package/lib/normalizeFontPropertyValue.d.ts.map +1 -0
- package/lib/normalizeFontPropertyValue.js +59 -54
- package/lib/normalizeFontPropertyValue.js.map +1 -0
- package/lib/parseCommandLineOptions.d.ts +9 -0
- package/lib/parseCommandLineOptions.d.ts.map +1 -0
- package/lib/parseCommandLineOptions.js +145 -149
- package/lib/parseCommandLineOptions.js.map +1 -0
- package/lib/parseFontVariationSettings.d.ts +3 -0
- package/lib/parseFontVariationSettings.d.ts.map +1 -0
- package/lib/parseFontVariationSettings.js +38 -36
- package/lib/parseFontVariationSettings.js.map +1 -0
- package/lib/progress.d.ts +27 -0
- package/lib/progress.d.ts.map +1 -0
- package/lib/progress.js +51 -54
- package/lib/progress.js.map +1 -0
- package/lib/sfntCache.d.ts +4 -0
- package/lib/sfntCache.d.ts.map +1 -0
- package/lib/sfntCache.js +67 -25
- package/lib/sfntCache.js.map +1 -0
- package/lib/stripLocalTokens.d.ts +3 -0
- package/lib/stripLocalTokens.d.ts.map +1 -0
- package/lib/stripLocalTokens.js +23 -21
- package/lib/stripLocalTokens.js.map +1 -0
- package/lib/subfont.d.ts +22 -1
- package/lib/subfont.d.ts.map +1 -1
- package/lib/subfont.js +7 -6
- package/lib/subfont.js.map +1 -1
- package/lib/subsetFontWithGlyphs.d.ts +4 -0
- package/lib/subsetFontWithGlyphs.d.ts.map +1 -1
- package/lib/subsetFontWithGlyphs.js +73 -14
- package/lib/subsetFontWithGlyphs.js.map +1 -1
- package/lib/subsetFonts.d.ts +1 -5
- package/lib/subsetFonts.d.ts.map +1 -1
- package/lib/subsetFonts.js +18 -17
- package/lib/subsetFonts.js.map +1 -1
- package/lib/subsetGeneration.d.ts +3 -6
- package/lib/subsetGeneration.d.ts.map +1 -1
- package/lib/subsetGeneration.js +42 -9
- package/lib/subsetGeneration.js.map +1 -1
- package/lib/types/shared.d.ts +11 -0
- package/lib/types/shared.d.ts.map +1 -0
- package/lib/types/shared.js +3 -0
- package/lib/types/shared.js.map +1 -0
- package/lib/unicodeRange.d.ts +3 -0
- package/lib/unicodeRange.d.ts.map +1 -0
- package/lib/unicodeRange.js +17 -30
- package/lib/unicodeRange.js.map +1 -0
- package/lib/unquote.d.ts +3 -0
- package/lib/unquote.d.ts.map +1 -0
- package/lib/unquote.js +18 -25
- package/lib/unquote.js.map +1 -0
- package/lib/variationAxes.d.ts +33 -0
- package/lib/variationAxes.d.ts.map +1 -0
- package/lib/variationAxes.js +127 -157
- package/lib/variationAxes.js.map +1 -0
- package/lib/warnAboutMissingGlyphs.d.ts +43 -0
- package/lib/warnAboutMissingGlyphs.d.ts.map +1 -0
- package/lib/warnAboutMissingGlyphs.js +139 -147
- package/lib/warnAboutMissingGlyphs.js.map +1 -0
- package/lib/wasmQueue.d.ts +3 -0
- package/lib/wasmQueue.d.ts.map +1 -0
- package/lib/wasmQueue.js +13 -10
- package/lib/wasmQueue.js.map +1 -0
- package/package.json +3 -2
package/lib/variationAxes.js
CHANGED
|
@@ -1,173 +1,143 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderNumberRange = renderNumberRange;
|
|
4
|
+
exports.getVariationAxisUsage = getVariationAxisUsage;
|
|
5
|
+
exports.getVariationAxisBounds = getVariationAxisBounds;
|
|
6
|
+
const getFontInfo = require("./getFontInfo");
|
|
7
|
+
const parseFontVariationSettings = require("./parseFontVariationSettings");
|
|
6
8
|
// CSS oblique without an explicit <angle> defaults to 14deg. The OpenType slnt
|
|
7
9
|
// axis uses the opposite sign convention (positive = counter-clockwise), so
|
|
8
10
|
// CSS maps oblique to slnt -14.
|
|
9
11
|
const DEFAULT_OBLIQUE_SLNT = -14;
|
|
10
|
-
|
|
11
|
-
// When no opsz values are determined from font-variation-settings, the axis is
|
|
12
|
-
// pinned to its default value rather than preserving the full range, which can
|
|
13
|
-
// significantly bloat variable font subsets.
|
|
14
|
-
const ignoredVariationAxes = new Set();
|
|
15
|
-
|
|
16
12
|
function clamp(value, min, max) {
|
|
17
|
-
|
|
13
|
+
return Math.min(Math.max(value, min), max);
|
|
18
14
|
}
|
|
19
|
-
|
|
20
15
|
function renderNumberRange(min, max) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} else {
|
|
24
|
-
return `${min}-${max}`;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getVariationAxisUsage(
|
|
29
|
-
htmlOrSvgAssetTextsWithProps,
|
|
30
|
-
parseFontWeightRange,
|
|
31
|
-
parseFontStretchRange
|
|
32
|
-
) {
|
|
33
|
-
const seenAxisValuesByFontUrlAndAxisName = new Map();
|
|
34
|
-
|
|
35
|
-
function noteUsedValue(fontUrl, axisName, axisValue) {
|
|
36
|
-
let seenAxes = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
|
|
37
|
-
if (!seenAxes) {
|
|
38
|
-
seenAxes = new Map();
|
|
39
|
-
seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
|
|
16
|
+
if (min === max) {
|
|
17
|
+
return String(min);
|
|
40
18
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
} else {
|
|
44
|
-
seenAxes.set(axisName, new Set([axisValue]));
|
|
19
|
+
else {
|
|
20
|
+
return `${min}-${max}`;
|
|
45
21
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (seenFontUrls.has(fontUrl)) continue;
|
|
62
|
-
seenFontUrls.add(fontUrl);
|
|
63
|
-
if (fontStyles.has('italic')) {
|
|
64
|
-
noteUsedValue(fontUrl, 'ital', 1);
|
|
65
|
-
}
|
|
66
|
-
// If any font-style value except italic is seen (including normal or oblique)
|
|
67
|
-
// we're also utilizing value 0:
|
|
68
|
-
if (fontStyles.size > (fontStyles.has('italic') ? 1 : 0)) {
|
|
69
|
-
noteUsedValue(fontUrl, 'ital', 0);
|
|
70
|
-
}
|
|
71
|
-
if (fontStyles.has('oblique')) {
|
|
72
|
-
// https://www.w3.org/TR/css-fonts-4/#font-style-prop
|
|
73
|
-
// oblique <angle>?
|
|
74
|
-
// [...] The lack of an <angle> represents 14deg.
|
|
75
|
-
// And also:
|
|
76
|
-
// Note: the OpenType slnt axis is defined with a positive angle meaning a counter-clockwise slant, the opposite direction to CSS.
|
|
77
|
-
// The CSS implementation will take this into account when using variations to produce oblique faces.
|
|
78
|
-
noteUsedValue(fontUrl, 'slnt', DEFAULT_OBLIQUE_SLNT);
|
|
79
|
-
}
|
|
80
|
-
// If any font-style value except oblique is seen (including normal or italic)
|
|
81
|
-
// we're also utilizing value 0:
|
|
82
|
-
if (fontStyles.size > (fontStyles.has('oblique') ? 1 : 0)) {
|
|
83
|
-
noteUsedValue(fontUrl, 'slnt', 0);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const minMaxFontWeight = parseFontWeightRange(props['font-weight']);
|
|
87
|
-
for (const fontWeight of fontWeights) {
|
|
88
|
-
noteUsedValue(fontUrl, 'wght', clamp(fontWeight, ...minMaxFontWeight));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const minMaxFontStretch = parseFontStretchRange(props['font-stretch']);
|
|
92
|
-
for (const fontStretch of fontStretches) {
|
|
93
|
-
noteUsedValue(
|
|
94
|
-
fontUrl,
|
|
95
|
-
'wdth',
|
|
96
|
-
clamp(fontStretch, ...minMaxFontStretch)
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
for (const fontVariationSettingsValue of fontVariationSettings) {
|
|
101
|
-
for (const [axisName, axisValue] of parseFontVariationSettings(
|
|
102
|
-
fontVariationSettingsValue
|
|
103
|
-
)) {
|
|
104
|
-
noteUsedValue(fontUrl, axisName, axisValue);
|
|
22
|
+
}
|
|
23
|
+
function getVariationAxisUsage(htmlOrSvgAssetTextsWithProps, parseFontWeightRange, parseFontStretchRange) {
|
|
24
|
+
const seenAxisValuesByFontUrlAndAxisName = new Map();
|
|
25
|
+
function noteUsedValue(fontUrl, axisName, axisValue) {
|
|
26
|
+
let seenAxes = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
|
|
27
|
+
if (!seenAxes) {
|
|
28
|
+
seenAxes = new Map();
|
|
29
|
+
seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
|
|
30
|
+
}
|
|
31
|
+
const existing = seenAxes.get(axisName);
|
|
32
|
+
if (existing) {
|
|
33
|
+
existing.add(axisValue);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
seenAxes.set(axisName, new Set([axisValue]));
|
|
105
37
|
}
|
|
106
|
-
}
|
|
107
38
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
39
|
+
// Since fontUsages are built from shared templates, all pages produce
|
|
40
|
+
// the same fontStyles/fontWeights/etc. for a given fontUrl. Process
|
|
41
|
+
// each unique fontUrl only once to avoid num_pages × redundant iterations.
|
|
42
|
+
const seenFontUrls = new Set();
|
|
43
|
+
for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
|
|
44
|
+
for (const { fontUrl, fontStyles, fontWeights, fontStretches, fontVariationSettings, props, } of fontUsages) {
|
|
45
|
+
if (seenFontUrls.has(fontUrl))
|
|
46
|
+
continue;
|
|
47
|
+
seenFontUrls.add(fontUrl);
|
|
48
|
+
if (fontStyles.has('italic')) {
|
|
49
|
+
noteUsedValue(fontUrl, 'ital', 1);
|
|
50
|
+
}
|
|
51
|
+
// If any font-style value except italic is seen (including normal or oblique)
|
|
52
|
+
// we're also utilizing value 0:
|
|
53
|
+
if (fontStyles.size > (fontStyles.has('italic') ? 1 : 0)) {
|
|
54
|
+
noteUsedValue(fontUrl, 'ital', 0);
|
|
55
|
+
}
|
|
56
|
+
if (fontStyles.has('oblique')) {
|
|
57
|
+
noteUsedValue(fontUrl, 'slnt', DEFAULT_OBLIQUE_SLNT);
|
|
58
|
+
}
|
|
59
|
+
// If any font-style value except oblique is seen (including normal or italic)
|
|
60
|
+
// we're also utilizing value 0:
|
|
61
|
+
if (fontStyles.size > (fontStyles.has('oblique') ? 1 : 0)) {
|
|
62
|
+
noteUsedValue(fontUrl, 'slnt', 0);
|
|
63
|
+
}
|
|
64
|
+
const minMaxFontWeight = parseFontWeightRange(props['font-weight']);
|
|
65
|
+
for (const fontWeight of fontWeights) {
|
|
66
|
+
noteUsedValue(fontUrl, 'wght', clamp(fontWeight, ...minMaxFontWeight));
|
|
67
|
+
}
|
|
68
|
+
const minMaxFontStretch = parseFontStretchRange(props['font-stretch']);
|
|
69
|
+
for (const fontStretch of fontStretches) {
|
|
70
|
+
noteUsedValue(fontUrl, 'wdth', clamp(fontStretch, ...minMaxFontStretch));
|
|
71
|
+
}
|
|
72
|
+
for (const fontVariationSettingsValue of fontVariationSettings) {
|
|
73
|
+
for (const [axisName, axisValue] of parseFontVariationSettings(fontVariationSettingsValue)) {
|
|
74
|
+
noteUsedValue(fontUrl, axisName, axisValue);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { seenAxisValuesByFontUrlAndAxisName };
|
|
111
80
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
let numAxesPinned = 0;
|
|
134
|
-
let numAxesReduced = 0;
|
|
135
|
-
const fontVariationEntries = Object.entries(fontInfo.variationAxes);
|
|
136
|
-
const seenAxisValuesByAxisName =
|
|
137
|
-
seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
|
|
138
|
-
if (fontVariationEntries.length > 0 && seenAxisValuesByAxisName) {
|
|
139
|
-
for (const [
|
|
140
|
-
axisName,
|
|
141
|
-
{ min, max, default: defaultValue },
|
|
142
|
-
] of fontVariationEntries) {
|
|
143
|
-
let seenAxisValues = seenAxisValuesByAxisName.get(axisName);
|
|
144
|
-
if (!seenAxisValues && !ignoredVariationAxes.has(axisName)) {
|
|
145
|
-
seenAxisValues = new Set([defaultValue]);
|
|
146
|
-
}
|
|
147
|
-
if (seenAxisValues && seenAxisValues.size === 1) {
|
|
148
|
-
variationAxes[axisName] = clamp([...seenAxisValues][0], min, max);
|
|
149
|
-
numAxesPinned += 1;
|
|
150
|
-
} else if (seenAxisValues) {
|
|
151
|
-
const minSeenValue = Math.min(...seenAxisValues);
|
|
152
|
-
const maxSeenValue = Math.max(...seenAxisValues);
|
|
153
|
-
variationAxes[axisName] = {
|
|
154
|
-
min: Math.max(minSeenValue, min),
|
|
155
|
-
max: Math.min(maxSeenValue, max),
|
|
81
|
+
async function getVariationAxisBounds(fontAssetsByUrl, fontUrl, seenAxisValuesByFontUrlAndAxisName) {
|
|
82
|
+
let fontInfo;
|
|
83
|
+
try {
|
|
84
|
+
const asset = fontAssetsByUrl.get(fontUrl);
|
|
85
|
+
if (!asset) {
|
|
86
|
+
return {
|
|
87
|
+
fullyInstanced: false,
|
|
88
|
+
numAxesPinned: 0,
|
|
89
|
+
numAxesReduced: 0,
|
|
90
|
+
variationAxes: {},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
fontInfo = await getFontInfo(asset.rawSrc);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Invalid font -- skip instancing, return safe defaults
|
|
97
|
+
return {
|
|
98
|
+
fullyInstanced: false,
|
|
99
|
+
numAxesPinned: 0,
|
|
100
|
+
numAxesReduced: 0,
|
|
101
|
+
variationAxes: {},
|
|
156
102
|
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
103
|
+
}
|
|
104
|
+
const variationAxes = {};
|
|
105
|
+
let fullyInstanced = true;
|
|
106
|
+
let numAxesPinned = 0;
|
|
107
|
+
let numAxesReduced = 0;
|
|
108
|
+
const fontVariationEntries = Object.entries(fontInfo.variationAxes);
|
|
109
|
+
const seenAxisValuesByAxisName = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
|
|
110
|
+
if (fontVariationEntries.length > 0 && seenAxisValuesByAxisName) {
|
|
111
|
+
for (const [axisName, { min, max, default: defaultValue },] of fontVariationEntries) {
|
|
112
|
+
let seenAxisValues = seenAxisValuesByAxisName.get(axisName);
|
|
113
|
+
if (!seenAxisValues) {
|
|
114
|
+
seenAxisValues = new Set([defaultValue]);
|
|
115
|
+
}
|
|
116
|
+
if (seenAxisValues.size === 1) {
|
|
117
|
+
const [only] = seenAxisValues;
|
|
118
|
+
variationAxes[axisName] = clamp(only, min, max);
|
|
119
|
+
numAxesPinned += 1;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
let minSeenValue = Infinity;
|
|
123
|
+
let maxSeenValue = -Infinity;
|
|
124
|
+
for (const v of seenAxisValues) {
|
|
125
|
+
if (v < minSeenValue)
|
|
126
|
+
minSeenValue = v;
|
|
127
|
+
if (v > maxSeenValue)
|
|
128
|
+
maxSeenValue = v;
|
|
129
|
+
}
|
|
130
|
+
variationAxes[axisName] = {
|
|
131
|
+
min: Math.max(minSeenValue, min),
|
|
132
|
+
max: Math.min(maxSeenValue, max),
|
|
133
|
+
};
|
|
134
|
+
fullyInstanced = false;
|
|
135
|
+
if (minSeenValue > min || maxSeenValue < max) {
|
|
136
|
+
numAxesReduced += 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
160
139
|
}
|
|
161
|
-
}
|
|
162
140
|
}
|
|
163
|
-
|
|
164
|
-
return { fullyInstanced, numAxesPinned, numAxesReduced, variationAxes };
|
|
141
|
+
return { fullyInstanced, numAxesPinned, numAxesReduced, variationAxes };
|
|
165
142
|
}
|
|
166
|
-
|
|
167
|
-
module.exports = {
|
|
168
|
-
standardVariationAxes,
|
|
169
|
-
ignoredVariationAxes,
|
|
170
|
-
renderNumberRange,
|
|
171
|
-
getVariationAxisUsage,
|
|
172
|
-
getVariationAxisBounds,
|
|
173
|
-
};
|
|
143
|
+
//# sourceMappingURL=variationAxes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variationAxes.js","sourceRoot":"","sources":["../src/variationAxes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
interface AtRuleLike {
|
|
2
|
+
some(predicate: (node: {
|
|
3
|
+
prop?: string;
|
|
4
|
+
}) => boolean): boolean;
|
|
5
|
+
append(decl: {
|
|
6
|
+
prop: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}): void;
|
|
9
|
+
}
|
|
10
|
+
interface FontFaceRelationLike {
|
|
11
|
+
from: {
|
|
12
|
+
markDirty(): void;
|
|
13
|
+
};
|
|
14
|
+
node: AtRuleLike;
|
|
15
|
+
}
|
|
16
|
+
interface FontFaceDeclaration {
|
|
17
|
+
'font-family'?: string;
|
|
18
|
+
relations: FontFaceRelationLike[];
|
|
19
|
+
}
|
|
20
|
+
interface FontUsageLike {
|
|
21
|
+
subsets?: Record<string, Buffer | Uint8Array>;
|
|
22
|
+
pageText: string;
|
|
23
|
+
fontFamilies: Set<string>;
|
|
24
|
+
codepoints: {
|
|
25
|
+
original: number[];
|
|
26
|
+
};
|
|
27
|
+
props: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
interface AssetTextEntry {
|
|
30
|
+
htmlOrSvgAsset: {
|
|
31
|
+
text: string;
|
|
32
|
+
urlOrDescription: string;
|
|
33
|
+
};
|
|
34
|
+
fontUsages: FontUsageLike[];
|
|
35
|
+
accumulatedFontFaceDeclarations: FontFaceDeclaration[];
|
|
36
|
+
}
|
|
37
|
+
interface AssetGraphLike {
|
|
38
|
+
warn(err: Error): void;
|
|
39
|
+
info(err: Error): void;
|
|
40
|
+
}
|
|
41
|
+
declare function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps: AssetTextEntry[], assetGraph: AssetGraphLike): Promise<void>;
|
|
42
|
+
export = warnAboutMissingGlyphs;
|
|
43
|
+
//# sourceMappingURL=warnAboutMissingGlyphs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warnAboutMissingGlyphs.d.ts","sourceRoot":"","sources":["../src/warnAboutMissingGlyphs.ts"],"names":[],"mappings":"AAIA,UAAU,UAAU;IAClB,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,GAAG,OAAO,CAAC;IAC/D,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACrD;AAED,UAAU,oBAAoB;IAC5B,IAAI,EAAE;QAAE,SAAS,IAAI,IAAI,CAAA;KAAE,CAAC;IAG5B,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,UAAU,mBAAmB;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,UAAU,cAAc;IACtB,cAAc,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,+BAA+B,EAAE,mBAAmB,EAAE,CAAC;CACxD;AAED,UAAU,cAAc;IACtB,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC;CACxB;AAED,iBAAe,sBAAsB,CACnC,4BAA4B,EAAE,cAAc,EAAE,EAC9C,UAAU,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC,CAoLf;AAED,SAAS,sBAAsB,CAAC"}
|
|
@@ -1,155 +1,147 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
async function warnAboutMissingGlyphs(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.catch((err) => {
|
|
25
|
-
assetGraph.warn(err);
|
|
26
|
-
return null;
|
|
27
|
-
})
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const subsetCharSetCache = new Map();
|
|
33
|
-
await Promise.all(
|
|
34
|
-
[...uniqueSubsetBuffers.entries()].map(async ([buffer, promise]) => {
|
|
35
|
-
subsetCharSetCache.set(buffer, await promise);
|
|
36
|
-
})
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
for (const {
|
|
40
|
-
htmlOrSvgAsset,
|
|
41
|
-
fontUsages,
|
|
42
|
-
accumulatedFontFaceDeclarations,
|
|
43
|
-
} of htmlOrSvgAssetTextsWithProps) {
|
|
44
|
-
let linesAndColumns;
|
|
45
|
-
// Dedupe scans for the same missing char across different fontUsages on
|
|
46
|
-
// this page. On KaTeX-heavy pages the same symbol is often missing in
|
|
47
|
-
// several font-families, and each scan is an O(N) walk of the HTML text.
|
|
48
|
-
const charLookupCache = new Map();
|
|
49
|
-
const lookupChar = (char) => {
|
|
50
|
-
let cached = charLookupCache.get(char);
|
|
51
|
-
if (cached) return cached;
|
|
52
|
-
let firstLocation;
|
|
53
|
-
let occurrences = 0;
|
|
54
|
-
if (char.length > 0) {
|
|
55
|
-
const sourceText = htmlOrSvgAsset.text;
|
|
56
|
-
let searchIdx = 0;
|
|
57
|
-
while (true) {
|
|
58
|
-
const charIdx = sourceText.indexOf(char, searchIdx);
|
|
59
|
-
if (charIdx === -1) break;
|
|
60
|
-
occurrences++;
|
|
61
|
-
if (occurrences === 1) {
|
|
62
|
-
if (!linesAndColumns) {
|
|
63
|
-
linesAndColumns = new LinesAndColumns(sourceText);
|
|
1
|
+
"use strict";
|
|
2
|
+
const lines_and_columns_1 = require("lines-and-columns");
|
|
3
|
+
const getFontInfo = require("./getFontInfo");
|
|
4
|
+
const unicodeRange = require("./unicodeRange");
|
|
5
|
+
async function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph) {
|
|
6
|
+
const missingGlyphsErrors = [];
|
|
7
|
+
// Collect all unique subset buffers and parse them concurrently.
|
|
8
|
+
// getFontInfo internally serializes harfbuzzjs WASM calls, so
|
|
9
|
+
// Promise.all just queues them up rather than running in parallel.
|
|
10
|
+
const uniqueSubsetBuffers = new Map();
|
|
11
|
+
for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
|
|
12
|
+
for (const fontUsage of fontUsages) {
|
|
13
|
+
if (!fontUsage.subsets)
|
|
14
|
+
continue;
|
|
15
|
+
const subsetBuffer = Object.values(fontUsage.subsets)[0];
|
|
16
|
+
if (!uniqueSubsetBuffers.has(subsetBuffer)) {
|
|
17
|
+
uniqueSubsetBuffers.set(subsetBuffer, getFontInfo(subsetBuffer)
|
|
18
|
+
.then((info) => new Set(info.characterSet))
|
|
19
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
20
|
+
.catch((rawErr) => {
|
|
21
|
+
assetGraph.warn(rawErr);
|
|
22
|
+
return null;
|
|
23
|
+
}));
|
|
64
24
|
}
|
|
65
|
-
const position = linesAndColumns.locationForIndex(charIdx);
|
|
66
|
-
firstLocation = `${htmlOrSvgAsset.urlOrDescription}:${
|
|
67
|
-
position.line + 1
|
|
68
|
-
}:${position.column + 1}`;
|
|
69
|
-
}
|
|
70
|
-
searchIdx = charIdx + char.length;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (!firstLocation) {
|
|
74
|
-
firstLocation = `${htmlOrSvgAsset.urlOrDescription} (generated content)`;
|
|
75
|
-
}
|
|
76
|
-
cached = { firstLocation, occurrences };
|
|
77
|
-
charLookupCache.set(char, cached);
|
|
78
|
-
return cached;
|
|
79
|
-
};
|
|
80
|
-
for (const fontUsage of fontUsages) {
|
|
81
|
-
if (!fontUsage.subsets) continue;
|
|
82
|
-
const subsetBuffer = Object.values(fontUsage.subsets)[0];
|
|
83
|
-
const characterSetLookup = subsetCharSetCache.get(subsetBuffer);
|
|
84
|
-
if (!characterSetLookup) continue; // getFontInfo failed on subset; already warned
|
|
85
|
-
|
|
86
|
-
let missedAny = false;
|
|
87
|
-
for (const char of fontUsage.pageText) {
|
|
88
|
-
// Turns out that browsers don't mind that these are missing:
|
|
89
|
-
if (char === '\t' || char === '\n') {
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const codePoint = char.codePointAt(0);
|
|
94
|
-
|
|
95
|
-
const isMissing = !characterSetLookup.has(codePoint);
|
|
96
|
-
|
|
97
|
-
if (isMissing) {
|
|
98
|
-
// Report only the first location plus a count of remaining
|
|
99
|
-
// occurrences. A character like U+200B can appear thousands of
|
|
100
|
-
// times on a page and per-occurrence lines drown the log.
|
|
101
|
-
const { firstLocation, occurrences } = lookupChar(char);
|
|
102
|
-
|
|
103
|
-
missingGlyphsErrors.push({
|
|
104
|
-
codePoint,
|
|
105
|
-
char,
|
|
106
|
-
htmlOrSvgAsset,
|
|
107
|
-
fontUsage,
|
|
108
|
-
location: firstLocation,
|
|
109
|
-
occurrences,
|
|
110
|
-
});
|
|
111
|
-
missedAny = true;
|
|
112
25
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
26
|
+
}
|
|
27
|
+
const subsetCharSetCache = new Map();
|
|
28
|
+
await Promise.all([...uniqueSubsetBuffers.entries()].map(async ([buffer, promise]) => {
|
|
29
|
+
subsetCharSetCache.set(buffer, await promise);
|
|
30
|
+
}));
|
|
31
|
+
// Codepoint unions per @font-face declaration, keyed by the at-rule node.
|
|
32
|
+
// Built across all fontUsages on a page, then flushed in a single append
|
|
33
|
+
// per @font-face so multiple fontUsages sharing a family don't lose data.
|
|
34
|
+
const unicodeRangeAccumulator = new Map();
|
|
35
|
+
for (const { htmlOrSvgAsset, fontUsages, accumulatedFontFaceDeclarations, } of htmlOrSvgAssetTextsWithProps) {
|
|
36
|
+
let linesAndColumns;
|
|
37
|
+
// Dedupe scans for the same missing char across different fontUsages on
|
|
38
|
+
// this page. On KaTeX-heavy pages the same symbol is often missing in
|
|
39
|
+
// several font-families, and each scan is an O(N) walk of the HTML text.
|
|
40
|
+
const charLookupCache = new Map();
|
|
41
|
+
const lookupChar = (char) => {
|
|
42
|
+
const cachedHit = charLookupCache.get(char);
|
|
43
|
+
if (cachedHit)
|
|
44
|
+
return cachedHit;
|
|
45
|
+
let firstLocation;
|
|
46
|
+
let occurrences = 0;
|
|
47
|
+
if (char.length > 0) {
|
|
48
|
+
const sourceText = htmlOrSvgAsset.text;
|
|
49
|
+
let searchIdx = 0;
|
|
50
|
+
while (true) {
|
|
51
|
+
const charIdx = sourceText.indexOf(char, searchIdx);
|
|
52
|
+
if (charIdx === -1)
|
|
53
|
+
break;
|
|
54
|
+
occurrences++;
|
|
55
|
+
if (occurrences === 1) {
|
|
56
|
+
if (!linesAndColumns) {
|
|
57
|
+
linesAndColumns = new lines_and_columns_1.LinesAndColumns(sourceText);
|
|
58
|
+
}
|
|
59
|
+
const position = linesAndColumns.locationForIndex(charIdx);
|
|
60
|
+
firstLocation = `${htmlOrSvgAsset.urlOrDescription}:${position.line + 1}:${position.column + 1}`;
|
|
61
|
+
}
|
|
62
|
+
searchIdx = charIdx + char.length;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!firstLocation) {
|
|
66
|
+
firstLocation = `${htmlOrSvgAsset.urlOrDescription} (generated content)`;
|
|
67
|
+
}
|
|
68
|
+
const result = { firstLocation, occurrences };
|
|
69
|
+
charLookupCache.set(char, result);
|
|
70
|
+
return result;
|
|
71
|
+
};
|
|
72
|
+
for (const fontUsage of fontUsages) {
|
|
73
|
+
if (!fontUsage.subsets)
|
|
74
|
+
continue;
|
|
75
|
+
const subsetBuffer = Object.values(fontUsage.subsets)[0];
|
|
76
|
+
const characterSetLookup = subsetCharSetCache.get(subsetBuffer);
|
|
77
|
+
if (!characterSetLookup)
|
|
78
|
+
continue; // getFontInfo failed on subset; already warned
|
|
79
|
+
let missedAny = false;
|
|
80
|
+
for (const char of fontUsage.pageText) {
|
|
81
|
+
// Turns out that browsers don't mind that these are missing:
|
|
82
|
+
if (char === '\t' || char === '\n') {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const codePoint = char.codePointAt(0);
|
|
86
|
+
if (codePoint === undefined)
|
|
87
|
+
continue;
|
|
88
|
+
const isMissing = !characterSetLookup.has(codePoint);
|
|
89
|
+
if (isMissing) {
|
|
90
|
+
// Report only the first location plus a count of remaining
|
|
91
|
+
// occurrences. A character like U+200B can appear thousands of
|
|
92
|
+
// times on a page and per-occurrence lines drown the log.
|
|
93
|
+
const { firstLocation, occurrences } = lookupChar(char);
|
|
94
|
+
missingGlyphsErrors.push({
|
|
95
|
+
codePoint,
|
|
96
|
+
char,
|
|
97
|
+
htmlOrSvgAsset,
|
|
98
|
+
fontUsage,
|
|
99
|
+
location: firstLocation,
|
|
100
|
+
occurrences,
|
|
101
|
+
});
|
|
102
|
+
missedAny = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (missedAny) {
|
|
106
|
+
for (const fontFace of accumulatedFontFaceDeclarations) {
|
|
107
|
+
const family = fontFace['font-family'];
|
|
108
|
+
if (!family || !fontUsage.fontFamilies.has(family))
|
|
109
|
+
continue;
|
|
110
|
+
const relation = fontFace.relations[0];
|
|
111
|
+
const node = relation.node;
|
|
112
|
+
if (node.some((decl) => decl.prop === 'unicode-range'))
|
|
113
|
+
continue;
|
|
114
|
+
let entry = unicodeRangeAccumulator.get(node);
|
|
115
|
+
if (!entry) {
|
|
116
|
+
entry = { relation, codepoints: new Set() };
|
|
117
|
+
unicodeRangeAccumulator.set(node, entry);
|
|
118
|
+
}
|
|
119
|
+
for (const cp of fontUsage.codepoints.original) {
|
|
120
|
+
entry.codepoints.add(cp);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
130
124
|
}
|
|
131
|
-
}
|
|
132
125
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
126
|
+
// Flush accumulated unicode-range declarations: one append per @font-face,
|
|
127
|
+
// covering every fontUsage that mapped to it.
|
|
128
|
+
for (const { relation, codepoints } of unicodeRangeAccumulator.values()) {
|
|
129
|
+
relation.node.append({
|
|
130
|
+
prop: 'unicode-range',
|
|
131
|
+
value: unicodeRange([...codepoints]),
|
|
132
|
+
});
|
|
133
|
+
relation.from.markDirty();
|
|
134
|
+
}
|
|
135
|
+
if (missingGlyphsErrors.length) {
|
|
136
|
+
const errorLog = missingGlyphsErrors.map(({ char, fontUsage, location, occurrences }) => {
|
|
137
|
+
const extra = occurrences > 1 ? ` (+${occurrences - 1} more)` : '';
|
|
138
|
+
return `- \\u{${char.codePointAt(0).toString(16)}} (${char}) in font-family '${fontUsage.props['font-family']}' (${fontUsage.props['font-weight']}/${fontUsage.props['font-style']}) at ${location}${extra}`;
|
|
139
|
+
});
|
|
140
|
+
const message = `Missing glyph fallback detected.
|
|
148
141
|
When your primary webfont doesn't contain the glyphs you use, browsers that don't support unicode-range will load your fallback fonts, which will be a potential waste of bandwidth.
|
|
149
142
|
These glyphs are used on your site, but they don't exist in the font you applied to them:`;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
143
|
+
assetGraph.info(new Error(`${message}\n${errorLog.join('\n')}`));
|
|
144
|
+
}
|
|
153
145
|
}
|
|
154
|
-
|
|
155
146
|
module.exports = warnAboutMissingGlyphs;
|
|
147
|
+
//# sourceMappingURL=warnAboutMissingGlyphs.js.map
|