Skip to content

Commit

Permalink
Disable notice about unused variation axis ranges when there's an out…
Browse files Browse the repository at this point in the history
…-of-bounds cubic-bezier animation timing function in play
  • Loading branch information
papandreou committed Aug 25, 2022
1 parent 2a47adc commit 1cf4ff4
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 29 deletions.
75 changes: 49 additions & 26 deletions lib/getCssRulesByProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,36 +145,59 @@ function getCssRulesByProperty(properties, cssSource, existingPredicates) {
});
});
}
} else if (
propName === 'animation' &&
properties.includes('animation-name')
) {
} else if (propName === 'animation') {
// Shorthand
const animationName = parseAnimationShorthand.parseSingle(
node.value
).name;
const parsedAnimation = parseAnimationShorthand.parseSingle(node.value);

// Split up combined selectors as they might have different specificity
specificity
.calculate(node.parent.selector)
.forEach((specificityObject) => {
const isStyleAttribute =
specificityObject.selector === 'bogusselector';
if (properties.includes('animation-name')) {
// Split up combined selectors as they might have different specificity
specificity
.calculate(node.parent.selector)
.forEach((specificityObject) => {
const isStyleAttribute =
specificityObject.selector === 'bogusselector';

rulesByProperty['animation-name'].push({
predicates: getCurrentPredicates(),
namespaceURI: defaultNamespaceURI,
selector: isStyleAttribute
? undefined
: specificityObject.selector.trim(),
specificityArray: isStyleAttribute
? [1, 0, 0, 0]
: specificityObject.specificityArray,
prop: 'animation-name',
value: animationName,
important: !!node.important,
rulesByProperty['animation-name'].push({
predicates: getCurrentPredicates(),
namespaceURI: defaultNamespaceURI,
selector: isStyleAttribute
? undefined
: specificityObject.selector.trim(),
specificityArray: isStyleAttribute
? [1, 0, 0, 0]
: specificityObject.specificityArray,
prop: 'animation-name',
value: parsedAnimation.name,
important: !!node.important,
});
});
});
}
if (properties.includes('animation-timing-function')) {
// Split up combined selectors as they might have different specificity
specificity
.calculate(node.parent.selector)
.forEach((specificityObject) => {
const isStyleAttribute =
specificityObject.selector === 'bogusselector';

rulesByProperty['animation-timing-function'].push({
predicates: getCurrentPredicates(),
namespaceURI: defaultNamespaceURI,
selector: isStyleAttribute
? undefined
: specificityObject.selector.trim(),
specificityArray: isStyleAttribute
? [1, 0, 0, 0]
: specificityObject.specificityArray,
prop: 'animation-timing-function',
value: parseAnimationShorthand.serialize({
name: '',
timingFunction: parsedAnimation.timingFunction,
}),
important: !!node.important,
});
});
}
} else if (propName === 'transition') {
// Shorthand
const transitionProperties = [];
Expand Down
43 changes: 41 additions & 2 deletions lib/subsetFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const gatherStylesheetsWithPredicates = require('./gatherStylesheetsWithPredicat
const findCustomPropertyDefinitions = require('./findCustomPropertyDefinitions');
const extractReferencedCustomPropertyNames = require('./extractReferencedCustomPropertyNames');
const parseFontVariationSettings = require('./parseFontVariationSettings');
const parseAnimationShorthand = require('@hookun/parse-animation-shorthand');
const stripLocalTokens = require('./stripLocalTokens');
const injectSubsetDefinitions = require('./injectSubsetDefinitions');
const cssFontParser = require('css-font-parser');
Expand Down Expand Up @@ -87,6 +88,21 @@ function getPreferredFontUrl(cssFontFaceSrcRelations = []) {
}
}

function isOutOfBoundsAnimationTimingFunction(animationTimingFunctionStr) {
if (typeof animationTimingFunctionStr !== 'string') {
return false;
}
const { timingFunction } = parseAnimationShorthand.parseSingle(
`${animationTimingFunctionStr} ignored-name`
);

if (timingFunction.type === 'cubic-bezier') {
const [, y1, , y2] = timingFunction.value;
return y1 > 1 || y1 < 0 || y2 > 1 || y2 < 0;
}
return false;
}

// Hack to extract '@font-face { ... }' with all absolute urls
function getFontFaceDeclarationText(node, relations) {
const originalHrefTypeByRelation = new Map();
Expand Down Expand Up @@ -182,6 +198,8 @@ function groupTextsByFontFamilyProps(
htmlOrSvgAsset: textAndProps.htmlOrSvgAsset,
text: textAndProps.text,
fontVariationSettings: textAndProps.props['font-variation-settings'],
animationTimingFunction:
textAndProps.props['animation-timing-function'],
props,
fontRelations: relations,
fontUrl,
Expand All @@ -208,6 +226,9 @@ function groupTextsByFontFamilyProps(
fontVariationSettings.toLowerCase() !== 'normal'
)
);
const hasOutOfBoundsAnimationTimingFunction = textsPropsArray.some((obj) =>
isOutOfBoundsAnimationTimingFunction(obj.animationTimingFunction)
);

let smallestOriginalSize;
let smallestOriginalFormat;
Expand Down Expand Up @@ -236,6 +257,7 @@ function groupTextsByFontFamilyProps(
fontUrl,
fontFamilies,
fontVariationSettings,
hasOutOfBoundsAnimationTimingFunction,
preload,
};
});
Expand Down Expand Up @@ -693,9 +715,14 @@ function warnAboutUnusedCustomVariationAxes(
assetGraph
) {
const seenAxisValuesByFontUrlAndAxisName = new Map();
const outOfBoundsAxesByFontUrl = new Map();

for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
for (const { fontUrl, fontVariationSettings } of fontUsages) {
for (const {
fontUrl,
fontVariationSettings,
hasOutOfBoundsAnimationTimingFunction,
} of fontUsages) {
let seenAxes = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
if (!seenAxes) {
seenAxes = new Map();
Expand All @@ -712,6 +739,14 @@ function warnAboutUnusedCustomVariationAxes(
} else {
seenAxes.set(axisName, [axisValue]);
}
if (hasOutOfBoundsAnimationTimingFunction) {
let outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl);
if (!outOfBoundsAxes) {
outOfBoundsAxes = new Set();
outOfBoundsAxesByFontUrl.set(fontUrl, outOfBoundsAxes);
}
outOfBoundsAxes.add(axisName);
}
}
}
}
Expand All @@ -722,6 +757,7 @@ function warnAboutUnusedCustomVariationAxes(
fontUrl,
seenAxisValuesByAxisName,
] of seenAxisValuesByFontUrlAndAxisName.entries()) {
const outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl) || new Set();
let font;
try {
font = fontkit.create(assetGraph.findAssets({ url: fontUrl })[0].rawSrc);
Expand All @@ -738,7 +774,10 @@ function warnAboutUnusedCustomVariationAxes(
if (standardVariationAxes.has(axisName)) {
continue;
}
if (seenAxisValuesByAxisName.has(axisName)) {
if (
seenAxisValuesByAxisName.has(axisName) &&
!outOfBoundsAxes.has(axisName)
) {
const usedValues = [
defaultValue,
...seenAxisValuesByAxisName.get(axisName),
Expand Down
54 changes: 53 additions & 1 deletion test/subsetFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ describe('subsetFonts', function () {
),
fontFamilies: expect.it('to be a', Set),
fontVariationSettings: expect.it('to be a', Set),
hasOutOfBoundsAnimationTimingFunction: false,
codepoints: {
original: expect.it('to be an array'),
used: [32, 72, 101, 108, 111],
Expand Down Expand Up @@ -2873,7 +2874,7 @@ describe('subsetFonts', function () {
});
});

describe('with a variable font that has unused custom axes', function () {
describe('with a variable font that has unused custom axis ranges', function () {
it('should emit an info event', async function () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
Expand All @@ -2897,6 +2898,57 @@ describe('subsetFonts', function () {
});
});
});

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 () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
__dirname,
'../testdata/subsetFonts/variable-font-underutilized-axis-with-bezier/'
),
});
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',
'Underutilized axes:\n YTAS: 400-750 used (649-854 available)'
),
});
});
});
});

describe('that goes out of bounds', function () {
it('should not inform about the axis being underutilized', async function () {
const assetGraph = new AssetGraph({
root: pathModule.resolve(
__dirname,
'../testdata/subsetFonts/variable-font-underutilized-axis-with-bezier-out-of-bounds/'
),
});
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('not to contain', 'YTAS:'),
});
});
});
});
});
});

describe('with omitFallbacks:true', function () {
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<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');
}

p {
font-family: RobotoFlex, sans-serif;
animation: 3s cubic-bezier(.97,.01,.42,1.52) infinite alternate foo;
}

@keyframes foo {
0% {
font-variation-settings: "XTRA" 200, "YTAS" 400;
}
100% {
font-variation-settings: "XTRA" 800, "YTAS" 700;
}
}
</style>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<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');
}

p {
font-family: RobotoFlex, sans-serif;
animation: 3s cubic-bezier(0,.75,.9,.58) infinite alternate foo;
}

@keyframes foo {
0% {
font-variation-settings: "XTRA" 200, "YTAS" 400;
}
100% {
font-variation-settings: "XTRA" 800, "YTAS" 700;
}
}
</style>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>

0 comments on commit 1cf4ff4

Please sign in to comment.