FontPack overview.
It possible to enumerate fonts using javascript. Site can also obtain more advanced information regarding fonts installed on system. This includes: list of glyphs for each font, glyph size and even the shape of each character. Many libraries use font information to compose fingerprint for target PC. Therefore, if font data won't be changed, the quality of fingerprint emulation would be lower.
In 25.4.0 BAS version we introduce new significant improvement on how fonts are being emulated:
- List of common fonts for Windows and Android platform are collected. They can be delivered to PC which runs BAS by installing FontPack. FontPack may also be used with any compiled script.
- Fingerprints format is also being improved, now it contains list of font files hashes from target PC.
- Hashes from each fingerprint are used to find font files inside FontPack. Files from FontPack are used instead or together with system font files.
Following approach allows font list for each profile to look exactly the same as on device where fingerprint was obtained. Not only font names are being replaced but also font data, so, for example, you can have Windows 11 fonts on Windows 10 system. It is also possible to emulate Android fonts on Windows platform.
How to use?
In order to apply new changes you need to download and install latest FontPack distributive:
- Version 1.0.0. Download.
Don't forget to run install.bat after unzip.
Font pack is installed for whole system. It means that it will be used for all BAS installations and all scripts written with BAS.
You need to unsure that “Use font pack” inside “Apply fingerprint” action is enabled. Screenshot. Note that you don't need to enable it explicitly, because this setting is active by default.
Make sure that you are using fresh fingerprints. Fingerprints collected prior 20 Jan 2023 may miss required information.
How it works?
Following diagram illustrates how font replacement works:
Fingerprint collection process has been changed. In previous versions only font family list was obtained. This information is not always sufficient for deep font emulation because different machines may have different font versions installed. For example, Windows 10 usually has Arial version 7.00 while Windows 11 has Arial 7.01. Both family names are “Arial”, but font files are slightly different. After update we collect also list of font names, not only font families. For each font name system tries to identify file which matches best. It saves file hash into fingerprint json file. The mechanism of identifying font file is not always accurate. It depends on if FontPack contains requested font. But if font is not present in database, it will be replaced with best match. For example, if database has fonts for Windows 8.1, Windows 10 and Windows 11 and Windows 7 font will be requested, the result would be font for Windows 8.1 as it is closest to Windows 7. As the result each fingerprint will have exact hash which can be used later to find file inside FontPack.
You can test how this algorithm works by visiting following page https://data.bablosoft.com/fontid/. It shows list of font names installed on your system together with font versions and font hashes.
There are a lot of fonts in database, so it is difficult to include them into BAS distribution, otherwise it will bloat its size significantly. So user must install FontPack separately. It is done once for the whole system. Once installed all scripts and BAS instances will automatically use it. If FontPack is not installed, BAS will still work but without benefits of accurate font replacement, it will be done in old way instead.
Each time browser need to render a text, it must select which font to use. Font selection algorithm is rather complicated and has many cases: font or fonts list may be explicitly declared through css, required font may not be present in system, browser need to find rare character inside system fonts, etc. BAS changes browser behavior for all that cases with following rules:
- Browser will search for required font inside FontPack database first.
- If required font won't be found inside FontPack, it will be searched inside system fonts.
- If certain font was not present on target machine, it will be blocked even if it present inside system font or FontPack.
Bringing this to a conclusion, system will try find as closest as possible font to font installed on target machine, but perfect match is not always possible.
Supported platforms.
Chrome font rendering system has a lot of platform specific code. For example, on Windows, DirectWrite is used to select fonts, obviously this API is not present on other platforms. This means that even if font list and font data will be the same, some additional efforts will require to emulate platforms other than Windows. Right now only emulation of Android platform is supported. Other operating systems will work with FontPack too, but its behavior will be exactly the same as Windows.
Here are examples of platform specific behavior on Android which is being emulated properly:
- Default fonts. If you create text without specifying font it will be rendered with “Times New Roman” on Windows and with “Noto Serif” on Android.
- Android font aliases. When using fonts on Android with css, browser uses aliases rather than real fonts installed on system. For example, if page has element with 'Monaco' font family, then text will be rendered not with 'Monaco' font family, but with its alias - 'Droid Sans Mono'. In fact font family list for Android will give very limited number, around 15, while phones usually has many more fonts.
- Fonts fallback sequence. If certain character is found in several fonts, different platforms may select different fonts. This behavior is emulated only partly.
Other examples, which is not being emulated yet:
- If certain character will be rendered inside canvas, the picture may be slightly different comparing to original platform. Use PerfectCanvas to resolve this.
- Some glyphs may be loaded on Windows and not loaded on Android and vice versa. This happens despite that font data is completely identical. Example is U+1FAE0 symbol.
- The size of some characters may vary slightly on different platforms.
Debug.
You can check if FontPack is installed on user PC by running following code:
native("fontpack","getfontpackpath","")
If returned string is not empty, FontPack is installed. If not, you can display a download link to user.
Use following command to enable logs:
_settings({"Fingerprints.FontReplacementLogs":"Enable"})!
Logs are written into s/UNIQUE_PROCESS_NAME.fonts.txt and disabled by default.