Skip to content

Commit

Permalink
Detect unused wdth variation axis ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
papandreou committed Sep 4, 2022
1 parent 87e848e commit d7758eb
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 2 deletions.
3 changes: 3 additions & 0 deletions lib/normalizeFontPropertyValue.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const cssFontWeightNames = require('css-font-weight-names');
const initialValueByProp = require('./initialValueByProp');
const unquote = require('./unquote');
const normalizeFontStretch = require('font-snapper/lib/normalizeFontStretch');

function normalizeFontPropertyValue(propName, value) {
const propNameLowerCase = propName.toLowerCase();
Expand All @@ -22,6 +23,8 @@ function normalizeFontPropertyValue(propName, value) {
} else {
return value;
}
} else if (propNameLowerCase === 'font-stretch') {
return normalizeFontStretch(value);
} else if (typeof value === 'string' && propNameLowerCase !== 'src') {
return value.toLowerCase();
}
Expand Down
50 changes: 48 additions & 2 deletions lib/subsetFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ function groupTextsByFontFamilyProps(
fontVariationSettings: textAndProps.props['font-variation-settings'],
fontStyle,
fontWeight,
fontStretch: normalizeFontPropertyValue(
'font-stretch',
textAndProps.props['font-stretch']
),
animationTimingFunction:
textAndProps.props['animation-timing-function'],
props,
Expand All @@ -234,6 +238,9 @@ function groupTextsByFontFamilyProps(
);
const fontStyles = new Set(textsPropsArray.map((obj) => obj.fontStyle));
const fontWeights = new Set(textsPropsArray.map((obj) => obj.fontWeight));
const fontStretches = new Set(
textsPropsArray.map((obj) => obj.fontStretch)
);
const fontVariationSettings = new Set(
textsPropsArray
.map((obj) => obj.fontVariationSettings)
Expand Down Expand Up @@ -274,6 +281,7 @@ function groupTextsByFontFamilyProps(
fontUrl,
fontFamilies,
fontStyles,
fontStretches,
fontWeights,
fontVariationSettings,
hasOutOfBoundsAnimationTimingFunction,
Expand Down Expand Up @@ -638,6 +646,9 @@ function cssAssetIsEmpty(cssAsset) {
}

function parseFontWeightRange(str) {
if (typeof str === 'undefined' || str === 'auto') {
return [-Infinity, Infinity];
}
let minFontWeight = 400;
let maxFontWeight = 400;
const fontWeightTokens = str.split(/\s+/).map((str) => parseFloat(str));
Expand All @@ -653,6 +664,27 @@ function parseFontWeightRange(str) {
return [minFontWeight, maxFontWeight];
}

function parseFontStretchRange(str) {
if (typeof str === 'undefined' || str.toLowerCase() === 'auto') {
return [-Infinity, Infinity];
}
let minFontStretch = 100;
let maxFontStretch = 100;
const fontStretchTokens = str
.split(/\s+/)
.map((str) => normalizeFontPropertyValue('font-stretch', str));
if (
[1, 2].includes(fontStretchTokens.length) &&
!fontStretchTokens.some(isNaN)
) {
minFontStretch = maxFontStretch = fontStretchTokens[0];
if (fontStretchTokens.length === 2) {
maxFontStretch = fontStretchTokens[1];
}
}
return [minFontStretch, maxFontStretch];
}

function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph) {
const missingGlyphsErrors = [];

Expand Down Expand Up @@ -745,7 +777,7 @@ These glyphs are used on your site, but they don't exist in the font you applied

const standardVariationAxes = new Set(['wght', 'wdth', 'ital', 'slnt', 'opsz']);
// Tracing the ranges of these standard axes require a bit more work, so just skip them for now:
const ignoredVariationAxes = new Set(['wdth', 'slnt', 'opsz']);
const ignoredVariationAxes = new Set(['slnt', 'opsz']);

function renderNumberRange(min, max) {
if (min === max) {
Expand All @@ -765,9 +797,10 @@ function warnAboutUnusedVariationAxes(
for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
for (const {
fontUrl,
fontVariationSettings,
fontStyles,
fontWeights,
fontStretches,
fontVariationSettings,
hasOutOfBoundsAnimationTimingFunction,
props,
} of fontUsages) {
Expand Down Expand Up @@ -806,6 +839,19 @@ function warnAboutUnusedVariationAxes(
}
}

const minMaxFontStretch = parseFontStretchRange(props['font-stretch']);
const seenFontStretchValues = [];
for (const fontStrech of fontStretches) {
seenFontStretchValues.push(_.clamp(fontStrech, ...minMaxFontStretch));
}
if (seenFontStretchValues.length > 0) {
if (seenAxes.has('wdth')) {
seenAxes.get('wdth').push(...seenFontStretchValues);
} else {
seenAxes.set('wdth', seenFontStretchValues);
}
}

for (const fontVariationSettingsValue of fontVariationSettings) {
for (const [axisName, axisValue] of parseFontVariationSettings(
fontVariationSettingsValue
Expand Down
26 changes: 26 additions & 0 deletions test/subsetFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -2927,6 +2927,32 @@ describe('subsetFonts', function () {
});
});

describe('for the wdth axis', function () {
it('should emit an info event', async function () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
__dirname,
'../testdata/subsetFonts/variable-font-unused-wdth-axis/'
),
});
await assetGraph.loadAssets('index.html');
await assetGraph.populate();
const infoSpy = sinon.spy().named('info');
assetGraph.on('info', infoSpy);

await subsetFonts(assetGraph);

expect(infoSpy, 'to have calls satisfying', function () {
infoSpy({
message: expect.it(
'to contain',
'wdth: 87.5-147 used (25-151 available)'
),
});
});
});
});

describe('for the ital axis', function () {
describe('when only font-style: normal is used', function () {
it('should emit an info event', async function () {
Expand Down
Binary file not shown.
38 changes: 38 additions & 0 deletions testdata/subsetFonts/variable-font-unused-wdth-axis/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<html>
<head>
<meta charset=utf-8>
<style>
@font-face {
font-family: RobotoFlex;
src: url('RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf') format('woff2-variations');
font-stretch: condensed 125;
}

p {
font-size: 100px;
font-family: RobotoFlex, sans-serif;
}

/* This one will exercise wdth 87.5 as it's in-range according to the @font-face */
.first {
font-stretch: semi-condensed;
}

/* This one will be rendered as faux stretch based on the highest font-stretch available according to the @font-face */
.second {
font-stretch: 200;
}

/* This one will exercise wdth 147 despite it being out of the font-stretch range of the @font-face */
.third {
font-stretch: 100;
font-variation-settings: "wdth" 147;
}
</style>
</head>
<body>
<p class="first">Hello</p>
<p class="second">there</p>
<p class="third">world!</p>
</body>
</html>

0 comments on commit d7758eb

Please sign in to comment.