If your application is a font utility that activates and deactivates fonts, you can register with ATS for Fonts to handle font queries. Figure 2-1 shows the path of a font query. The application asks the ATS client for a font. The ATS client passes the request to any font utility that is registered to receive queries. When the font utility finds the font, it obtains the file specification of the font, and then activates the font using the appropriate ATS function calls.
The query, activation, and notification process is opaque to the application that needs the font. The font activation appears to happen automatically because the application needing the font is not required to do anything to activate the font. Font activation occurs behind the scenes, provided the font is available to be activated somewhere on the system.
You must do the following to set up your Carbon or Cocoa application to handle font queries:
Create a callback to handle any font queries sent to your application. Your callback should look similar to the following:
CFPropertyListRef MyQueryCallback (ATSFontQueryMessageID msgID, |
CFPropertyListRef data, |
void * refCon) |
{ |
CFPropertyListRef reply = NULL; |
switch (msgID) |
{ |
case kATSQueryActivateFontMessage: |
// Your code to parse and handle the property list data |
// passed from the query. |
reply = NULL; |
} |
return reply; |
} |
See Listing 2-6 for an example of a function that parses and handles the property list data passed from the query. The property list data is passed in the form of a Core Foundation dictionary (CFDictionary).
This callback only handles the case of a font activation query. You would need to add cases for other types of queries should these be available in the future. Font activation queries should always return NULL as shown in this example.
Register for queries by calling the function ATSCreateFontQueryRunLoopSource as follows:
CFRunLoopSourceRef source = |
ATSCreateFontQueryRunLoopSource (0, |
0, |
MyQueryCallback, |
NULL); |
The function ATSCreateFontQueryRunLoopSource creates a Core Foundation run loop source reference (CFRunLoopSourceRef) to convey font queries from the ATS server to your font utility application
Add the run loop source you obtained from the function ATSCreateFontQueryRunLoopSource by writing code similar to the following:
CFRunLoopAddSource (CFRunLoopGetCurrent(), |
source, |
kCFRunLoopDefaultMode); |
The function CFRunLoopGetCurrent returns the run loop for the current thread. The function CFRunLoopAddSource adds an input source to the current run loop. The input source monitors the run loop for a font query. When it detects a font query, it invokes your callback.
In the general case, a font query is packaged as a Core Foundation property list (CFPropertyListRef). A missing-font query in particular uses a Core Foundation dictionary (CFDictionaryRef) that contains key-value pairs to specify the needed font. You need to obtain information from the dictionary, such as the font’s name, to determine whether you manage the font in question. You may also need to look up other values in the dictionary to determine what you must do to satisfy the query.
Listing 2-6 shows a function (MyHandleFontRequest) that looks for the queried font by various names. When the name is found, the function translates it to a a file specification, then calls the function ATSFontActivateFromFileSpecification to activate the font. A detailed explanation for each numbered line of code appears following the listing.
Note: You should use ATSFontActivateFromFileSpecification only in Mac OS X v10.4 and earlier. In Mac OS X v10.5 and later, this function is deprecated, so you should instead use ATSFontActivateFromFileReference.
Listing 2-6 A function that handles a font query in Mac OS X v10.4 and earlier
void MyHandleFontRequest (CFDictionaryRef theDict) |
{ |
OSStatus status; |
CFStringRef theName = NULL; |
const FSSpec* fontFileSpec = NULL; |
ATSFontContainerRef = myFontContainerRef; |
if (CFDictionaryContainsKey (theDict, kATSQueryQDFamilyName)) // 1 |
{ |
theName = CFDictionaryGetValue (theDict, kATSQueryQDFamilyName); |
fontFileSpec = MyFindByQDFamilyName (theName ); |
} |
else if (CFDictionaryContainsKey (theDict, kATSQueryFontName)) // 2 |
{ |
theName = CFDictionaryGetValue(theDict, kATSQueryFontName); |
fontFileSpec = MyFindByFontName (theName); |
} |
else if (CFDictionaryContainsKey (theDict, |
kATSQueryFontPostScriptName))// 3 |
{ |
theName = CFDictionaryGetValue (theDict, |
kATSQueryFontPostScriptName); |
fontFileSpec = MyFindByPostScriptName (theName); |
} |
// If needed, you can add code to handle other query types. |
if (fontFileSpec != NULL) // 4 |
{ |
status = ATSFontActivateFromFileSpecification ( |
fontFileSpec, |
kATSFontContextGlobal, |
kATSFontFormatUnspecified, |
NULL, NULL, |
myFontContainerRef);// 5 |
} |
} |
Here’s what the code does:
Checks to see if the CFDictionary contains the kATSQueryQDFamilyName key. If the key is in the dictionary, then the code obtains the QuickDraw family name of the font and calls your function (MyFindByQDFamilyName) to obtain the file specification associated with the name.
If the name hasn’t been found yet, checks to see if the CFDictionary contains the kATSQueryFontName key. If the key is in the dictionary, then the code obtains the full name of the font and calls your function (MyFindByFontName) to obtain the file specification associated with the full font name.
If the name hasn’t been found yet, checks to see if the CFDictionary contains the kATSQueryFontPostScriptName key. If the key is in the dictionary, then the code obtains the PostScript name derived from the font's FOND resource or from the font’s sfnt name table. Then calls your function (MyFindByPostScriptName) to obtain the file specification associated with the PostScript font name.
Checks to see if a value is assigned to the font file specification.
Activates the file specification for the requested font. Because you are activating the font in response to a query from another applications, you need to specify a global context (kATSFontContextGlobal) so the font is available to all applications. You should always pass kATSFontFormatUnspecified, as the system automatically detects the format of the font. If you want to deactivate the font later, you must pass a font container reference (myFontContainerRef) and retain the container returned to you by the function ATSFontActivateFromFileSpecification. To deactivate the font, you pass the font container reference to the function ATSFontDeactivate.
Last updated: 2007-12-11