UIFont from a CSS definition
If you need to get a matching UIFont
object from a CSS definition like “font-family: Arial; font-size: 24px; font-weight: bold;
” you have no way to do it with the API that iOS provides for three reasons.
First, there is a non-API method on UIFont
called +(UIFont*)fontWithMarkupDescription:(NSString*)markupDescription; that could do the conversion/lookup most of the time. Using it will get your App rejected by Apple. Second, the only way to create a UIFont
is with [UIFont fontWithName:@"Arial-BoldMT" size:24]
. But for this API you need to know the exact font name. And last, the CSS only provides a rough description of the font. In the best case only one font-family
is provided that matches exactly one on the system. But if a “font-family: Family-Foo, Family-Bar, monospace;
” is defined, you need to figure out which font family to chose on iOS that is monospace.
It comes down to two problems:
- Find the closest available
font-family
for the vague description provided by the CSS. - Find the right font name in the family for regular, bold, italic or both.
With this post I want to present you our temporary solution to these problems until Apple decides to make the fontWithMarkupDesciption method public (enhancement request is already filed ;)).
We splitted the solution into two parts. The FontResolver
and the FontRegistry
. The FontResolver
determines a valid system font-family from the CSS definition. Definitions like serif, monospace and sans-serif are supported, too. If no matches are found, we fall back to a system default. The FontRegistry
uses the found font-family to compute a font name to use. The registry itself is a singleton and stores a mapping from font-families (plus bold, italic… variants) to font-names that will be initialized on the first call. As a result all following lookups will just pick the font name in a dictionary, which is really fast by the way. Of course all this was done test driven. In the tests we used Apple’s internal method to validate that our implementation behaves the same with all font families available on iOS. As we had to implement this on our own we added a few extra features.
To make this clear let’s take a look at an example. Let’s say we have this CSS definition: font-family: monospace; font-weight: bold;
. In this case we expect that a valid UIFont object will be returned. Our implementation returns CourierNewPS-BoldMT
while Apple’s implementation returns nil
. I think you got it ;).
If you think this can be useful for you too, we have created a Gist on github licensed under the EPL 1.0. Any feedback and ideas are welcome. So, feel free to leave a comment.