├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .mocharc.yml ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .vscode └── launch.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── cases └── unicode-range-fallbacks │ └── index.html ├── images └── before-after.png ├── lib ├── HeadlessBrowser.js ├── cli.js ├── extractReferencedCustomPropertyNames.js ├── findCustomPropertyDefinitions.js ├── gatherStylesheetsWithPredicates.js ├── getCssRulesByProperty.js ├── getFontInfo.js ├── initialValueByProp.js ├── injectSubsetDefinitions.js ├── normalizeFontPropertyValue.js ├── parseCommandLineOptions.js ├── parseFontVariationSettings.js ├── stripLocalTokens.js ├── subfont.js ├── subsetFonts.js ├── unicodeRange.js └── unquote.js ├── package.json ├── renovate.json ├── test ├── .eslintrc.yml ├── cli.js ├── expect.js ├── extractReferencedCustomPropertyNames.js ├── findCustomPropertyDefinitions.js ├── gatherStylesheetsWithPredicates.js ├── generatedHtml.js ├── getCssRulesByProperty.js ├── injectSubsetDefinitions.js ├── normalizeFontPropertyValue.js ├── parseCommandLineOptions.js ├── parseFontVariationSettings.js ├── referenceImages.js ├── stripLocalTokens.js ├── subfont.js ├── subsetFonts.js ├── unicodeRange.js └── unquote.js └── testdata ├── browserslistInPackageJson ├── index.html └── package.json ├── canonicalUrlWithPathComponent ├── OpenSans.ttf └── index.html ├── canonicalUrlWithoutPathComponent ├── OpenSans.ttf └── index.html ├── differentCodepointsOnDifferentPages ├── OpenSans.ttf ├── first.html └── second.html ├── dynamicallyInjectedText ├── OpenSans.ttf └── index.html ├── dynamicallyRemovedText ├── OpenSans.ttf └── index.html ├── gatherStylesheetsWithPredicates ├── cssImportWithMedia │ ├── a.css │ └── index.html ├── cssImportWithMediaWithExistingIncomingMedia │ ├── a.css │ └── index.html ├── cyclicCssImport │ ├── a.css │ └── index.html ├── htmlStyle │ ├── a.css │ └── index.html ├── htmlStyleWithMediaAttribute │ ├── a.css │ └── index.html ├── inlineHtmlStyle │ └── index.html ├── inlineHtmlStyleWithMediaAttribute │ └── index.html ├── sameStylesheetIncludedTwice │ ├── a.css │ ├── b.css │ └── index.html └── unloadedCssAssets │ ├── a.css │ └── index.html ├── iframe ├── SourceSerifVariable-Roman.ttf.woff2 └── index.html ├── k3k702ZOKiLJc3WVjuplzHhCUOGz7vYGh680lGh-uXM.woff ├── noFontUsageOnOnePage ├── OpenSans.ttf ├── first.html └── second.html ├── pageWithErrors ├── OpenSans.ttf └── index.html ├── pageWithStrictCsp ├── OpenSans.ttf └── index.html ├── referenceImages ├── fontVariant │ ├── IBMPlexSans-Italic.woff │ ├── IBMPlexSans-Regular.woff │ └── index.html ├── fullyInstancedVariableFont │ ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf │ └── index.html ├── ligatures │ ├── Roboto-400.woff2 │ └── index.html ├── missingGlyphs │ ├── IBMPlexSans-Italic.woff │ ├── IBMPlexSans-Regular.woff │ ├── JimNightshade-400.woff2 │ └── index.html ├── unusedVariants │ ├── IBMPlexSans-Italic.woff │ ├── IBMPlexSans-Regular.woff │ └── index.html └── withoutLigatures │ ├── Roboto-400.woff2 │ └── index.html ├── smiley.svg ├── stylesheetAtOtherOrigin └── referencesFont │ └── index.html └── subsetFonts ├── JimNightshade-400.ttf ├── Montserrat-400.ttf ├── OpenSans-400.ttf ├── OpenSans-400.woff ├── OpenSans-400.woff2 ├── Roboto-300.ttf ├── Roboto-300.woff ├── Roboto-300.woff2 ├── Roboto-300i.ttf ├── Roboto-300i.woff ├── Roboto-400.ttf ├── Roboto-400.woff ├── Roboto-400.woff2 ├── Roboto-500.ttf ├── Roboto-500.woff ├── Roboto-500.woff2 ├── SpaceMono-400.ttf ├── css-import-twice-different-css ├── index.html └── styles.css ├── css-import-twice └── index.html ├── css-import └── index.html ├── css-source-map-external ├── OpenSans.ttf ├── index.html ├── styles.css ├── styles.css.map └── styles.less ├── css-source-map-inline ├── OpenSans.ttf ├── index.html ├── styles.css └── styles.less ├── emojis ├── IBMPlexSans-Regular.woff ├── index-1.html └── index-2.html ├── existing-prefetch ├── OpenSans.ttf └── index.html ├── existing-preload ├── OpenSans.ttf └── index.html ├── firstPageNoSubset ├── IBMPlexSans-Regular.woff ├── index-1.html └── index-2.html ├── font-face-defaults-and-casing ├── OpenSans.ttf ├── OpenSans2.ttf └── index.html ├── font-family-with-escape ├── OpenSans.ttf └── index.html ├── font-shorthand-with-custom-property └── index.html ├── font-shorthand └── index.html ├── font-weight-and-style-omitted ├── OpenSans.ttf └── index.html ├── google-webfont-ref-in-javascript └── index.html ├── html-link └── index.html ├── inline-one-subset-multi-page ├── IBMPlexSans-Italic.woff ├── IBMPlexSans-Regular.woff ├── index-1.html └── index-2.html ├── inline-subsets-multi-page ├── IBMPlexSans-Italic.woff ├── IBMPlexSans-Regular.woff ├── index-1.html └── index-2.html ├── inline-subsets ├── OpenSans.ttf └── index.html ├── issue131 ├── about.html ├── assets │ ├── fonts │ │ └── fontawesome-all.min.css │ └── webfonts │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.svg │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ └── fa-regular-400.woff2 └── index.html ├── local-font-family-case-difference ├── OpenSans.ttf └── index.html ├── local-invalid ├── OpenSans.ttf └── index.html ├── local-mixed ├── LocalSans.ttf └── index.html ├── local-single ├── OpenSans.ttf └── index.html ├── local-unused-with-subfont-text ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff └── index.html ├── local-unused ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff └── index.html ├── local-used-multipage-with-subfont-text ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff ├── page1.html ├── page2.html └── styles.css ├── local-used-with-subfont-text ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff └── index.html ├── local-used ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff └── index.html ├── local-with-no-css-rules-in-font-face-stylesheet-only-comment ├── OpenSans.ttf └── index.html ├── local-with-no-css-rules-in-font-face-stylesheet-only-license-comment ├── OpenSans.ttf └── index.html ├── local-with-no-css-rules-in-font-face-stylesheet ├── OpenSans.ttf └── index.html ├── local-with-noscript ├── OpenSans.ttf └── index.html ├── missing-font-family ├── IBMPlexSans-Regular.woff └── index.html ├── missing-glyphs-multiple-variants ├── InputMono-Medium.woff2 ├── InputMono-Regular.woff2 ├── OutputSans-Bold.woff2 ├── OutputSans-Regular.woff2 └── index.html ├── missing-glyphs-unicode-range ├── OpenSans.ttf └── index.html ├── missing-glyphs ├── OpenSans.ttf └── index.html ├── missing-tab-and-newline-glyphs ├── OpenSans.ttf └── index.html ├── multi-entry-points-ssr ├── first.html ├── font1.woff2 ├── font2.woff2 ├── second.html └── styles.css ├── multi-family └── index.html ├── multi-page-same-subset ├── IBMPlexSans-Italic.woff ├── IBMPlexSans-Regular.woff ├── index-1.html └── index-2.html ├── multi-page-with-same-local-style-file ├── css │ └── style.css ├── fonts │ ├── JetBrainsMono-Bold.ttf │ ├── JetBrainsMono-Italic.ttf │ └── JetBrainsMono-Regular.ttf ├── index.html └── subindex.html ├── multi-page ├── about.html └── index.html ├── multi-weight └── index.html ├── multiple-font-face-with-same-src ├── OpenSans.ttf └── index.html ├── no-fallbacks ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff ├── KFOmCnqEu92Fr1Mu4mxM.woff └── index.html ├── non-truetype-and-truetype ├── icomoon.dev.svg ├── icomoon.eot ├── icomoon.svg ├── icomoon.ttf ├── icomoon.woff └── index.html ├── non-truetype-font ├── index.html ├── one.eot ├── three.svg └── two.eot ├── nonExistentFont ├── Roboto-400.woff2 └── index.html ├── one-page-with-no-font-face-ssr ├── first.html ├── font1.woff2 ├── second.html └── styles.css ├── one-page-with-no-usage-ssr ├── first.html ├── font1.woff2 ├── second.html └── styles.css ├── svg ├── img-element │ ├── KFOmCnqEu92Fr1Mu4mxM.woff │ ├── image.svg │ └── index.html ├── inline-in-html-font-face-in-both-places │ ├── KFOmCnqEu92Fr1Mu4mxM.woff │ └── index.html ├── inline-in-html-with-html-font-face │ ├── KFOmCnqEu92Fr1Mu4mxM.woff │ └── index.html └── inline-in-html-with-own-font-face │ ├── KFOmCnqEu92Fr1Mu4mxM.woff │ └── index.html ├── two-pages-import-css ├── index1.html ├── index2.html └── styles.css ├── two-variable-fonts-animated ├── Venn_Regular.woff2 ├── Venn_VF_1-500.woff2 ├── Venn_VF_501-900.woff2 └── index.html ├── unused-font ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff ├── KFOmCnqEu92Fr1Mu4mxM.woff └── index.html ├── unused-variant-on-one-page ├── IBMPlexSans-Italic.woff ├── IBMPlexSans-Regular.woff ├── index-1.html └── index-2.html ├── unused-variant-preload-google └── index.html ├── unused-variant-preload ├── InputMono-Medium.woff2 ├── InputMono-Regular.woff2 └── index.html ├── unused-variant ├── KFOjCnqEu92Fr1Mu51TzBic6CsI.woff ├── KFOmCnqEu92Fr1Mu4mxM.woff └── index.html ├── variable-font-in-supports-block-with-fallback ├── Venn_Regular.woff2 ├── Venn_VF.woff2 └── index.html ├── variable-font-in-supports-block-with-two-fallback-variants ├── Venn_Bold.woff2 ├── Venn_Regular.woff2 ├── Venn_VF.woff2 └── index.html ├── variable-font-that-can-be-fully-instanced ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html ├── variable-font-that-can-be-partially-instanced ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html ├── variable-font-underutilized-axis-with-bezier-out-of-bounds ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html ├── variable-font-underutilized-axis-with-bezier ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html ├── variable-font-unused-axes ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html ├── variable-font-unused-ital-axis ├── FontStyleTest-ital-VF.woff2 ├── italic.html ├── normal.html ├── normal_and_italic.html └── styles.css ├── variable-font-unused-slnt-axis ├── 2021-05-Extendomatic │ ├── ExtendomaticVariable-VF.woff2 │ ├── LICENSE.txt │ └── README.txt ├── normal.html ├── normal_and_oblique.html ├── oblique.html └── styles.css ├── variable-font-unused-wdth-axis ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html ├── variable-font-unused-wght-axis ├── RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf └── index.html └── woff2-original ├── BngRUXZYTXPIvIBgJJSb6u9mxLCGwR2oefDo.woff2 ├── BngRUXZYTXPIvIBgJJSb6u9mxLCIwR2oefDofMY.woff2 └── index.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /testdata/ 2 | /node_modules/ 3 | /coverage/ 4 | /vendor/ 5 | /puppeteer-browsers/ 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["standard", "prettier", "prettier/standard"], 3 | "plugins": ["mocha"], 4 | "rules": { 5 | "prefer-template": "error", 6 | "mocha/no-exclusive-tests": "error", 7 | "mocha/no-nested-tests": "error", 8 | "mocha/no-identical-title": "error", 9 | "prefer-const": [ 10 | "error", 11 | { 12 | "destructuring": "all", 13 | "ignoreReadBeforeAssign": false 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 'on': 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | name: Node ${{ matrix.node }} 10 | strategy: 11 | matrix: 12 | node: 13 | - '14' 14 | - '16' 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Setup node 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node }} 21 | - run: npm install 22 | - run: npm test 23 | 24 | test-targets: 25 | runs-on: ubuntu-latest 26 | name: ${{ matrix.targets.name }} 27 | strategy: 28 | matrix: 29 | targets: 30 | - name: 'Lint' 31 | target: 'lint' 32 | - name: 'Coverage' 33 | target: 'coverage' 34 | 35 | steps: 36 | - uses: actions/checkout@v2 37 | - name: Setup node 38 | uses: actions/setup-node@v1 39 | with: 40 | node-version: '14' 41 | - run: npm install 42 | - run: npm run ${{ matrix.targets.target }} 43 | - name: Upload coverage 44 | uses: coverallsapp/github-action@master 45 | with: 46 | github-token: ${{ secrets.GITHUB_TOKEN }} 47 | if: ${{ matrix.targets.target == 'coverage' }} 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .nyc_output 4 | puppeteer-browsers 5 | -------------------------------------------------------------------------------- /.mocharc.yml: -------------------------------------------------------------------------------- 1 | timeout: 300000 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock = false 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /coverage/ 3 | /.nyc_output/ 4 | /puppeteer-browsers/ 5 | 6 | # Don't battle npm i --save 7 | /package.json 8 | 9 | # Generated 10 | /CHANGELOG.md 11 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Test suite", 11 | "program": "${workspaceFolder}/node_modules/.bin/_mocha", 12 | "args": ["--timeout", "9999999999"], 13 | "skipFiles": [ 14 | "/**" // Prevent stepping through async_hooks.js et al. 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2017 Peter Brandt Müller 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /cases/unicode-range-fallbacks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 30 | 31 | 32 | 33 |

A🐮

34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /images/before-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/images/before-after.png -------------------------------------------------------------------------------- /lib/HeadlessBrowser.js: -------------------------------------------------------------------------------- 1 | const urlTools = require('urltools'); 2 | const puppeteer = require('puppeteer-core'); 3 | const pathModule = require('path'); 4 | 5 | async function transferResults(jsHandle) { 6 | const results = await jsHandle.jsonValue(); 7 | for (const [i, result] of results.entries()) { 8 | const resultHandle = await jsHandle.getProperty(String(i)); 9 | const elementHandle = await resultHandle.getProperty('node'); 10 | result.node = elementHandle; 11 | } 12 | return results; 13 | } 14 | 15 | async function downloadOrLocatePreferredBrowserRevision() { 16 | const browserFetcher = new puppeteer.BrowserFetcher({ 17 | path: pathModule.resolve(__dirname, '..', 'puppeteer-browsers'), 18 | }); 19 | const preferredRevision = puppeteer.default.defaultBrowserRevision; 20 | const localRevisions = await browserFetcher.localRevisions(); 21 | let revisionInfo; 22 | if (localRevisions.includes(preferredRevision)) { 23 | revisionInfo = await browserFetcher.revisionInfo(preferredRevision); 24 | } else { 25 | console.log(`Downloading Chromium ${preferredRevision}`); 26 | revisionInfo = await browserFetcher.download(preferredRevision); 27 | } 28 | return puppeteer.launch({ 29 | executablePath: revisionInfo.executablePath, 30 | }); 31 | } 32 | 33 | class HeadlessBrowser { 34 | constructor({ console }) { 35 | this.console = console; 36 | } 37 | 38 | _ensureBrowserDownloaded() {} 39 | 40 | _launchBrowserMemoized() { 41 | // Make sure we only download and launch one browser per HeadlessBrowser instance 42 | return (this._launchPromise = 43 | this._launchPromise || downloadOrLocatePreferredBrowserRevision()); 44 | } 45 | 46 | async tracePage(htmlAsset) { 47 | const assetGraph = htmlAsset.assetGraph; 48 | const browser = await this._launchBrowserMemoized(); 49 | const page = await browser.newPage(); 50 | 51 | // Make up a base url to map to the assetgraph root. 52 | // Use the canonical root if available, so that it'll be 53 | // easier to handle absolute and protocol-relative urls pointing 54 | // at it, as well as fall through to the actual domain if some 55 | // assets aren't found in the graph. 56 | const baseUrl = assetGraph.canonicalRoot 57 | ? assetGraph.canonicalRoot.replace(/\/?$/, '/') 58 | : 'https://example.com/'; 59 | 60 | // Intercept all requests made by the headless browser, and 61 | // fake a response from the assetgraph instance if the corresponding 62 | // asset is found there: 63 | await page.setRequestInterception(true); 64 | page.on('request', (request) => { 65 | const url = request.url(); 66 | if (url.startsWith(baseUrl)) { 67 | let agUrl = url.replace(baseUrl, assetGraph.root); 68 | if (/\/$/.test(agUrl)) { 69 | agUrl += 'index.html'; 70 | } 71 | const asset = assetGraph.findAssets({ 72 | isLoaded: true, 73 | url: agUrl, 74 | })[0]; 75 | if (asset) { 76 | request.respond({ 77 | status: 200, 78 | contentType: asset.contentType, 79 | body: asset.rawSrc, 80 | }); 81 | return; 82 | } 83 | } 84 | // Not found, let the original request through: 85 | request.continue(); 86 | }); 87 | 88 | page.on('requestfailed', (request) => { 89 | const response = request.response(); 90 | if (response && response.status() > 400) { 91 | this.console.error( 92 | `${request.method()} ${request.url()} returned ${response.status()}` 93 | ); 94 | } else { 95 | this.console.error( 96 | `${request.method()} ${request.url()} failed: ${ 97 | request.failure().errorText 98 | }` 99 | ); 100 | } 101 | }); 102 | 103 | page.on('pageerror', this.console.error); 104 | page.on('error', this.console.error); 105 | 106 | // Prevent the CSP of the page from rejecting our injection of font-tracer 107 | await page.setBypassCSP(true); 108 | 109 | await page.goto( 110 | urlTools.resolveUrl( 111 | baseUrl, 112 | urlTools.buildRelativeUrl(assetGraph.root, htmlAsset.url) 113 | ) 114 | ); 115 | 116 | await page.addScriptTag({ 117 | path: require.resolve('font-tracer/dist/fontTracer.browser.js'), 118 | }); 119 | 120 | const jsHandle = await page.evaluateHandle( 121 | /* global fontTracer */ 122 | /* istanbul ignore next */ 123 | () => fontTracer(document) 124 | ); 125 | return transferResults(jsHandle); 126 | } 127 | 128 | async close() { 129 | const launchPromise = this._launchPromise; 130 | if (launchPromise) { 131 | this._launchPromise = undefined; 132 | const browser = await launchPromise; 133 | await browser.close(); 134 | } 135 | } 136 | } 137 | 138 | module.exports = HeadlessBrowser; 139 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { yargs, help, ...options } = require('./parseCommandLineOptions')(); 4 | 5 | require('@gustavnikolaj/async-main-wrap')(require('./subfont'), { 6 | processError(err) { 7 | yargs.showHelp(); 8 | if (err.constructor === SyntaxError) { 9 | // Avoid rendering a stack trace for the wrong usage errors 10 | err.customOutput = err.message; 11 | } 12 | return err; 13 | }, 14 | })(options, console); 15 | -------------------------------------------------------------------------------- /lib/extractReferencedCustomPropertyNames.js: -------------------------------------------------------------------------------- 1 | const postcssValueParser = require('postcss-value-parser'); 2 | 3 | function extractReferencedCustomPropertyNames(cssValue) { 4 | const rootNode = postcssValueParser(cssValue); 5 | const customPropertyNames = new Set(); 6 | for (const node of rootNode.nodes) { 7 | if ( 8 | node.type === 'function' && 9 | node.value === 'var' && 10 | node.nodes.length >= 1 && 11 | node.nodes[0].type === 'word' && 12 | /^--/.test(node.nodes[0].value) 13 | ) { 14 | customPropertyNames.add(node.nodes[0].value); 15 | } 16 | } 17 | return customPropertyNames; 18 | } 19 | 20 | module.exports = extractReferencedCustomPropertyNames; 21 | -------------------------------------------------------------------------------- /lib/findCustomPropertyDefinitions.js: -------------------------------------------------------------------------------- 1 | const extractReferencedCustomPropertyNames = require('./extractReferencedCustomPropertyNames'); 2 | 3 | // Find all custom property definitions grouped by the custom properties they contribute to 4 | function findCustomPropertyDefinitions(cssAssets) { 5 | const definitionsByProp = {}; 6 | const incomingReferencesByProp = {}; 7 | for (const cssAsset of cssAssets) { 8 | cssAsset.eachRuleInParseTree((cssRule) => { 9 | if ( 10 | cssRule.parent.type === 'rule' && 11 | cssRule.type === 'decl' && 12 | /^--/.test(cssRule.prop) 13 | ) { 14 | (definitionsByProp[cssRule.prop] = 15 | definitionsByProp[cssRule.prop] || new Set()).add(cssRule); 16 | for (const customPropertyName of extractReferencedCustomPropertyNames( 17 | cssRule.value 18 | )) { 19 | (incomingReferencesByProp[cssRule.prop] = 20 | incomingReferencesByProp[cssRule.prop] || new Set()).add( 21 | customPropertyName 22 | ); 23 | } 24 | } 25 | }); 26 | } 27 | const expandedDefinitionsByProp = {}; 28 | for (const prop of Object.keys(definitionsByProp)) { 29 | expandedDefinitionsByProp[prop] = new Set(); 30 | const seenProps = new Set(); 31 | const queue = [prop]; 32 | while (queue.length > 0) { 33 | const referencedProp = queue.shift(); 34 | if (!seenProps.has(referencedProp)) { 35 | seenProps.add(referencedProp); 36 | if (definitionsByProp[referencedProp]) { 37 | for (const cssRule of definitionsByProp[referencedProp]) { 38 | expandedDefinitionsByProp[prop].add(cssRule); 39 | } 40 | } 41 | const incomingReferences = incomingReferencesByProp[referencedProp]; 42 | if (incomingReferences) { 43 | for (const incomingReference of incomingReferences) { 44 | queue.push(incomingReference); 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | return expandedDefinitionsByProp; 52 | } 53 | 54 | module.exports = findCustomPropertyDefinitions; 55 | -------------------------------------------------------------------------------- /lib/gatherStylesheetsWithPredicates.js: -------------------------------------------------------------------------------- 1 | module.exports = function gatherStylesheetsWithPredicates( 2 | assetGraph, 3 | htmlAsset 4 | ) { 5 | const assetStack = []; 6 | const incomingMedia = []; 7 | const conditionalCommentConditionStack = []; 8 | const result = []; 9 | (function traverse(asset, isWithinNotIeConditionalComment, isWithinNoscript) { 10 | if (assetStack.includes(asset)) { 11 | // Cycle detected 12 | return; 13 | } else if (!asset.isLoaded) { 14 | return; 15 | } 16 | assetStack.push(asset); 17 | for (const relation of assetGraph.findRelations({ 18 | from: asset, 19 | type: { 20 | $in: [ 21 | 'HtmlStyle', 22 | 'SvgStyle', 23 | 'CssImport', 24 | 'HtmlConditionalComment', 25 | 'HtmlNoscript', 26 | ], 27 | }, 28 | })) { 29 | if (relation.type === 'HtmlNoscript') { 30 | traverse(relation.to, isWithinNotIeConditionalComment, true); 31 | } else if (relation.type === 'HtmlConditionalComment') { 32 | conditionalCommentConditionStack.push(relation.condition); 33 | traverse( 34 | relation.to, 35 | isWithinNotIeConditionalComment || 36 | (relation.conditionalComments && 37 | relation.conditionalComments.length > 0), 38 | isWithinNoscript 39 | ); 40 | conditionalCommentConditionStack.pop(); 41 | } else { 42 | const media = relation.media; 43 | if (media) { 44 | incomingMedia.push(media); 45 | } 46 | traverse( 47 | relation.to, 48 | isWithinNotIeConditionalComment || 49 | (relation.conditionalComments && 50 | relation.conditionalComments.length > 0), 51 | isWithinNoscript 52 | ); 53 | if (media) { 54 | incomingMedia.pop(); 55 | } 56 | } 57 | } 58 | assetStack.pop(); 59 | if (asset.type === 'Css') { 60 | const predicates = {}; 61 | for (const incomingMedium of incomingMedia) { 62 | predicates[`mediaQuery:${incomingMedium}`] = true; 63 | } 64 | for (const conditionalCommentCondition of conditionalCommentConditionStack) { 65 | predicates[`conditionalComment:${conditionalCommentCondition}`] = true; 66 | } 67 | if (isWithinNoscript) { 68 | predicates.script = false; 69 | } 70 | if (isWithinNotIeConditionalComment) { 71 | predicates['conditionalComment:IE'] = false; 72 | } 73 | result.push({ 74 | text: asset.text, 75 | predicates, 76 | }); 77 | } 78 | })(htmlAsset); 79 | 80 | return result; 81 | }; 82 | -------------------------------------------------------------------------------- /lib/getFontInfo.js: -------------------------------------------------------------------------------- 1 | const fontverter = require('fontverter'); 2 | 3 | async function getFontInfoFromBuffer(buffer) { 4 | const harfbuzzJs = await require('harfbuzzjs'); 5 | 6 | const blob = harfbuzzJs.createBlob(await fontverter.convert(buffer, 'sfnt')); // Load the font data into something Harfbuzz can use 7 | const face = harfbuzzJs.createFace(blob, 0); // Select the first font in the file (there's normally only one!) 8 | 9 | const fontInfo = { 10 | characterSet: Array.from(face.collectUnicodes()), 11 | variationAxes: face.getAxisInfos(), 12 | }; 13 | 14 | face.destroy(); 15 | blob.destroy(); 16 | 17 | return fontInfo; 18 | } 19 | 20 | const fontInfoPromiseByBuffer = new WeakMap(); 21 | 22 | module.exports = function getFontInfo(buffer) { 23 | if (!fontInfoPromiseByBuffer.has(buffer)) { 24 | fontInfoPromiseByBuffer.set(buffer, getFontInfoFromBuffer(buffer)); 25 | } 26 | return fontInfoPromiseByBuffer.get(buffer); 27 | }; 28 | -------------------------------------------------------------------------------- /lib/initialValueByProp.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // 'font-family': 'serif' 3 | 'font-weight': 'normal', 4 | 'font-style': 'normal', 5 | 'font-stretch': 'normal', 6 | content: 'normal', 7 | quotes: '"«" "»" "‹" "›" "‘" "’" "\'" "\'" "\\"" "\\""', // Wide default set to account for browser differences 8 | 'list-style-type': 'none', 9 | display: 'inline', 10 | 'animation-name': 'none', 11 | 'text-transform': 'none', 12 | 'transition-property': 'all', 13 | 'transition-duration': '0s', 14 | 'counter-increment': 'none', 15 | 'counter-reset': 'none', 16 | 'counter-set': 'none', 17 | 'white-space': 'normal', 18 | }; 19 | -------------------------------------------------------------------------------- /lib/injectSubsetDefinitions.js: -------------------------------------------------------------------------------- 1 | const postcssValueParser = require('postcss-value-parser'); 2 | 3 | function injectSubsetDefinitions(cssValue, webfontNameMap, replaceOriginal) { 4 | const subsetFontNames = new Set( 5 | Object.values(webfontNameMap).map((name) => name.toLowerCase()) 6 | ); 7 | const rootNode = postcssValueParser(cssValue); 8 | let isPreceededByWords = false; 9 | for (const [i, node] of rootNode.nodes.entries()) { 10 | let possibleFontFamily; 11 | let lastFontFamilyTokenIndex = i; 12 | if (node.type === 'string') { 13 | possibleFontFamily = node.value; 14 | } else if (node.type === 'word' || node.type === 'space') { 15 | if (!isPreceededByWords) { 16 | const wordSequence = []; 17 | for (let j = i; j < rootNode.nodes.length; j += 1) { 18 | if (rootNode.nodes[j].type === 'word') { 19 | wordSequence.push(rootNode.nodes[j].value); 20 | lastFontFamilyTokenIndex = j; 21 | } else if (rootNode.nodes[j].type !== 'space') { 22 | break; 23 | } 24 | } 25 | possibleFontFamily = wordSequence.join(' '); 26 | } 27 | isPreceededByWords = true; 28 | } else { 29 | isPreceededByWords = false; 30 | } 31 | if (possibleFontFamily) { 32 | const possibleFontFamilyLowerCase = possibleFontFamily.toLowerCase(); 33 | if (subsetFontNames.has(possibleFontFamilyLowerCase)) { 34 | // Bail out, a subset font is already listed 35 | return cssValue; 36 | } else if (webfontNameMap[possibleFontFamilyLowerCase]) { 37 | const newToken = { 38 | type: 'string', 39 | value: webfontNameMap[possibleFontFamilyLowerCase].replace( 40 | /'/g, 41 | "\\'" 42 | ), 43 | quote: "'", 44 | }; 45 | if (replaceOriginal) { 46 | rootNode.nodes.splice( 47 | rootNode.nodes.indexOf(node), 48 | lastFontFamilyTokenIndex - i + 1, 49 | newToken 50 | ); 51 | } else { 52 | rootNode.nodes.splice(rootNode.nodes.indexOf(node), 0, newToken, { 53 | type: 'div', 54 | value: ',', 55 | after: ' ', 56 | }); 57 | } 58 | return postcssValueParser.stringify(rootNode); 59 | } 60 | } 61 | } 62 | return cssValue; 63 | } 64 | 65 | module.exports = injectSubsetDefinitions; 66 | -------------------------------------------------------------------------------- /lib/normalizeFontPropertyValue.js: -------------------------------------------------------------------------------- 1 | const cssFontWeightNames = require('css-font-weight-names'); 2 | const initialValueByProp = require('./initialValueByProp'); 3 | const unquote = require('./unquote'); 4 | const normalizeFontStretch = require('font-snapper/lib/normalizeFontStretch'); 5 | 6 | function normalizeFontPropertyValue(propName, value) { 7 | const propNameLowerCase = propName.toLowerCase(); 8 | if (value === undefined) { 9 | return initialValueByProp[propName]; 10 | } 11 | if (propNameLowerCase === 'font-family') { 12 | return unquote(value); 13 | } else if (propNameLowerCase === 'font-weight') { 14 | let parsedValue = value; 15 | if (typeof parsedValue === 'string') { 16 | // FIXME: Stripping the +bolder... suffix here will not always yield the correct result 17 | // when expanding animations and transitions 18 | parsedValue = parsedValue.replace(/\+.*$/, '').toLowerCase(); 19 | } 20 | parsedValue = parseFloat(cssFontWeightNames[parsedValue] || parsedValue); 21 | if (parsedValue >= 1 && parsedValue <= 1000) { 22 | return parsedValue; 23 | } else { 24 | return value; 25 | } 26 | } else if (propNameLowerCase === 'font-stretch') { 27 | return normalizeFontStretch(value); 28 | } else if (typeof value === 'string' && propNameLowerCase !== 'src') { 29 | return value.toLowerCase(); 30 | } 31 | return value; 32 | } 33 | 34 | module.exports = normalizeFontPropertyValue; 35 | -------------------------------------------------------------------------------- /lib/parseCommandLineOptions.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | 3 | module.exports = function parseCommandLineOptions(argv) { 4 | let yargs = require('yargs'); 5 | if (argv) { 6 | yargs = yargs(argv); 7 | } 8 | yargs 9 | .usage( 10 | 'Create optimal font subsets from your actual font usage.\n$0 [options] ' 11 | ) 12 | .options('root', { 13 | describe: 14 | 'Path to your web root (will be deduced from your input files if not specified)', 15 | type: 'string', 16 | demand: false, 17 | }) 18 | .options('canonical-root', { 19 | alias: ['canonicalroot'], 20 | describe: 21 | 'URI root where the site will be deployed. Must be either an absolute, a protocol-relative, or a root-relative url', 22 | type: 'string', 23 | demand: false, 24 | }) 25 | .options('output', { 26 | alias: 'o', 27 | describe: 'Directory where results should be written to', 28 | type: 'string', 29 | demand: false, 30 | }) 31 | .options('browsers', { 32 | describe: 33 | "Override your projects browserslist configuration to specify which browsers to support. Controls font formats and polyfill. Defaults to browserslist's default query if your project has no browserslist configuration", 34 | type: 'string', 35 | demand: false, 36 | }) 37 | .options('formats', { 38 | describe: 39 | 'Font formats to use when subsetting. The default is to select the formats based on the browser capabilities as specified via --browsers or the browserslist configuration.', 40 | type: 'string', // type: 'array' is weird: https://github.com/yargs/yargs/issues/846 41 | choices: ['woff2', 'woff', 'truetype'], 42 | coerce(formats) { 43 | // Make sure we support comma-separated syntax: --format truetype,woff 44 | return _.flatten( 45 | _.flatten([formats]).map((format) => format.split(',')) 46 | ); 47 | }, 48 | }) 49 | .options('text', { 50 | describe: 51 | 'Additional characters to include in the subset for every @font-face found on the page', 52 | type: 'string', 53 | }) 54 | .options('fallbacks', { 55 | describe: 56 | 'Include fallbacks so the original font will be loaded when dynamic content gets injected at runtime. Disable with --no-fallbacks', 57 | type: 'boolean', 58 | default: true, 59 | }) 60 | .options('dynamic', { 61 | describe: 62 | 'Also trace the usage of fonts in a headless browser with JavaScript enabled', 63 | type: 'boolean', 64 | default: false, 65 | }) 66 | .options('in-place', { 67 | alias: 'i', 68 | describe: 'Modify HTML-files in-place. Only use on build artifacts', 69 | type: 'boolean', 70 | default: false, 71 | }) 72 | .options('inline-css', { 73 | describe: 'Inline CSS that declares the @font-face for the subset fonts', 74 | type: 'boolean', 75 | default: false, 76 | }) 77 | .options('font-display', { 78 | describe: 'Injects a font-display value into the @font-face CSS', 79 | type: 'string', 80 | default: 'swap', 81 | choices: ['auto', 'block', 'swap', 'fallback', 'optional'], 82 | }) 83 | .options('recursive', { 84 | alias: 'r', 85 | describe: 86 | 'Crawl all HTML-pages linked with relative and root relative links. This stays inside your domain', 87 | type: 'boolean', 88 | default: false, 89 | }) 90 | .options('relative-urls', { 91 | describe: 'Issue relative urls instead of root-relative ones', 92 | type: 'boolean', 93 | default: false, 94 | }) 95 | .options('instance', { 96 | describe: 97 | "Experimentally instance variable fonts when the variation space isn't fully used", 98 | type: 'boolean', 99 | default: false, 100 | }) 101 | .options('silent', { 102 | alias: 's', 103 | describe: `Do not write anything to stdout`, 104 | type: 'boolean', 105 | default: false, 106 | }) 107 | .options('debug', { 108 | alias: 'd', 109 | describe: 'Verbose insights into font glyph detection', 110 | type: 'boolean', 111 | default: false, 112 | }) 113 | .options('dry-run', { 114 | alias: ['dry', 'dryrun'], 115 | describe: `Don't write anything to disk`, 116 | type: 'boolean', 117 | default: false, 118 | }) 119 | .check(({ harfbuzz, subsetPerPage, inlineFonts }) => { 120 | // Fail instead of silently ignoring legacy switches. 121 | // This prevents --subset-per-page etc. from implicitly being interpreted as 'string', 122 | // which means that it would consume a following non-option cli param 123 | if (subsetPerPage !== undefined) { 124 | return '--[no-]subset-per-page is no longer supported as of subfont 6.0.0'; 125 | } 126 | if (inlineFonts !== undefined) { 127 | return '--[no-]inline-fonts is no longer supported as of subfont 6.0.0'; 128 | } 129 | if (harfbuzz !== undefined) { 130 | return '--[no-]harfbuzz is no longer supported as of subfont 6.0.0 (harfbuzz is always used now)'; 131 | } else { 132 | return true; 133 | } 134 | }) 135 | .wrap(require('yargs').terminalWidth()); 136 | 137 | const { _: inputFiles, ...rest } = yargs.argv; 138 | 139 | return { 140 | yargs, 141 | inputFiles, 142 | ...rest, 143 | }; 144 | }; 145 | -------------------------------------------------------------------------------- /lib/parseFontVariationSettings.js: -------------------------------------------------------------------------------- 1 | const postcssValueParser = require('postcss-value-parser'); 2 | 3 | module.exports = function* parseFontVariationSettings(value) { 4 | let state = 'BEFORE_AXIS_NAME'; 5 | let axisName; 6 | for (const token of postcssValueParser(value).nodes) { 7 | if (token.type === 'space') { 8 | continue; 9 | } 10 | switch (state) { 11 | case 'BEFORE_AXIS_NAME': { 12 | if (token.type !== 'string') { 13 | return; 14 | } 15 | axisName = token.value; 16 | state = 'AFTER_AXIS_NAME'; 17 | break; 18 | } 19 | case 'AFTER_AXIS_NAME': { 20 | if (token.type === 'word') { 21 | const axisValue = parseFloat(token.value); 22 | if (!isNaN(axisValue)) { 23 | yield [axisName, axisValue]; 24 | } 25 | } 26 | state = 'AFTER_AXIS_VALUE'; 27 | break; 28 | } 29 | case 'AFTER_AXIS_VALUE': { 30 | if (token.type !== 'div' || token.value !== ',') { 31 | return; 32 | } 33 | axisName = undefined; 34 | state = 'BEFORE_AXIS_NAME'; 35 | break; 36 | } 37 | } 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /lib/stripLocalTokens.js: -------------------------------------------------------------------------------- 1 | const postcssValueParser = require('postcss-value-parser'); 2 | 3 | module.exports = function stripLocalTokens(cssValue) { 4 | const rootNode = postcssValueParser(cssValue); 5 | for (let i = 0; i < rootNode.nodes.length; i += 1) { 6 | const node = rootNode.nodes[i]; 7 | if (node.type === 'function' && node.value.toLowerCase() === 'local') { 8 | let numTokensToRemove = 1; 9 | if (i + 1 < rootNode.nodes.length) { 10 | const nextToken = rootNode.nodes[i + 1]; 11 | if (nextToken.type === 'div' && nextToken.value === ',') { 12 | numTokensToRemove += 1; 13 | if (i + 2 < rootNode.nodes.length) { 14 | rootNode.nodes[i + 2].before = node.before; 15 | } 16 | } 17 | } 18 | rootNode.nodes.splice(i, numTokensToRemove); 19 | i -= 1; 20 | } 21 | } 22 | return postcssValueParser.stringify(rootNode); 23 | }; 24 | -------------------------------------------------------------------------------- /lib/unicodeRange.js: -------------------------------------------------------------------------------- 1 | // A much, much smarter person than me solved this problem, and their code represents the bulk of the work here: 2 | // http://stackoverflow.com/questions/2270910/how-to-convert-sequence-of-numbers-in-an-array-to-range-of-numbers 3 | 4 | function getHexValue(num) { 5 | return num.toString(16).toUpperCase(); 6 | } 7 | 8 | /** 9 | * Generates a unicode-range string from an array of unicode codepoints 10 | * @param {Number[]} codePoints The code points 11 | * @return {String} The resulting [unicode-range](https://developer.mozilla.org/en-US/docs/Web/CSS/%40font-face/unicode-range) 12 | */ 13 | const getUnicodeRanges = (codePoints) => { 14 | const ranges = []; 15 | let start, end; 16 | 17 | codePoints.sort((a, b) => a - b); 18 | 19 | for (let i = 0; i < codePoints.length; i++) { 20 | start = codePoints[i]; 21 | end = start; 22 | 23 | while (codePoints[i + 1] - codePoints[i] === 1) { 24 | end = codePoints[i + 1]; 25 | i++; 26 | } 27 | 28 | ranges.push( 29 | start === end 30 | ? `U+${getHexValue(start)}` 31 | : `U+${getHexValue(start)}-${getHexValue(end)}` 32 | ); 33 | } 34 | 35 | return ranges.toString(); 36 | }; 37 | 38 | module.exports = getUnicodeRanges; 39 | -------------------------------------------------------------------------------- /lib/unquote.js: -------------------------------------------------------------------------------- 1 | function unescapeCssString(str) { 2 | return str.replace( 3 | /\\([0-9a-f]{1,6})(\s?)/gi, 4 | ($0, hexChars, followingWhitespace) => 5 | `${String.fromCharCode(parseInt(hexChars, 16))}${ 6 | hexChars.length === 6 ? followingWhitespace : '' 7 | }` 8 | ); 9 | } 10 | 11 | module.exports = function unquote(str) { 12 | if (typeof str !== 'string') { 13 | return str; 14 | } 15 | 16 | return str.replace( 17 | /^'([^']*)'$|^"([^"]*)"$/, 18 | ($0, singleQuoted, doubleQuoted) => 19 | typeof singleQuoted === 'string' 20 | ? unescapeCssString(singleQuoted.replace(/\\'/g, "'")) 21 | : unescapeCssString(doubleQuoted.replace(/\\"/g, '"')) 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "subfont", 3 | "version": "7.2.1", 4 | "description": "Speeds up your pages initial paint by automatically subsetting local or Google fonts and loading them optimally", 5 | "engines": { 6 | "node": ">=10.0.0" 7 | }, 8 | "scripts": { 9 | "lint": "eslint . && prettier --check '**/*.{js,md}'", 10 | "test": "mocha && npm run lint", 11 | "travis": "npm run coverage && npm run lint", 12 | "coverage": "nyc --reporter=lcov --reporter=text -- mocha", 13 | "preversion": "offline-github-changelog --next=${npm_new_version} > CHANGELOG.md && git add CHANGELOG.md" 14 | }, 15 | "bin": { 16 | "subfont": "lib/cli.js" 17 | }, 18 | "main": "lib/subfont.js", 19 | "files": [ 20 | "lib", 21 | "*.md" 22 | ], 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/Munter/subfont.git" 26 | }, 27 | "keywords": [ 28 | "google", 29 | "font", 30 | "fonts", 31 | "webfont", 32 | "webfonts", 33 | "subset", 34 | "subsetting", 35 | "commandline", 36 | "cli", 37 | "automation", 38 | "woff", 39 | "woff2", 40 | "preload" 41 | ], 42 | "author": "Peter Müller ", 43 | "license": "MIT", 44 | "bugs": { 45 | "url": "https://github.com/Munter/subfont/issues" 46 | }, 47 | "homepage": "https://github.com/Munter/subfont#readme", 48 | "dependencies": { 49 | "@gustavnikolaj/async-main-wrap": "^3.0.1", 50 | "@hookun/parse-animation-shorthand": "^0.1.5", 51 | "assetgraph": "^7.8.1", 52 | "browserslist": "^4.13.0", 53 | "css-font-parser": "^2.0.0", 54 | "css-font-weight-names": "^0.2.1", 55 | "css-list-helpers": "^2.0.0", 56 | "font-snapper": "^1.2.0", 57 | "font-tracer": "^3.7.0", 58 | "fontverter": "^2.0.0", 59 | "gettemporaryfilepath": "^1.0.1", 60 | "harfbuzzjs": "^0.3.3", 61 | "lines-and-columns": "^1.1.6", 62 | "lodash": "^4.17.15", 63 | "memoizesync": "^1.1.1", 64 | "postcss": "^8.3.11", 65 | "postcss-value-parser": "^4.0.2", 66 | "pretty-bytes": "^5.1.0", 67 | "puppeteer-core": "^19.8.5", 68 | "specificity": "^0.4.1", 69 | "subset-font": "^2.3.0", 70 | "urltools": "^0.4.1", 71 | "yargs": "^15.4.0" 72 | }, 73 | "devDependencies": { 74 | "combos": "^0.2.0", 75 | "coveralls": "^3.0.9", 76 | "css-generators": "^0.2.0", 77 | "eslint": "^7.4.0", 78 | "eslint-config-prettier": "^6.7.0", 79 | "eslint-config-standard": "^14.0.0", 80 | "eslint-plugin-import": "^2.22.0", 81 | "eslint-plugin-mocha": "^7.0.1", 82 | "eslint-plugin-node": "^11.1.0", 83 | "eslint-plugin-promise": "^4.0.1", 84 | "eslint-plugin-standard": "^4.0.0", 85 | "html-generators": "^1.0.3", 86 | "httpception": "^3.0.0", 87 | "magicpen-prism": "^3.0.2", 88 | "mocha": "^8.0.1", 89 | "nyc": "^15.1.0", 90 | "offline-github-changelog": "^1.6.1", 91 | "prettier": "~2.3.0", 92 | "proxyquire": "^2.1.1", 93 | "puppeteer": "^19.8.5", 94 | "sinon": "^9.0.2", 95 | "unexpected": "^11.8.1", 96 | "unexpected-check": "^2.3.1", 97 | "unexpected-resemble": "^5.0.1", 98 | "unexpected-set": "^2.0.1", 99 | "unexpected-sinon": "^10.11.2" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /test/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | mocha: true 3 | -------------------------------------------------------------------------------- /test/cli.js: -------------------------------------------------------------------------------- 1 | const pathModule = require('path'); 2 | const childProcess = require('child_process'); 3 | const expect = require('unexpected').clone(); 4 | 5 | function consumeStream(stream) { 6 | return new Promise((resolve, reject) => { 7 | const buffers = []; 8 | stream 9 | .on('data', (buffer) => buffers.push(buffer)) 10 | .on('end', () => resolve(Buffer.concat(buffers))) 11 | .on('error', reject); 12 | }); 13 | } 14 | 15 | async function runSubfont(...args) { 16 | const proc = childProcess.spawn( 17 | pathModule.resolve(__dirname, '..', 'lib', 'cli.js'), 18 | args 19 | ); 20 | 21 | const promises = { 22 | exit: new Promise((resolve, reject) => { 23 | proc.on('error', reject).on('exit', (exitCode) => { 24 | if (exitCode === 0) { 25 | resolve(); 26 | } else { 27 | const err = new Error(`Child process exited with ${exitCode}`); 28 | err.exitCode = exitCode; 29 | reject(err); 30 | } 31 | }); 32 | }), 33 | stdin: new Promise((resolve, reject) => { 34 | proc.stdin.on('error', reject).on('close', resolve); 35 | }), 36 | stdout: consumeStream(proc.stdout), 37 | stderr: consumeStream(proc.stderr), 38 | }; 39 | 40 | proc.stdin.end(); 41 | 42 | let err; 43 | try { 44 | await Promise.all(Object.values(promises)); 45 | } catch (_err) { 46 | err = _err; 47 | } 48 | return { 49 | err, 50 | stdout: (await promises.stdout).toString('utf-8'), 51 | stderr: (await promises.stderr).toString('utf-8'), 52 | }; 53 | } 54 | 55 | describe('cli', function () { 56 | it('should display usage info if --help is passed', async function () { 57 | const { err, stdout } = await runSubfont('--help'); 58 | expect(err, 'to be falsy'); 59 | expect(stdout, 'to contain', 'Options:'); 60 | expect(stdout, 'not to contain', 'No input files'); 61 | }); 62 | 63 | it('should display usage info if an error is encountered', async function () { 64 | const { err, stderr } = await runSubfont('i-do-not-exist.html'); 65 | expect(err, 'to have property', 'exitCode', 1); 66 | expect(stderr, 'to contain', 'Options:'); 67 | }); 68 | 69 | it('should a wrong usage error without a stack trace', async function () { 70 | const { err, stderr } = await runSubfont('https://example.com'); 71 | expect(err, 'to have property', 'exitCode', 1); 72 | expect( 73 | stderr, 74 | 'to contain', 75 | '--output has to be specified when using non-file input urls' 76 | ); 77 | expect(stderr, 'not to match', /^\s+at/m); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /test/expect.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected') 2 | .clone() 3 | .use(require('unexpected-sinon')) 4 | .use(require('unexpected-resemble')) 5 | .use(require('unexpected-check')) 6 | .use(require('magicpen-prism')); 7 | const subsetFonts = require('../lib/subsetFonts'); 8 | const pathModule = require('path'); 9 | const AssetGraph = require('assetgraph'); 10 | const sinon = require('sinon'); 11 | 12 | let browser; 13 | async function getBrowser() { 14 | if (!browser) { 15 | browser = await require('puppeteer').launch(); 16 | 17 | after(async function () { 18 | await browser.close(); 19 | }); 20 | } 21 | return browser; 22 | } 23 | 24 | async function screenshot(browser, assetGraph, fileName, bannedUrls) { 25 | const page = await browser.newPage(); 26 | await page.setRequestInterception(true); 27 | const loadedUrls = []; 28 | page.on('request', (request) => { 29 | const url = request.url(); 30 | loadedUrls.push(url); 31 | if (url.startsWith('https://example.com/')) { 32 | let agUrl = url.replace('https://example.com/', assetGraph.root); 33 | if (/\/$/.test(agUrl)) { 34 | agUrl += 'index.html'; 35 | } 36 | const asset = assetGraph.findAssets({ 37 | isLoaded: true, 38 | url: agUrl, 39 | })[0]; 40 | if (asset) { 41 | request.respond({ 42 | status: 200, 43 | contentType: asset.contentType, 44 | body: asset.rawSrc, 45 | }); 46 | return; 47 | } 48 | } 49 | request.continue(); 50 | }); 51 | await page.goto(`https://example.com/${fileName}`); 52 | if (bannedUrls) { 53 | const loadedBannedUrls = loadedUrls.filter((url) => 54 | bannedUrls.includes(url) 55 | ); 56 | if (loadedBannedUrls.length > 0) { 57 | throw new Error( 58 | `One or more of the original fonts were loaded:\n ${loadedBannedUrls.join( 59 | '\n ' 60 | )}` 61 | ); 62 | } 63 | } 64 | const screenshot = await page.screenshot(); 65 | await page.close(); 66 | return screenshot; 67 | } 68 | 69 | expect.addAssertion( 70 | ' to render the same after subsetting ', 71 | async (expect, fileName, options = {}) => { 72 | const assetGraph = new AssetGraph({ 73 | root: pathModule.dirname(fileName), 74 | }); 75 | const warnSpy = sinon.spy(); 76 | assetGraph.on('warn', warnSpy); 77 | await expect( 78 | assetGraph, 79 | 'to render the same after subsetting', 80 | options, 81 | pathModule.basename(fileName) 82 | ); 83 | expect(warnSpy, 'was not called'); 84 | } 85 | ); 86 | 87 | expect.addAssertion( 88 | ' to render the same after subsetting ', 89 | async (expect, assetGraph, options, fileName = 'index.html') => { 90 | const [htmlAsset] = await assetGraph.loadAssets(fileName); 91 | const originalText = htmlAsset.text; 92 | expect.subjectOutput = (output) => { 93 | output.code(originalText, 'html'); 94 | }; 95 | 96 | await assetGraph.populate(); 97 | const browser = await getBrowser(); 98 | const fontsBefore = assetGraph 99 | .findAssets({ type: { $in: ['Ttf', 'Woff', 'Woff2', 'Eot'] } }) 100 | .map((asset) => 101 | asset.url.replace(assetGraph.root, 'https://example.com/') 102 | ); 103 | const screenshotBefore = await screenshot(browser, assetGraph, fileName); 104 | const { fontInfo } = await subsetFonts(assetGraph, options); 105 | if (fontInfo.length > 0) { 106 | const screenshotAfter = await screenshot( 107 | browser, 108 | assetGraph, 109 | fileName, 110 | fontsBefore 111 | ); 112 | await expect(screenshotAfter, 'to resemble', screenshotBefore, { 113 | mismatchPercentage: expect.it('to be less than', 0.3), 114 | }); 115 | } 116 | } 117 | ); 118 | 119 | module.exports = expect; 120 | -------------------------------------------------------------------------------- /test/extractReferencedCustomPropertyNames.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected').clone().use(require('unexpected-set')); 2 | 3 | const extractReferencedCustomPropertyNames = require('../lib/extractReferencedCustomPropertyNames'); 4 | 5 | describe('extractReferencedCustomPropertyNames', function () { 6 | it('should return the empty set when no custom properties are referenced', function () { 7 | expect( 8 | extractReferencedCustomPropertyNames('foo(bar), local(abc), bla-bla'), 9 | 'to equal', 10 | new Set() 11 | ); 12 | }); 13 | 14 | it('should return the name of a referenced custom property', function () { 15 | expect( 16 | extractReferencedCustomPropertyNames('foo(bar), var(--abc), bla-bla'), 17 | 'to equal', 18 | new Set(['--abc']) 19 | ); 20 | }); 21 | 22 | it('should return the name of a referenced custom property with a default value', function () { 23 | expect( 24 | extractReferencedCustomPropertyNames( 25 | "foo(bar), var(--abc, 'the default'), bla-bla" 26 | ), 27 | 'to equal', 28 | new Set(['--abc']) 29 | ); 30 | }); 31 | 32 | it('should return the names of multiple referenced custom properties', function () { 33 | expect( 34 | extractReferencedCustomPropertyNames( 35 | 'foo(bar), var(--abc), bla-bla, var(--def)' 36 | ), 37 | 'to equal', 38 | new Set(['--abc', '--def']) 39 | ); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/findCustomPropertyDefinitions.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected').clone().use(require('unexpected-set')); 2 | const findCustomPropertyDefinitions = require('../lib/findCustomPropertyDefinitions'); 3 | const AssetGraph = require('assetgraph'); 4 | 5 | describe('findCustomPropertyDefinitions', function () { 6 | it('should find a single property', function () { 7 | const assetGraph = new AssetGraph(); 8 | const cssAsset = assetGraph.addAsset({ 9 | type: 'Css', 10 | text: ` 11 | :root { 12 | --foo: abc; 13 | } 14 | `, 15 | }); 16 | expect(findCustomPropertyDefinitions([cssAsset]), 'to satisfy', { 17 | '--foo': [{ value: 'abc' }], 18 | }); 19 | }); 20 | 21 | it('should find multiple definitions of the same custom property', function () { 22 | const assetGraph = new AssetGraph(); 23 | const cssAsset = assetGraph.addAsset({ 24 | type: 'Css', 25 | text: ` 26 | :root { 27 | --foo: abc; 28 | } 29 | 30 | html { 31 | --foo: def; 32 | } 33 | `, 34 | }); 35 | expect(findCustomPropertyDefinitions([cssAsset]), 'to satisfy', { 36 | '--foo': [{ value: 'abc' }, { value: 'def' }], 37 | }); 38 | }); 39 | 40 | it('should include the definitions of custom properties that contribute', function () { 41 | const assetGraph = new AssetGraph(); 42 | const cssAsset = assetGraph.addAsset({ 43 | type: 'Css', 44 | text: ` 45 | :root { 46 | --quux: def; 47 | --bar: var(--quux); 48 | } 49 | 50 | html { 51 | --foo: var(--bar); 52 | } 53 | `, 54 | }); 55 | expect(findCustomPropertyDefinitions([cssAsset]), 'to satisfy', { 56 | '--foo': [ 57 | { prop: '--foo', value: 'var(--bar)' }, 58 | { prop: '--bar', value: 'var(--quux)' }, 59 | ], 60 | '--bar': [ 61 | { prop: '--bar', value: 'var(--quux)' }, 62 | { prop: '--quux', value: 'def' }, 63 | ], 64 | '--quux': [{ prop: '--quux', value: 'def' }], 65 | }); 66 | }); 67 | 68 | it('should ignore custom property look-alikes inside strings', function () { 69 | const assetGraph = new AssetGraph(); 70 | const cssAsset = assetGraph.addAsset({ 71 | type: 'Css', 72 | text: ` 73 | :root { 74 | --quux: def; 75 | --bar: 'var(--quux)'; 76 | } 77 | 78 | html { 79 | --foo: var(--bar); 80 | } 81 | `, 82 | }); 83 | expect(findCustomPropertyDefinitions([cssAsset]), 'to satisfy', { 84 | '--foo': [ 85 | { prop: '--foo', value: 'var(--bar)' }, 86 | { prop: '--bar', value: "'var(--quux)'" }, 87 | ], 88 | '--bar': [{ prop: '--bar', value: "'var(--quux)'" }], 89 | '--quux': [{ prop: '--quux', value: 'def' }], 90 | }); 91 | }); 92 | 93 | it('should not break when there is a cyclic definition', function () { 94 | const assetGraph = new AssetGraph(); 95 | const cssAsset = assetGraph.addAsset({ 96 | type: 'Css', 97 | text: ` 98 | :root { 99 | --foo: var(--bar); 100 | } 101 | 102 | html { 103 | --bar: var(--foo); 104 | } 105 | `, 106 | }); 107 | expect(findCustomPropertyDefinitions([cssAsset]), 'to satisfy', { 108 | '--foo': [ 109 | { prop: '--foo', value: 'var(--bar)' }, 110 | { prop: '--bar', value: 'var(--foo)' }, 111 | ], 112 | }); 113 | }); 114 | 115 | it('should not break when an undefined custom property is referenced', function () { 116 | const assetGraph = new AssetGraph(); 117 | const cssAsset = assetGraph.addAsset({ 118 | type: 'Css', 119 | text: ` 120 | :root { 121 | --foo: var(--bar); 122 | } 123 | `, 124 | }); 125 | expect(findCustomPropertyDefinitions([cssAsset]), 'to satisfy', { 126 | '--foo': [{ prop: '--foo', value: 'var(--bar)' }], 127 | }); 128 | }); 129 | }); 130 | -------------------------------------------------------------------------------- /test/gatherStylesheetsWithPredicates.js: -------------------------------------------------------------------------------- 1 | const pathModule = require('path'); 2 | const gatherStylesheetsWithPredicates = require('../lib/gatherStylesheetsWithPredicates'); 3 | const expect = require('unexpected') 4 | .clone() 5 | .use(require('unexpected-sinon')) 6 | .addAssertion( 7 | ' to produce result satisfying ', 8 | async (expect, subject, value) => { 9 | const assetGraph = new AssetGraph({ 10 | root: pathModule.resolve( 11 | __dirname, 12 | '../testdata/gatherStylesheetsWithPredicates', 13 | subject 14 | ), 15 | }); 16 | 17 | await assetGraph.loadAssets('index.html'); 18 | await assetGraph.populate(); 19 | 20 | return expect( 21 | gatherStylesheetsWithPredicates( 22 | assetGraph, 23 | assetGraph.findAssets({ type: 'Html' })[0] 24 | ), 25 | 'to satisfy', 26 | value 27 | ); 28 | } 29 | ); 30 | const AssetGraph = require('assetgraph'); 31 | const sinon = require('sinon'); 32 | 33 | describe('gatherStylesheetsWithIncomingPredicates', function () { 34 | it('should follow inline HtmlStyle relations', function () { 35 | return expect('inlineHtmlStyle', 'to produce result satisfying', [ 36 | { text: '\n .a { font-weight: 500; }\n ', predicates: {} }, 37 | ]); 38 | }); 39 | 40 | it('should support the media attribute when following an inline HtmlStyle', function () { 41 | return expect( 42 | 'inlineHtmlStyleWithMediaAttribute', 43 | 'to produce result satisfying', 44 | [ 45 | { 46 | text: '\n .a { font-weight: 500; }\n ', 47 | predicates: { 'mediaQuery:3d-glasses': true }, 48 | }, 49 | ] 50 | ); 51 | }); 52 | 53 | it('should follow non-inline HtmlStyle relations', function () { 54 | return expect('htmlStyle', 'to produce result satisfying', [ 55 | { text: '.a { font-weight: 500; }\n', predicates: {} }, 56 | ]); 57 | }); 58 | 59 | it('should support the media attribute when following a non-inline HtmlStyle', function () { 60 | return expect( 61 | 'htmlStyleWithMediaAttribute', 62 | 'to produce result satisfying', 63 | [ 64 | { 65 | text: '.a { font-weight: 500; }\n', 66 | predicates: { 'mediaQuery:3d-glasses': true }, 67 | }, 68 | ] 69 | ); 70 | }); 71 | 72 | it('should list a stylesheet twice when it is being included multiple times', function () { 73 | return expect( 74 | 'sameStylesheetIncludedTwice', 75 | 'to produce result satisfying', 76 | [ 77 | { text: '.a { font-weight: 600; }\n', predicates: {} }, 78 | { text: '.b { font-weight: 500; }\n', predicates: {} }, 79 | { 80 | text: '.a { font-weight: 600; }\n', 81 | predicates: { 'mediaQuery:3d-glasses': true }, 82 | }, 83 | ] 84 | ); 85 | }); 86 | 87 | it('should pick up a media list attached to a CssImport', function () { 88 | return expect('cssImportWithMedia', 'to produce result satisfying', [ 89 | { 90 | text: '.a { font-weight: 600; }\n', 91 | predicates: { 'mediaQuery:projection': true }, 92 | }, 93 | { text: '\n @import "a.css" projection;\n ', predicates: {} }, 94 | ]); 95 | }); 96 | 97 | it('should stack up the incoming media following HtmlStyle -> CssImport', function () { 98 | return expect( 99 | 'cssImportWithMediaWithExistingIncomingMedia', 100 | 'to produce result satisfying', 101 | [ 102 | { 103 | text: '.a { font-weight: 600; }\n', 104 | predicates: { 105 | 'mediaQuery:3d-glasses': true, 106 | 'mediaQuery:projection': true, 107 | }, 108 | }, 109 | { 110 | text: '\n @import "a.css" projection;\n ', 111 | predicates: { 'mediaQuery:3d-glasses': true }, 112 | }, 113 | ] 114 | ); 115 | }); 116 | 117 | it('should not break when there is a cyclic CssImport', function () { 118 | return expect('cyclicCssImport', 'to produce result satisfying', [ 119 | { 120 | text: '@import "a.css";\n\n.a { font-weight: 600; }\n', 121 | predicates: {}, 122 | }, 123 | ]); 124 | }); 125 | 126 | it('should not break when there are unloaded Css assets', async function () { 127 | const warnSpy = sinon.spy().named('warn'); 128 | const assetGraph = new AssetGraph({ 129 | root: pathModule.resolve( 130 | __dirname, 131 | '../testdata/gatherStylesheetsWithPredicates/unloadedCssAssets/' 132 | ), 133 | }); 134 | await assetGraph.on('warn', warnSpy); 135 | await assetGraph.loadAssets('index.html'); 136 | await assetGraph.populate(); 137 | expect( 138 | gatherStylesheetsWithPredicates( 139 | assetGraph, 140 | assetGraph.findAssets({ type: 'Html' })[0] 141 | ), 142 | 'to satisfy', 143 | [{ text: '@import "notfoundeither.css";\n', predicates: {} }] 144 | ); 145 | expect(warnSpy, 'to have calls satisfying', () => { 146 | warnSpy(/ENOENT.*notFound\.css/); 147 | warnSpy(/ENOENT.*notfoundeither\.css/); 148 | }); 149 | }); 150 | }); 151 | -------------------------------------------------------------------------------- /test/generatedHtml.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { html } = require('html-generators'); 3 | const { stylesheet } = require('css-generators'); 4 | const AssetGraph = require('assetgraph'); 5 | const pathModule = require('path'); 6 | const stringify = require('html-generators/src/stringify'); 7 | const expect = require('./expect'); 8 | 9 | describe('generated html', function () { 10 | let smileySvgBase64; 11 | 12 | before(async function () { 13 | smileySvgBase64 = `data:image/svg+xml;base64,${fs 14 | .readFileSync( 15 | pathModule.resolve(__dirname, '..', 'testdata', 'smiley.svg') 16 | ) 17 | .toString('base64')}`; 18 | }); 19 | 20 | function fixBogusUrls(text) { 21 | return text.replace(/url\([^)]*\)/g, `url(${smileySvgBase64})`); 22 | } 23 | 24 | function fixupUnsupportedHtmlConstructs(obj) { 25 | if (obj.text) { 26 | obj.text = fixBogusUrls(obj.text); 27 | } 28 | if (obj.type === 'tag') { 29 | if (obj.tag === 'object') { 30 | delete obj.attributes.data; 31 | } 32 | if ('src' in obj.attributes) { 33 | delete obj.attributes.src; 34 | } 35 | for (const child of obj.children) { 36 | fixupUnsupportedHtmlConstructs(child); 37 | } 38 | } 39 | if (obj.attributes && obj.attributes.style) { 40 | obj.attributes.style = fixBogusUrls(obj.attributes.style); 41 | } 42 | } 43 | 44 | it('should render the same before and after subsetting', async function () { 45 | return expect( 46 | async (htmlObjectTree, stylesheet) => { 47 | fixupUnsupportedHtmlConstructs(htmlObjectTree); 48 | 49 | stylesheet = fixBogusUrls(stylesheet) 50 | .replace(/all: (?:initial|unset);/g, '') // Makes the contents of stylesheets visible 51 | .replace(/font-variant-caps: [^;]+;/, '') // See build #260.3 failure 52 | .replace(/oblique [0-9.]+\w+/, 'oblique'); // oblique with an angle is not yet fully standardized or implemented in font-snapper 53 | const head = htmlObjectTree.children[0]; 54 | head.children.push({ 55 | type: 'tag', 56 | tag: 'style', 57 | attributes: [], 58 | children: [ 59 | { 60 | type: 'text', 61 | value: ` 62 | @font-face { 63 | font-family: 'IBM Plex Sans'; 64 | font-style: normal; 65 | font-weight: 400; 66 | src: url('IBMPlexSans-Regular.woff') format('woff'); 67 | } 68 | 69 | @font-face { 70 | font-family: 'IBM Plex Sans'; 71 | font-style: italic; 72 | font-weight: 400; 73 | src: url('IBMPlexSans-Italic.woff') format('woff'); 74 | } 75 | body { 76 | font-family: 'IBM Plex Sans', sans-serif; 77 | font-style: normal; 78 | font-weight: 400; 79 | } 80 | 81 | ${stylesheet} 82 | `, 83 | }, 84 | ], 85 | }); 86 | 87 | const assetGraph = new AssetGraph({ 88 | root: pathModule.resolve( 89 | __dirname, 90 | '..', 91 | 'testdata', 92 | 'subsetFonts', 93 | 'unused-variant-on-one-page' 94 | ), 95 | }); 96 | const text = stringify(htmlObjectTree); 97 | assetGraph.addAsset({ 98 | url: `${assetGraph.root}index.html`, 99 | type: 'Html', 100 | text, 101 | }); 102 | await assetGraph.populate(); 103 | return expect(assetGraph, 'to render the same after subsetting', { 104 | omitFallbacks: true, 105 | }); 106 | }, 107 | 'to be valid for all', 108 | { 109 | maxIterations: 2, 110 | generators: [ 111 | html({ 112 | excludedDescendants: new Set([ 113 | 'svg', 114 | 'script', 115 | 'style', 116 | 'progress', 117 | ]), 118 | }), 119 | stylesheet(), 120 | ], 121 | } 122 | ); 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /test/injectSubsetDefinitions.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected'); 2 | const injectSubsetDefinitions = require('../lib/injectSubsetDefinitions'); 3 | 4 | describe('injectSubsetDefinitions', function () { 5 | const webfontNameMap = { 6 | 'times new roman': 'times new roman__subset', 7 | }; 8 | 9 | it('should inject before a doublequoted font family name', function () { 10 | expect( 11 | injectSubsetDefinitions('"times new roman"', webfontNameMap), 12 | 'to equal', 13 | '\'times new roman__subset\', "times new roman"' 14 | ); 15 | }); 16 | 17 | it('should inject before a singlequoted font family name', function () { 18 | expect( 19 | injectSubsetDefinitions("'times new roman'", webfontNameMap), 20 | 'to equal', 21 | "'times new roman__subset', 'times new roman'" 22 | ); 23 | }); 24 | 25 | it('should inject before a "bareword" font family name', function () { 26 | expect( 27 | injectSubsetDefinitions('times new roman', webfontNameMap), 28 | 'to equal', 29 | "'times new roman__subset', times new roman" 30 | ); 31 | }); 32 | 33 | it('should match the font-family case sensitively', function () { 34 | expect( 35 | injectSubsetDefinitions('Times new rOman', webfontNameMap), 36 | 'to equal', 37 | "'times new roman__subset', Times new rOman" 38 | ); 39 | }); 40 | 41 | it('should tolerate multiple spaces between words', function () { 42 | expect( 43 | injectSubsetDefinitions('times new roman', webfontNameMap), 44 | 'to equal', 45 | "'times new roman__subset', times new roman" 46 | ); 47 | }); 48 | 49 | it('should ignore occurrences that are immediately preceeded by other barewords', function () { 50 | expect( 51 | injectSubsetDefinitions('sorry times new roman, other', webfontNameMap), 52 | 'to equal', 53 | 'sorry times new roman, other' 54 | ); 55 | }); 56 | 57 | it('should ignore occurrences that are succeeded by other barewords', function () { 58 | expect( 59 | injectSubsetDefinitions('times new roman yeah', webfontNameMap), 60 | 'to equal', 61 | 'times new roman yeah' 62 | ); 63 | }); 64 | 65 | it('should not inject the subset into a value that already has it, same casing', function () { 66 | expect( 67 | injectSubsetDefinitions( 68 | "'times new roman__subset', times new roman", 69 | webfontNameMap 70 | ), 71 | 'to equal', 72 | "'times new roman__subset', times new roman" 73 | ); 74 | }); 75 | 76 | it('should not inject the subset into a value that already has it, case difference in existing value', function () { 77 | expect( 78 | injectSubsetDefinitions( 79 | "'TIMES new roman__subset', times new roman", 80 | webfontNameMap 81 | ), 82 | 'to equal', 83 | "'TIMES new roman__subset', times new roman" 84 | ); 85 | }); 86 | 87 | it('should not inject the subset into a value that already has it, case difference in webfontNameMap value', function () { 88 | expect( 89 | injectSubsetDefinitions("'times new roman__subset', times new roman", { 90 | 'times new roman': 'TIMES new roman__subset', 91 | }), 92 | 'to equal', 93 | "'times new roman__subset', times new roman" 94 | ); 95 | }); 96 | 97 | it('should escape singlequotes in the subset font name', function () { 98 | expect( 99 | injectSubsetDefinitions('"times new roman"', { 100 | 'times new roman': "times'new'roman__subset", 101 | }), 102 | 'to equal', 103 | "'times\\'new\\'roman__subset', \"times new roman\"" 104 | ); 105 | }); 106 | 107 | describe('when replaceOriginal is true', function () { 108 | it('should replace a "bareword" font family name that is the last token', function () { 109 | expect( 110 | injectSubsetDefinitions('times new roman', webfontNameMap, true), 111 | 'to equal', 112 | "'times new roman__subset'" 113 | ); 114 | }); 115 | 116 | it('should replace a "bareword" font family name before a comma', function () { 117 | expect( 118 | injectSubsetDefinitions('times new roman, serif', webfontNameMap, true), 119 | 'to equal', 120 | "'times new roman__subset', serif" 121 | ); 122 | }); 123 | 124 | it('should replace a quoted font family name before a comma', function () { 125 | expect( 126 | injectSubsetDefinitions( 127 | '"times new roman", serif', 128 | webfontNameMap, 129 | true 130 | ), 131 | 'to equal', 132 | "'times new roman__subset', serif" 133 | ); 134 | }); 135 | }); 136 | }); 137 | -------------------------------------------------------------------------------- /test/normalizeFontPropertyValue.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected'); 2 | const normalizeFontPropertyValue = require('../lib/normalizeFontPropertyValue'); 3 | 4 | describe('normalizeFontPropertyValue', function () { 5 | describe('with font-weight', function () { 6 | it('should convert normal to 400', function () { 7 | expect( 8 | normalizeFontPropertyValue('font-weight', 'normal'), 9 | 'to equal', 10 | 400 11 | ); 12 | }); 13 | 14 | it('should convert bold to 700', function () { 15 | expect( 16 | normalizeFontPropertyValue('font-weight', 'bold'), 17 | 'to equal', 18 | 700 19 | ); 20 | }); 21 | 22 | it('should parse an in-range integer as a number', function () { 23 | expect(normalizeFontPropertyValue('font-weight', '300'), 'to equal', 300); 24 | }); 25 | 26 | it('should parse in-range exponential notation', function () { 27 | expect(normalizeFontPropertyValue('font-weight', '3e2'), 'to equal', 300); 28 | }); 29 | 30 | it('should ignore a value > 1000', function () { 31 | expect( 32 | normalizeFontPropertyValue('font-weight', '1001'), 33 | 'to equal', 34 | '1001' 35 | ); 36 | }); 37 | 38 | it('should ignore a value < 1', function () { 39 | expect( 40 | normalizeFontPropertyValue('font-weight', '0.1'), 41 | 'to equal', 42 | '0.1' 43 | ); 44 | }); 45 | 46 | it('should parse an in-range value with decimals', function () { 47 | expect( 48 | normalizeFontPropertyValue('font-weight', '234.56'), 49 | 'to be close to', 50 | 234.56 51 | ); 52 | }); 53 | 54 | it('should strip extra characters', function () { 55 | expect( 56 | normalizeFontPropertyValue('font-weight', 'bold+lighter+bolder'), 57 | 'to equal', 58 | 700 59 | ); 60 | }); 61 | }); 62 | 63 | describe('with another property', function () { 64 | it('should return the value', function () { 65 | expect( 66 | normalizeFontPropertyValue('foo-bar', 'quux baz'), 67 | 'to equal', 68 | 'quux baz' 69 | ); 70 | }); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/parseCommandLineOptions.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected'); 2 | const parseCommandLineOptions = require('../lib/parseCommandLineOptions'); 3 | 4 | describe('parseCommandLineOptions', function () { 5 | it('should return an object with the parsed options', function () { 6 | expect( 7 | parseCommandLineOptions(['--dryrun', '--no-fallbacks', '--recursive']), 8 | 'to satisfy', 9 | { 10 | root: undefined, 11 | canonicalRoot: undefined, 12 | output: undefined, 13 | debug: false, 14 | dryRun: true, 15 | silent: false, 16 | inlineCss: false, 17 | fontDisplay: 'swap', 18 | inPlace: false, 19 | inputFiles: [], 20 | recursive: true, 21 | fallbacks: false, 22 | dynamic: false, 23 | } 24 | ); 25 | }); 26 | 27 | it('should allow repeating --formats', function () { 28 | expect( 29 | parseCommandLineOptions(['--formats', 'truetype', '--formats', 'woff2']), 30 | 'to satisfy', 31 | { 32 | formats: ['truetype', 'woff2'], 33 | } 34 | ); 35 | }); 36 | 37 | it('should allow passing a comma-separated list of formats', function () { 38 | const options = parseCommandLineOptions(['--formats', 'truetype,woff2']); 39 | 40 | expect(options, 'to satisfy', { 41 | formats: ['truetype', 'woff2'], 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /test/parseFontVariationSettings.js: -------------------------------------------------------------------------------- 1 | const parseFontVariationSettings = require('../lib/parseFontVariationSettings'); 2 | 3 | describe('parseFontVariationSettings', function () { 4 | const expect = require('unexpected') 5 | .clone() 6 | .addAssertion( 7 | ' to come out as ', 8 | (expect, subject, expectedValue) => { 9 | const parsedValue = [...parseFontVariationSettings(subject)]; 10 | expect(parsedValue, 'to equal', expectedValue); 11 | } 12 | ); 13 | 14 | it('should ignore extra whitespace', function () { 15 | expect(' "FOOB" 200 , "QUUX" 400', 'to come out as', [ 16 | ['FOOB', 200], 17 | ['QUUX', 400], 18 | ]); 19 | }); 20 | 21 | describe('with unsupported input', function () { 22 | it('should ignore content after double comma', function () { 23 | expect('"FOOB" 200,, "QUUX" 400', 'to come out as', [['FOOB', 200]]); 24 | }); 25 | 26 | it('should ignore content after an axis name given as a non-string', function () { 27 | expect('"FOOB" 200, 123 400, "BAAZ" 800', 'to come out as', [ 28 | ['FOOB', 200], 29 | ]); 30 | }); 31 | 32 | it('should ignore a value given as custom property', function () { 33 | expect('"FOOB" 200, "QUUX" var(--blah), "BAAZ" 800', 'to come out as', [ 34 | ['FOOB', 200], 35 | ['BAAZ', 800], 36 | ]); 37 | }); 38 | 39 | it('should ignore a value given as a string', function () { 40 | expect('"FOOB" "200", "BAAZ" 800', 'to come out as', [['BAAZ', 800]]); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/referenceImages.js: -------------------------------------------------------------------------------- 1 | const expect = require('./expect'); 2 | const combos = require('combos'); 3 | const pathModule = require('path'); 4 | 5 | function getPathToTestCase(name) { 6 | return pathModule.resolve( 7 | __dirname, 8 | '..', 9 | 'testdata', 10 | 'referenceImages', 11 | name, 12 | 'index.html' 13 | ); 14 | } 15 | 16 | describe('reference images', function () { 17 | for (const options of combos({ 18 | inlineCss: [false, true], 19 | omitFallbacks: [false, true], 20 | dynamic: [false, true], 21 | })) { 22 | describe(`with ${Object.keys(options) 23 | .map((key) => `${key}: ${options[key]}`) 24 | .join(', ')}`, function () { 25 | it('should render a simple test case without ligatures', async function () { 26 | await expect( 27 | getPathToTestCase('withoutLigatures'), 28 | 'to render the same after subsetting', 29 | options 30 | ); 31 | }); 32 | 33 | it('should render ligatures correctly', async function () { 34 | await expect( 35 | getPathToTestCase('ligatures'), 36 | 'to render the same after subsetting', 37 | options 38 | ); 39 | }); 40 | 41 | it('should render missing glyphs', async function () { 42 | await expect( 43 | getPathToTestCase('missingGlyphs'), 44 | 'to render the same after subsetting', 45 | options 46 | ); 47 | }); 48 | 49 | it('should render unused variants', async function () { 50 | await expect( 51 | getPathToTestCase('unusedVariants'), 52 | 'to render the same after subsetting', 53 | options 54 | ); 55 | }); 56 | 57 | it('should render font-variant-*', async function () { 58 | await expect( 59 | getPathToTestCase('fontVariant'), 60 | 'to render the same after subsetting', 61 | options 62 | ); 63 | }); 64 | 65 | it('should render a variable font that can be fully instanced', async function () { 66 | await expect( 67 | getPathToTestCase('fullyInstancedVariableFont'), 68 | 'to render the same after subsetting', 69 | options 70 | ); 71 | }); 72 | }); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /test/stripLocalTokens.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected').clone(); 2 | const stripLocalTokens = require('../lib/stripLocalTokens'); 3 | 4 | expect.addAssertion( 5 | ' to come out as ', 6 | (expect, subject, value) => { 7 | expect(stripLocalTokens(subject), 'to equal', value); 8 | } 9 | ); 10 | 11 | describe('stripLocalTokens', function () { 12 | it('should strip a standalone local(...) token', function () { 13 | expect('local(foo)', 'to come out as', ''); 14 | }); 15 | 16 | it('should strip an initial local(...) token and a following comma', function () { 17 | expect('local(foo), url(bar)', 'to come out as', 'url(bar)'); 18 | }); 19 | 20 | it('should strip a local(...) token surrounded by multple other tokens and leave a comma', function () { 21 | expect( 22 | 'url(foo), local(bar), url(quux)', 23 | 'to come out as', 24 | 'url(foo), url(quux)' 25 | ); 26 | }); 27 | 28 | it('should ignore the casing of the word local', function () { 29 | expect( 30 | 'url(foo), LOCAL(bar), url(quux)', 31 | 'to come out as', 32 | 'url(foo), url(quux)' 33 | ); 34 | }); 35 | 36 | it('should support singlequoted strings', function () { 37 | expect( 38 | `url('foo'), local('bar'), url('quux')`, 39 | 'to come out as', 40 | "url('foo'), url('quux')" 41 | ); 42 | }); 43 | 44 | it('should support doublequoted strings', function () { 45 | expect( 46 | `url("foo"), local("bar"), url("quux")`, 47 | 'to come out as', 48 | 'url("foo"), url("quux")' 49 | ); 50 | }); 51 | 52 | it('should strip multiple consecutive local(...) tokens with space between them', function () { 53 | expect( 54 | `url('foo'), local(bar), local(quux), url('baz')`, 55 | 'to come out as', 56 | "url('foo'), url('baz')" 57 | ); 58 | }); 59 | 60 | it('should strip multiple consecutive local(...) tokens with space before and after the comma', function () { 61 | expect( 62 | `url('foo') , local(bar) , local(quux) , url('baz')`, 63 | 'to come out as', 64 | "url('foo') , url('baz')" 65 | ); 66 | }); 67 | 68 | it('should strip multiple initial, consecutive local(...) tokens', function () { 69 | expect( 70 | `local('Roboto Bold Italic'), local('Roboto-BoldItalic'), url(KFOjCnqEu92Fr1Mu51TzBic6CsI.woff) format('woff')`, 71 | 'to come out as', 72 | `url(KFOjCnqEu92Fr1Mu51TzBic6CsI.woff) format('woff')` 73 | ); 74 | }); 75 | 76 | it('should strip multiple consecutive local(...) tokens without space between them', function () { 77 | expect( 78 | `url('foo'), local(bar),local(quux), url('baz')`, 79 | 'to come out as', 80 | "url('foo'), url('baz')" 81 | ); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/unicodeRange.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected'); 2 | const unicodeRange = require('../lib/unicodeRange'); 3 | 4 | describe('unicode range', function () { 5 | // https://github.com/Munter/subfont/issues/106 6 | it('should compress into a range', function () { 7 | expect(unicodeRange([0x64, 0x20, 0x62, 0x63]), 'to equal', 'U+20,U+62-64'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/unquote.js: -------------------------------------------------------------------------------- 1 | const expect = require('unexpected'); 2 | const unquote = require('../lib/unquote'); 3 | 4 | describe('unquote', function () { 5 | describe('with a non-string', function () { 6 | it('should return the argument unchanged', function () { 7 | expect(unquote(undefined), 'to be undefined'); 8 | }); 9 | }); 10 | 11 | describe('with a singlequoted string', function () { 12 | it('should return the contents of the quotes', function () { 13 | expect(unquote("'foo'"), 'to equal', 'foo'); 14 | }); 15 | 16 | describe('with a 4 letter hex escape sequence', function () { 17 | describe('followed by a single whitespace character', function () { 18 | it('should decode the escape sequence and not include the whitespace', function () { 19 | expect(unquote("'foo \\263a bar'"), 'to equal', 'foo ☺bar'); 20 | }); 21 | }); 22 | 23 | describe('followed by two whitespace characters', function () { 24 | it('should decode the escape sequence and not include the first whitespace', function () { 25 | expect(unquote("'foo \\263a bar'"), 'to equal', 'foo ☺ bar'); 26 | }); 27 | }); 28 | 29 | describe('not followed by a space or hex character', function () { 30 | it('should decode the escape sequence', function () { 31 | expect(unquote("'foo \\263az'"), 'to equal', 'foo ☺z'); 32 | }); 33 | }); 34 | }); 35 | 36 | describe('with a 6 letter hex escape sequence', function () { 37 | describe('followed by a single whitespace character', function () { 38 | it('should decode the escape sequence and include the whitespace', function () { 39 | expect(unquote("'foo \\00263a bar'"), 'to equal', 'foo ☺ bar'); 40 | }); 41 | }); 42 | 43 | describe('followed by two whitespace characters', function () { 44 | it('should decode the escape sequence and include the whitespace', function () { 45 | expect(unquote("'foo \\00263a bar'"), 'to equal', 'foo ☺ bar'); 46 | }); 47 | }); 48 | 49 | describe('not followed by a space or hex character', function () { 50 | it('should decode the escape sequence', function () { 51 | expect(unquote("'foo \\00263az'"), 'to equal', 'foo ☺z'); 52 | }); 53 | }); 54 | 55 | describe('followed by a hex character', function () { 56 | it('should decode the escape sequence without the following hex character', function () { 57 | expect(unquote("'foo \\00263a0'"), 'to equal', 'foo ☺0'); 58 | }); 59 | }); 60 | }); 61 | 62 | describe('with multiple escape sequences', function () { 63 | it('should decode all the escape sequences', function () { 64 | expect(unquote("'foo \\263a bar \\263a'"), 'to equal', 'foo ☺bar ☺'); 65 | }); 66 | }); 67 | }); 68 | 69 | describe('with a doublequoted string', function () { 70 | it('should return the contents of the quotes', function () { 71 | expect(unquote('"foo"'), 'to equal', 'foo'); 72 | }); 73 | }); 74 | 75 | describe('with an unquoted string', function () { 76 | it('should return the string', function () { 77 | expect(unquote('foo'), 'to equal', 'foo'); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /testdata/browserslistInPackageJson/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /testdata/browserslistInPackageJson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "browserslist": ["Chrome >= 36", "Safari 5"] 3 | } 4 | -------------------------------------------------------------------------------- /testdata/canonicalUrlWithPathComponent/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/canonicalUrlWithPathComponent/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/canonicalUrlWithPathComponent/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /testdata/canonicalUrlWithoutPathComponent/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/canonicalUrlWithoutPathComponent/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/canonicalUrlWithoutPathComponent/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /testdata/differentCodepointsOnDifferentPages/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/differentCodepointsOnDifferentPages/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/differentCodepointsOnDifferentPages/first.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |

Foo

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/differentCodepointsOnDifferentPages/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |

Bar

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/dynamicallyInjectedText/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/dynamicallyInjectedText/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/dynamicallyInjectedText/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /testdata/dynamicallyRemovedText/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/dynamicallyRemovedText/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/dynamicallyRemovedText/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 22 | 23 | 24 |

Dynamically removed text

25 | 26 | 27 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/cssImportWithMedia/a.css: -------------------------------------------------------------------------------- 1 | .a { font-weight: 600; } 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/cssImportWithMedia/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/cssImportWithMediaWithExistingIncomingMedia/a.css: -------------------------------------------------------------------------------- 1 | .a { font-weight: 600; } 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/cssImportWithMediaWithExistingIncomingMedia/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/cyclicCssImport/a.css: -------------------------------------------------------------------------------- 1 | @import "a.css"; 2 | 3 | .a { font-weight: 600; } 4 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/cyclicCssImport/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/htmlStyle/a.css: -------------------------------------------------------------------------------- 1 | .a { font-weight: 500; } 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/htmlStyle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/htmlStyleWithMediaAttribute/a.css: -------------------------------------------------------------------------------- 1 | .a { font-weight: 500; } 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/htmlStyleWithMediaAttribute/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/inlineHtmlStyle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/inlineHtmlStyleWithMediaAttribute/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/sameStylesheetIncludedTwice/a.css: -------------------------------------------------------------------------------- 1 | .a { font-weight: 600; } 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/sameStylesheetIncludedTwice/b.css: -------------------------------------------------------------------------------- 1 | .b { font-weight: 500; } 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/sameStylesheetIncludedTwice/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/unloadedCssAssets/a.css: -------------------------------------------------------------------------------- 1 | @import "notfoundeither.css"; 2 | -------------------------------------------------------------------------------- /testdata/gatherStylesheetsWithPredicates/unloadedCssAssets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/iframe/SourceSerifVariable-Roman.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/iframe/SourceSerifVariable-Roman.ttf.woff2 -------------------------------------------------------------------------------- /testdata/iframe/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Demo 9 | 10 | 26 | 27 |

Subfont Demo Page

28 |

29 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas 30 | faucibus, sem vel placerat laoreet, sapien tellus scelerisque sapien, quis 31 | convallis enim risus ac neque. Donec vulputate nunc vitae fermentum 32 | eleifend. Aliquam vitae congue enim, nec malesuada lacus. Nunc vulputate, 33 | elit sit amet vestibulum viverra, ante eros sollicitudin nisi, sit amet 34 | aliquam nunc urna sed felis. Proin ac mattis urna. Integer in 35 | felis nunc. Nullam sed velit neque. Aenean congue, arcu ac auctor 36 | convallis, mauris turpis lobortis lectus, vitae porttitor enim dui sit 37 | amet lorem. Mauris ac erat fringilla, porttitor nibh vel, laoreet ex. 38 |

39 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /testdata/k3k702ZOKiLJc3WVjuplzHhCUOGz7vYGh680lGh-uXM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/k3k702ZOKiLJc3WVjuplzHhCUOGz7vYGh680lGh-uXM.woff -------------------------------------------------------------------------------- /testdata/noFontUsageOnOnePage/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/noFontUsageOnOnePage/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/noFontUsageOnOnePage/first.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |

Foo

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/noFontUsageOnOnePage/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/pageWithErrors/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/pageWithErrors/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/pageWithErrors/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | 19 | 22 | 23 |
Foo
24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/pageWithStrictCsp/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/pageWithStrictCsp/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/pageWithStrictCsp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |
Foo
20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/referenceImages/fontVariant/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/fontVariant/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/referenceImages/fontVariant/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/fontVariant/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/referenceImages/fontVariant/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 163 | 164 | 165 | 166 | a á ă â ä ạ à ả ā ą å ǻ ã ắ ặ ằ ẳ ẵ ấ ậ ầ ẩ ẫ ğ ĝ ģ ġ ß α ά а ӓ ӑ ¯ ˙ ¨ ˝ ´ ` ˆ ˇ ˚ ΄ ̉   167 | g g 0 0 ˜ ˜ ˜ ˘ ˘ ˘ 168 | 169 | 170 | 0 1 2 3 4 5 6 7 8 9 171 | 172 | 173 | 0 1 2 3 4 5 6 7 8 9 / 174 | ⁄ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ 175 | ² ³ ¹ ⁰ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ 176 | ⁄² ⁄³ ⁄¹ ⁄⁰ ⁄⁴ ⁄⁵ ⁄⁶ ⁄⁷ ⁄⁸ ⁄⁹ ₀² ₀³ ₀¹ ₀⁰ ₀⁴ ₀⁵ ₀⁶ ₀⁷ ₀⁸ ₀⁹ ₁² ₁³ ₁¹ ₁⁰ ₁⁴ ₁⁵ ₁⁶ ₁⁷ ₁⁸ ₁⁹ ₂² ₂³ ₂¹ ₂⁰ ₂⁴ ₂⁵ ₂⁶ ₂⁷ ₂⁸ ₂⁹ ₃² ₃³ ₃¹ ₃⁰ ₃⁴ ₃⁵ ₃⁶ ₃⁷ ₃⁸ ₃⁹ ₅² ₅³ ₅¹ ₅⁰ ₅⁴ ₅⁵ ₅⁶ ₅⁷ ₅⁸ ₅⁹ ₆² ₆³ ₆¹ ₆⁰ ₆⁴ ₆⁵ ₆⁶ ₆⁷ ₆⁸ ₆⁹ ₇² ₇³ ₇¹ ₇⁰ ₇⁴ ₇⁵ ₇⁶ ₇⁷ ₇⁸ ₇⁹ ₈² ₈³ ₈¹ ₈⁰ ₈⁴ ₈⁵ ₈⁶ ₈⁷ ₈⁸ ₈⁹ ₉² ₉³ ₉¹ ₉⁰ ₉⁴ ₉⁵ ₉⁶ ₉⁷ ₉⁸ ₉⁹ 177 | 178 | 179 | 0 1 2 3 4 5 6 7 8 9 180 | 181 | 182 | a o 183 | 184 | 185 | a g 0 á ă â ä ạ à ả ā ą å ǻ ã ắ ặ ằ ẳ ẵ ấ ậ ầ ẩ ẫ ğ ĝ ģ ġ ß α ά а ӓ ӑ 186 | 187 | 188 | 0 1 2 3 4 5 6 7 8 9 189 | 190 | 191 | a á ă â ä ạ à ả ā ą å ǻ ã ắ ặ ằ ẳ ẵ ấ ậ ầ ẩ ẫ α ά а ӓ ӑ 192 | 193 | 194 | g ğ ĝ ģ ġ 195 | 196 | 197 | 0 198 | 199 | 200 | 0 201 | 202 | 203 | ß 204 | 205 | 206 | 0 1 2 3 4 5 6 7 8 9 207 | 208 | 209 | 0 1 2 3 4 5 6 7 8 9 210 | 211 | 212 | 0 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /testdata/referenceImages/fullyInstancedVariableFont/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/fullyInstancedVariableFont/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/referenceImages/fullyInstancedVariableFont/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 |

Hello, world!

14 | 15 | 16 | -------------------------------------------------------------------------------- /testdata/referenceImages/ligatures/Roboto-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/ligatures/Roboto-400.woff2 -------------------------------------------------------------------------------- /testdata/referenceImages/ligatures/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 |

Waffle stuffings

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/referenceImages/missingGlyphs/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/missingGlyphs/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/referenceImages/missingGlyphs/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/missingGlyphs/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/referenceImages/missingGlyphs/JimNightshade-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/missingGlyphs/JimNightshade-400.woff2 -------------------------------------------------------------------------------- /testdata/referenceImages/missingGlyphs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 27 | 28 | 29 |
load('中国').then(function
30 | 31 |
Hello!
32 | 33 | 34 | -------------------------------------------------------------------------------- /testdata/referenceImages/unusedVariants/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/unusedVariants/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/referenceImages/unusedVariants/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/unusedVariants/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/referenceImages/unusedVariants/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 | foo 24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/referenceImages/withoutLigatures/Roboto-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/referenceImages/withoutLigatures/Roboto-400.woff2 -------------------------------------------------------------------------------- /testdata/referenceImages/withoutLigatures/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 |

Hello, world!

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/smiley.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/stylesheetAtOtherOrigin/referencesFont/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
Hello
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/subsetFonts/JimNightshade-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/JimNightshade-400.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/Montserrat-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Montserrat-400.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/OpenSans-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/OpenSans-400.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/OpenSans-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/OpenSans-400.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/OpenSans-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/OpenSans-400.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-300.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-300.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-300.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-300i.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-300i.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-300i.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-300i.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-400.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-400.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-400.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-500.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-500.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-500.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-500.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/Roboto-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/Roboto-500.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/SpaceMono-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/SpaceMono-400.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/css-import-twice-different-css/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 |

Hello

16 | 17 |

world

18 | 19 | 20 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-import-twice-different-css/styles.css: -------------------------------------------------------------------------------- 1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans'; 2 | 3 | h1 { 4 | font-family: 'Open Sans'; 5 | } 6 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-import-twice/index.html: -------------------------------------------------------------------------------- 1 | 9 | 10 |

Hello

11 | 12 |

world

13 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-import/index.html: -------------------------------------------------------------------------------- 1 | 8 | 9 |

Hello

10 | 11 |

world

12 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-external/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/css-source-map-external/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-external/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Hello, world!
9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-external/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Open Sans; 3 | src: url(OpenSans.ttf); 4 | } 5 | body div { 6 | font-family: Open Sans, sans-serif; 7 | border: 1px solid black; 8 | } 9 | /*# sourceMappingURL=styles.css.map */ -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-external/styles.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["styles.less"],"names":[],"mappings":"AAAA;EACE,sBAAA;EACA,sBAAA;;AAGF,IACE;EACE,kCAAA;EACA,uBAAA","file":"styles.css"} -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-external/styles.less: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Open Sans; 3 | src: url(OpenSans.ttf); 4 | } 5 | 6 | body { 7 | div { 8 | font-family: Open Sans, sans-serif; 9 | border: 1px solid black; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-inline/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/css-source-map-inline/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-inline/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Hello, world!
9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-inline/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Open Sans; 3 | src: url(OpenSans.ttf); 4 | } 5 | body div { 6 | font-family: Open Sans, sans-serif; 7 | border: 1px solid black; 8 | } 9 | /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlcy5sZXNzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0Usc0JBQUE7RUFDQSxzQkFBQTs7QUFHRixJQUNFO0VBQ0Usa0NBQUE7RUFDQSx1QkFBQSIsImZpbGUiOiJzdHlsZXMuY3NzIn0= */ -------------------------------------------------------------------------------- /testdata/subsetFonts/css-source-map-inline/styles.less: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Open Sans; 3 | src: url(OpenSans.ttf); 4 | } 5 | 6 | body { 7 | div { 8 | font-family: Open Sans, sans-serif; 9 | border: 1px solid black; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /testdata/subsetFonts/emojis/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/emojis/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/emojis/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | 20 | 🤗🤞 21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/emojis/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | 21 | 👊🤗 22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/subsetFonts/existing-prefetch/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/existing-prefetch/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/existing-prefetch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 18 | 19 | 20 |

foo

21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/existing-preload/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/existing-preload/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/existing-preload/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 18 | 19 | 20 |

foo

21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/firstPageNoSubset/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/firstPageNoSubset/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/firstPageNoSubset/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | 15 | ABCDEFGHIJKLMNOPQRSTUVWXYZ 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/subsetFonts/firstPageNoSubset/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | 21 | ABCDEFGHIJKLM 22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/subsetFonts/font-face-defaults-and-casing/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/font-face-defaults-and-casing/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/font-face-defaults-and-casing/OpenSans2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/font-face-defaults-and-casing/OpenSans2.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/font-face-defaults-and-casing/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30 | 31 | 32 |

Hello, world!

33 |

Hello, yourself!

34 | 35 | 36 | -------------------------------------------------------------------------------- /testdata/subsetFonts/font-family-with-escape/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/font-family-with-escape/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/font-family-with-escape/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Hello!
23 |
World!
24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/subsetFonts/font-shorthand-with-custom-property/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 |

Hello

25 | -------------------------------------------------------------------------------- /testdata/subsetFonts/font-shorthand/index.html: -------------------------------------------------------------------------------- 1 | 18 | 19 |

Hello

20 | -------------------------------------------------------------------------------- /testdata/subsetFonts/font-weight-and-style-omitted/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/font-weight-and-style-omitted/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/font-weight-and-style-omitted/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 |

foo

16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/subsetFonts/google-webfont-ref-in-javascript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /testdata/subsetFonts/html-link/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 |

Hello

10 | 11 |

world

12 | -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-one-subset-multi-page/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/inline-one-subset-multi-page/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-one-subset-multi-page/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/inline-one-subset-multi-page/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-one-subset-multi-page/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 27 | 28 | foo 29 | 30 | 31 | -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-one-subset-multi-page/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 27 | 28 | quuxbaz 29 | 30 | 31 | -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-subsets-multi-page/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/inline-subsets-multi-page/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-subsets-multi-page/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/inline-subsets-multi-page/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-subsets-multi-page/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 27 | 28 | foobar 29 | 30 | 31 | -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-subsets-multi-page/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 27 | 28 | quuxbaz 29 | 30 | 31 | -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-subsets/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/inline-subsets/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/inline-subsets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 18 | 19 | 20 |

Hello!

21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | debug_subfont 8 | 9 | 10 | 11 | 12 | 13 |

About us

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/assets/fonts/fontawesome-all.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.6 by @fontawesome - http://fontawesome.com 3 | * License - http://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | 6 | .fa, 7 | .fab, 8 | .fal, 9 | .far, 10 | .fas { 11 | -moz-osx-font-smoothing: grayscale; 12 | -webkit-font-smoothing: antialiased; 13 | display: inline-block; 14 | font-style: normal; 15 | font-variant: normal; 16 | text-rendering: auto; 17 | line-height: 1; 18 | } 19 | 20 | .fa-star:before { 21 | content: '\f005'; 22 | } 23 | 24 | @font-face { 25 | font-family: Font Awesome\ 5 Free; 26 | font-style: normal; 27 | font-weight: 400; 28 | src: url(../webfonts/fa-regular-400.eot); 29 | src: url(../webfonts/fa-regular-400.eot?#iefix) format('embedded-opentype'), 30 | url(../webfonts/fa-regular-400.woff2) format('woff2'), 31 | url(../webfonts/fa-regular-400.woff) format('woff'), 32 | url(../webfonts/fa-regular-400.ttf) format('truetype'), 33 | url(../webfonts/fa-regular-400.svg#fontawesome) format('svg'); 34 | } 35 | 36 | .far { 37 | font-weight: 400; 38 | } 39 | 40 | .fa, 41 | .far, 42 | .fas { 43 | font-family: Font Awesome\ 5 Free; 44 | } 45 | -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/issue131/assets/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/issue131/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | debug_subfont 10 | 14 | 15 | 16 | 17 | 18 |

19 | Christmas Images - Adorable boy with a dog 20 |

21 | https://thegraphicsfairy.com/vintage-christmas-image-boy-snow/About 26 | 27 | 28 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-font-family-case-difference/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-font-family-case-difference/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-font-family-case-difference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 23 | 24 | 25 |

Hello, world!

26 |

Hello, yourself!

27 | 28 | 29 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-invalid/OpenSans.ttf: -------------------------------------------------------------------------------- 1 | 0000 2 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-invalid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 18 | 19 | 20 | 21 |

Local font files

22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-mixed/LocalSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-mixed/LocalSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-mixed/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 24 | 25 | 26 | 27 |

Local Sans

28 |

Open Sans

29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-single/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-single/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-single/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 18 | 19 | 20 | 21 |

Local font files

22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-unused-with-subfont-text/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-unused-with-subfont-text/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/local-unused-with-subfont-text/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 |

This does not use the webfont

16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-unused/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-unused/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/local-unused/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 |

This does not use the webfont

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used-multipage-with-subfont-text/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-used-multipage-with-subfont-text/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used-multipage-with-subfont-text/page1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Hello, world!

8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used-multipage-with-subfont-text/page2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Aloha, world!

8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used-multipage-with-subfont-text/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Roboto; 3 | font-style: italic; 4 | font-weight: 700; 5 | src: url(KFOjCnqEu92Fr1Mu51TzBic6CsI.woff) format('woff'); 6 | -subfont-text: '0123456789'; 7 | } 8 | 9 | h1 { 10 | font-family: Roboto; 11 | font-weight: 700; 12 | } 13 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used-with-subfont-text/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-used-with-subfont-text/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used-with-subfont-text/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | 20 |

Hello, world!

21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-used/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/local-used/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 |

Hello, world!

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet-only-comment/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet-only-comment/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet-only-comment/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 |

Local font files

16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet-only-license-comment/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet-only-license-comment/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet-only-license-comment/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 |

Local font files

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-no-css-rules-in-font-face-stylesheet/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 |

Local font files

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-noscript/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/local-with-noscript/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/local-with-noscript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 20 | 21 | 22 |

Local font files

23 | 24 | 25 | -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-font-family/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-font-family/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-font-family/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | foo 14 | 15 | -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-multiple-variants/InputMono-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-glyphs-multiple-variants/InputMono-Medium.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-multiple-variants/InputMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-glyphs-multiple-variants/InputMono-Regular.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-multiple-variants/OutputSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-glyphs-multiple-variants/OutputSans-Bold.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-multiple-variants/OutputSans-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-glyphs-multiple-variants/OutputSans-Regular.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-multiple-variants/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 32 | 33 |
load('中国').then(function
34 | 35 |
Hello!
36 | 37 | 38 | -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-unicode-range/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-glyphs-unicode-range/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs-unicode-range/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 19 | 20 | 21 |

Hello, 中国!

22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-glyphs/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-glyphs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 18 | 19 | 20 |

Hello, 中国!

21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-tab-and-newline-glyphs/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/missing-tab-and-newline-glyphs/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/missing-tab-and-newline-glyphs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 18 | 19 | 20 |

Tab: , newline:

21 | 22 | 23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-entry-points-ssr/first.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
foo
8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-entry-points-ssr/font1.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-entry-points-ssr/font1.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-entry-points-ssr/font2.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-entry-points-ssr/font2.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-entry-points-ssr/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
bar
8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-entry-points-ssr/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: font1; 3 | src: url(font1.woff2); 4 | } 5 | 6 | @font-face { 7 | font-family: font2; 8 | src: url(font2.woff2); 9 | } 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-family/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 |

Hello

19 |

Dark

20 |

Cruel

21 | 22 |

world

23 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-same-subset/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-page-same-subset/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-same-subset/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-page-same-subset/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-same-subset/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 25 | 26 | 27 | ABCDEFGHIJKLMNOPQRSTUVWXYZ 28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-same-subset/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 25 | 26 | 27 | ABCDEFGHIJKLMNOPQRSTUVWXYZ 28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-with-same-local-style-file/css/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'jetbrain'; 3 | font-style: normal; 4 | font-weight: 400; 5 | font-display: swap; 6 | src: url(../fonts/JetBrainsMono-Regular.ttf) format('truetype'); 7 | } 8 | @font-face { 9 | font-family: 'jetbrain'; 10 | font-style: italic; 11 | font-weight: 400; 12 | font-display: swap; 13 | src: url(../fonts/JetBrainsMono-Italic.ttf) format('truetype'); 14 | } 15 | @font-face { 16 | font-family: 'jetbrain'; 17 | font-style: normal; 18 | font-weight: 700; 19 | font-display: swap; 20 | src: url(../fonts/JetBrainsMono-Bold.ttf) format('truetype'); 21 | } 22 | 23 | 24 | body{ 25 | font-family: 'jetbrain', serif; 26 | } 27 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-with-same-local-style-file/fonts/JetBrainsMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-page-with-same-local-style-file/fonts/JetBrainsMono-Bold.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-with-same-local-style-file/fonts/JetBrainsMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-page-with-same-local-style-file/fonts/JetBrainsMono-Italic.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-with-same-local-style-file/fonts/JetBrainsMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multi-page-with-same-local-style-file/fonts/JetBrainsMono-Regular.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-with-same-local-style-file/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Hello World 10 | 11 | subindex 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page-with-same-local-style-file/subindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Hello, go back 10 | home 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 13 | 14 | 15 | 16 | home 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-page/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 13 | 14 | 15 | 16 | about 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multi-weight/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 |
Hello
23 |
Dark
24 |
Cruel
25 | 26 |

world

27 | -------------------------------------------------------------------------------- /testdata/subsetFonts/multiple-font-face-with-same-src/OpenSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/multiple-font-face-with-same-src/OpenSans.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/multiple-font-face-with-same-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 |

Hello, world!

24 |

Hello, yourself!

25 | 26 | 27 | -------------------------------------------------------------------------------- /testdata/subsetFonts/no-fallbacks/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/no-fallbacks/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/no-fallbacks/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/no-fallbacks/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/no-fallbacks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 27 |

Hello!

28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-and-truetype/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/non-truetype-and-truetype/icomoon.eot -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-and-truetype/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/non-truetype-and-truetype/icomoon.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-and-truetype/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/non-truetype-and-truetype/icomoon.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-and-truetype/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 17 | 18 | 19 | 20 |

Hello World

21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-font/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 23 | 24 | 25 |

one

26 |

two

27 |

three

28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-font/one.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/non-truetype-font/one.eot -------------------------------------------------------------------------------- /testdata/subsetFonts/non-truetype-font/two.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/non-truetype-font/two.eot -------------------------------------------------------------------------------- /testdata/subsetFonts/nonExistentFont/Roboto-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/nonExistentFont/Roboto-400.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/nonExistentFont/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 |
Hello
19 | 20 | 21 | -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-font-face-ssr/first.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
foo
8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-font-face-ssr/font1.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/one-page-with-no-font-face-ssr/font1.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-font-face-ssr/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Foo bar 6 | 7 | -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-font-face-ssr/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: font1; 3 | src: url(font1.woff2); 4 | } 5 | -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-usage-ssr/first.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
foo
8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-usage-ssr/font1.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/one-page-with-no-usage-ssr/font1.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-usage-ssr/second.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/subsetFonts/one-page-with-no-usage-ssr/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: font1; 3 | src: url(font1.woff2); 4 | } 5 | -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/img-element/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/svg/img-element/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/img-element/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | Hello, world! 13 | 14 | -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/img-element/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/inline-in-html-font-face-in-both-places/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/svg/inline-in-html-font-face-in-both-places/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/inline-in-html-font-face-in-both-places/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 |

Yay

14 | 15 | 16 | 24 | 25 | Hello, world! 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/inline-in-html-with-html-font-face/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/svg/inline-in-html-with-html-font-face/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/inline-in-html-with-html-font-face/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | Hello, world! 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/inline-in-html-with-own-font-face/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/svg/inline-in-html-with-own-font-face/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/svg/inline-in-html-with-own-font-face/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | Hello, world! 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /testdata/subsetFonts/two-pages-import-css/index1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 |
foo
7 | 8 | -------------------------------------------------------------------------------- /testdata/subsetFonts/two-pages-import-css/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 |
foo
7 | 8 | -------------------------------------------------------------------------------- /testdata/subsetFonts/two-pages-import-css/styles.css: -------------------------------------------------------------------------------- 1 | @import 'https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900'; 2 | -------------------------------------------------------------------------------- /testdata/subsetFonts/two-variable-fonts-animated/Venn_Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/two-variable-fonts-animated/Venn_Regular.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/two-variable-fonts-animated/Venn_VF_1-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/two-variable-fonts-animated/Venn_VF_1-500.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/two-variable-fonts-animated/Venn_VF_501-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/two-variable-fonts-animated/Venn_VF_501-900.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/two-variable-fonts-animated/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 32 | 33 | 34 |

Hello, world!

35 | 36 | 37 | -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-font/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-font/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-font/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-font/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-font/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 27 |

Hello!

28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-on-one-page/IBMPlexSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-variant-on-one-page/IBMPlexSans-Italic.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-on-one-page/IBMPlexSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-variant-on-one-page/IBMPlexSans-Regular.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-on-one-page/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 25 | 26 | 27 | ABCDEFGHIJKLMNOPQRSTUVWXYZ 28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-on-one-page/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 25 | 26 | 27 | ABCDEFGHIJKLMNOPQRSTUVWXYZ 28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-preload-google/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Hello
8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-preload/InputMono-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-variant-preload/InputMono-Medium.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-preload/InputMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-variant-preload/InputMono-Regular.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant-preload/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | foo 23 | 24 | 25 | -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-variant/KFOjCnqEu92Fr1Mu51TzBic6CsI.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant/KFOmCnqEu92Fr1Mu4mxM.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/unused-variant/KFOmCnqEu92Fr1Mu4mxM.woff -------------------------------------------------------------------------------- /testdata/subsetFonts/unused-variant/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 27 |

Hello!

28 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-fallback/Venn_Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-in-supports-block-with-fallback/Venn_Regular.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-fallback/Venn_VF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-in-supports-block-with-fallback/Venn_VF.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-fallback/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 |

Hello, world!

28 | 29 | 30 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/Venn_Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/Venn_Bold.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/Venn_Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/Venn_Regular.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/Venn_VF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/Venn_VF.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-in-supports-block-with-two-fallback-variants/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 34 | 35 | 36 |

Hello, world!

37 | 38 | 39 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-that-can-be-fully-instanced/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-that-can-be-fully-instanced/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-that-can-be-fully-instanced/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 |

Hello, world!

14 | 15 | 16 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-that-can-be-partially-instanced/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-that-can-be-partially-instanced/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-that-can-be-partially-instanced/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 |

Hello, world!

14 |

Yo, world!

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-underutilized-axis-with-bezier-out-of-bounds/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-underutilized-axis-with-bezier-out-of-bounds/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-underutilized-axis-with-bezier-out-of-bounds/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | 26 |

Hello, world!

27 | 28 | 29 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-underutilized-axis-with-bezier/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-underutilized-axis-with-bezier/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-underutilized-axis-with-bezier/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | 26 |

Hello, world!

27 | 28 | 29 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-axes/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-unused-axes/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-axes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | 26 |

Hello, world!

27 | 28 | 29 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-ital-axis/FontStyleTest-ital-VF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-unused-ital-axis/FontStyleTest-ital-VF.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-ital-axis/italic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 |

Hello, world!

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-ital-axis/normal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 |

Hello, world!

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-ital-axis/normal_and_italic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 |

Hello, world!

19 |

Hello, world!

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-ital-axis/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: MyFontFamily; 3 | src: url('FontStyleTest-ital-VF.woff2') format('woff2-variations'); 4 | } 5 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-slnt-axis/2021-05-Extendomatic/ExtendomaticVariable-VF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-unused-slnt-axis/2021-05-Extendomatic/ExtendomaticVariable-VF.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-slnt-axis/2021-05-Extendomatic/README.txt: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | Order Reference: 2022-09-10-c04de76 4 | Licensee: Andreas Lind 5 | E-mail: andreaslindpetersen@gmail.com 6 | 7 | ## Fonts included: 8 | * Extendomatic, Font of the Month: May 2021 9 | 10 | Your purchase entitles you to use the fonts according to the following limitations: 11 | 12 | ### Testing License 13 | 14 | * 1 desktop workstation, for testing purposes only 15 | * 0 monthly unique web visitors, for testing purposes only 16 | * 0 apps or e-books, for testing purposes only 17 | 18 | 19 | Please refer to LICENSE.txt for the full terms of the license. If you would like to exceed any of these limitations, you can purchase an upgrade (and pay only the difference in price) by contacting me at david@djr.com. 20 | 21 | ## Using the fonts 22 | 23 | Please refer to INSTALL.txt for desktop installation instructions and font cache troubleshooting. 24 | 25 | For an example of how to use the web font files via CSS @font-face, please consult the CSS file included in the web fonts folder. 26 | 27 | Happy typesetting! 28 | 29 | - DJR -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-slnt-axis/normal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 |

Hello, world!

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-slnt-axis/normal_and_oblique.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 |

Hello, world!

19 |

Hello, world!

20 | 21 | 22 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-slnt-axis/oblique.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 |

Hello, world!

15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-slnt-axis/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Extendomatic; 3 | /* LICENSE: 2021-05-Extendomatic/LICENSE.txt */ 4 | src: url('2021-05-Extendomatic/ExtendomaticVariable-VF.woff2') 5 | format('woff2-variations'); 6 | } 7 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-wdth-axis/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-unused-wdth-axis/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-wdth-axis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 32 | 33 | 34 |

Hello

35 |

there

36 |

world!

37 | 38 | 39 | -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-wght-axis/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/variable-font-unused-wght-axis/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf -------------------------------------------------------------------------------- /testdata/subsetFonts/variable-font-unused-wght-axis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 32 | 33 | 34 |

Hello

35 |

there

36 |

world!

37 | 38 | 39 | -------------------------------------------------------------------------------- /testdata/subsetFonts/woff2-original/BngRUXZYTXPIvIBgJJSb6u9mxLCGwR2oefDo.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/woff2-original/BngRUXZYTXPIvIBgJJSb6u9mxLCGwR2oefDo.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/woff2-original/BngRUXZYTXPIvIBgJJSb6u9mxLCIwR2oefDofMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munter/subfont/cd46e563335ec95d80386703d5aa0f9c7b2db252/testdata/subsetFonts/woff2-original/BngRUXZYTXPIvIBgJJSb6u9mxLCIwR2oefDofMY.woff2 -------------------------------------------------------------------------------- /testdata/subsetFonts/woff2-original/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 31 | 32 | 33 |

Hello, world!

34 | 35 | --------------------------------------------------------------------------------