diff --git a/lib/subsetFonts.js b/lib/subsetFonts.js index 485c6a49..64aad70d 100644 --- a/lib/subsetFonts.js +++ b/lib/subsetFonts.js @@ -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'] @@ -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'], @@ -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 @@ -266,6 +273,7 @@ function groupTextsByFontFamilyProps( props: { ...textsPropsArray[0].props }, fontUrl, fontFamilies, + fontStyles, fontWeights, fontVariationSettings, hasOutOfBoundsAnimationTimingFunction, @@ -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) { @@ -757,6 +766,7 @@ function warnAboutUnusedVariationAxes( for (const { fontUrl, fontVariationSettings, + fontStyles, fontWeights, hasOutOfBoundsAnimationTimingFunction, props, @@ -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) { @@ -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) { diff --git a/test/subsetFonts.js b/test/subsetFonts.js index 3b861638..7a681ca8 100644 --- a/test/subsetFonts.js +++ b/test/subsetFonts.js @@ -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, @@ -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 () { diff --git a/testdata/subsetFonts/variable-font-unused-ital-axis/FontStyleTest-ital-VF.woff2 b/testdata/subsetFonts/variable-font-unused-ital-axis/FontStyleTest-ital-VF.woff2 new file mode 100644 index 00000000..1c038913 Binary files /dev/null and b/testdata/subsetFonts/variable-font-unused-ital-axis/FontStyleTest-ital-VF.woff2 differ diff --git a/testdata/subsetFonts/variable-font-unused-ital-axis/italic.html b/testdata/subsetFonts/variable-font-unused-ital-axis/italic.html new file mode 100644 index 00000000..da1eba7e --- /dev/null +++ b/testdata/subsetFonts/variable-font-unused-ital-axis/italic.html @@ -0,0 +1,16 @@ + + + + + + + +

Hello, world!

+ + diff --git a/testdata/subsetFonts/variable-font-unused-ital-axis/normal.html b/testdata/subsetFonts/variable-font-unused-ital-axis/normal.html new file mode 100644 index 00000000..fb5dc62f --- /dev/null +++ b/testdata/subsetFonts/variable-font-unused-ital-axis/normal.html @@ -0,0 +1,16 @@ + + + + + + + +

Hello, world!

+ + diff --git a/testdata/subsetFonts/variable-font-unused-ital-axis/normal_and_italic.html b/testdata/subsetFonts/variable-font-unused-ital-axis/normal_and_italic.html new file mode 100644 index 00000000..627f7794 --- /dev/null +++ b/testdata/subsetFonts/variable-font-unused-ital-axis/normal_and_italic.html @@ -0,0 +1,21 @@ + + + + + + + +

Hello, world!

+

Hello, world!

+ + diff --git a/testdata/subsetFonts/variable-font-unused-ital-axis/styles.css b/testdata/subsetFonts/variable-font-unused-ital-axis/styles.css new file mode 100644 index 00000000..fd58edef --- /dev/null +++ b/testdata/subsetFonts/variable-font-unused-ital-axis/styles.css @@ -0,0 +1,4 @@ +@font-face { + font-family: MyFontFamily; + src: url('FontStyleTest-ital-VF.woff2') format('woff2-variations'); +}