Glyph class membership predicate for glyph class tokens

Just to preface: I know this is a big feature request and I don’t expect you to accept it or to handle it in any timely manner. Still, this is something that is useful and fills a gap to other feature languages like FEE.


I propose an additional glyph class predicate field: classes. This allows to check whether a glyph is part of a glyph class or not.

$[classes contains "CombiningMarks"]

This predicate can, of course, be combined with other predicates like isAligned, countOfUnicodes, etc. But, it is also very useful on its own because it allows to perform all basic set operations on glyphs classes.

Set operations


Identity (trivial)

# @A
[ $[classes contains "A"] ]

Identity is trivial since it is the same as writing @A.


Complement

# complement(@A)
[ $[not classes contains "A"] ]

Union (trivial)

# union(@A, @B)
[ $[classes contains "A" or classes contains "B"] ]

Set union is the second trivial example since [@A @B] already does a similar thing. The difference is that a union does not contain duplicate members.


Intersection

# intersection(@A, @B)
[ $[classes contains "A" and classes contains "B"] ]

Difference

# difference(@A, @B)
[ $[classes contains "A" and not classes contains "B"] ]

Symmetric difference

# symmetric_difference(@A, @B)
# -- expressed as union of differences:
[ $[(classes contains "A" and not classes contains "B") or (not classes contains "A" and classes contains "B")] ]
# -- expressed as “in one but not both”:
[ $[(classes contains "A" or classes contains "B") and not (classes contains "A" and classes contains "B")] ]

(I don’t think the symmetric difference is particularly useful for font-design, but it is neat that it is possible.)


Details

The new classes field would be a list of strings where each string corresponds to a glyph class that contains the respective glyph. Using the standard contains operator one can check whether a glyph belongs to a class or not.

For example, all non-digit glyphs:

$[not classes contains "Digits"]

The classes field should probably contain only class names of classes defined above the token. This also makes recursive predicates impossible.

The syntax is not clear to me. If I understand correctly, it should look like this:

$[NOT name IN classes(Digits)]

or

$[NOT classes(Digits) CONTAINS name]

And can you give an useful example that can’t be done with the existing API? You don’t need a class “Digits” and more. Instead of @Digits, you can use this:

$[category == "Number"]

And it seems I did something right when setting up the token parsing code. It took me 20 min to implement this :wink:

The syntax is not important to me. I don’t know how you have structured your internal data-model or if you can provide custom predicate function like in

$[NOT classes(Digits) CONTAINS name]

I did have a look at the NSPredicate spec and it seemed to me that function names are not extensible:

If you know a way to implement such a custom predicate function than the second of your proposed syntaxes is a great syntax in my eye. What is the name referring to in your code? All you need is a class name.

  • I have a class of top marks (@BottomMark) and a class of narrow marks (@NarrowMark) and want some feature code to operate on narrow bottom marks – the intersection of the two classes.
  • In some other place I want the bottom marks without narrow marks. (The difference of the two classes.)
  • The complement is useful for some ignore code where I want to ignore everything except for all members of a glyph class.

What is the this referring to? The $[category == "Number"]? Or the class membership predicate?

Maybe my initial syntax proposal was confusing. This is what I would dream of:

$[inClass(BottomMark) == true and inClass(NarrowMark) == true]

I am not sure if this would fit the syntax of NSPredicate.

I preprocess the token and it expands to the content of the class

The predicate is used to filter the glyph list. So “name” is a property of the glyph. So you can query all properties on the glyph, even kerning groups and the note. You can use exactly the same stuff that can be done in the sidebar filters. Check the CustomFilter.plist for the actual syntax.

The later.

1 Like

Ah, now I get it! The classes function returns the list of names for a given glyph class name. Makes sense! I think you could even have classes return actual glyphs and check with contains self instead of contains name, but that would probably not be as user friendly for people unfamiliar with Obj-C.

\( ゚ヮ゚)/

The predicate has to compare a property of the object that is filter (the glyph). So you need to mention one.

$[name in classes(BottomMark) and name in classes(NarrowMark)]

You could save some work by using this (assuming that you use a “.narrow” suffix)

$[name in classes(BottomMark) and name contains '.narrow']

And you could even add tags to your marks and query that:

$[tags contains 'below']
1 Like

I try my best with naming, but a names can never hold all the metadata I need. Tags look great. I can’t find resources on glyph tags. Are they accessible from the GUI?

The classes contain strings, not glyphs. So that would be a big overhead.
and you could even do it you have set up your classes in a specific way.

$[classes(Digits) CONTAINS leftKerningGroup]

Might I suggest renaming the classes(…) function to class(…). I think that is what confused me initially since the function returns just a single class.

Great! Tags will come in handy.

In fact, tags are the new classes.* And if I ever need a class for a tag, that will be easy enough thanks to tokens and your help. Thank you!

* Classes are still useful if the order of the elements is important, e.g. for sub @A by @B where the order of glyphs in @A and @B must match.

The tags predicate does not work for me. Say I have /n and /o with the tag spacinghelp and /o additionally has the tag round. Now I want to lift a glyph after an /m if it is a spacinghelp but not round, like so:

I try to do this with the following code:

@NonRoundSpacinghelp = [$[tags contains "spacinghelp" and not tags contains "round"]];
pos m @NonRoundSpacinghelp' <0 300 0 0>;

The preview works:

But the exported file does not:

Test-file from the screenshots above: Test.glyphs (7.1 KB)

macOS 11.1 (20C69), Glyphs 3.0.3 (3059), tested in HarfBuzz

Thanks for the file. We have a look.

1 Like

Should work with the next build :slight_smile:

1 Like

It works in 3.0.3 (3061). Thank you!