Fonts
Cohtml supports TrueType/OpenType fonts and collections (.ttf/.ttc/.otf/.otc). @font-face
declarations in CSS are the recommended way of loading and using fonts. If you want to learn more about using fonts in the frontend here.
Differences from the HTML Standard
A major difference from the HTML Standard is that fonts are global to the whole system and not unloaded after changing pages. This means that @font-face
loaded from one View
can be used in another View
. A @font-face
from one page can affect the next page that is loaded after following a link or changing the URL. Registered fonts are kept loaded and cannot be overwritten. Subsequent @font-face
declarations matching the font description of a previously registered font will be ignored. We are keeping the fonts alive because it is common behavior in games to use the same fonts across multiple pages and this avoids loading and unloading the same font.
Another difference is that the load
event is fired after fonts are loaded. We feel that this makes more sense for games instead of marking a page as loaded with various fallback fonts and font styles which will be substituted later on.
Font preloading
Unity3D doesn’t support partial reads, which means that the raw font data will always be loaded in memory in order to be used when needed. Be careful with the size of the fonts you use. You should place all the fonts you want to use in aFonts
folder located in any Resources
folder inside the Assets
folder of your project and change the file extension of each font to “.bytes”. This is necessary so that when Cohtml is initialized all fonts will be loaded in memory via the Unity3D Resources.LoadAll
API.You can register fonts from
C# using the cohtml.Net.IUISystem.RegisterFont
API call. It works similar to the @font-face
declaration. Additionally, the API allows using the original font name and styles when font description isn’t provided, unlike @font-face
which is always explicit. The RegisterFont
API also supports loading all fonts from a font collection when a font description isn’t provided. Providing a font description when loading a font collection will load only the first font from the collection similar to @font-face
.
Register font on the default system:
CohtmlUISystem.GetDefaultUISystem().SystemNative.RegisterFont("coui://UIResources/Fonts/Oliver-Regular.ttf");
Register font on a custom system:
CohtmlUISystem systemComponent;
void Start()
{
systemComponent = GetComponent<CohtmlUISystem>();
systemComponent.SystemNative.RegisterFont("coui://UIResources/Fonts/Oliver-Regular.ttf");
}
Default font
The family name that was passed in the library parameter
cohtml.LibraryParams.DefaultStyleFontFamily
on initialize will be used when font-family for an element isn’t specified.
Font family fallback
Cohtml supports font-family fallback per character. You can specify multiple font families to be used for a single element, for example 'Droid Sans', 'Noto Sans CJK', Emoji
. All characters available in Droid Sans
will be used first, then for any missing character in Droid Sans
, Noto Sans CJK
will be used and so on.
Font weight fallback
Cohtml supports font-weight fallback per font-family and will try to select an available weight that is closest to the requested one within the same font-family. Font-family match has higher precedence than font-weight. For example, if you have Droid Sans
registered as a Regular
style font and you have an element that should render text as bold which uses font families Droid Sans, Noto Sans Bold
, Cohtml will pick Droid Sans
and will draw the text with Regular font style, instead of drawing it bold with Noto Sans
Font style fallback
Cohtml doesn’t support font-style fallback yet, so styles like Italic
and Oblique
should be specified explicitly in order for a font match to occur. Cohtml won’t match fonts with the same font-family name and different styles.
Generic Font Families
Cohtml doesn’t support generic font families functionality, but recognizes those keywords (serif
, sans-serif
, monospace
) in a font-family declaration and uses a specified font-family instead. The font-family that is going to be used can be configured when initializing the system with the
cohtml.SystemSettings.GenericFontFamilyNameFont
option. By default, Cohtml will use the default font for generic font families.
Additional font fallbacks
Cohtml allows to specify additional fallback font families using cohtml::View::SetAdditionalFontFallbacks
. It works as if the specified families from C++ are appended at the back of the font families defined in a stylesheet.
Fonts issues with trails and artifacts
Cohtml determines the glyph dimensions using the stored information about the glyphs bounding box from the font. When calculating the containing element size based on the content, the width of the container is determined from the sum of all glyph bounding box widths of the longest text line. The assumption is that glyphs will never be drawn outside of their bounding box. However, some fonts have glyphs that extend beyond the specified bounding box. This is a trick that font designers use to avoid specifying kerning for some glyphs. When such glyphs are drawn as first or last in the line, the part of the glyph that extends beyond its bounding box will be drawn outside of the containing elements bounding box. When the element is moved/hidden/removed it will only clear its bounding box which will leave artifacts for each part of the glyphs drawn outside.
The following image shows a case where the glyphs extend beyond its bounding box:
When reworking the font isn’t possible, elements using that font can be padded slightly (for example padding-right: 0.1em;
) so that the element bounding box covers the extended part of the glyph. Additionally overflow: hidden;
can be used to prevent artifacts from appearing altogether, but do mind that this will clip the parts of the glyphs that extend beyond the elements bounding box. The two CSS properties can be used together for the best results.
Cohtml determines the line’s height using the stored information about it from the font that the font designer has specified. When calculating the containing element size based on the content, the height of the container is determined by the line height multiplied by the number of lines. The assumption is that the line height will always be bigger than the height of the glyphs, otherwise the lines of text will cross with each other and will become unreadable. The typical ratio between the line height and glyphs height is around 1.25. The CSS property line-height
can override this for accessibility reasons and it usually involves increasing the space between the line by setting line-height ratio to around 1.5 for better readability. When adjusting the line-height from CSS we suggest always using a ratio instead of absolute values like <length>
and <percentage>
. Line-height ratios below 1 will cause the top and the bottom of the glyphs to extend beyond the containing element bounding box. When the element is moved/hidden/removed it will only clear its bounding box which will leave artifacts for each part of the glyphs drawn outside. When setting line-height ratios below 1, the same workaround with overflow and padding can be used in order to avoid artifacts.
Recent changes
Since version 1.13, there are a few notable changes to the text rendering. Mainly, Cohtml can now render text on fractional pixel positions. This makes text animations look smooth and avoids unexpected pixel snapping. Also, the size threshold for using SDF rendering is changed to 10 pixels (previously 18 pixels) so that all text smaller than 10 pixels is rendered using SDF. For more information, see the migration guide.
The changes with version 1.13 bring one caveat to the font rendering. Some fonts (e.g. Bitter) have crossing segments in the contour data saved in the TrueType font file. This interferes with the rendering of SDF glyphs on the GPU. In the case of such fonts, the glyphs will be rendered with artifacts. The following images illustrate what we mean
In case you find yourself needing to use such fonts, there are several strategies to remedy that:
- Fix the font itself. You can use a tool like FontForge to remove the crossings parts of the path. Load the font in FontForge, select all glyphs (Ctrl-A), and then choose Element->Overlap->Remove Overlaps (Ctrl-Shift-O). After the overlaps are removed, save the font as TrueType font.
- Alternatively, if editing the font file is not possible, you can turn off the GPU SDF glyph rendering through a developer option. See the migration guide for more information.