UIFont from a CSS definition

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:

  1. Find the closest available font-family for the vague description provided by the CSS.
  2. 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.

<script src="https://gist.github.com/3181324.js?file=FontRegistry.m"></script>
<script src="https://gist.github.com/3181324.js?file=FontResolver.m"></script>


No Comments

Post a Comment