Skip to content

Commit

Permalink
Detect unused ital variation axis ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
papandreou committed Sep 4, 2022
1 parent 4fcf7df commit b848b21
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 5 deletions.
37 changes: 32 additions & 5 deletions lib/subsetFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ function groupTextsByFontFamilyProps(
const { relations, ...props } = activeFontFaceDeclaration;
const fontUrl = getPreferredFontUrl(relations);

const fontStyle = normalizeFontPropertyValue(
'font-style',
textAndProps.props['font-style']
);

let fontWeight = normalizeFontPropertyValue(
'font-weight',
textAndProps.props['font-weight']
Expand All @@ -206,6 +211,7 @@ function groupTextsByFontFamilyProps(
htmlOrSvgAsset: textAndProps.htmlOrSvgAsset,
text: textAndProps.text,
fontVariationSettings: textAndProps.props['font-variation-settings'],
fontStyle,
fontWeight,
animationTimingFunction:
textAndProps.props['animation-timing-function'],
Expand All @@ -226,6 +232,7 @@ function groupTextsByFontFamilyProps(
const fontFamilies = new Set(
textsPropsArray.map((obj) => obj.props['font-family'])
);
const fontStyles = new Set(textsPropsArray.map((obj) => obj.fontStyle));
const fontWeights = new Set(textsPropsArray.map((obj) => obj.fontWeight));
const fontVariationSettings = new Set(
textsPropsArray
Expand Down Expand Up @@ -266,6 +273,7 @@ function groupTextsByFontFamilyProps(
props: { ...textsPropsArray[0].props },
fontUrl,
fontFamilies,
fontStyles,
fontWeights,
fontVariationSettings,
hasOutOfBoundsAnimationTimingFunction,
Expand Down Expand Up @@ -735,8 +743,9 @@ These glyphs are used on your site, but they don't exist in the font you applied
}
}

const standardVariationAxes = new Set(['wght', '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(['ital', 'slnt', 'opsz']);
const ignoredVariationAxes = new Set(['slnt', 'opsz']);

function renderNumberRange(min, max) {
if (min === max) {
Expand All @@ -757,6 +766,7 @@ function warnAboutUnusedVariationAxes(
for (const {
fontUrl,
fontVariationSettings,
fontStyles,
fontWeights,
hasOutOfBoundsAnimationTimingFunction,
props,
Expand All @@ -766,6 +776,23 @@ function warnAboutUnusedVariationAxes(
seenAxes = new Map();
seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
}
const seenItalValues = [];
if (fontStyles.has('italic')) {
seenItalValues.push(1);
}
// If any font-style value except italic is seen (including normal or oblique)
// we're also utilizing value 0:
if (fontStyles.size > fontStyles.has('italic') ? 1 : 0) {
seenItalValues.push(0);
}
if (seenItalValues.length > 0) {
if (seenAxes.has('ital')) {
seenAxes.get('ital').push(...seenItalValues);
} else {
seenAxes.set('ital', seenItalValues);
}
}

const minMaxFontWeight = parseFontWeightRange(props['font-weight']);
const seenFontWeightValues = [];
for (const fontWeight of fontWeights) {
Expand Down Expand Up @@ -824,10 +851,10 @@ function warnAboutUnusedVariationAxes(
continue;
}
if (seenAxisValuesByAxisName.has(name) && !outOfBoundsAxes.has(name)) {
const usedValues = [
defaultValue,
...seenAxisValuesByAxisName.get(name),
];
const usedValues = [...seenAxisValuesByAxisName.get(name)];
if (!standardVariationAxes.has(name)) {
usedValues.push(defaultValue);
}
const minUsed = Math.min(...usedValues);
const maxUsed = Math.max(...usedValues);
if (minUsed > min || maxUsed < max) {
Expand Down
74 changes: 74 additions & 0 deletions test/subsetFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ describe('subsetFonts', function () {
'https://fonts.gstatic.com/s/opensans/'
),
fontFamilies: expect.it('to be a', Set),
fontStyles: expect.it('to be a', Set),
fontWeights: expect.it('to be a', Set),
fontVariationSettings: expect.it('to be a', Set),
hasOutOfBoundsAnimationTimingFunction: false,
Expand Down Expand Up @@ -2926,6 +2927,79 @@ describe('subsetFonts', function () {
});
});

describe('for the ital axis', function () {
describe('when only font-style: normal is used', function () {
it('should emit an info event', async function () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
__dirname,
'../testdata/subsetFonts/variable-font-unused-ital-axis/'
),
});
await assetGraph.loadAssets('normal.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',
'Underutilized axes:\n ital: 0 used (0-1 available)'
),
});
});
});
});

describe('when only font-style: italic is used', function () {
it('should emit an info event', async function () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
__dirname,
'../testdata/subsetFonts/variable-font-unused-ital-axis/'
),
});
await assetGraph.loadAssets('italic.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',
'Underutilized axes:\n ital: 1 used (0-1 available)'
),
});
});
});
});

describe('when both font-style: normal and font-style: italic are used', function () {
it('should not emit an info event', async function () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
__dirname,
'../testdata/subsetFonts/variable-font-unused-ital-axis/'
),
});
await assetGraph.loadAssets('normal_and_italic.html');
await assetGraph.populate();
const infoSpy = sinon.spy().named('info');
assetGraph.on('info', infoSpy);

await subsetFonts(assetGraph);

expect(infoSpy, 'was not called');
});
});
});

describe('being animated with a cubic-bezier timing function', function () {
describe('that stays within bounds', function () {
it('should inform about the axis being underutilized', async function () {
Expand Down
Binary file not shown.
16 changes: 16 additions & 0 deletions testdata/subsetFonts/variable-font-unused-ital-axis/italic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<html>
<head>
<meta charset=utf-8>
<link rel="stylesheet" href="styles.css">
<style>
p {
font-size: 100px;
font-family: MyFontFamily, sans-serif;
font-style: italic;
}
</style>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
16 changes: 16 additions & 0 deletions testdata/subsetFonts/variable-font-unused-ital-axis/normal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<html>
<head>
<meta charset=utf-8>
<link rel="stylesheet" href="styles.css">
<style>
p {
font-size: 100px;
font-family: MyFontFamily, sans-serif;
font-style: normal;
}
</style>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<html>
<head>
<meta charset=utf-8>
<link rel="stylesheet" href="styles.css">
<style>
p {
font-size: 100px;
font-family: MyFontFamily, sans-serif;
font-style: normal;
}

.italic {
font-style: italic;
}
</style>
</head>
<body>
<p>Hello, world!</p>
<p class="italic"">Hello, world!</p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@font-face {
font-family: MyFontFamily;
src: url('FontStyleTest-ital-VF.woff2') format('woff2-variations');
}

0 comments on commit b848b21

Please sign in to comment.