What should be done to do this with OpenType features?

Hi,

I have designed fonts before. Persian fonts. But I had never changed too much the OpenType features except the ligatures and initial, medial,... and diacritics and stuff like that. 

Sorry if this is lame or a disappointment :) I am not a code enthusiast and now I'm doing this with FontCreator 9 and its Open Type Designer.


As you may saw in previous posts of mine, at the moment, I'm designing a Persian font with detached separated glyphs (like a Latin one).

And I have decided to do a substitution. But it is a little complicated and I only do these things with the OT Designer, so maybe it is my lack of scripting capabilities.

It goes like this:

Substitute Kaf (only inital and medial forms) with a glyph I added myself to the Persian standard glyphs named _longKaf if and only if all the next glyphs after Kaf are some glyphs gathered in a Class for example @NotDotAbove. Also do all of these only when the font is set to {salt}.

I did single sub, it worked but does the sub all the time. I also did {calt}, it also worked but works even without enabling the {calt} in Adobe Illustrator and {salt} also worked, after enabling the {salt} option, but does that for all glyphs.





So I want to know which kind of substitution works better here and how? Any help?  

Comments

  • Kent Lew
    Kent Lew Posts: 937
    I think the substitution you want is
        sub Kaf' @NotDotAbove by _LongKaf;
    But you may encounter obstacles getting that to work the way you want by assigning it to {salt}. I don’t know if Illustrator’s implementation of {salt} recognizes contextual substitutions.

    For Illustrator, you may be better off assigning it to {calt}, but that may not give you quite the same discretionary aspect you desire.

  • Craig Eliason
    Craig Eliason Posts: 1,436
    Look into "ignore" statements. The OpenType Cookbook is a useful survey. And this Glyphs tutorial might be helpful too, even if you're not using Glyphs.
  • Nick Shinn
    Nick Shinn Posts: 2,207
    edited July 2016
    {salt} does not have support in a lot of applications, so probably not good to use.
    Refer to this table:
    https://www.typotheque.com/fonts/opentype_feature_support

    Are you using “ignore” in your code?
  • Kent Lew said:
    I think the substitution you want is
        sub Kaf' @NotDotAbove by _LongKaf;
    But you may encounter obstacles getting that to work the way you want by assigning it to {salt}. I don’t know if Illustrator’s implementation of {salt} recognizes contextual substitutions.

    For Illustrator, you may be better off assigning it to {calt}, but that may not give you quite the same discretionary aspect you desire.

    Thanks. Does it ignore glyphs? or Does it just substitute kaf with _longkaf?
    I can put this code in FontCreator as well?
  • Look into "ignore" statements. The OpenType Cookbook is a useful survey. And this Glyphs tutorial might be helpful too, even if you're not using Glyphs.
    Thanks. I am using FontCreator. I will read that.
  • {salt} does not have support in a lot of applications, so probably not good to use.
    Refer to this table:
    https://www.typotheque.com/fonts/opentype_feature_support

    Are you using “ignore” in your code?
    I thought maybe I can use reverse chaining context, tried that. But I don't know the ignore command in FontCreator. Because there are some other substitutions and I don't know where should I put it? 
  • Kent Lew said:
    I think the substitution you want is
        sub Kaf' @NotDotAbove by _LongKaf;
    But you may encounter obstacles getting that to work the way you want by assigning it to {salt}. I don’t know if Illustrator’s implementation of {salt} recognizes contextual substitutions.

    For Illustrator, you may be better off assigning it to {calt}, but that may not give you quite the same discretionary aspect you desire.

    {salt} does not have support in a lot of applications, so probably not good to use.
    Refer to this table:
    https://www.typotheque.com/fonts/opentype_feature_support

    Are you using “ignore” in your code?
    Actually AI CS6 supports {salt} and {calt} and I wrote in the post that both works but I can't make some glyphs to be ignored.
  • Kent Lew
    Kent Lew Posts: 937
    Yes, AI supports {salt}, but it may not recognize GSUB type 6 rules assigned to that feature tag.

    I don’t see a need for ignore statements, given [how I interpret] the description of what Shahab is trying to achieve — “substitute Kaf with _LongKaf if and only if the glyph that follows belongs to @NotDotAbove class.” That’s a textbook GSUB type 6, as far as I can tell.

    Which is the code I wrote above.
  • Kent Lew
    Kent Lew Posts: 937
    I did single sub, it worked but does the sub all the time. I also did {calt}
    A single sub (GSUB type 1), by definition, works in all contexts. You can register a rule to {calt} but that won’t make it contextual unless the rule is actually written as a contextual substitution (GSUB type 6).

    Shahab — It will help us to help you if you show the code you are trying to use.
  • Shahab Siavash
    Shahab Siavash Posts: 141
    edited July 2016
    Kent Lew said:
    Yes, AI supports {salt}, but it may not recognize GSUB type 6 rules assigned to that feature tag.

    I don’t see a need for ignore statements, given [how I interpret] the description of what Shahab is trying to achieve — “substitute Kaf with _LongKaf if and only if the glyph that follows belongs to @NotDotAbove class.” That’s a textbook GSUB type 6, as far as I can tell.

    Which is the code I wrote above.
    Thanks a lot! Great. I'm sorry I didn't know about this.
    But there is a problem. It loads the _longkaf and a space after that. I put that in salt and calt, same result.

    See?


  • Kent Lew said:
    I did single sub, it worked but does the sub all the time. I also did {calt}
    A single sub (GSUB type 1), by definition, works in all contexts. You can register a rule to {calt} but that won’t make it contextual unless the rule is actually written as a contextual substitution (GSUB type 6).

    Shahab — It will help us to help you if you show the code you are trying to use.
    Sure. Thanks. I do the codes in OpenType Designer of FontCreator. So I had to change your code to this:

    lookup SingleSubstitution7 {
      lookupflags RightToLeft;

      sub uniFB90 @NoDotsAbove -> _LongKaf;
    }

    And it worked but the problem is in the previous comment. 

    It goes like this:
    Type Kaf
    Type next glyph
    Kaf converts to _LongKaf
    Secong glyph dissapears
    Type third glyph
    Result: _LongKaf+Third Glyph
  • Kent Lew said:

    A single sub (GSUB type 1), by definition, works in all contexts. You can register a rule to {calt} but that won’t make it contextual unless the rule is actually written as a contextual substitution (GSUB type 6).

    I don't know about this part, actually.
  • Ray Larabie
    Ray Larabie Posts: 1,431
    @Erwin Denissen
    Do you know how this could be coded in FontCreator?
  • @Shahab Siavash
    Maybe you've chosen ligature substitute instead of chaining contextual substitute. I saw a "L" in the tree view.
    The code in AFDKO is

    lookup subKafToLongKaf {
        sub kaf by longkaf;
    } subKafToLongKaf;
    
    lookup caltLongKaf {
        sub kaf' lookup subKafToLongKaf @nodotabove;
    } caltLongKaf;
    
    feature calt {
        ......
        lookup caltLongKaf;
    } calt;

  • @Erwin Denissen
    Do you know how this could be coded in FontCreator?
    Thanks a lot. :)

  • @Shahab Siavash
    Maybe you've chosen ligature substitute instead of chaining contextual substitute. I saw a "L" in the tree view.
    The code in AFDKO is

    lookup subKafToLongKaf {
        sub kaf by longkaf;
    } subKafToLongKaf;
    
    lookup caltLongKaf {
        sub kaf' lookup subKafToLongKaf @nodotabove;
    } caltLongKaf;
    
    feature calt {
        ......
        lookup caltLongKaf;
    } calt;

    I've chosen Single Substitution, because it is only one glyph in each case that needs to be changed. Am I right? I am not? There is no ligature. Where did you see a "L"? 
  • Kent Lew
    Kent Lew Posts: 937
    I am not familiar with the FontCreator interface/syntax, but what you are doing appears to be adding a ligature substitution now. In your screen shot, the Input indicates two glyphs and the Output is a single glyph. So, even though you’ve identified it as a Single Substitution, it is showing up in the tree view with an "L" icon, as Belleve points out (the highlighted line in the left pane).

    And that is why you get the behavior you describe where the second glyph disappears. Both Inputs are being replaced by the Output.
    I've chosen Single Substitution, because it is only one glyph in each case that needs to be changed. Am I right?
    No. It is a single glyph that needs to be changed, but it is in a specific context: “if and only if followed by a glyph in the NoDotAbove class.” That makes it a different kind of lookup, not a Type 1 Single Substitution.

    If you look closely at the code I provided in Adobe Feature File syntax, there is a single quote mark (') following the target Kaf. In this syntax, that symbol marks that glyph as the target for substitution and the unmarked remainder becomes the context. Thus, this rule gets interpreted and compiled as a Type 6 Chaining Contextual Substitution.

    You need to add your rule as a ChainingContext rule. The Input needs to be your Kaf (uniFB90, I presume). The LookAhead needs to be @NoDotsAbove (I don’t know how FontCreator will present the field for this or exactly what it will be called). And the Output needs to be your _LongKaf.

    I assume that when this is done correctly the icon for the lookup will appear just like the ones in the tree under “Mark Positioning Via Substitution (mset)” — i.e., an S with a chain-link background.

    Good luck.
  • Kent Lew said:
    I am not familiar with the FontCreator interface/syntax, but what you are doing appears to be adding a ligature substitution now. In your screen shot, the Input indicates two glyphs and the Output is a single glyph. So, even though you’ve identified it as a Single Substitution, it is showing up in the tree view with an "L" icon, as Belleve points out (the highlighted line in the left pane).

    And that is why you get the behavior you describe where the second glyph disappears. Both Inputs are being replaced by the Output.
    I've chosen Single Substitution, because it is only one glyph in each case that needs to be changed. Am I right?
    No. It is a single glyph that needs to be changed, but it is in a specific context: “if and only if followed by a glyph in the NoDotAbove class.” That makes it a different kind of lookup, not a Type 1 Single Substitution.

    If you look closely at the code I provided in Adobe Feature File syntax, there is a single quote mark (') following the target Kaf. In this syntax, that symbol marks that glyph as the target for substitution and the unmarked remainder becomes the context. Thus, this rule gets interpreted and compiled as a Type 6 Chaining Contextual Substitution.

    You need to add your rule as a ChainingContext rule. The Input needs to be your Kaf (uniFB90, I presume). The LookAhead needs to be @NoDotsAbove (I don’t know how FontCreator will present the field for this or exactly what it will be called). And the Output needs to be your _LongKaf.

    I assume that when this is done correctly the icon for the lookup will appear just like the ones in the tree under “Mark Positioning Via Substitution (mset)” — i.e., an S with a chain-link background.

    Good luck.
    First thanks a lot for helping me :) Your comments are really insightful. 

    I didn't see the L icon actually because it wasn't an L. It was really a Single Substitution before the new code. But as you mentioned FontCreator does not understand your code. After I inserted your code it became like this. Before that it was like this:


    You can see the S icon. But the problem obviously is that there is no rule to include @NoDotsAbove. At least in SingleSub as you again mentioned that. (in FontCreator)

    So, I actually did ChainingContext too, before. FC has Input and Lookahead. But it does it all the time, so I thought it is not a right thing to do and changed it. It looks like this:





    Everything is ok, but it sets {calt} by default. Always does this. It is the same in Adobe InDesign and Illustrator CS6. I recall that you wrote something about this in the comments, but I didn't understand what {calt} is actually a {calt}? 

    And also would you recommend to do this as {calt} or {salt} when it's a ChainingContext?


    The code goes like this:

    lookup ChainingContext3 {
      lookupflags RightToLeft;

      context uniFB90 (@NoDotsAbove);
      sub 0 SingleSubstitution7;
    }

    And:

    lookup SingleSubstitution7 {
      lookupflags RightToLeft;

      sub uniFB90 -> _LongKaf;
    }


    Thanks a lot :)
  • Shahab Siavash
    Shahab Siavash Posts: 141
    edited July 2016

    @Kent Lew And I also added it for Persian gaf and initial and medial forms of both.
    Searched and read the GSUB 6, but still works by default.
    Sorry for the trouble.
    Thanks for all of your helps. 
  • Kent Lew
    Kent Lew Posts: 937
    As I said, this is slightly unfamiliar syntax for me, but your new code looks correct to me.
    And also would you recommend to do this as {calt} or {salt} when it's a ChainingContext?

    Ah, now comes the problem of what feature to assign it to. The problem with these two options is that you want this substitution to be discretionary and contextual (meaning, it only happens if the user turns it on, but then it only happens in certain contexts).

    The challenge is that {calt} is generally not considered discretionary, although it can be turned on and off in most user interfaces. It is generally turned on by default in all applications.

    The {salt} feature is typically a discretionary feature and not on by default. However, it is typically not a contextual feature and I suspect there are some applications that might not correctly apply contextual rules assigned to it. I have a vague recollection of this being the case with Adobe Illustrator, but I have not tested to confirm.

    Also, InDesign does not provide user access to {salt}.

    I would ordinarily put such a feature as this in a Stylistic Set. But stylistic sets are not supported by Adobe Illustrator, which you specifically mention using.

    I can think of a workaround for the Illustrator contextual issue, if I am indeed correct about that; but it would be cumbersome nuisance.

    Perhaps you can test to see if the {salt} feature of Illustrator correctly applies your _LongKaf contextually if you assign your ChainingContext3 lookup to {salt}.

  • As I said, this is slightly unfamiliar syntax for me, but your new code looks correct to me.
    Thanks a lot. There was good information in this discussion for me. I really appreciate that. :)

    The challenge is that {calt} is generally not considered discretionary, although it can be turned on and off in most user interfaces. It is generally turned on by default in all applications.

    Yes! I could not make it as a {calt} with this if.

    The {salt} feature is typically a discretionary feature and not on by default. However, it is typically not a contextual feature and I suspect there are some applications that might not correctly apply contextual rules assigned to it. I have a vague recollection of this being the case with Adobe Illustrator, but I have not tested to confirm.
    Also, InDesign does not provide user access to {salt}. 

    Actually AI supports this and also AID provide access to {salt}. Of course I have to say I have the CS6 ME (Middle Eastern) versions.

    Perhaps you can test to see if the {salt} feature of Illustrator correctly applies your _LongKaf contextually if you assign your ChainingContext3 lookup to {salt}.

    Thanks! and good news is that I got this finally working! Thanks to you.

    It is working as a {salt} with the "if and only if" condition for the glyphs after and only when user select the {salt} for initial and medial forms of Kaf and Gaf to _LongKaf and _LongGaf. Now it is functional in Illustrator, InDesign and Photoshop.


    Wonderful experience here, @Kent Lew :)