[RFC] Deep-check for monospacity #317
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Before this change, a font is considered monospace if
fontdbflags itas such.
fontdbchecks theposttable for this property.But some fonts don't set that property there.
Most notably, "Noto Sans Mono" is among these fonts. Monospace as
a property is said to be communicated in other places like
OS/2'spanose, but that's not set in the Noto font either.Loosely based on a
fontconfigfunction calledFcFreeTypeSpacing(), this commit adds an additional check againstfonts that are not set as
monospacedbyfontdb. The horizontaladvances of all glyphs of a cmap unicode table are checked to see
if they are monospace. Proportionality with double-width and
treble-width advances is taken into consideration. Treble width
advances exist in the aforementioned Noto font.
The checks should be efficient, but the overhead is not in the noise.
So these extra checks are only run if the "monospace_fallback" crate
feature is enabled.
This change also requires library users to check monospacity with
FontSystem::is_monospace()instead ofFaceInfo::monospacedfromfontdbto be in-sync with cosmic-text's view. This requirement wasprobably coming in the future anyway for when cosmic-text adds support
for variable fonts.
This depends on harfbuzz/ttf-parser#174 for making the check more efficient.
How many fonts have this issue?
Running this on my system returns 220 such fonts:
Sorted output:
Details
Monaspace Argon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Argon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Argon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Argon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Argon Light: [487 glyphs, advances: [1240]] Monaspace Argon Light: [487 glyphs, advances: [1240]] Monaspace Argon Medium: [487 glyphs, advances: [1240]] Monaspace Argon Medium: [487 glyphs, advances: [1240]] Monaspace Argon SemiBold: [487 glyphs, advances: [1240]] Monaspace Argon SemiBold: [487 glyphs, advances: [1240]] Monaspace Argon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide: [487 glyphs, advances: [1398]] Monaspace Argon SemiWide: [487 glyphs, advances: [1398]] Monaspace Argon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Argon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Argon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Argon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Argon Wide Light: [487 glyphs, advances: [1555]] Monaspace Argon Wide Light: [487 glyphs, advances: [1555]] Monaspace Argon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Argon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Argon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Argon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Argon Wide: [487 glyphs, advances: [1555]] Monaspace Argon Wide: [487 glyphs, advances: [1555]] Monaspace Argon Wide: [487 glyphs, advances: [1555]] Monaspace Argon Wide: [487 glyphs, advances: [1555]] Monaspace Argon: [487 glyphs, advances: [1240]] Monaspace Argon: [487 glyphs, advances: [1240]] Monaspace Argon: [487 glyphs, advances: [1240]] Monaspace Argon: [487 glyphs, advances: [1240]] Monaspace Krypton ExtraBold: [488 glyphs, advances: [1240]] Monaspace Krypton ExtraBold: [488 glyphs, advances: [1240]] Monaspace Krypton ExtraLight: [488 glyphs, advances: [1240]] Monaspace Krypton ExtraLight: [488 glyphs, advances: [1240]] Monaspace Krypton Light: [488 glyphs, advances: [1240]] Monaspace Krypton Light: [488 glyphs, advances: [1240]] Monaspace Krypton Medium: [488 glyphs, advances: [1240]] Monaspace Krypton Medium: [488 glyphs, advances: [1240]] Monaspace Krypton SemiBold: [488 glyphs, advances: [1240]] Monaspace Krypton SemiBold: [488 glyphs, advances: [1240]] Monaspace Krypton SemiWide ExtraBold: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide ExtraBold: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide ExtraLight: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide ExtraLight: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide Light: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide Light: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide Medium: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide Medium: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide SemiBold: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide SemiBold: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide: [488 glyphs, advances: [1398]] Monaspace Krypton SemiWide: [488 glyphs, advances: [1398]] Monaspace Krypton Wide ExtraBold: [488 glyphs, advances: [1555]] Monaspace Krypton Wide ExtraBold: [488 glyphs, advances: [1555]] Monaspace Krypton Wide ExtraLight: [488 glyphs, advances: [1555]] Monaspace Krypton Wide ExtraLight: [488 glyphs, advances: [1555]] Monaspace Krypton Wide Light: [488 glyphs, advances: [1555]] Monaspace Krypton Wide Light: [488 glyphs, advances: [1555]] Monaspace Krypton Wide Medium: [488 glyphs, advances: [1555]] Monaspace Krypton Wide Medium: [488 glyphs, advances: [1555]] Monaspace Krypton Wide SemiBold: [488 glyphs, advances: [1555]] Monaspace Krypton Wide SemiBold: [488 glyphs, advances: [1555]] Monaspace Krypton Wide: [488 glyphs, advances: [1555]] Monaspace Krypton Wide: [488 glyphs, advances: [1555]] Monaspace Krypton Wide: [488 glyphs, advances: [1555]] Monaspace Krypton Wide: [488 glyphs, advances: [1555]] Monaspace Krypton: [488 glyphs, advances: [1240]] Monaspace Krypton: [488 glyphs, advances: [1240]] Monaspace Krypton: [488 glyphs, advances: [1240]] Monaspace Krypton: [488 glyphs, advances: [1240]] Monaspace Neon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Neon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Neon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Neon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Neon Light: [487 glyphs, advances: [1240]] Monaspace Neon Light: [487 glyphs, advances: [1240]] Monaspace Neon Medium: [487 glyphs, advances: [1240]] Monaspace Neon Medium: [487 glyphs, advances: [1240]] Monaspace Neon SemiBold: [487 glyphs, advances: [1240]] Monaspace Neon SemiBold: [487 glyphs, advances: [1240]] Monaspace Neon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide: [487 glyphs, advances: [1398]] Monaspace Neon SemiWide: [487 glyphs, advances: [1398]] Monaspace Neon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Neon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Neon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Neon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Neon Wide Light: [487 glyphs, advances: [1555]] Monaspace Neon Wide Light: [487 glyphs, advances: [1555]] Monaspace Neon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Neon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Neon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Neon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Neon Wide: [487 glyphs, advances: [1555]] Monaspace Neon Wide: [487 glyphs, advances: [1555]] Monaspace Neon Wide: [487 glyphs, advances: [1555]] Monaspace Neon Wide: [487 glyphs, advances: [1555]] Monaspace Neon: [487 glyphs, advances: [1240]] Monaspace Neon: [487 glyphs, advances: [1240]] Monaspace Neon: [487 glyphs, advances: [1240]] Monaspace Neon: [487 glyphs, advances: [1240]] Monaspace Radon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Radon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Radon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Radon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Radon Light: [487 glyphs, advances: [1240]] Monaspace Radon Light: [487 glyphs, advances: [1240]] Monaspace Radon Medium: [487 glyphs, advances: [1240]] Monaspace Radon Medium: [487 glyphs, advances: [1240]] Monaspace Radon SemiBold: [487 glyphs, advances: [1240]] Monaspace Radon SemiBold: [487 glyphs, advances: [1240]] Monaspace Radon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide: [487 glyphs, advances: [1398]] Monaspace Radon SemiWide: [487 glyphs, advances: [1398]] Monaspace Radon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Radon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Radon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Radon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Radon Wide Light: [487 glyphs, advances: [1555]] Monaspace Radon Wide Light: [487 glyphs, advances: [1555]] Monaspace Radon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Radon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Radon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Radon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Radon Wide: [487 glyphs, advances: [1555]] Monaspace Radon Wide: [487 glyphs, advances: [1555]] Monaspace Radon Wide: [487 glyphs, advances: [1555]] Monaspace Radon Wide: [487 glyphs, advances: [1555]] Monaspace Radon: [487 glyphs, advances: [1240]] Monaspace Radon: [487 glyphs, advances: [1240]] Monaspace Radon: [487 glyphs, advances: [1240]] Monaspace Radon: [487 glyphs, advances: [1240]] Monaspace Xenon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Xenon ExtraBold: [487 glyphs, advances: [1240]] Monaspace Xenon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Xenon ExtraLight: [487 glyphs, advances: [1240]] Monaspace Xenon Light: [487 glyphs, advances: [1240]] Monaspace Xenon Light: [487 glyphs, advances: [1240]] Monaspace Xenon Medium: [487 glyphs, advances: [1240]] Monaspace Xenon Medium: [487 glyphs, advances: [1240]] Monaspace Xenon SemiBold: [487 glyphs, advances: [1240]] Monaspace Xenon SemiBold: [487 glyphs, advances: [1240]] Monaspace Xenon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide ExtraBold: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide ExtraLight: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide Light: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide Medium: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide SemiBold: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide: [487 glyphs, advances: [1398]] Monaspace Xenon SemiWide: [487 glyphs, advances: [1398]] Monaspace Xenon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Xenon Wide ExtraBold: [487 glyphs, advances: [1555]] Monaspace Xenon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Xenon Wide ExtraLight: [487 glyphs, advances: [1555]] Monaspace Xenon Wide Light: [487 glyphs, advances: [1555]] Monaspace Xenon Wide Light: [487 glyphs, advances: [1555]] Monaspace Xenon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Xenon Wide Medium: [487 glyphs, advances: [1555]] Monaspace Xenon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Xenon Wide SemiBold: [487 glyphs, advances: [1555]] Monaspace Xenon Wide: [487 glyphs, advances: [1555]] Monaspace Xenon Wide: [487 glyphs, advances: [1555]] Monaspace Xenon Wide: [487 glyphs, advances: [1555]] Monaspace Xenon Wide: [487 glyphs, advances: [1555]] Monaspace Xenon: [487 glyphs, advances: [1240]] Monaspace Xenon: [487 glyphs, advances: [1240]] Monaspace Xenon: [487 glyphs, advances: [1240]] Monaspace Xenon: [487 glyphs, advances: [1240]] Monoisome: [1262 glyphs, advances: [1024, 2048]] Noto Sans Mono Black: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans Mono ExtraBold: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans Mono Medium: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans Mono SemiBold: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans Mono Thin: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans Mono: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans Mono: [3490 glyphs, advances: [600, 1200, 1800]] Noto Sans SignWriting: [679 glyphs, advances: [1000]] ProggyCleanTTSZ: [226 glyphs, advances: [448]]All of these font files come from Archlinux packages. Most matches belong to Monaspace. But others include "Noto Sans Mono", "Noto Sans SignWriting", "ProggyCleanTTSZ", and Monoisome (a part of Monoid).
Performance Considerations
Timings listed in seconds are (pre_cache, caching, total). Caching timings are noisy a little bit.
No mono_proportional check
With mono_proportional check
So, with 220 extra fonts detected, only ~0.04s is spent on mono_proportional checking, and ~0.11s is spent on caching the extra fonts.