Application Frameworks • 58:55
Learn how to work with fonts in your Carbon and Cocoa applications. This session describes how your application can interact with the system font registry via the ATS font activation APIs, explain how to integrate the Font Panel in your application, show how to iterate through all fonts in the system, and more.
Speakers: Xavier Legros, Robin Mikawa, Nathan Taylor
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Thank you, Xavier. So, as Xavier said, my name is Robin Mikawa. I'm the manager of the Type Engineering team at Apple Computer. And I'll be talking to you today about fonts. But not just fonts. I'm going to be talking about the font system architecture and how it works, how it interacts with your application software, and how you can take advantage of it to make a really, really excellent user experience. So, let's get started.
So why am I talking about fonts? Why are fonts important? Well, think about it this way. Imagine rolling the clock back 20, 30 years and think about how fonts worked back then. You would have had one font on the system, maybe a green or amber screen, and that's it. Maybe at best you had a handful of fonts that you had to deal with.
Well, things have obviously changed since then. We have dozens of fonts that get installed by default on Mac OS X. Users can install even more fonts on their systems. Applications come with specialized fonts along with them. So you have tons of fonts you get to deal with, even by default.
Another thing that we've gotten feedback on with Mac OS X has been that fonts are complicated. People have to deal with a whole variety of issues with regard to fonts, even with just installing or previewing them. You might have encountered that with your family members, asking, well, where do I put these fonts? I see a bunch of different directories with the name fonts on it.
Where does it go? And so what we've tried to do with Panther is tie into that whole initiative to put the user at the center. As opposed to having fonts very computer-centric and file-centric, we want to make it so that the users can really take advantage of fonts and really find it easy and convenient to use and really take advantage of all the stuff that font developers and you guys have put in to make these things expressive and fully functional.
So what I'll be talking about today, I'm going to be starting off with a description of the font architecture. You're going to get a chance to understand what the system does, what it does for you, and what all the different components do and how they interact with each other. The second part of the session, I'll be talking about what you can do to take advantage of the system and bring it across to your applications and really make things shine.
So let me just dive straight into the first section. You can think of it this way. I'm going to be lifting up the hood on the system, pulling out the font engine or the font system, and showing you how all the different pieces work. And right up here, I've got a short list of all the different components related to the font architecture.
So let me just run through them. First off, we've got the font database system, the font registry, as we call it. This keeps track of all the information related to the fonts and manages all the fonts that the user can access. Secondly, we have the font rasterizers. It's the font engine that basically takes the font data, the raw font data, converts it over to data that can be used by other parts of the system, such as the graphics system or the printing architecture or even your applications.
The next level up, we've got the messaging system. One thing that you should understand is that we have implemented a centralized font server that keeps track of all of this information. In order for it to communicate the font data to your applications and to other processes on the system, it needs to send messages, and these are based on the Mach kernel messaging system.
Another level up, we've got the caching system. We've got the caches to optimize performance so that you don't have to always hit the lower levels of the system to get the font data that you need. And then this is the next level up. We've got the programming interface.
This is what you've traditionally heard in the past and what we've really focused on. What I'm trying to do here is connect you to the operating system and show you what the programming interface can do for you and why we've told you to do certain things as opposed to others.
And then finally, on top of that, as part of this initiative to put the user at the center, we've implemented and exposed a number of standard user interface elements that you could take advantage of so that your applications really fit in, have a consistent user interface, and take advantage of all the new features that we've implemented for Panther.
So what I've just described is a short list of all the different components, or the major components in the font system. What this diagram shows you are how they interact with each other. So over on the far right, you'll see two of the components. Those are the components that reside within the font server, or the ATS server, as you might have seen it called within the system.
The ATS, by the way, stands for Apple Type Services, and that's actually the main component that my team is responsible for. So within the server, centralized for all of the different processes available on the system, we've got the font rasterizers and the font database management system, or the font registry.
On the left-hand side of the screen, you see everything that resides mainly within your application context as opposed to the font server. That includes the user interface, whether you implement it or the system implements it or some combination between that. We have the programming interface and we have the caches. And in between the two of them, we have messages going back and forth across to communicate the font-related data that your applications need and, more importantly, what your users need.
Okay, so let me start diving into the details of this diagram. First off, let me work from the very basics here. The font registry itself, it is the central repository of font information. You can also think of it as the interface to the file system that lives underneath everything else. So users, for example, might install fonts. We track that information. We handle mapping in all of the file-related information and pull it into the font registry. database.
The font registry also tracks all the different locations that are supported on Mac OS X for installing fonts, and it also keeps track of the files that are associated with the fonts within each of those locations. The font registry is also responsible for managing the support for access privileges and multiple users. So for example, we've done a considerable amount of work for Panther to support the new fast user switching feature that you might have seen in the keynote.
Another piece of information that we keep track of with the fonts has to do with the state and also the usage of the fonts. Part of the work that we do within the font registry is we synthesize data and provide a canonical format for accessing font-related data. There's a number of different pieces of information, including the character mapping information, the paths, the outline data, the bitmap information, the metrics. We handle all of that through the font registry and other parts of the font architecture.
We also keep track of fonts that somehow get corrupted or actually bad starting off. We can actually tag those fonts as corrupted or bad or potentially causing a crash during runtime and prevent other users or other processes from running into that problem again. And that state information is kept track of in the font registry.
One additional piece of information, or one additional service provided by the font registry, is keeping track of all the different, the multitude of file formats available for fonts. So, for example, some fonts are stored in single files, other ones are stored in multiple files that get associated with each other in certain ways, you know, by file name or maybe something buried deep within the font file. Another thing we keep track of is whether or not that particular font data is stored within the data fork or resource fork of a file.
So that covers the basics of what the font registry does. Next, I'll be describing what the font rasterizers do. Now, you can think of these as the basic engines. These know all the details about the font data. They can take the font data that's stored in the file system, run through it, and spit out other forms of data that can be used by other parts of the system.
So that includes graphic data, the bitmaps, the paths, the outlines that get rendered through the graphics systems. We also provide support for converting data from what's natively stored on disk to the formats used in, for example, PDF documents when you embed font data within them. Also, we convert data to the form used when downloading fonts to the printing system, generating PostScript forms of the font. for example.
The other thing that we do with the font rasterizers is very similar to the way the font registry handles different file formats. The font rasterizers, they actually know all the details about the different formats available out there. So not only can fonts be stored in different file formats, they can be stored in different data formats themselves.
So we've got the standard technologies that are out there right now, TrueType, PostScript. We support multiple forms of them, including the Type 1 format that you're probably used to on Mac OS 9 and older. And we also support the new CFF or Compact Font format that's available with the OpenType form of the PostScript fonts and also used in PDF documents. And then last but not least, we support the older or legacy bitmap-only formats. that were available for Quickdraw-based applications.
Okay, so next, let me talk about the messaging system. As I mentioned before, the main thing about messages is that they are based on the lower level kernel messaging system. They're the inter-process communication mechanism for going back and forth between the font server and your processes and other processes on the system.
Another key thing that you can remember from this is that pretty much any programming interface related to the font may ultimately result in a message that goes from your application out to the server and potentially back. Note that this can take time, and I'll be touching on this subject a little bit later on.
Now, messages can be categorized into different classes. The one that's probably most relevant to you is that when changes occur within the font registry, The font server will actually broadcast messages out to any clients that are interested, notification about these changes. Similarly, there's also support for your applications to send notification messages back to the ATS server so that you can notify us to do certain actions or update our font registry.
There's one additional flavor of messages or quirk on it that we've implemented through our API, and that includes support for actually hooking into the messaging system. The way this works, for example, is basically since a number of messages that applications can send out for querying about missing fonts, let's say you open a document, it doesn't have the fonts you need, what that can often do is trigger a message across the font server to ask for a replacement or to find out whether it's actually present or not.
We've provided a mechanism so that you can hook into that process, intercept that message, and provide your own level of support for handling that missing font. So some font utility application vendors have actually taken advantage of this and provided a user interface or even automatically provide the appropriate font and activate it within the system. So this shows you some of the strengths and benefits of going to a messaging system.
The next level are the caches. Now, as I mentioned before, there is a cost to doing messages and having this whole font server-based architecture. What we try to do with the caches, and what we've succeeded actually, is making sure that the most commonly used functions and the most commonly used data that you access is available as fast as possible through this caching mechanism.
You'll notice that the key areas that we're trying to shield you from are the lower levels in the font system. So, for example, the font registry corresponds to the file system usage. It takes time to pull in a font file, read it in, and handle it and process it. In fact, processing it is the next level up that we try to reduce the impact performance-wise on your applications. It takes time to run through.
In fact, for PostScript fonts, we have to parse through the entire PostScript font program in order to get even basic data such as the metrics or one glyph outline. And finally, as I mentioned, messaging takes time. It's often much faster to just do a simple function call to access your font data locally from within a cache than sending a message off to the font server and coming back with that data.
Okay, so this is what you're probably most familiar with and what you deal with on a day-to-day basis when it comes to fonts. So, as I mentioned earlier, ATS, Apple Type Services, we provide a direct API into the font system through the ATS font API. What this programming interface allows you to do is modify or manage the contents of the font registry. You can also query the font registry for information.
We also provide support for accessing data directly from the font rasterizers. And finally, you can hook into the messaging system and take advantage of it with your own application software. There are other APIs that are available that are built on top of the underlying ATS APIs, and those include the text system available within Cocoa or Carbon, and also the legacy Quickdraw-based font manager is built on top of the ATS font system.
Now this is the last block diagram from the architecture that I'll go over. This is a description of All the features that you might want to have the user interface with regard to fonts support for you and your customers. First and foremost, you want to be able to select or change the font and style information in your documents or in any piece of text.
You also want to be able to access glyph-specific information within a font. This includes stuff like what characters does this particular font support, or can I get access to different variants on a character. And this is especially important in the Asian market where there are different forms of the Han characters that people use in, for example, their last names.
Another feature of the fonts that you can get access through the user interface are the typographic features. This includes support for turning on and off ligatures or other variant forms within the font. And then finally, as I mentioned, one thing that people have really asked us for in the operating system is a really easy way to manage the fonts that you have, your collection of fonts. This includes your entire library of fonts.
There have been-- users have asked for ways to install their fonts much more easily and to be able to preview their fonts much more easily. And so with Panther, we try to make that much more robust, much more simple. And also, we want to have room for growing and providing additional services. So with that, I'd like to bring up one of the other engineers on my team. His name is Nathan Taylor. And he'll give you a demonstration of some of the work we've done for Panther.
Thank you, Robin. As Robin said, I'm Nathan Taylor. I'm an engineer with the Apple Type Engineering Group. And I'm very excited to show you the new user interface and the user interfaces that you should implement for presenting fonts in a consistent way to your users of the system. We've taken the user-centric approach to heart here. And if you saw the keynote, you saw a brief glimpse of something I am very excited to show you today. So with that, I'd like to switch to demo one, please.
Okay, users just bought a bunch of fonts, downloaded some fonts from the internet, doesn't really know necessarily what they look like, and biggest question we've gotten is where should we put these fonts? You know, there are many font folders, which is the best one to place them in? We've tried to tell people how to do it in Tech Notes, but there's a much easier way, and let me show you.
I'm going to open up a folder of fonts here and go to one that's not currently installed in Mac OS X. It's a font that you know and love from Mac OS 9. This is the Type 1 version of it. And if the user just double clicks the font, The FontBook application comes up and shows a quick preview of the font where they can switch between and examine the different styles.
And with a single click of a single button here, the font will be installed in what we consider the appropriate place at this point in time. That is the user's fonts folder. When the font is installed, the main font book user interface comes up, selects the font, and they can see that their action has actually taken effect.
This gives a quick and easy interface to browse the fonts in the system. With simple arrow keys or mouse actions, the users can look at the various fonts that are installed, get an idea of what's available, and if there are some that they don't want or they're never going to use, there's an option to turn them off. I don't speak Korean, I don't read Korean, I don't write Korean. I'm never going to use the Korean fonts that always show up at the top of the font list. Well, I can simply select them in FontBook and disable them.
Once FontBook is able to fonts, they will no longer be available and not show up in the fonts window in Cocoa or Carbon applications. and Koba. It's also possible to just add a bunch of fonts. We have a breakdown of the font library that shows how fonts are grouped and categorized. There are the user fonts that are just my fonts.
There are the computer fonts, which are shared between all users of the system. Network and classic similarly. Users can move fonts around between these directors if they want to. What I'm going to do now is add a bunch of fonts, the rest of the fonts from that big folder I took Palitino from.
And just add all the fonts there. I'm going to show you building collections and searching for fonts. So all those fonts have been added. You can see I've got Avenir, Bodoni. All the ones I just added are all selected. What I can do now is, I know I just installed a bunch of ITC fonts, but I want to group them so I can easily find them within my application.
So, we have collection management in Mac OS X to do this, and using the new collection management system provided by the Cocoa layer, we can create a new collection. Name it my ITC fonts. And I want to add fonts to this. Well, they're somewhere in this list, right? Well, let's find them.
Type ITC and I get all the fonts that match my search string. I can then select all these fonts. and drag them over to my collection there. If I switch back to text edit now, you'll see that the ITC Fonts collection is available. And selecting that collection shows those fonts. I can then simply use them. They're available immediately.
Likewise, there are ways for users to quickly manipulate collections. They can tweak the collections. They can remove individual faces from them. They can remove families. They can also disable the collections from within the Font Panel or from within FontBook application. Say, for example, I don't like the heavy faces here. You can select them and disable them from this. Let me do that again. Disable them from the ITC collection, rather than the library, which I've already showed you.
And now, if I look at that family, Franklin Gothic, the heavy faces are not there anymore. Easily just re-enabling them brings them back. If I don't want to use that collection of fonts now, I can simply disable the collection and the collection is hidden from the UI. The fonts are still active for other apps to use, but The collection has been hidden from the UI. While you may ask, I want to group these and disable the fonts as a whole. As optional behavior, we do have the possibility to disable the whole thing.
Pulling down the option key and disabling this will do what the alert here says and disable all of those fonts from the library. If I look in all fonts here, you can see that the ITC fonts are marked off and the font is not
[Transcript missing]
So what do you need to do in your applications to take advantage of this new functionality we're providing to the users? We've made it easier for the users to manipulate their fonts. We think this is going to allow them to do it more often.
They don't need to know where fonts live in the system. They can just launch an application and turn things off as they wish. If your app doesn't react to these changes, the user interface that you present will not be consistent across the board, and we'd like it to be user-centric so that everything feels the same in every application.
The first thing you can do, and the least we ask you to do, is implement support for ATS font notifications. If you have a Carbon application or Cocoa application, but in a Carbon application, if you implement support for notifications, we will notify you and call back a callback that you create. And in this case, I put up alert to be extremely obvious.
If we take a look in the fonts menu, Avenir, Badoni, these fonts have been added to the Fonts menu and immediately updated. If I were to disable them, they would not show up next time the font was activated and the Fonts menu was opened. This corrects the problem of having to quit the app and relaunch the app from the old days and makes it so much more consistent.
But there's one step further you can go, and this is what we really ask you to do. You can implement the fonts window. If you're doing a Cocoa application, it's pretty easy. It's right there for you. In Carbon, it's quite possible, but it's not quite as easy, but it's not hard at all. And let me give you an example.
Let me just show you real quick. I've got a similar version of Simple Text here that has a font window implemented. Close it, bring it back up. Like the other one, I've got the same fonts, and if I re-enable that ITC collection, I can show you that... All the support for collection management and the user managed collections are there.
If you implement the Fonts window, subscribing to ATS notifications actually become unnecessary because the Fonts window handles that automatically for you behind the scenes. So what do you need to do to do this? Adding notifications is really a piece of cake. First, I chose to implement the standard fonts menu.
Three new function calls and effectively only three new lines of code. To add notifications, I just created one callback and made one function call. Whenever that notification came across, my callback updated the font menu, and that was it. It's a little more work to put in the fonts window, but we really don't think it's that hard.
If you've been moving to a Carbon Events based application, you probably already have a standard Carbon Event handler. But that's the first thing you need to do. And the handler I have in here is about 20 lines of code. Next I put in a handler attached to the window to handle the font window events, the font changes the user made in the Fonts Panel, and that's about 25 lines of code. The last thing you need to do is update the Fonts Window with the user selection with one new function call.
Well, Robin also mentioned that there were a bunch of other new features to the Fonts window. You see that there's a search field here. We also have a direct access to managing fonts. brings up Fontbook directly, and if the user has another font management application, we expect it to bring that up.
Further, we have Typography Palette. This provides access to the various font features that are not default and are very sensible. Zafino is a very pretty font that we install with Mac OS X, but it has a lot of features that you can't get to right on the surface. If you implement support for the Typography Palette, you can get access to specialized ligatures, Ornaments, stylistic variants, old style figures, small caps, a whole bunch of works.
Japanese fonts even have a lot more to offer in this typographic palette. For example, Hiragino, one of the Japanese fonts we ship with the system, has many features. You can see this is a huge palette here. There's support for Japanese features like kana widths, where you can have full width, half width, or proportional widths for kana characters. There's also support for stylistic variants and other features that the font may provide.
The last thing I want to show you is the Character Palette. You may have seen this in other presentations, but There's direct access to get to specific characters and to see all the characters supported by a font. Unfortunately, we may have a little bit more work to do on the Character Palette, but I think you've seen it before. You'll have a window, access to all the glyphs or all the Unicode points of the font, and you'll be able to see everything that's available.
We hope you like the new user-centric approach to managing fonts on Mac OS X, and we really hope you take two points home from today's presentation. One, we want a user-focused approach. To do that, we ask you to implement one of two approaches in your application. At a minimum, respond to ATS font notifications.
Don't make the user relaunch your application to see new fonts. Or two, even better, anywhere you would use a font menu, provide access to the Fonts Panel so we can have a standard user interface for fonts across the entire system. Thank you. I'd now like to invite Robin back to stage to finish the rest of the presentation.
Thanks, Nathan. So you've seen some of the really cool user-level features that we've been working on for Mac OS X in Panther. So let me recap. This is the second part of the presentation. This is where I go into what you can do in your application software to take advantage of some of the features that we've implemented and also to implement newer, cooler features in your applications. So if there's just two things you're going to take away from this presentation and you go back home from WWDC and implement in your applications, it's, as Nathan pointed out, the first two items up here.
One, add support for the standard user interface, i.e., the fonts window or the Font Panel if you're old school like me. Also, add support, number two, for handling not font notifications. This will allow you to make sure that your applications are as responsive as possible to any changes in the font registry that the user initiates or other applications trigger.
I'll also cover some lower level topics that are of interest to you. The third item is particularly important because people have asked. We have a number of different font referencing systems in both Carbon and Cocoa. And I'll go into detail about how you can interact with the font system, the ATS font system, which underlies everything, and take advantage of those features within those layers. I'll also go into some more detail about specifics within ATS itself, such as getting access or managing the contents of the font registry, getting access to information stored within it, and querying the font rasterizers for information specific to glyphs.
Okay, so, as I said, one of the key things we're asking you to do is adopt a standard user interface. Now, if you use Cocoa, you get a lot of that for free. In fact, you get most of that for free, as Nathan pointed out. But within Carbon applications, you still need to do some amount of work. It's not too bad, in fact. If you look up here, I've encapsulated the main work that you need to do. In fact, the first one's so easy, I don't even have to make a slide for it.
If you have a standard, if you're using the standard Carbon event-based application event handler, all you have to do is add a menu item that triggers off of that standard command ID, which is to show and hide the Font Panel. Once that's in place, you're done. Anytime the user selects that menu item, it'll switch between the two different states for showing and hiding the Font Panel, and it will initiate the Font Panel code, pull it in, instantiate it, and show it. on screen for you.
The other three items I'll go into a little bit more detail in the next couple of slides, but they include support for handling font selection events that come from the Font Panel to your application. So that includes whenever a user changes the state of the Font Panel, you get a notification about that through a standard Carbon event.
Similarly, if somehow the state of your document changes, for example, if a user clicks through and sets the cursor in different locations within your document, you want the Font Panel to reflect those changes and sync up. And so there is an API to allow you to do that.
And then finally, the Font Panel, as you can tell, is specific to the current user focus. So what you want to do is if a user switches between different windows, you want to be able to notify the Font Panel that something has changed and that it should pay attention and also notify a different window or event reference.
So first off, handling font selection events is straightforward and it's built in and integrated with the Carbon Event System. All you need to do is handle the standard font selection event. It's of the event class fonts, and we have a specific event type called font selection. Within that event, you can pull out the parameters related to that event using the standard Carbon event calls, and we provide information on the current state of the Font Panel. So originally, it was mainly the typeface family, the font or the typeface, and the size that was important.
Now as you can see, we've added a bunch of additional new features with Panther, such as the typography palette, and there's other features that are related to stylistic effects, such as handling strikethroughs and underlines, and other cooler effects that you might not have been able to get natively within the font or on previous systems.
So that information is stored within a dictionary that gets passed back through the Carbon event that you can also parse and grab standard pieces of information. So the typography, the information about the typographic features are actually stored, for example, as a ATSU style attribute, ATSUI style attribute, that you can then pass to the ATSUI text system in Carbon to render appropriately. Similarly, we've added support for the text style information, such as the strikethroughs, the underlines, and the other cool features.
There's one more thing that's pretty cool is that we also include information about multiple master variations. So you didn't get a chance to see it here, but if you install a multiple master font, you can use the typography palette to go through all the different axes in a multiple master font and take advantage of those cool features. In fact, the Apple standard font now, Myriad, is provided as a multiple master font. So I take advantage of that personally all the time on my system right now.
Okay, so when you set the font selection through either changes in the cursor position or the user uses some other mechanism in your application to change the setting of the font in your document, what you need to do is provide notification back to the Font Panel that something has changed.
The way you do this is you use the standard HIToolbox function to get the target event ref. This is a new data type that's available. This is what's used by the Font Panel, and in its function to set the information for the current selection, you pass the target event ref and an array of data types that are specific to the text system that you're currently using. So, for example, you can pass in.
An array of Atsui style objects that correspond to the current selection of your text. It might actually just be one if it's only a single style run, or it could be multiple ones. Once the Font Panel gets it, it parses through that and it sets its state accordingly.
So, for example, if you had two style runs that had like Helvetica as the family, but maybe bold and italic, you'll see that reflected accordingly in the Font Panel, where the family will be set to Helvetica with the style or typeface information. left blank to indicate multiple selection. Similarly, we also support passing in Quickdraw text information, which consists of the traditional Quickdraw family name and the style bit array.
Okay, so when users switch between windows on your application, you need to notify the Font Panel that that's of the change. And so within your event handler, what you want to do is provide support for the standard Carbon event that notifies you that the window focus has changed or that the window focus has been relinquished.
And all you have to do at that point is call that same function to set the state of the Font Panel, but just pass it a null event target ref. What that does is it resets the Font Panel so it knows it doesn't need to send events out to the previous window anymore, and it can clear its state.
Usually what happens right after that is the user has selected another window, and you get a window focus acquired event. When you handle that event, you basically do the same thing. You can pull out the window reference from the event parameters, pull out the target event ref from that, and then pass that information, plus any additional style information that you have, to the Font Panel to indicate the new selection within the new window.
Okay, so that was it. That's all you have to do to support the font window within your Carbon applications. So next, handling font notifications. That's the other key thing I'd like for you to remember from this particular session. And let me go into some more details on that.
What handling font notification does for you is it allows your applications to be much more responsive to changes that users do or other applications do to the state of the fonts that are in their library. So as Nathan kept pointing out, you don't have to shut down your application, or your users don't have to shut down your application, just to be able to get a new font that's been dropped into one of their fonts folders. That's a big thing, and we need your help to be able to do that.
Secondly, and I won't go into much more detail here today, but it bears mentioning, you can also send notifications to the font server if, for example, your application installs fonts programmatically using, let's say, the file manager calls or standard Unix file system calls that pass underneath the radar of the system.
We've got hooks into places like the finder that let us know when changes occur within the standard font directories. But if your application, for example, at launch time installs application-specific fonts, this is a key way to actually notify the font system that something else has changed. And what we will do is we'll scan the directory, identify those changes, and then do a broadcast out to all the clients who are interested and have subscribed for changes.
So getting back to the first point, in order to make your applications more responsive, all you have to do is implement one callback function to handle the notification. What you next have to do is basically register it with the system, and you're done. All you have to do is call the standard ATS font notification subscribe function, pass in your callback.
You can also pass in a refcon if you want to, so you can get additional data into your callback function. But otherwise, that's all it takes. When you want to deregister, it's not required, but if you want to get rid of it before your app shuts down, you can certainly do that with a similar function in the ATS font API.
Okay, so the next topic. I'll be talking about how to exchange data back and forth with the other components in the system. First and foremost, the easiest thing to remember about exchanging data with Cocoa and the underlying Quartz system is that fonts are uniquely identified by PostScript name.
Whenever you get a name back from within Cocoa, it will be generally a PostScript name. Similarly, if you want to instantiate an NSFont instance, when you're asked for a name, you can query the ATS font system for the PostScript name, pass it in along with the size, and you can instantiate an NSFont reference.
On Panther, we've also implemented support for a more powerful kind of mega NS font reference. It's the NS font descriptor. You could think of it this way. As opposed to just one instance or one font, within the Font Panel, you can take a whole slice across it and actually specify a descriptor for that. So here's an example.
You can actually specify an NSFont descriptor just by the family name, and that will include all the fonts that belong within that family as one descriptor. Similarly, you can go off in the other direction and get more detail. You can specify a family or just, let's say, a font by postscript name, and that's more like the traditional NSFont. Or you could go even further and specify a size, which gives you what we traditionally call a strike. It's one specific combination of font and size within that class.
There are other attributes that you can actually pass in, as opposed to passing in a postscript name or other information that includes stuff. Well, the way it works is with the font descriptor class, you can pass in a dictionary of attributes. And the more information you put in, the more specific the descriptor will be.
Okay, so when you work with Carbon, that's had a longer history in terms of the different font references that are available. But one key thing to remember is that both the ATSUI and Quickdraw components, they support identifying fonts uniquely by the traditional Quickdraw font family name and style bit array. Note that ATSUI is actually pretty cool in that it actually handles the core graphics, so the quartz mechanism also. So you can handle those font references using the PostScript name also.
One thing that we provide at both the Quick Draw, well, primarily at the Quick Draw layer is conversion functions that allow you to go back and forth between the newer ATS font references and the older font references and font family references. One of the key reasons we ask you to do that is that in the future, or also even now, there are slight differences within the data types.
Some are, there's sign differences, and there's also size differences. Some of the references are 16-bit as opposed to 32-bit or 32-bit signed. What these conversion functions allow you to do is kind of shield yourself from any future changes and also any potential changes that might happen if you simply assign one of the older data types to the newer ATS font ones. So please, avoid typecasting, use the conversion functions, avoid direct assignment because you might get implicit type promotion that causes confusion. problems with the signage. Use the conversion functions.
Okay, so let me get into some more details about mucking around with the contents of the font registry. Now, why would you want to do this? Well, think of it this way. Here's a typical example. You've got a font that you've licensed with your application, you use it in your user interface, but you don't want to stick it for general purpose usage out in the standard library.
And so what you can do is you can actually activate that privately just exactly the same way the file system or the operating system would do, but just for your font. What I'll be talking about is giving you a chance to kind of hook into that and take advantage of that also if you're interested.
So when you activate and deactivate fonts, what we recommend that you do is pass in a file reference. That's really the easiest way for you to do it, mainly because there's a lot of information there that we can actually parse through, file types, contents of the files, even suffixes on the files, to figure out what exact format it is. We can take care of the rest for you, so you don't have to worry about it.
Note that up here, I'm passing in an unspecified format, mainly because I'm passing in a file reference. Another cool thing that you can take advantage of is if you put, let's say, your app-specific font within your bundle someplace, maybe within the resource folder of the bundle, you can just pass in a pointer to the top level of the bundle. We'll trundle down through it recursively and activate any fonts that reside in any of the subdirectories. Another part of this example is that I've actually activated the font locally so that it's only available for my application.
What you get back from this function is a container reference. With this container reference, you can later deactivate exactly the same set of fonts that were stored in that file or in that directory using this function to deactivate the fonts. There's one thing that's pretty cool, though, is that ATS will keep track of fonts that are activated locally within your applications, so you don't have to get rid of it yourself. When your app shuts down, we'll deactivate those fonts for you.
Okay, so with Panther, we've provided support for additional APIs or classes that allow you to modify the contents and remove and add font collections, just as the Font Book does. In Cocoa, you simply use the NSFontManager class with a variety of new APIs that are available to do this.
Similarly, we've implemented support in Carbon with C callable wrapper functions to those same methods that let you call these functions from within your Carbon applications. So font collections, they're identified uniquely by name. What you see up on the Font Panel are the unique names for those font collections.
Another cool thing is that font collections go back to those font descriptors I described earlier. So the same actions that users can do to kind of grab an instance of a font or, you know, a particular font strike, drag it in and set up a font collection entry, you can do the same thing at this level as long as you define a font descriptor.
Okay, we're almost there. I've got two sections describing how to interact directly with the ATS font system. The first one, if you notice, I've badged this with the caches entry in the architecture diagram. The reason for this is that we've implemented a number of high-level functions that optimize access to this data through the caching system as much as possible.
So we've identified that you guys tend to use PostScript names a lot, especially with my recommendation on interacting with the Cocoa Tech system. We've got that optimized. We also have an optimized function to get at the file references associated with a particular font. All of this information is cached so that you don't have to worry about triggering messages, hitting file system, making file system calls, and potentially even triggering font rasterization effort.
Now, what I'll go into in more detail in the next two slides are the lower level functions that bypass those higher level, easy to use functions. And that includes the function that lets you kind of go straight to the file system, grab the font data out of those files, and parse it yourself. I'll also give you some information on how to enumerate every single font or font family within the font registry and do whatever you want with those entries.
So when you want to pull out data related to fonts directly from the file system, we provided a couple of standard functions to do that. This one happens to be the one to get the font table. Think of it this way. The way we've made a standard format for the fonts is similar to the way TrueType fonts or OpenType fonts are defined. They consist of a directory of font tables, each of which contain a specific class of data.
So I mentioned earlier in the presentation that we have character mapping tables. Those are stored in tables that are indicated by the CMAP tag or C-M-A-P. We also have support for accessing the glyph data. You can access any of the font table data that's available for these fonts.
Now the convention is you make an initial call to these functions, either ATS font, get table, or the directory version. You pass it in the font ref and the tag indicating what data you want, and you pass in a null buffer. In return, you get back the length of the data that the function will return to you.
And this is what happens in the second call. In the second call, you can actually malloc right then and there a buffer to hold that data based on the size you got in the first call. Pass in the buffer this time and get it filled in with the data that you need.
Now if you have any more questions about how to process this information, it's available in the specs for the OpenType font format and the TrueType font format. So as you can see, this is pretty low-level stuff, but for a lot of you out there, this is your meat and potatoes. This is what you want to deal with.
The other people involved with this usually use the high-level functions. So if you have any requests for us, we'd be happy to implement it. So please, use the bug reporter. Let us know what features you'd like to have that otherwise you'd have to go through the lower levels of the ATS font system to get at.
Okay, when you enumerate fonts and font families, there's a similar convention, or there's a standard convention also, and they consist of iterator objects. Essentially, all you have to do is create an iterator object based on a bunch of criteria. Set up a while loop that calls the iterator object for each successive entry. And when it's done, it'll give you a status code back indicating that the iteration is done. And then finally, you release the iterator object to return the system resources back to the operating system.
So some of the different things you can do with the iterator object include filtering them. You can pass in any of a variety of standard predefined filters, such as filtering by font location or by the generation in which they got activated. So if you want to find out if there were any fonts that were activated after you last checked the registry, you can check a generation count and then filter based on that. You can also pass in your own custom filter function to do the filtering yourself based on whatever criteria you specify.
And if you notice here, I'm actually using a similar way to restrict or actually in this case, totally unrestrict the scope of the iteration. I've chosen a global context with unrestricted scope so I can see every single font available on the system for all the processes. Okay, one last item.
When you want to access glyph data, this is where you interact directly with the font rasterizers. Or, in this particular case, the ATSUI text system eases the burden on you somewhat and allows you to mimic exactly what the ATSUI tech system does, but gets you back this data directly.
So it has two functions to access two different flavors of glyph data format, glyph paths in two different formats. Essentially, the glyph paths define the shape of the glyphs that you can then pass into, let's say, the court system or draw yourself directly on screen or manipulate just as if it were a regular graphics object.
Now the ATSUI APIs take advantage of the higher levels of the ATSUI system, so you can pass in information from a standard ATSUI text layout object. So you can take advantage of how it specifies, let's say, a run of characters, pass that information in, and get just the glyph information for those characters. In addition, they match exactly the way ATSUI would draw it, so you can still take advantage of trying to mimic exactly what ATSUI does, but get into the lower layers of it and directly access the font data through these APIs.
So usually what you do is you determine what the native glyph data format is for a particular font, and there's an API to do that. If you don't do that, the functions for accessing the glyph pass will actually convert the data accordingly for you. So if you ask for quadratic and you ask to get the glyph data for a PostScript font that's normally defined in cubic data, then it will convert it accordingly.
The other thing that you have to do is implement a series of callback functions that process the standard Standard operations that define the glyph's shape. So this includes, for example, let's say in cubic, you have a move to operator, a line to operator, a curve to operator, and a closed path operator. The line to operator basically defines a straight line segment, and the curve to defines any arbitrary curve. Okay.
So just to wrap things up here, what I've talked about today is that there's a lot going on in the operating system that hides the complexity of fonts for you. We've implemented a lot of stuff. You've seen how the architecture works and how they interact and how they touch on the APIs that you take advantage of at your level in your software.
The other thing I've covered is that if you go away from WWDC and implement just these two aspects of the system, you're going to help us push forward this idea of putting the user at the center and making it so much easier to use their fonts and so much powerful that people will be flocking to your applications. So adopt the standard user interface. Add support for handling the fonts window. You see how much you'll get with it. The typography palette, the character palette, the interaction with FontBook, and handling support for font collections.
At the very least, you should also support handling font notifications so that your apps become much more responsive to changes in the system. There are a couple of related topics either later on this week or that you can review after WWDC. It includes the Unicode session and the Cocoa Text session.
Our evangelist for this area is Xavier Legro, so you can contact him specifically about some of those bugs or features or new APIs that you like. And something that you guys have been asking for, documentation on this part of the system. Well, my team has worked really hard this year to put together the documentation with the technical publications people, and we've got them up there. So take a look at them. They're really cool. There's also related documentation about the various text systems available on Mac OS X, including Atsui, Cocoa, and there's also documentation for the legacy font manager APIs available in Quickdraw.