Font attributes


(Andreas Kiel) #1

For my app it would be helpful to know details of the installed fonts to filter the displayed fonts:
Serif <-> Non-Serif
Supported languages
Monospace <-> Proportional
(Ornamental or not)

Is there a somehow fast way to do something like that?


(Shane Stanley) #2

You can use the fixedPitch property to check for monospaced fonts. I suspect you will have to delve into NSFontDescriptor for stuff like whether a font uses serifs.


(Andreas Kiel) #3

Thanks Shane,

I tried the “fixedPitch” but getting errors.
It’s probably cause I didn’t use it correctly.
During launch I use:

    set allFontFamilies to sharedFontManager's availableFontFamilies
    repeat with fontFamily in allFontFamilies
        set familyFontStyleList to (sharedFontManager's availableMembersOfFontFamily:fontFamily)
        set fontFamily to (current application's NSFont's fontWithName:fontFamily |size|:30)

        set isMonospace to (fontFamily's objectForKey:"fixedPitch")
    end repeat

(Andreas Kiel) #4

To answer my own question (in case somebody has a similar question)

        set curFont to (current application's NSFont's fontWithName:fontFamily |size|:0.0)
        set isMonospace to (curFont's fixedPitch) as integer

(Andreas Kiel) #5

For sans-serif I’ve searched the docs and found:
NSFontDescriptor ->
typealias NSFontFamilyClass ->
var NSFontSansSerifClass: Int ->

But I’ve no idea how to make it work :frowning:


(Shane Stanley) #6

This should give you something to work with:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

-- classes, constants, and enums used
property NSFontManager : a reference to current application's NSFontManager
property NSFontDescriptorTraitMonoSpace : a reference to 1024
property NSFontDescriptorClassSansSerif : a reference to -2.147483648E+9
property NSFontDescriptor : a reference to current application's NSFontDescriptor
property NSFontSymbolicTrait : a reference to current application's NSFontSymbolicTrait
property NSDictionary : a reference to current application's NSDictionary
property NSSet : a reference to current application's NSSet
property NSFontTraitsAttribute : a reference to current application's NSFontTraitsAttribute

set fontTraits to NSDictionary's dictionaryWithObject:(NSFontDescriptorClassSansSerif + NSFontDescriptorTraitMonoSpace) forKey:NSFontSymbolicTrait
set fontAttribs to NSDictionary's dictionaryWithObject:fontTraits forKey:NSFontTraitsAttribute
set fontDesc to NSFontDescriptor's fontDescriptorWithFontAttributes:fontAttribs
set theDescriptors to fontDesc's matchingFontDescriptorsWithMandatoryKeys:(missing value)
set fontNames to theDescriptors's valueForKeyPath:"fontAttributes.NSFontNameAttribute"

Make sure you use properties for those enums, as in the example. They’ve changed recently.


(Andreas Kiel) #7

Wow, it would have taken quite a long time for me to figure out.
Some questions though for understanding.

property NSFontDescriptorTraitMonoSpace : a reference to 1024
property NSFontDescriptorClassSansSerif : a reference to -2.147483648E+9

What does that numbers mean?

And another question regarding the language/script thing. I have an old script which did work in ASS but doesn’t with ASobjC (and it’s pretty slow).

property fbTypeFaceList : {}
property fbTypeFaceInfoList : {}
property fbTypeFamilyList : {}

tell application "Font Book"
	set my fbTypeFaceList to every typeface
	
	set fbTypeFaceInfoList to {}
	set fbTypeFamilyList to {}
	
	set f to 0
	repeat with fbTypeFace in my fbTypeFaceList
		set f to f + 1
		set fbFaceProp to (properties of fbTypeFace) as record
		(*
		if f = 1 then
			log fbFaceProp
		end if
		*)
		set fontInfo to (fbFaceProp's typeface additional info) as record
		set fbTypeFamily to (fontInfo's FBFaceFamilyName)
		if fbTypeFamily is not in fbTypeFamilyList then
			set end of fbTypeFamilyList to fbTypeFamily
			set fontScripts to (fontInfo's FBFaceScripts)
			set fontLangs to (fontInfo's FBFaceLanguages)
			set end of my fbTypeFaceInfoList to {fontFamily:fbTypeFamily, fontScriptList:fontScripts, fontLangList:fontLangs}
		end if
	end repeat
	quit
end tell
return fbTypeFaceInfoList

Is there an option to do something like this with a similar approach?


(Shane Stanley) #8

Me too. Thank Google and, in this case, stackoverflow. The key to most of these things is finding some Objective-C code that does what you want. Then it’s just a matter of translating it — not always easy, but that’s something you can always ask here about.

The values are enums — they’re just labels that normally get changed to numbers when Objective-C code is compiled. In AppleScriptObjC, they’re normally interpreted at run-time, on the basis of frameworks’ .bridgesupport files.

Apple have changed the names of quite a few in recent times, which doesn’t matter in a compiled situation. But that’s problematic for run-time evaluation, because an enum name you use now might not exist on the Mac your script is running under.

Script Debugger’s code-completion uses the values in the .bridgesupport files (going back multiple versions of the OS), and provides the sort of property you see above. The a reference to is just a way to hint at what’s going on.

When done this way, there’s no need for AppleScript to look up the values at run-time. This can also have other advantages, but the main aim is to increase backwards compatibility.

Probably. Google is your friend.


(Andreas Kiel) #9

Shane

A delayed “Big Thank You” for the detailed explanation and all the help.

While I somehow understand now the enums approach (or somehow the reason for them) I still have no idea how to work with them.
For example: [ NSFontDescriptorClassOrnamentals ]
How do I get the enum?


(Shane Stanley) #10

Normally you just use Script Debugger’s code-completion. You will need to add suitable use statements, which are ignored in Xcode projects.

But in this case there’s a 64-bit bug in Apple’s .bridgesupport file, so it’s wrongly using a negative value. The correct value in this case should be 2415919104. I’ll log a bug on this so Script Debugger overrides the value in a future release.