Essentials • iOS, OS X • 53:38
Learn practical techniques on font and layout handling with Core Text in iOS and OS X. See how to address commonly encountered issues, increase your app's performance, and learn about font embedding and support.
Speaker: Ned Holbrook
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. Welcome to session 226, Core Text and Fonts. My name is Ned Holbrook. I'll be your tour guide for this afternoon. We've got quite a few things to speak about, so let's get started. So we're going to be discussing a number of things this afternoon. First of all, we're going to be discussing new features provided by Core Text in Mountain Lion and iOS 6. The two big ones are a new API for accessing line bounds, and we're going to be discussing baseline alignment.
We're also going to be touching on a number of individual techniques. We'll be giving a quick overview of vertical text. We'll be talking about a number of font topics. And along the way, we'll also be mentioning some advice for you to keep in mind while working with Core Text in order to avoid any common pitfalls.
[Transcript missing]
I'd like to call your attention especially to UIKit as in iOS 6, UIKit now offers some really great support for attributed strings. So the reason I call this out is because there might be some people in this room who are looking at Core Text because previously there was no real UIKit level mechanism for dealing with attributed strings. And so we're really delighted to have that available in iOS 6.
And so if you're here just because of that, then I encourage you to check out the UIKit sessions on attributed strings. There was one just now that you can catch on video later, I'm sure. And there will be another advanced session tomorrow, so you can check your schedule for that. And of course, Core Text is the heart of complex text layout on WebKit as well.
So this talk assumes that we're going to be talking about the core text of complex text layout. This talk assumes that you have used Core Text before. We're going to be talking specifically about Core Text. But again, if you're not comfortable dealing with it directly, then please talk to our hair level framework.
Core Text has been available in OS X since Leopard and iOS 3.2. Basically what that means is that if you're targeting any sort of modern platform at this point, Core Text will be there. Core Text itself is a top-level framework on iOS, meaning it lives in system library frameworks, and that's where you link to it. And also on Mountain Lion.
So previous to Mountain Lion, Core Text was a part of the application services umbrella framework, which meant that in order to use Core Text, you had to link to application services. But as I mentioned on Mountain Lion, it is now also a top-level framework. So your existing code will continue to function just fine, but for new OS X projects, we encourage you to go ahead and link to Core Text directly in system library frameworks.
I'd be remiss if I didn't point out that atsui and ATS for text layout and font management on OS X are still incredibly deprecated. So if you have any legacy code that is still using either of these frameworks, now is definitely the time to plan your exit strategy. And so in particular, some ATS functionality has only relatively recently been moved into Core Text.
So if you were kind of on the edge there with making the move, we think everything is in place for you now. So if you have any questions about making that transition, please come see us at our lab tomorrow, and we'd be glad to help you with that. So the text nerd in me is very excited to be able to talk about some of our new features.
So this first slide is one of a number on line bounds. So when I say line bounds, so of course Core Text takes an attributed string as input and gives you a line with positioned glyphs and all the relevant style information. And when I say line bounds, I mean the measurements that pertain to that CT line object as it's been laid out.
So these are the measurements or metrics we sometimes call them for that laid out line. What I've done in this slide is I've taken the results of calling an existing API, CT line get typographic bounds, on this attributed string where I've set this text using the Heffler text. text font. : And what I've done is I've constructed a bit of a diagram showing what those values represent. And so, of course, the width of this rectangle would be the width as returned by the API.
The In the lower left, near the lower left, there's sort of an orange blob which indicates the line origin. That's kind of a reference point for all the measurements in this particular line. And then for this slide, I've also indicated the baseline on which the text sits. So basically it's y equals zero across the line there.
And so of course the amount of the box below the baseline is the descent and the amount above would be the ascent of the line. And one thing to note about this particular example is that the way the font is constructed, you'll note that there's not quite enough room here.
So this is kind of a way that some older fonts were constructed, but imagine if this line had an accent above the capital letter here, or one of these other letters with a sender. And there would be no room for it in the line bounds. And so I call this out because internally what Cortex has done in the past when you're filling a frame using CTFramesetter, Core Text has applied an adjustment factor in order to pad out the lines to give space for those accented capital letters because they're incredibly common in other Latin-based languages. So not English, you probably wouldn't see many, but for other languages you certainly would. And so we need to provide that room so that the text won't regularly be falling outside of the frame that you've supplied.
So now, instead, I'd like to call a new API. This is available in Mountain Lion and iOS 6, ctline-get-bounds-with-options. So right now I'm calling this particular API with no options, that's the zero. I'll be touching on some options in just a moment. But the one thing that I hope you'll note is that compared to the previous results, there's two things.
One is that the result you can't see on the slide, but it is actually returned as simply a CG rectangle or CG rect since it's generally a lot easier to deal with a single value being returned from a function than a number of output parameters as with the older function.
And also the default result of this, calling this new API, includes that adjustment that we had previously applied internally that you could sort of deduce by, you know, reverse engineering where the line ended up in the frame. But now you can simply access that directly. And so if you needed to match that computation for whatever reason, then it's available to you through this new API.
As I advance to the next few slides, I want to call your attention in particular to the left and right sides of this rectangle on screen. Because I'm going to start passing some different options to this API and it's going to have an effect on either side. So let's go ahead and advance now as I invoke "Use Optical Bounds".
So this is a very slight difference here, but you may have noticed that the edges of the box have been pulled in a little bit here. What's going on here is that optical bounds are very closely related to the typographic bounds, the regular measurement of the line, but in this case the font designer has specified that the way that the font is likely to be perceived by our eyes means that they don't line up exactly with just the glyph measurements.
And so the optical bounds in this case have been designed to pull in on either of these curly quotes here, because the way our eyes see rounded shapes is a bit different than the way we see straight lines, and so the font designer has compensated for that by providing this information in the font.
The next option we're going to see is going to be a very much more obvious change as we use hanging punctuation. So this is an option. It's sometimes seen in some typeset pages. Gutenberg did some of it, but it kind of fell to the wayside. Well, computers can make this a lot easier.
Hanging punctuation is the process of letting the insignificant punctuation in a line hang off of either margin in a frame or on a page. So of course this requires knowing that that can possibly happen and so not simply clipping the text to the immediate bounds of the frame. But this is certainly a pretty interesting example.
One thing I would note is that of course not every glyph can hang off either side. Some of them are limited to just the right or left, for instance. And this information can come from the font. The AAT prop table has a "can hang" bit. That the font designer can set indicating that they want a particular glyph to hang on one side or the other.
But in the absence of that information, since that's not super common yet, you can... Core Text also has a list of characters that are appropriate for hanging on the correct sides for standard Roman typography. So that's something you can play with even without a particular font. The last example I'm going to show you how you can combine these two options. Another subtle thing here, but watch on the left side of this box as I advance.
And you'll see there the effect of applying both hanging punctuation and optical bounds. What's happened here is that the font designer has set the cap J so that of course it's snug up against that curly quote there, but the font designer also decided that when set against the left margin, that cap J should get a little bit of extra space so that the tail isn't hanging completely out as it would otherwise. So that's an example of how options can be combined.
Another variant of calling this API is to use glyph path bounds. So previous to the availability of CTLineGetBounds with options and still available is an API called CTLineGetImageBounds. But it was a bit of a misnomer in that it was doing exactly what this option is doing, which is simply computing the minimum bounding rectangle of all of the glyph paths in the line. And it was also pretty difficult to actually use. If you've tried to use it, it's rather cumbersome.
So we wanted to make it available through this new API. It's a lot simpler to use. But I also wanted to call out the fact that these glyph path bounds are not generally relevant when dealing with typography. Since, as you can imagine, it depends greatly on what the particular glyphs in a line are. So you wouldn't want to use these glyph path bounds when determining how to set two lines, one after the other, on top of each other.
Because if one of the lines didn't have any descenders, for instance, which can happen, then of course you wouldn't see anything below the baseline whatsoever. So this value is more appropriate for input to some other process. Maybe you're implementing a drawing application and need to know the coverage of the glyph paths. Or maybe the glyph paths themselves are part of a graphical composition that you're using in your application. Or document handling. But this is available as another option for the new API.
It's all fine and good. I mean, information is good, but another way to make use of this is to actually apply it, and you can do that automatically using a new paragraph style specifier, which is used by CTFramesetter to affect the line edges during frame filling. So, for instance, if you specified the option for using hang punctuation and set that on a paragraph style, CTFramesetter would automatically hang that punctuation and vary the line lengths appropriately to make that effect possible very easily.
The other big feature that we wanted to call your attention to is baseline alignment. This is kind of a case of back to the future. This technology has been around for a while, but it's been a bit neglected. But as we expand our global coverage in Apple, one of the things that we learned is that the naive way of doing things wasn't sufficient when dealing with mixed scripts or writing systems. Because some of them have very different typographic conventions relative to Roman text.
So I wanted to give you some examples of how this is actually useful or why it might be interesting. Certainly it's interesting to us and you might have some ideas as to how to put it to use in your application as well. So in this example we have "Hello World!" but "world" is set in Han characters, so if you speak Chinese, for instance, it might make sense. I did a rough translation there.
This is the layout that you would currently get from Core Text or any higher level framework. It looks okay. What I've done is I've set that string in Myriad, but of course since Myriad the font doesn't contain either of those Han characters, we have font fallback occurring here. So this is a different font that has the Han characters. And it looks okay. Everything is set on this blue baseline here, which I'm going to call the natural baseline. This is just placing each glyph origin at y=0.
But a native speaker of Chinese perhaps might note that their baseline actually should sit a bit lower than the standard Roman baseline. And so by enabling baseline alignment here to let those Han characters sit on the ideographic baseline, a native speaker would feel that this is a much better appearance. Now this is a bit of a subtle example, and so I wanted another example that would make things a bit more obvious.
So here's another "Hello World," this part in Hindi. And so what's interesting about the Devanagari script is that it actually operates on a different notion of a baseline completely. It uses what's called a hanging baseline. And so rather than natively setting on top of a baseline, such as this natural baseline here, you'll see that there's a crossbar from which the letters hang.
And so a native speaker would expect that when you change the point size of that text, that it would actually, if you made it larger, it would actually extend down from that hanging baseline, rather than sitting higher up as we're used to, or we English speakers are used to.
And so I'm going to increase the point size by quite a bit to emphasize the effect, but this is actually the expected behavior for a script that uses a hanging baseline. Ned Holbrook And so a native speaker would expect that when you change the point size of that text, that it would actually, if you made it larger, it would actually extend down from that hanging baseline, rather than sitting higher up as we're used to, or English speakers are used to.
And so a native speaker would expect that when you change the point size of that text, that it would actually extend down from that hanging baseline, rather than sitting higher up as we're used to, or English speakers are used to, or English speakers are used to, or even if you're using a natural baseline, that it would actually extend down from that hanging baseline. So you'll see here that even though the line itself still has the expected natural baseline, the larger point size of that Devanagari text causes it to hang down.
So that's great, but maybe you're not localizing your application into a language that requires this type of special treatment. The other neat thing about baseline alignment is that you can use it for some more fun effects maybe or something else. We'll find out what you all can come up with.
In this particular example, I'm just going to implement some simple drop caps like you might see at the beginning of a children's storybook or maybe a magazine that you read uses an effect similar to this. But this example I'm going to make use of that hanging baseline from the previous example, but I'm just going to apply it manually to these capital letters. And so in this case I can override the baseline for the Roman glyphs here and set them on the hanging baseline as I change their size.
So how do you actually do this? Well, Each font has multiple baselines. A baseline is essentially a vertical offset relative to that natural baseline I was showing you. And there are a number of them that I've shown you already. The Roman, which in most fonts corresponds to the natural baseline. Ideographic, hanging in there, a couple of others for certain purposes.
Each glyph in a font has associated with it a default baseline. One of those types of baselines is appropriate for each glyph by default. Either the font can specify that or we'll use the character range in which that character comes from to determine what the baseline should be by default.
And then the process of alignment is simply taking two adjacent runs of text, either with different fonts or different attributes. One of them is going to be a reference, that is, it's going to stay put, and the other one is going to move up or down so that we can pick the same type of baseline from each of those runs and match them up. So that's what baseline alignment is going to be doing.
: We do this by specifying those alignment parameters using string attributes. The most important one is the reference, which is specified using the reference info attribute. And this is what activates baseline alignment. By default, it's disabled because, A, we don't want to be affecting the layout of text that you previously expected to see in a certain way, and also because, well, it would be rude. So you need to specify that in some way. And then some options are to also give some special definition to the baselines being moved and also overriding which particular baseline in the set of baselines is going to be aligned. Otherwise, we'll use the default baseline.
So this is what it looks like in its simplest form. This is how I implemented both of the Hello World examples. What I've done is I have a mutable attributed string. I'm adding my reference info to it, and that's a dictionary containing various keys and values, but the important one in this case is the reference font. This says -- this defines the set of baselines relative to which I'm going to move anything that might need moving.
So this will be applied to any fallback fonts, for instance, and we can also use it in the case of the point size changes. So since a CT font has an inherent point size, of course, in the Hindi example when we changed the point size, the reference font remained unchanged. I didn't change that in that example at all, and so it used the hanging baseline. from the original point size.
[Transcript missing]
And as I mentioned previously about using the highest level framework possible, you may be doing this all from the App Kit level. And so App Kit also added NS Font Collection in Lion and, of course, that's toll-free bridge with CT Font Collection. So instances of either class can be used interchangeably with either API, either Core Texts or App Kits. And it remains the preferred way to enumerate fonts. So if your application needs to get a list of fonts available to it while it's running, then CT Font Collection is the most efficient way to access that information.
Another feature pertains to typographic features. So Core Text supports two font formats, both AAT, Apple Advanced Typography, and OpenType. And both of these font formats have what are called typographic or layout features. They're special rules essentially in the font that change the layout. So a simple example would be a ligature where two glyphs appearing next to each other would get combined into a ligated glyph. But there are lots of other typographic features that fonts might offer.
And Since Core Text API is modeled after the AAT font specification, there were some OpenType features that weren't easily accessible. That is that you couldn't activate those features in code.
[Transcript missing]
So the way things were is that if you saw an AAT feature specified in our header, SFNTLayoutTypes.h, and it had a natural correspondence, a natural equivalence with an OpenType feature, then activating, requesting that AAT feature for an OpenType font would do the right thing.
But there were quite a few OpenType features that didn't have a natural correspondence with an existing AAT feature specification. And so what we've done in Mountain Lion and iOS 6 is we've added new features, new AAT features that naturally correspond to one of these OpenType features that was previously inaccessible. So in this example, I'm enabling Petite Caps, which is under the PCAP lookup in an OpenType font.
And so we've added this new feature. And so we've added this new AAT feature in order to activate the OpenType layout for this particular font. And this is something we'll be revisiting in the future. We may add a new API for direct access, but in the meantime, this should get you going with nearly all of the commonly requested OpenType features to enable in your fonts.
And on a bit of trivia, I would note that as of OS X Lion, AppKit added NSWritingDirection for specifying bidirectional embedding or overrides. And I'm not going to go into it now, but suffice it to say that it's now implemented at the Core Text level as well, which makes near as much no difference on OS X, but of course it means that now this feature is available on iOS as well. So if you have been making use of that, now you can do so on iOS.
Okay, well, we got the easy stuff out of the way, right? No, this next section is not so much advanced topics as it is perhaps a bit of a grab bag. We hear a number of questions from developers repeatedly, and so we thought that we'd address some of these common questions that seem to come up as we talk to you, and we also want to call out some new tidbits that you might be interested in.
Amen. The first is vertical text. Perhaps the trickiest thing with vertical text is just figuring out where to start. And so I'm not going to delve a lot into vertical text, but I would like to give just a quick overview of what that means from a layout perspective.
So there are two steps in enabling vertical text. One is getting the right layout, that is selecting the proper glyphs for vertical layout. And the other is getting the line to go in the right place. So naturally instead of sitting horizontally across a frame or page or whatever, it needs to go vertically. Well, the good news is those two steps are pretty much unrelated other than in the way that they're used.
And so we can demonstrate what it means to enable vertical text by following those two steps in action. The first thing we're going to do is enable those vertical glyphs, or activate vertical layout for this line. We're going to do that by setting a string attribute to a Boolean value of "yes." Essentially what that does from the line's perspective -- the line doesn't really care what it's doing here, but if you look at it in a horizontal perspective, it kind of looks like all the glyphs are just lying on their sides. Now, all of these glyphs are simply rotated, but in some cases, they might require slightly different glyph forms, or they might get different metrics or whatever, but for this simple example, I'm just going to show them being rotated.
So that's great, but of course it's still not very legible, and so what we need to do next is we simply just need to rotate that line into place. And so you'll note that these are somewhat unrelated, but they're both necessary for actually making use of vertical text.
So it's pretty easy to do that, but it's also not, because there's a lot of rotation involved. Some things go one way and other things go the other. And the way that our graphic system is based makes it fairly complicated to keep track of all these various transforms that are in flight at one time. And so use a higher level framework.
If possible, you should check out NSTextView on OS X. It has really great support for vertical writing. And so we'd urge you to go that route if at all possible. You'll get all the benefits of NSTextView besides. If you can't or don't want to do that, then CTFramesetter has an option that you can set when creating a frame that will do the rotation for you and take into account the proper bounds for vertical writing.
And then of course the vertical glyphs are simply just enabled by the string attribute. But if you're not using one of those, like I said, it's surprisingly complicated, and so I would urge you to come talk to us during our lab or grab us some other time, and we can talk about what it means and get you going on that.
Font names. So, fonts have lots of names. Most fonts have a lot more names than I can show on this slide, in fact. If you're curious, you can take a look at what you can find in FontBook on OS X, where you'll see a lot of, most if not all of the names in a particular font. But in this case, I wanted to use a particular example of Times New Roman Italic.
The first name on this slide is the most important. It's called the Postscript Name. We use it internally as a sort of identifier or, you know, a unique token for each font that is installed on the system. So what's special about this name is, well, for one, certain characters are illegal in it.
That's simply a specification thing, so you'll know if there's no spaces, that's a good giveaway that it's a PostScript name. But also, crucially, it's not localized. Most, if not all, other font names can be localized. So Times New Roman might not be Times New Roman in every language.
Another thing to note is that although it looks like the full or display name, depending on the terminology, is unique, you'll note that these other two names, the family and style names, those are almost definitely not unique. In particular, the family name is probably shared among other fonts in the same family, so Times New Roman Bold, for instance, would have the same family name. And likewise, the style name is probably that same thing for lots and lots of other fonts on the system. And why does this matter? Well, there's a function that I'm almost positive that you know of, having used Core Text, called ctfontcreateWithName.
And this function was designed to accept just the PostScript name. But we made the decision a while ago in order to be a bit more generous and accept any of these names. But the problem is that on a more constrained environment, like you would find on an iOS device, this can be quite costly to actually provide a reasonable result for anything other than the PostScript name.
So as I mentioned, you have the case of localized names to deal with. You could also specify the family name, in which case we try to do something consistent. We try to consistently give you the standard weight of that family. But that of course means we need to figure out what all of the members of that family are.
There's a lot of processing that's going on. And so we've got a number of scenarios brought to us by developers where they've been simply creating a font and things kind of just grind to a halt. and that's because we were trying to be nice. We're going to stop being so lenient.
[Transcript missing]
So rest assured this behavior is going to remain in its current state for any of your applications until they are linked against that future OS. But now is a good time to start updating your code to make sure you're supplying the right kind of name to CT Font Create With Name. So what we've done in iOS X is we've added some logging.
In this case, someone has inadvertently specified I don't know, it's probably the family name for Noya Helvetica, when in fact the PostScript name obviously is going to not have a space for one. But the developer in this case can set a breakpoint on this function in the second log statement, and they can check the backtrace and see what code is responsible for using the wrong name.
So you might be asking yourself, well, what am I supposed to do if I want to use one of those other names? Well, we've always had a way of doing that. It's just that it wasn't really needed because you could just do it the easy way instead. But basically what you would want to do in that case, maybe you have a document format that specifies a different type of name.
Or maybe you're even getting data from the Internet where you can't really know in advance that it's going to be a postscript name necessarily. And so in this case what you can do is you can use a font descriptor as a sort of a query. In this case the attributes specify a family name of Times New Roman.
And by using that particular attribute when creating matching font descriptors, then you're telling Core Text that it's only to consult family names that it knows about in order to find an appropriate font or fonts. And there are other attributes for, for instance, the display name and the style name, and you can use those as appropriate. So basically by signaling your intent, by telling us exactly which name you're trying to find a matching font for, we can do a much better job of not grinding to a halt.
Font fallback, some would say, is a crucial component to Unicode Text Layout because up until recently it's been impossible to construct a single font that covers all of Unicode. And besides, doing so would be prohibitively costly and time consuming. So basically, Unicode wants you to be able to specify any character in the standard and it's entirely unlikely that you're going to try to adjust the font for every particular character in that string. And so it's very important to be able to rely on having a fallback mechanism in place.
And so our default mechanism for that we call the system cascade, which is a list of fonts that will consult if the specified font is not the one that you're looking for. And so our default mechanism for that is that the specified font does not cover one or more of the characters in the string that you've asked to layout.
But in some cases, developers have asked for a way to modify the behavior of the system cascade. Well, the mechanism we've had in place for -- since the beginning of Core Text is to use this attribute to specify the cascade list or user cascade list as opposed to the system cascade list. And what that is is a list of fonts that you can specify as an attribute to either a font or a font descriptor, and we will consult those in order whenever we need to search for fallback.
Prior to consulting the system cascade. So one thing you could also do with this mechanism like this is to find out when you want to -- some developers have asked us that they don't want to consult the system cascade at all. They just want to use their own fallback fonts and they want to be able to detect when they've run out of those fonts effectively. And so all you need is a font that covers every character in Unicode.
Probably isn't going to be able to do anything useful with that, but it at least claims to support every character in Unicode and both of our platforms have a font with that property. It's called Last Resort. And so if you specify that, it will act as a terminator in the user fallback cascade list. And so you can detect that that's occurred by checking the run attributes on the line and see that that has been the case.
Now, I did say that up until recently you couldn't construct a font that covered all of Unicode. Well, Mountain Lion adds support for a new ISO IEC standard for composite font references. And this is an XML standard or XML specification that allows you to define a single font as being built up of multiple component fonts. And there's a lot of attributes and fine tuning that you can do on that. So if you have very, very specific fallback functionality to be implemented on Mountain Lion, you could check out the composite font DTD on the Mountain Lion install.
A lot of you are embedding fonts in your application bundle, most likely by sticking an OpenType or TrueType font in your app bundle, maybe in the resources directory or somewhere else. But some of you have noted that you've talked to font vendors and the vendor has a licensing requirement that says that they don't want you doing that.
They don't want you to be able to just put a font file in your bundle where someone could come along and just snoop it and find it and take it out. And so I wanted to note that you don't need fonts to be in their own files in order to activate them for use in your application.
Thank you. This has always been the case, but we've added a lot of the permutations, and so you should have a lot of flexibility in being able to do that now. So one example would be maybe you want to take the font data and compile it into your application somehow. Or maybe you want to take a bunch of font files and you want to splice them together into a single big file that doesn't look like a font file on its own, but you know how to extract the individual font pieces out of that.
There's a number of ways to do this. Once you have found the data for the font that you want to activate in your application, one way to do it on Mountain Lion or iOS is to create a graphics font, we call it, or a CG font ref with that data. And then in this particular example, I'm going to register that graphics font using CT font manager register graphics font.
And by registering it, what that does is it means that I can go ahead and access that font using any of its names. So for instance, if I could use CT font create with name using the PostScript name of that particular font that I had registered and access it that way.
Alternatively, I could create a CT font directly from that graphics font using CT font create with graphics font. And then on Lion or higher, there's another option that you have which is to create a font descriptor from that data. That's another way of doing this. It's a bit interesting because by doing that, you make the font not available via its names.
You need to have that font descriptor on hand in order to create a font from it. Same as if you had created a CT font from the graphics font. So that way, if you for some reason wanted to know exactly what part of your code was making use of that font, then you'd have to hand around this font descriptor, a reference to it, in order to be able to create a font from it.
: We do have some sample code which we have posted for WWDC which has an application that demonstrates one technique for doing this. It demonstrates having some fonts that are bundled up, not in their own files, but bundled up in an application, showing you how to activate that, one way to activate it anyway, and also demonstrates using those fonts in a user cascade list. So you can see both of these last two slides, there's a code sample available to you that you can pull down and take a look at. So emoji.
Emoji are these great little graphics, these images that are text, but they're also colorful and exciting. And people have really, really gotten into emoji. Since they first appeared on iOS and then were adapted to be part of the Unicode specification, we've seen incredible adoption of these. I'm sure you've sent or received a few of these guys yourself and many others besides. So, but there are a few notes to be made when dealing with emoji.
One is that we've ended up with sort of a case of emoji soup. The problem that many people ran into when first trying to make use of emoji, whether as a developer or as a user, is that many of these emoji characters had been unified, as they were called, with existing Unicode characters.
So in this particular example, if I had a document or a message or something where I sent it to some other platform and opened it up and read it there, I couldn't be guaranteed whether I would see the text representation, the sort of black and white pictograph there on top, or the emoji representation, which in Lion and iOS 5 was a completely different glyph.
So we have tweaked some things to make some of these problematic glyphs more accessible. So we've done some of these things to make some of these glyphs less problematic, but there are still cases where you may need to programmatically identify which particular representation of one of these unified characters you need. And so the solution specified by Unicode is to define variation sequences.
So these are essentially character tags that you can apply that indicate that one of these particular representations is to be preferred. And so if you simply sent that heart character, you wouldn't be guaranteed any particular appearance. In particular, due to historical constraints, some platforms prefer the text representation, some prefer the emoji-style presentation.
But using a variation sequence for this particular character, the middle example, I've specified the text variation selector, and so if possible, the system will give me the text representation. And of course, the last example there is the emoji-style presentation. And so... you can control that using those variation sequences.
And these are supported on both Mountain Lion and iOS 6. In particular, some cases, maybe your user interface designer had used a glyph as part of a user interface element, and all of a sudden things blew up when things changed due to the Unicode specification. And so in this case, you can specify exactly what you need.
When it comes to drawing color glyphs, well, there's actually a -- you know, the font has to be different in order to carry this color information around with it. And so simply using the lowest level function in order to draw glyphs from that font is not going to work. But so basically, again, it comes down to a case of using the highest level framework.
If you're simply drawing a string using AppKit, UIKit, whatever, everything will work just fine. If you're using one of the standard CT drawing functions, CT frame draw, line draw, run draw, again, that will work just fine. You'll end up with the standard glyphs or the color glyphs as necessary. But if you are drawing directly into a CG context yourself, the solution is to use CT font draw glyphs.
You can use this on any font. It doesn't have to be a font with color. It's just a font that you can use to show glyphs at positions. And so if you're drawing a color glyph, this will do the right thing whether or not it's a black and white glyph or a color glyph. So simply use that. It's analogous to that CG context show glyphs at positions function. And you'll get the correct behavior.
You might also have instances where your font is displaying text using some fancy graphical treatment. And that treatment may not work properly in the presence of color glyphs. And so if you need to identify that a glyph itself has color data, you can do so by consulting the CT font symbolic traits. And if a font supports color glyphs, then you can check for an individual glyph whether or not it has an outline, and the absence of an outline would signify a color glyph.
So speaking of drawing into a CG context, another question that comes up is, well, how do I have control over the drawing parameters for that context? So as I mentioned, Core Text was designed to be easily interoperable, you know, directly accessible for use with CG context drawing if necessary.
So one instance might be you have some sort of fancy display where you need to stroke the glyphs with different parameters. You might do it once in one stroke width and then again with another stroke width. But you want to reuse those glyphs, that layout, between both those drawing operations.
And you say, well, gee, I don't want to have to specify a different string attribute and then get a new line and draw it all. Well, that's not necessary. So the goal here is that Core Text should only set what it needs to. And it should respect what was otherwise set. So let me explain what that means. So most string attributes correspond to a particular drawing parameter. That is, there's a stroke width string attribute. And if you've specified that, it should take precedence over whatever was set in that CG context that you're going to draw into.
But if it's absent, and since it's defined as being unset, it doesn't affect the drawing parameter for the stroke width, then you should be able to specify that directly as a context drawing parameter. And then make sure that that attribute isn't present in the string that you're laying out.
And so that way you can set it to your first value, draw the string, and then set it to the next value and draw the string. And Core Text will respect that because, of course, it's just drawing through Core Graphics itself. But that way you have very fine-grained control over what is getting set in that context.
One exception to the rule, of course, is the foreground color. As was mentioned in the Attributed Strings introduction just previous to this session, that attribute has a default value of black. And so if you want to modify the foreground color between drawing a line, then of course you'll need to specify foreground color from context attribute name. It takes a Boolean, and when that's set to true, Core Text will not touch that drawing parameter either. Finally, one more oldie but goodie.
Core Text will not synthesize missing font styles. And by missing, I mean you might expect, coming from other platforms or older technologies, that you can simply request a bold font and get a bold version of whatever font you're using. Well, Core Text has always taken the approach that it should prefer the information given to it by the font. If the designer hasn't gone to the trouble of drawing a bold version of the font, then Core Text is not going to take it upon itself to try to make the plain weight bold.
There are some developers who need to be able to bold arbitrary fonts. Perhaps they have some document format that requires that they indicate a bold font or some other reason. You can certainly implement your own synthetic styles in your application, but this is something that Core Text is still not going to ever do.
One approach for instance for synthesizing an italic would be to simply skew the font matrix and that would give you a slanted appearance, not a true italic appearance, but that might be one way. For bolding, there's really no one panacea. There's no one great way of doing that.
So of course if you need any more information, there are a number of nice links here to Jake Behrens who is the evangelist. He can help you locate information if you're having a hard time with that. Otherwise, of course, there's the standard documentation, interface guidelines. Developer Forum is a very, very helpful resource for finding out from your peer developers how to make use of this technology more effectively and also Apple engineers.
Again, very, very interesting stuff given in the UI kit sessions on Attributed Strings. You will have already missed the introduction to Attributed Strings session as it's passed now, but you'll be able to catch it on tape delay, I'm sure. Also the advanced Attributed Strings session is going on tomorrow morning at 10:15, so I urge you to check that out. There's going to be some really neat stuff discussed there. And with that, I'd say thank you very much and have a wonderful rest of the conference.