Contextual anchors

I’ve had a look through this other thread, about Arabic, but wanted to figure out how this might work for Burmese.

In this case, I would like to shift the mark to the left when the base is followed by the tallAA sign ါ. I’ve added a *_top anchor to the mark, but I’m not sure what to write in the anchor context box. If I just write * tallAA-myanmar, the mark isn’t moving anywhere.

1 Like

Ah wait, I see it works if I put the contextual anchor on the base. But what if I want only this mark to move, but not others? That’s likely to happen with some combinations in Burmese. And it’s much more efficient to place one contextual anchor on a mark than one on every possible base glyph. Especially if different marks need to move by different amounts (also very likely).

Also, I need the repositioning to ignore any marks below. Currently a * top anchor on the base is only used when the base is followed directly by the tallAa, but of course there could be plenty of other marks on the base.

Here’s what I get at the moment:

To figure this out, it might be easiest to manually write the context anchor code in a feature in Font Info. And if you figured out the best way, figure out how to put it in an anchor. It might be that the current capabilities are not enough for that and that I need to improve it.

1 Like

So normally I’d figure this out with a contextual positioning adjustment in the mark feature, is that what you mean?

The rule here would be something like:

lookup myanmarContextualAboveMarkShift {
     lookupflag UseMarkFilteringSet @abovemarks;
     pos kinzi-myanmar' aaTall-myanmar <-150 0 0 0>;
     } myanmarContextualAboveMarkShift;

But of course anchors would be a better way as they’d interpolate

This is simple positioning. The anchors will produce a mark positioning.
But, you can access anchors in feature code. Instead of writing a number, do this:

${A:anchors.top.x}

or

${A:lsb}
${A:rsb}
${A:tsb}
${A:bsb}
${A:width}
2 Likes

Oh I didn’t know the OT rules could refer directly to the anchors. What’s that syntax? I don’t know what the $ or A or x refer to.

“A” is a glyph name.
“x” is the x-coordinate. Can be “x” or “y”.

1 Like

Thanks. I tried this code:

lookup myanmarContextualAboveMarkShift {
     lookupflag UseMarkFilteringSet @myanmarAbovemarks;
     pos kinzi-myanmar' aaTall-myanmar ${kinzi-myanmar:anchors._topleft.x};
     } myanmarContextualAboveMarkShift;

The result was that the tallAA is now pushed to the right, when I wanted to move the mark to the left:

you need to keep the rest of the value record (the <x 0 0 0>).

1 Like

Hm. I think I misunderstood what the anchor is doing. I wanted the mark to shift to the left, so I put a topleft anchor further to the right on that mark glyph:

Then the code:

lookup myanmarContextualAboveMarkShift {
     lookupflag UseMarkFilteringSet @myanmarAbovemarks;
     pos kinzi-myanmar' aaTall-myanmar <${kinzi-myanmar:anchors._topleft.x} 0 0 0>;
     } myanmarContextualAboveMarkShift;

produces a shift to the right unfortunately:

Ok. After lengthy discussions with Georg this morning, it seems there are quite a number of possible approaches, if I understand things…

Approach 1
Duplicate mark glyph and adjust anchors so the mark sits further to the left. Substitute that version of the glyph before ါ. This is interpolatable and requires no manual GPOS rules, and it can be contextual, but it adds an extra glyph (for each mark that needs contextual positioning, there could be a lot) and needs another lookup in the GSUB rules.

Approach 2
Use only one version of the mark glyph, but add a contextual rule manually to reposition it to the left. This would be interpolatable if using a number token, and can be contextual, but the value of the number token would have to be measured for each master and updated if outlines/sidebearings are adjusted. For scripts with a lot of marks, there will be a lot of number tokens to keep track of, and GPOS rules will need to be written manually to deploy those tokens in the right contexts.

lookup myanmarContextualAboveMarkShift {
     lookupflag UseMarkFilteringSet @myanmarAbovemarks;
     pos kinzi-myanmar' [aaTall-myanmar aaTall_asat-myanmar] <-120 0 0 0>;
} myanmarContextualAboveMarkShift;

Approach 3
Use a contextual anchor as outlined above. Have a *top anchor on every base (it doesn’t work for *_top anchors on marks yet) and in the anchor context box, input the sequence that should trigger the switch to that anchor. This would be most efficient as there’s no extra glyph or manual GPOS rules to write, but requires the new anchor on every base, and it can’t currently ignore belowmarks or have more than one context rule.

Screenshot 2022-10-17 at 14.47.46

Approach 4
Add a _topleft anchor to the mark, but offset it to the left of the LSB, so it has a negative value. Then tokenise this value in a manual GPOS rule to shift it left from its auto-generated position by that negative amount:

lookup myanmarContextualAboveMarkShift {
     lookupflag UseMarkFilteringSet @myanmarAbovemarks;
     pos kinzi-myanmar' [aaTall-myanmar aaTall_asat-myanmar] <${kinzi-myanmar:anchors._topleft.x} 0 0 0>;
} myanmarContextualAboveMarkShift;

Approach 5
Define specific anchors manually for this context. This takes the mark out from its usual position and allows it to be positioned absolutely, and can use tokens and be contextual.

# Automatic Code End

markClass kinzi-myanmar <0 0> @TOP_SHIFTLEFT;

lookup myanmarContextualAboveMarkShift {
     lookupflag UseMarkFilteringSet @myanmarAbovemarks;
     position base @myanmarBaseConsonants' <anchor ${kinzi-myanmar:width} 0> mark @TOP_SHIFTLEFT' [aaTall-myanmar aaTall_asat-myanmar]; # This finds the width of kinzi glyph and places kinzi that amount from the lsb of the base. 
} myanmarContextualAboveMarkShift;

This would necessitate either calculations with tokens, or a new rule for each base (they’re all different widths)


I believe Approach 4 does things most efficiently for me in this case :slight_smile: Did I miss some other clever approach?

1 Like

Hm. How about when we want to do this in a stylistic set? I can’t seem to figure out a way for these GPOS rules to append to the BLWM feature when SS17 is applied.

feature ss17 { # Alternate positioning

# Automatic Code End
# This stylistic set wants to append to the BLWM feature

lookup alternateSubjoinedPositions {
	# Tuck wide subjoined below whole cluster when followed by -aa vowels
	lookupflag UseMarkFilteringSet @myanmarBelowMarks; # We do not want top marks to interfere with these positioning rules.
	# Remember these anchors need to be at x-coordinate that corresponds to the amount of shifting, not the actual position the marks will anchor to.
	# First with consonants that take tall Aa:
 	pos kha-myanmar @myanmarBT2' [aaTall-myanmar aaTall_asat-myanmar] <${kha-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos ga-myanmar @myanmarBT2' [aaTall-myanmar aaTall_asat-myanmar] <${ga-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos nga-myanmar @myanmarBT2' [aaTall-myanmar aaTall_asat-myanmar] <${nga-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos da-myanmar @myanmarBT2' [aaTall-myanmar aaTall_asat-myanmar] <${da-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos pa-myanmar @myanmarBT2' [aaTall-myanmar aaTall_asat-myanmar] <${pa-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos wa-myanmar @myanmarBT2' [aaTall-myanmar aaTall_asat-myanmar] <${wa-myanmar:anchors.bottomShift.x} 0 0 0>;
	# Then with consonants that take round AA:
	pos ca-myanmar @myanmarBT2' aaSign-myanmar <${ca-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos na-myanmar.short @myanmarBT2' aaSign-myanmar.afterNa <${na-myanmar.short:anchors.bottomShift.x} 0 0 0>; 
	pos ba-myanmar @myanmarBT2' aaSign-myanmar <${ba-myanmar:anchors.bottomShift.x} 0 0 0>; 
	pos ma-myanmar @myanmarBT2' aaSign-myanmar <${ma-myanmar:anchors.bottomShift.x} 0 0 0>; 
	} alternateSubjoinedPositions;

} ss17;

@GeorgSeifert I think the only way to achieve alternate positioning within a stylistic set, at present, is to have duplicate glyphs with different anchors, right? SS17 can’t append manual positioning rules after Automatic BLWM code, unless I’ve missed something.

For several of the SEAsian scripts there are different traditions of mark positioning, so a more efficient process for engineering this type of thing would be very helpful. The contextual anchors feature looks very promising, but it’s not very robust yet.

Can you send me a file that has the pos rule in the stylistic set feature?

Thanks! You’ll see in the source from GitHub I’ve got some lines of code in the comment pane for SS17:

If you can figure out a way for that to work, I can replace the current ss17 rules which are using GSUB for the same effect.

What was the conclusion here, please?

Little bump? :slight_smile:

I think we need to talk about that again.

I added the option to add a prefix for the lookup.

Bildschirmfoto 2023-05-21 um 23.57.49

(and gave the context string a bit more space)

The part before the ; will be at the beginning of the lookup. (I might need to shorten that class name :wink: )

2 Likes

Is it possible to give multiple contexts for the same anchor? For example, a common problem is that you want a rule to fire whether or not there are any dots on beh, so both

lookupflag UseMarkFilteringSet @TopMarks;
* [behDotless-ar.medi.alef] @KAFm

and also

lookupflag UseMarkFilteringSet @TopMarks;
* [behDotless-ar.medi.alef] @TopMarks @KAFm

Or do I have to duplicate all the anchors with behDotless?