Font Management and Text Scaling

Session 227 WWDC 2019

Starting with iOS 13, your iOS app can contribute fonts for systemwide use. Understand how fonts are managed on iOS, and learn how to install and access fonts. Get details on the font picker interface that allows users to choose fonts, and the System UI fonts that are now available for use in your app. Review best practices for text scaling that works regardless of device.

[ Music ]

[ Applause ]

Good morning.

My name is Julio Gonzalez.

I manage the Type Engineering Team and it's great to be here with you today to share with you all the new advances that we have for text and fonts in iOS.

We have a full agenda today.

I'll start by showing you some access to some new system fonts for your apps.

I will then continue by showing you what it takes to build an app that can make fonts available systemwide as well as how to make an app access those very same fonts.

Then, we'll talk about some new mechanisms that we have for apps to select fonts.

And we'll end up by talking about some text scaling considerations that you may have as you bring your iPad apps to the Mac.

Let's get started.

We'll be making available three new system fonts in all the new releases.

The first one is a rounded system font which you can see here being used by the schedule label at the very top of the Reminders app.

There is also a serif system font that we're making available which you see here being used in multiple places in the Books application.

Finally, we're making available the monospaced system font which you may have seen before used in Swift Playgrounds.

I encourage you to consult the Human Interface Guidelines to see what are the best uses of these system fonts in your application UIs.

You can get access to the system fonts by new APIs in UIFontDescriptor.

We've defined four new constants.

The first one, the default is the standard system sans serif system font that you've all used throughout the years.

And then, we've defined a constant for each of the new system fonts that we're making available.

You can use these constants with a new method called withDesign whose purpose is to transform a font descriptor from one design to another.

It's fairly simple to use.

You start with a font descriptor.

In this case, we're getting a font descriptor from a bold system font that we've instantiated.

And then, what we want to do is actually obtain a rounded system font.

So, we make the withDesign call with the rounded constant.

And if that's successful, we're able to instantiate our rounded bold system font.

Notice we instantiated the system font using a high-level API.

We did not instantiate the system font by using its name which leads me to the next topic.

We've noticed that many apps still today instantiate system fonts by name.

This is something that in the past we've strongly discouraged apps to do.

So, it's starting with the new releases, any such font instantiation will fail.

You need to use one of the high-level system calls to instantiate such fonts.

You know that you're instantiating a system font by name because if you look at the name that you're passing with if it starts with a dot, you're using a, an Apple private name.

Now, there are many good reasons to instantiate fonts by name.

That's how you get access to custom system fonts in your apps as well as if you are parsing a document, that's how you would instantiate a font that the document needs.

Now, we've also noticed that many apps are not handling properly font instantiation by name.

Sometimes, they crash.

And the reason is, is because they don't actually look at the return of the instantiation.

They assume that it's always going to succeed.

As we change fonts in the OS for some of our fonts, or we remove fonts from the OS, those, those fonts are no longer present.

So, your apps cannot assume that a font that isn't in one version of the OS will be in another.

You need to pay attention to the result of the instantiation and take appropriate action in the app and substitute that with another font if necessary.

With that, I'd like to switch subjects to something that I as a user and as a developer of fonts have been waiting for a long time.

And that is the ability for apps to be able to install fonts systemwide in the OS.

So, we call these apps Font Provider Apps.

And basically, they are apps that you submit to the Store which can make fonts available systemwide in the OS.

Along with those apps, we've created a very simple UI setting in which users can browse the fonts that applications have installed as well as remove fonts that they no longer want to use.

To create one of these apps, there are two things that the app needs to do.

First, it must obtain entitlement.

And second, as the app gets submitted to the store, it needs to be submitted with all the fonts that the app can make available to the OS.

This is important.

The fonts need to be part of your bundle, or they could be part of an asset catalog.

The key thing is that the OS will not let a font provider application install any arbitrary fonts.

As you submit your fonts to the store for validation, it'll run through a similar validation that like what we do in, in macOS in Font Book.

One of the things we do is we check for the type of the format of the, of the font.

We support all the modern formats; ttf, otf, ttc, and all of its modern variants.

What we do not support are old font formats such as suitcase fonts or postscript fonts.

To obtain the entitlement is fairly easy.

In Xcode, now there's a new capability called Fonts.

Once you select it, you're presented with two options.

The first option is to install fonts.

And that gives the app the ability to make fonts available systemwide.

The second option is to use installed fonts.

And why do we need this option?

Well, by default, apps do not get access to user installed fonts.

The app needs to opt in by selecting this capability to be able to see those fonts.

Now, clients of or users of these applications will have some expectations.

The first one will be that the app should provide a meaningful UI where users can browse fonts, install, and remove fonts.

That's necessary because, in iOS, we do not have an application that can install fonts in the OS like we have in macOS.

Also, the application should respond to system font change notifications.

And the reason it needs to do so is because the user is able to remove fonts in the settings app and the app should notice when that happens and update its UI.

And finally, if you're a font provider application that plans to make a large set of fonts available to the, to the user, a large library of fonts.

We highly recommend that you use On-Demand resources and package your fonts in an asset catalog.

That's a far more effective way to deliver fonts that your users need because the users will only download the fonts that they actually are going to use.

Instead of downloading a huge font library that may be sitting where they only use a handful of fonts.

So, let me walk over to the demo machine and show you how this feature works.

So, let's assume that the user has downloaded from the store an application that browses documents.

And this is one such app.

I call it the Font Consumer app.

And here on the left, it has a set of documents that I can display.

On the right, it just shows the contents of the document.

Let's go ahead and reload this document.

Notice the sheet comes up.

This sheet is not put up by the app.

It is put up by the OS.

And it does so because it noticed that this app is trying to access three fonts that have not been made available to this application.

So, this application is just substituting the fonts and showing the contents of this document in Helvetica.

So, what's left for the user to do but to go ahead and try to get an app that can make those fonts available to the OS?

So, let's assume that they've gone to the store and downloaded such an app.

I call it the Font Provider App.

On the left, it has a set of fonts that I can make available.

On the right, it shows just a simple preview of the fonts.

Let's go ahead and register all the fonts.

Notice again, this sheet comes up.

This is not put up by the app.

It is put up by the OS.

And this is necessary because we do not allow in the OS apps to install fonts silently on the user's behalf.

The user must provide consent.

And this is what this dialog does.

So, let's go ahead and provide the consent.

Notice the UI, the all the font names went from red to black.

It's a simple way for the app indicate that the fonts are registered.

Let's make sure that they are registered.

I can now go to the Settings app and in General, Fonts.

It's a new setting here.

You have a list of fonts that all font provider apps have made available.

So, we see the fonts that the Font Provider app made available.

I can go browse one of the fonts.

Century Schoolbook.

And you can see here different previews of the fonts.

I will just at this stage, just attempt to remove this font.

I'll go ahead and do so.

Century Schoolbook will be removed.

Now, it's no longer in the list.

Now, the expectation is that my app should have noticed that the font was removed.

And indeed, it now shows in red because it listened to font change notifications and it updated the UI.

Let's go ahead and reregister all the fonts.

I'll go walk back to my Font Consumer app and what I see now is that the document no longer displays with Helvetica.

It actually listened to font change notifications that well and took notice that all the fonts have now been made available.

If I look at other documents, I see that they're not using Helvetica.

They're using different fonts that the Font Provider app made available.

So, now let me show you in code what it takes to build one of these apps.

So, in CoreText, in particular in CTFontManager.h, we've introduced a brand-new set of APIs.

And all these APIs are documented in that header file.

There are three new ways to register fonts.

One of them is by using the FontURLs that point to font files.

The other one is you can register fonts by using FontDescriptors.

And the final one is you can register fonts that are present in asset catalogs.

And this is the way that you would use if you have a large library of fonts.

You would create an asset catalog and you would use On-Demand resources to deliver those to your user.

Please, note that this last API is not available in the seed that you have but it will be available in the next upcoming seed.

There is also a new API, too, that Font Provider applications can use to get access to the registered fonts.

And finally, an API that any application can use to see what fonts have been installed by the user.

You gain access to this API by selecting that entitlement of use fonts that I showed you earlier.

So, let's look at how these APIs are used in the two demo apps.

Let's start with the Font Provider app.

It's a very simple app that has about 20 fonts.

And you basically register fonts by family.

So, what we do is we gather all the font files and the URLs that points to them.

And once we have them, we call our registration API and then, we update our UI as necessary.

Let's start by looking at the code that updates the UI.

You notice that both the Font Consumer app and the Font Provider app leverage font notifications to update the UI.

We use the same technique when we register fonts in this demo.

And to listen to one of these notifications is fairly simple.

We tell the notification service center to observe KCTFontManager registration, that's a handful.

RegisterFontsChanged Notification.

And once we get one of these notifications, simply in our selector what we do is we update the registered fonts.

And I'll show you the code for that in a second.

And then, we update our UI which you saw in the Font Provider app.

Basically, for font families that are registered, it shows the names in black and unregistered in red.

To register the fonts, we gather the font files that represent the families that we want to register, and we call our new API CTFontManagerRegister FontURLs.

We pass the list of font URLs along with a scope, a registration scope called persistent.

This is new to iOS 13 which indicates make the fonts available systemwide.

And also, a Boolean flag, in this case, enabled, that we want to make all those fonts visible to the OS.

The API takes a closure.

And the reason it needs a closure is because it is an asynchronous API.

As you're registering fonts, your closure will get called, maybe multiple times as errors are getting discovered would be one example.

When the whole operation is done, the done parameter in the closure is set to true.

For this demo, the only thing I do on the closure is I just look for errors.

And I just logged into this.

I don't update my UI.

What I update, I use, I rely on the notification mechanism to update my UI.

And once I receive that notification, this is the method that gets called.

And simply, I call the new API CTFontManagerCopyRegister FontDescriptors to know what fonts have been made available by my app.

Once I have that, it's very simple.

I just log my list of font descriptors, update my model inside for the families, and update my UI from there on.

The font consuming app, it's, it's a very simple app that just parses documents.

And the key to this type of apps that parse documents is to as the whole document is getting parsed, you figure out what fonts can be instantiated and you keep a list, a running list of fonts that are essentially missing.

Now, fonts may be missing because the user never installed the fonts, or the fonts have not yet been made available to the process.

You actually need to make use of the new API to request those fonts from the OS.

Once you have them, you go ahead and update UI or update the document.

So, for the app to parse a document, this is a very simple rich text format document expressed as JSON.

And what it does, it just walks every run, tries to instantiate a font.

If it can't, it replaces with Helvetica.

But as it replaces it, it keeps a running tab of all the font names that it couldn't instantiate.

With that in hand, now I can build a list or an array of font descriptors that use those names and pass that array to CTFontManagerRequestFont.

And what this new API will do is it will notice or see if any fonts have been installed by the user using Font Provider apps.

And if so, it makes it available for instantiation on the app.

If any fonts have not been made available, then those fonts are displayed using the missing font dialog that you saw.

The API takes a closure.

And for this app, we simply for the visible document we just update all the missing fonts with whatever fonts have become available.

So, as you see, it's very straightforward for an app to make use of fonts that other apps make available.

Now, I'd like to share with you some considerations for font provider apps that are important.

First, a font provider app cannot operate on fonts that don't belong to it.

For example, it cannot try to unregister a font that another font provider app has registered.

Similarly, a font provider app cannot override a font that another font provider app has made available or is installed with the system.

There's a limit by the OS on how many fonts can be registered.

There is not like a hard number for it.

It's basically, it depends on the type of fonts that have been installed by the different font providers.

Each font, it can consume different amount of resources.

Fonts installed this way do not participate in font fallback.

Basically, what it means is that if the system determines that your font is the only way that it's possible to display a given font, it won't be automatically substituted to be used.

In essence, the only way to use these fonts is if the font is referenced by name.

Finally, font provider apps own the fonts that they install.

What that means is that if the user deletes an app that has fonts installed, those fonts are also removed.

Now, the system does warn the user, indicates that it's trying to delete an app that has fonts installed.

And the user has the opportunity to back out.

This concludes my section of the talk.

But before I go, I just want to share with you how excited we all are about this feature.

Having the ability to install a variety of fonts in the OS that all apps can use at one point in time, it's essential for great content creation.

And having this feature in place will allow us to unlock that power in the platform, especially in the iPad platform.

With that, I'd like to invite to the stage Eric Dudiak, who will be talking to you about some new techniques for selecting fonts in the OS.

[ Applause ]

Hi. Thank you, Julio.

So, I'm Eric Dudiak, an engineer on the UIKit Team.

We've just seen how you can provide and install custom fonts.

But your application may also want to consume those fonts.

So, let's take a look at how you allow users to select and use the custom fonts that they've installed.

The first thing an application might do is try to enumerate all the fonts available on the system and simply present that to the user.

Then, allowing them to pick from one of those fonts.

However, enumerating all the fonts on the system will only provide the list of built-in fonts.

It will not show any of the custom fonts.

And this is not allowed out of a concern for privacy.

So, instead, when your application wants to allow the user to select one of their installed fonts, we've provided a new View Controller in UIKit.

And that is UIFontPickerViewController.

Now, it can be presented modally, and it'll default to that new sheet presentation that you've seen in iOS 13.

Alternatively, if you, say a productivity app with an inspector, you might want to embed it in the sidebar.

And that is also supported by the Font Picker.

So, let's take a look at UIFontPickerViewController.

So, for security purposes, it runs entirely out of process from your application.

And by default, it will also only show the built-in fonts.

You'll need to use an entitlement to see those user-installed fonts.

After a user selects a font in the Font Picker, that font will be available to the presenting application through the normal font APIs, however, only after the user selected it and only the font that the user selected.

So, to facilitate all the different kinds of apps out there, there are some great customization options on UIFontPickerViewController.

For example, an application might want to show specific faces.

Now, by default, the Font Picker will only show families of fonts.

This is similar to applications like Mail and is familiar to many users.

However, if you have an application where it makes sense to show additional weights of the different fonts, such as semi-bold or medium, you can optionally enable that in the configuration of the Font Picker.

Additionally, your application gets to choose whether it gets the WYSIWYG presentation seen here or a more default presentation of every font displayed in the system font.

Now, your application may also want to filter down the list of fonts available to the user.

And you have two different ways to do this.

First, you can filter by trait.

So, if your application shows source code, for example, you may only want to see or may only want to show monospaced fonts to the user, since that's going to be a more natural experience for seeing source code.

And here, we see filtering by trait to just monospaced.

Additionally, your application may need the font to support a certain language in order to make sense in the context it's being used.

And for that, we provide a Filter Predicate API that lets you filter down to a single language or combination of languages that the font needs to support in order to be presented.

And in this case, we see the Font Picker configured to show only fonts that support Chinese.

Now, the Font Picker also exists on macOS for UIKit apps.

If you just present the Font Picker, instead of that modal sheet presentation that we saw earlier, you'll see something like this.

A more traditional Mac menu.

In order to control the presentation of where this menu shows up in your applications since it should show up over the button the user just clicked, use the UIPopoverPresentationController off the new controller to select which view is presenting it.

Beyond that, the semantics of using the menu are fundamentally similar to the View Controller.

Clicking away from the menu, for example, is the same as dismissing the View Controller.

And when the user does select a font in the menu, it'll automatically send the Delegate APIs just as the View Controller normally would and will then close the menu.

This is simply a way to provide a much more traditional experience on macOS around font picking so that your app feels like what a user expects on a normal Mac app.

Of course, macOS has additional font picking options.

And this is in the form of the macOS Font Panel.

This is supported in UIKit apps when running on macOS.

It's even part of the default menu bar options.

So, a user can turn it on and off at any time and select different font settings anytime your application is running.

Now, you can also programmatically control the presentation of the Font Panel.

And you can access that through UITextFormattingCoordinator.

From there, you can see if the panel is currently displayed as well as manually toggle its presentation on and off.

So, because of the nonmodal nature of the Font Panel, there's a few considerations for your application when it's running on macOS.

Changes that come in from the Font Panel will go through the responder chain.

When using standard UIKit controls, this is handled for you automatically through the UITextFormattingCoordinator.

In fact, the shared UITextFormattingCoordinator can even be used as a delegate for the Font Picker we saw earlier so you can also route those changes through your responder chain.

However, if you have custom UI responders in your application, you may need to adopt some of the new UIResponderStandardEditActions protocol methods in order to be notified when changes are made through the Font Panel.

This will allow your custom responders to update their displays accordingly.

Now, let's take a quick look at a demo of how this all works.

Great. So, here's our Font Consuming application.

And here we see it's already using custom fonts.

But one of the great features of this application is that it also lets the user select the font that they want to see rather than just showing the font.

We can change the font for the document at any time.

And I can do that simply by just pushing this say Change Title button.

And when I do, we see that I get the Font Picker.

I get the list of recently used fonts that I've used.

I can also search it and scrub through it to find exactly the font that I want.

Now, we've also gone ahead and customized it to show additional faces.

So, I can see any number of faces on a given font and scrub through it and find exactly the font that I want.

Let's see.

Let's use Papyrus.

Great. So, I can change the title just like that.

And you can do that in any application.

Provides a great standard control that users will get accustomed to on iOS.

Of course, of course, since this is an iPad app, we can also build it for macOS.

And here, we see that.

This is the same app that I was just showing you a second ago on iPadOS, now running on macOS.

Now, since we didn't do much to customize how we present that Font Picker off the title menu.

If I go ahead and just push the exact same button without changing any of my code in my app, we see that instead of a Font Picker ViewController that I saw when I was running on iPadOS, I get a menu.

And in that menu, I still get many of the same functionalities that I got in the Font Picker running on iPadOS.

I still see Recents at the top.

And I can still select individual faces.

I'm also still getting that WYSIWYG presentation so I get a good idea of exactly what the font that I pick will look like.

In this case, I'll just go ahead and select Comic Sans.

Now, we've done some additional customization in our app for when it's running on macOS.

Since we have that Font Panel available to us, we've gone ahead and updated our body here to go ahead and respond to any changes coming in from the Font Panel.

And since we've done that, we've also made it so that the Change Body button rather than showing the Font Picker, when it's running on macOS, we actually show the Font Panel.

This lets us do some additional customization.

So, I can change the font just like I could in the Font Picker.

But on macOS, I can also make some additional formatting changes in here.

Can change, say, the text size or even the text color.

And this provides a very rich experience on macOS that users are accustomed to from Mac apps over the years.

So, that's great.

That's our sample app.

Let's take a look at how we did that in our code.

So, first, let's take a look at how we created the Font Picker.

And the very first step of that is creating a configuration for it.

In this case, we initialize the configuration object and tell it that we want to include faces when we're showing the Font Picker.

With our configuration set up, we can now create the Font Picker passing in that configuration.

The configuration will determine how the Font Picker behaves over its entire lifecycle.

We also set ourselves up as the delegate to the Font Picker so that we get all the callbacks when the user selects a font.

And finally, we just go ahead and present the Font Picker like we would any other View Controller.

Now, in the delegate callbacks, we see that we can get the font that the user selected directly off the Font Picker.

Here, we see the delegate callback for when the user does select a font.

And in this case, we're taking the font off the Font Picker that is the one selected and sending it to an attributed string in our application.

Of course, if the user cancels selecting a font, we're also notified of that so we can make any appropriate changes necessary for the cancelation.

Now, finally, let's look at our custom responder code.

So, this is how we handled the Font Panel when running on macOS.

In this case, it's a single method that we implemented that lets us know when the user made changes to the attributes that we should be using.

And rather than just getting the set of attributes that they changed, we actually get this convenient closure that takes in the set of attributes we currently have.

And passes out the set of attributes as they should be after the user change was applied.

Now, the reason for this is that current attributes may stay the same or may change based on what the user changed.

So, for example, if underlining is currently in effect, the user changing the foreground color of the text shouldn't change that underlining.

And in this case, the conversionHandler will take care of that for us.

So, let's just do a quick recap of font selection.

Instead of enumerating through all the fonts on the system, when wanting to show user fonts there's a new View Controller, UIFontPickerViewController on iOS, iPadOS, and even macOS.

Additionally, when running your UIKit app on macOS, the Font Panel is available.

This has a few additional considerations as custom responders may need to handle attribute changes that can happen anytime your application is running.

Standard text views will handle this automatically.

Now, I'd like to invite Donna up to talk some about text scaling across Apple's platforms.

[ Applause ]

Thank you, Eric.

So, text scaling is a new concept that we're introducing in iOS 13 and macOS Catalina.

And today, we're going to cover how to use this new concept to make sure that the text sizes in your app look consistent everywhere.

So, now as iOS developers, you're probably familiar with the Human Interface Guidelines.

And this table from the guidelines shows the font sizes for the default dynamic typesetting.

Now, most text in UIKit apps uses the Body Text Style which is 17 points.

And here's what that looks like on an iPad.

It's pretty easy to read.

Right. You look at that same 17-point text on a Mac, it looks a little bit different.

And when you put the two side-by-side, you can see that by comparison, the 17-point text on the Mac looks a bit big.

And that's because on the Mac we're more accustomed to a smaller default font size closer to 13 points, as shown here.

But again, if we take that same 13-point text and we look at it on an iPad, it looks very small and it's difficult to read.

Now, this inconsistency has existed for a long time.

And we chose 17 points as the base size for our visual type scaling in iOS to make text easy to read and easy to interact with on touchscreens.

But as we move forward, the cross-platform user experience is only going to become more important.

Now, that you can bring your iPad apps to the Mac, users will notice this difference in text size when running your iPad app on the Mac alongside an AppKit app.

When copying and pasting text between apps and when viewing documents side-by-side.

And so, how do we make the text size look consistent everywhere?

Ideally, if we're looking at the same text in the same font and size, we would want it to look something like this where the visual scaling fits each platform.

And there are really two different visual scalings here.

There's the scaling that's used on iOS and iPadOS where 17 points is the default size.

And we will call this the iOS text scaling.

And then, there's the scaling used on macOS and other non-Apple platforms where the default size is closer to 13 points.

And we'll call this the standard text scaling.

And we want you as developers to be aware of these two different text scalings and to use the standard text scaling in situations where it will improve the cross-platform user experience.

So, now let's take a look at some of these situations.

First up, is iPad apps on the Mac.

And since UITextViews are the control of choice for displaying large amounts of text, this is where you're most likely to notice the difference.

And we wanted to give you an easy way to address this.

So, in iOS 13, we've added a new property to UITextView.

It's called usesStandardTextScaling.

And when you turn this on, UIKit will automatically adjust the rendering of the text inside the Text View to match the standard text scaling.

So, we go back to our text here.

We can see that the scaling is looking a little bit off, right.

Well, let's check out what happens when we turn on usesStandardTextScaling.

Ah, that's much better.

Using this new property is a really great way to ensure that your text displays in the standard text scaling.

But do take note, usesStandardTextScaling is turned off by default.

And that's because code that uses custom transforms on Text Views might have unexpected results when combined with this property.

And so, if you want to use the standard text scaling, make sure you enable this for each of your Text Views.

Next, let's talk about text scaling with copy and paste.

Now, since iOS uses a unique text scaling, you might notice this visual size difference when copying and pasting text between UIKit and AppKit apps.

And if you've ever used the Universal Clipboard, you might actually have already noticed this.

Well, the good news is now you actually don't have to do anything to get this.

Starting in the latest OS, you get visually consistent copy and paste for free.

And let's take a look at how that works.

So, I got my two platforms here.

iOS on the left and macOS on the right.

And on each of these platforms, Copy and Paste moves text between two different layers of the system.

The runtime layer depicted by our little runner here, and the persistence layer represented by these discs.

Now, text in the Text View exists in the runtime layer as an attributed string.

And when you copy that text, it moves if from the Text View in the runtime layer to the PasteBoard in the persistence layer.

And it's serialized to rich text format or RTF for storage on the PasteBoard.

Now, on the latest OS, we've added a new behavior for attributed string APIs that write RTF.

So, now when you create your RTF from an attributed string it'll add metadata that indicates which text scaling it's using.

So, now when text is copied on iOS it will be automatically tagged with that metadata this says it's using, the iOS text scaling.

Now, we've also added new behavior for the RTF reading APIs on attributed string.

And so, when you're creating an attributed string from RTF, the system will look for that text scaling metadata and it'll adjust the font sizes for you if it's needed.

Going back to our original text, we have that text that we copied on iOS.

And when we paste it on the Mac the system will see that metadata that says it's using the iOS text scaling.

And then, the font point sizes will be adjusted in the attributes string so that when the text is displayed on the Mac, it looks visually similar in size to that original text in iOS.

And the end result is a lot like this example from earlier.

But the font sizes will be different.

The original text we copied here on iOS is using a size of 17 points.

And the pasted text on the Mac is using a size of 13 points.

Now, having different font sizes between these two platforms is okay for copy and paste because that font size information is transient.

It exists only in the runtime layer.

But RTF is also a document format and this isn't a great solution for the persistence in the storage layer.

And that leads to our final situation, working with text scaling for document interchange.

And we need to weigh special considerations here to balance the desire for cross-platform visual consistency with the need for integrity in the document model.

And so, to have the text look the same across platforms and also keep the same font sizes in the document, what we really need is the ability to use one text scaling for viewing the document and a different scaling for saving it.

And there's two different ways that we can approach this.

We can change the document model and use different font sizes for viewing versus saving.

Or we can change the document view by changing the rendering scale and keep the font size the same when saving.

We've actually implemented both of these approaches for RTF since this is a common format that we use internally.

And I'd like to share with you the fundamental techniques that we use to do this so that you can apply some of our techniques to build support for text scaling into your own workflows and document formats.

So, the first thing we did was we extended our format to tag documents with that text scaling metadata.

Document parsers and viewers will need this information to understand which text scaling the document is using.

Since preexisting documents are not going to have this metadata, we also needed to migrate them to use the new format.

And for RTF, this happens automatically once the documents are saved with the latest OS.

Now, we also needed to make sure that our documents have the correct text scaling associated with them.

And this is especially important for that initial migration.

So, we're introducing a new attributed string API to help out with that in the form of new document attributes.

Now, you can use the text scaling document attribute to set the metadata in the document on Save using attributed string writing APIs like data from range.

If you need to, you can also convert the document to a particular text scaling when you save it.

And you do this by specifying both of the new document attributes.

Now, for the model-based approach, we needed a way to control conversions between text scalings when opening documents.

And we've introduced even more attributed string API for that purpose.

New reading options for target and source text scaling.

And you can control which text scaling will be used by specifying these reading options when creating your attributed string from an RTF document.

And finally, for the view-based approach, we recommend using the standard text scaling.

Now, for RTF documents, you do this by combining the new API.

You first set the target text scaling to standard when you're reading your RTF into an attributed string.

And then, you set usesStandardTextScaling on your Text View that will display the document.

Ooh, okay.

We covered a lot of ground today.

Now, as a reminder, here's what you've learned.

IOS apps can now make fonts available systemwide.

Use name instantiation only for non-system fonts.

And remember, the name instantiation is not guaranteed.

Use On-Demand resources to deliver fonts to the OS.

And use standard text scaling for the best cross-platform user experience.

Come visit us at the Text and Fonts Lab in a couple hours to learn more about all the topics that we've covered here today.

And you can also come talk to us at the Labs for iPad apps and Mac to learn more about text scaling.

We're really excited to see what you'll create with these new capabilities.

Thank you and enjoy the rest of the conference.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US