Wsuperior and CCMP

The font users, to be compatible with fonts developed by other providers, use a wsuperior for both lower and upper case preceding characters.
My default wsuperior works fine with lower case, as in:
CC43
But I haven’t figured out how to manage wsuperior with upper case, as in (too low):
CC45
I created a composite, and used CCMP, but maybe my CCMP is inaccurate
CC46
CC49

I’ve looked around the forum to learn more about auto-CCMP, but still don’t have a good grasp to know how to make it work.

You don’t need precomposed glyphs. Just make a wsuperior.high and use code like this.

lookup wsuperiorHigh {
	lookupflag IgnoreMarks;
	sub @Uppercase wsuperior' by wsuperior.high;
} wsuperiorHigh;

add a class called Uppercase and set it to automatic.
The line lookupflag IgnoreMarks; means that all marks that might be between the Uppercase glyph and the w are ignored and don’t interfere.

And to use a single wsuperior is not for compatibility with other fonts, this is how Unicode works.

Thanks! What feature set do place the code into?

Also, what is the difference in usage of wsuperior and Wsuperior? I naively assumed that Wsuperior was used in conjunction with prior uppercase characters.

I got it the code figured out, it’s all new to me. :grinning: Looks good now. Thanks!

I don’t know about the details but it is probably used for something else.
And having two different ᵂ on the keyboard would be really confusing and error prone.
It is a font problem that the shape doesn’t look right next to uppercase.

I’m back to this problem again. I’m unsure when the change happened. For a wsuperior (wood) following a glyph combo of Q commaabovecomb the display appears to show a wmod and not a wmod.high.
2023-11-11_17-49-00
Here is the CCMP:
2023-11-11_17-52-03
and here is UPPERCASE:


2023-11-11_17-54-11

Thoughts?

The code looks good. The “Q” + “commaabovecomb” are single glyphs and not precomposed?
And can you check if the “commaabovecomb” is correctly set set as Mark in the GDEF table?

This is what I see:


Can you copy paste the full code? Put it between three ```?

@MMK_L_A = [A Aacute Agrave];
@MMK_L_B = [B];
@MMK_L_C = [C Ccaron C.low Ccaron.low];
@MMK_L_D = [D O Oacute Ograve Q];
@MMK_L_E = [E Eacute Edieresis Egrave];
@MMK_L_F = [F];
@MMK_L_G = [G];
@MMK_L_J = [J];
@MMK_L_K = [K];
@MMK_L_L = [L];
@MMK_L_P = [P];
@MMK_L_R = [R];
@MMK_L_S = [S Scaron];
@MMK_L_T = [T];
@MMK_L_U = [U Uacute Ugrave];
@MMK_L_V = [V];
@MMK_L_W = [W];
@MMK_L_X = [X];
@MMK_L_Y = [Y];
@MMK_L_Z = [Z];
@MMK_L_a = [a aacute agrave];
@MMK_L_b = [b p];
@MMK_L_c = [c ccaron];
@MMK_L_comma = [period comma];
@MMK_L_e = [e eacute egrave];
@MMK_L_f = [f];
@MMK_L_g = [g];
@MMK_L_h = [h m n];
@MMK_L_hyphen = [hyphen endash emdash];
@MMK_L_j = [j];
@MMK_L_k = [k];
@MMK_L_o = [schwa o oacute ograve];
@MMK_L_quoteleft = [quotedblleft quoteleft];
@MMK_L_quoteright = [quotedblright quoteright];
@MMK_L_quotesingle = [quotedbl quotesingle];
@MMK_L_r = [r];
@MMK_L_s = [s scaron];
@MMK_L_t = [t];
@MMK_L_v = [v];
@MMK_L_w = [w];
@MMK_L_x = [x];
@MMK_L_y = [y];
@MMK_L_z = [z];
@MMK_R_A = [A Aacute Agrave];
@MMK_R_C = [C Ccaron G O Oacute Ograve Q C.low Ccaron.low];
@MMK_R_J = [J];
@MMK_R_S = [S Scaron];
@MMK_R_T = [T];
@MMK_R_U = [U Uacute Ugrave];
@MMK_R_V = [V];
@MMK_R_W = [W];
@MMK_R_X = [X];
@MMK_R_Y = [Y];
@MMK_R_Z = [Z];
@MMK_R_a = [a aacute agrave];
@MMK_R_c = [c ccaron e eacute egrave schwa o oacute ograve];
@MMK_R_colon = [colon semicolon];
@MMK_R_comma = [period comma];
@MMK_R_d = [d q];
@MMK_R_f = [f];
@MMK_R_g = [g];
@MMK_R_hyphen = [hyphen endash emdash];
@MMK_R_m = [m n];
@MMK_R_p = [p];
@MMK_R_question = [question parenright braceright bracketright];
@MMK_R_quoteright = [quotedblright quoteright];
@MMK_R_quotesingle = [quotedbl quotesingle];
@MMK_R_r = [r];
@MMK_R_s = [s scaron];
@MMK_R_t = [t];
@MMK_R_u = [u uacute ugrave];
@MMK_R_v = [v];
@MMK_R_w = [w];
@MMK_R_x = [x];
@MMK_R_y = [y];
@MMK_R_z = [z];
	markClass [gravecomb] <anchor 178 569> @mark_top;
	markClass [acutecomb] <anchor 177 588> @mark_top;
	markClass [caroncomb] <anchor 193 584> @mark_top;
	markClass [caroncomb_commaabovecomb] <anchor -168 581> @mark_top;
	markClass [commaabovecomb] <anchor -126 551> @mark_top;
	markClass [dotbelowcomb] <anchor -50 0> @mark_bottom;
### class:0:Uppercase ###
@Uppercase = [
### open class 'Uppercase' ###
A Aacute Agrave B C C_caroncomb_commaabovecomb Ccaron D E Eacute Edieresis Egrave Schwa F G H I Iacute Igrave J K L Lbar Lbelt Lmiddletilde Lslash M N O Oacute Ograve P Q R S Scaron T U Uacute Ugrave V W X Y Z C.low Ccaron.low
### close class 'Uppercase' ###
];

### prefix:-1:Languagesystems ###
### open prefix 'Languagesystems' ###
languagesystem DFLT dflt;
languagesystem latn dflt;
### close prefix 'Languagesystems' ###

### prefix:-1:Prefix ###
### open prefix 'Prefix' ###
lookup SUB_24 {
	sub zero.numr by zero.dnom;
	sub one.numr by one.dnom;
	sub two.numr by two.dnom;
	sub three.numr by three.dnom;
	sub four.numr by four.dnom;
	sub five.numr by five.dnom;
	sub six.numr by six.dnom;
	sub seven.numr by seven.dnom;
	sub eight.numr by eight.dnom;
	sub nine.numr by nine.dnom;
} SUB_24;
lookup SUB_25 {
	sub zero.numr by zero.dnom;
	sub one.numr by one.dnom;
	sub two.numr by two.dnom;
	sub three.numr by three.dnom;
	sub four.numr by four.dnom;
	sub five.numr by five.dnom;
	sub six.numr by six.dnom;
	sub seven.numr by seven.dnom;
	sub eight.numr by eight.dnom;
	sub nine.numr by nine.dnom;
} SUB_25;
lookup SUB_27 {
	sub A by ordfeminine;
	sub O by ordmasculine;
	sub a by ordfeminine;
	sub o by ordmasculine;
} SUB_27;
lookup SUB_3 {
	sub i by idotless;
} SUB_3;
lookup SUB_4 {
	sub i by idotless;
} SUB_4;

### close prefix 'Prefix' ###

### feature:0:aalt ###
feature aalt {
### open feature 'aalt' ###
feature dnom;
feature frac;
feature ordn;
feature sups;
feature numr;
### close feature 'aalt' ###
} aalt;

### feature:1:ccmp ###
feature ccmp {
### open feature 'ccmp' ###
script latn;
lookup ccmp_Other_1 {
	@CombiningTopAccents = [acutecomb caroncomb commaabovecomb dieresiscomb gravecomb macroncomb];
	@CombiningNonTopAccents = [dotbelowcomb graphemejoinercomb];
	sub [i]' @CombiningTopAccents by [idotless];
	sub [i]' @CombiningNonTopAccents @CombiningTopAccents by [idotless];
} ccmp_Other_1;

lookup ccmp_Other_2 {
	lookupflag 0;
	sub caroncomb commaabovecomb by caroncomb_commaabovecomb;
} ccmp_Other_2;
lookup ccmp_Other_3 {
	sub C caroncomb_commaabovecomb by C_caroncomb_commaabovecomb;
	sub C caroncomb by Ccaron;
	sub c caroncomb_commaabovecomb by c_caroncomb_commaabovecomb;
	sub c caroncomb by ccaron;
	sub C caroncomb commaabovecomb by C_caroncomb_commaabovecomb;
	sub Ccaron commaabovecomb by C_caroncomb_commaabovecomb;
	sub x caroncomb by x_caron;
	sub X caroncomb by X_caron;
} ccmp_Other_3;

lookup wsuperiorHigh {
	lookupflag IgnoreMarks;
	sub @Uppercase wmod' by wmod.high;
} wsuperiorHigh;
### close feature 'ccmp' ###
} ccmp;

### feature:2:dnom ###
feature dnom {
### open feature 'dnom' ###
sub zero by zero.dnom;
sub one by one.dnom;
sub two by two.dnom;
sub three by three.dnom;
sub four by four.dnom;
sub five by five.dnom;
sub six by six.dnom;
sub seven by seven.dnom;
sub eight by eight.dnom;
sub nine by nine.dnom;
### close feature 'dnom' ###
} dnom;

### feature:3:frac ###
feature frac {
### open feature 'frac' ###
lookup FRAC {
	sub slash by fraction;
} FRAC;
lookup UP {
	sub [zero one two three four five six seven eight nine] by [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr];
} UP;
lookup DOWN {
	sub fraction [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr]' by [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom];
	sub [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom] [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr]' by [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom];
} DOWN;
### close feature 'frac' ###
} frac;

### feature:4:ordn ###
feature ordn {
### open feature 'ordn' ###
sub [zero one two three four five six seven eight nine] [A a]' by ordfeminine;
sub [zero one two three four five six seven eight nine] [O o]' by ordmasculine;
### close feature 'ordn' ###
} ordn;

### feature:6:sups ###
feature sups {
### open feature 'sups' ###
sub zero by zerosuperior;
sub one by onesuperior;
sub two by twosuperior;
sub three by threesuperior;
sub four by foursuperior;
sub five by fivesuperior;
sub six by sixsuperior;
sub seven by sevensuperior;
sub eight by eightsuperior;
sub nine by ninesuperior;
### close feature 'sups' ###
} sups;

### feature:7:numr ###
feature numr {
### open feature 'numr' ###
sub zero by zero.numr;
sub one by one.numr;
sub two by two.numr;
sub three by three.numr;
sub four by four.numr;
sub five by five.numr;
sub six by six.numr;
sub seven by seven.numr;
sub eight by eight.numr;
sub nine by nine.numr;
### close feature 'numr' ###
} numr;

### feature:-1:mark ###
feature mark {
	lookup mark_latn {
		lookupflag 0;
		pos base A <anchor 345 742> mark @mark_top;
		pos base C <anchor 364 751> mark @mark_top;
		pos base E <anchor 351 742> mark @mark_top;
		pos base I <anchor 159 742> mark @mark_top;
		pos base K <anchor 392 742> mark @mark_top;
		pos base L <anchor 341 0> mark @mark_bottom <anchor 341 742> mark @mark_top;
		pos base Lmiddletilde <anchor 329 742> mark @mark_top;
		pos base Lslash <anchor 318 742> mark @mark_top;
		pos base M <anchor 469 0> mark @mark_bottom <anchor 469 742> mark @mark_top;
		pos base N <anchor 389 0> mark @mark_bottom <anchor 389 742> mark @mark_top;
		pos base O <anchor 382 752> mark @mark_top;
		pos base P <anchor 379 742> mark @mark_top;
		pos base Q <anchor 382 752> mark @mark_top;
		pos base S <anchor 326 752> mark @mark_top;
		pos base T <anchor 302 742> mark @mark_top;
		pos base U <anchor 364 742> mark @mark_top;
		pos base W <anchor 507 742> mark @mark_top;
		pos base X <anchor 321 0> mark @mark_bottom <anchor 333 744> mark @mark_top;
		pos base Y <anchor 328 742> mark @mark_top;
		pos base C.low <anchor 370 659> mark @mark_top;
		pos base Ccaron.low <anchor 347 791> mark @mark_top;
		pos base a <anchor 262 536> mark @mark_top;
		pos base c <anchor 295 540> mark @mark_top;
		pos base e <anchor 297 540> mark @mark_top;
		pos base i <anchor 132 742> mark @mark_top;
		pos base idotless <anchor 129 532> mark @mark_top;
		pos base j <anchor 135 744> mark @mark_top;
		pos base k <anchor 320 742> mark @mark_top;
		pos base l <anchor 132 0> mark @mark_bottom <anchor 132 742> mark @mark_top;
		pos base lambdastroke <anchor 268 695> mark @mark_top;
		pos base lmiddletilde <anchor 213 742> mark @mark_top;
		pos base lslash <anchor 157 742> mark @mark_top;
		pos base m <anchor 467 0> mark @mark_bottom <anchor 467 530> mark @mark_top;
		pos base n <anchor 305 0> mark @mark_bottom <anchor 328 540> mark @mark_top;
		pos base o <anchor 299 540> mark @mark_top;
		pos base p <anchor 318 540> mark @mark_top;
		pos base q <anchor 274 540> mark @mark_top;
		pos base s <anchor 262 538> mark @mark_top;
		pos base t <anchor 174 710> mark @mark_top;
		pos base u <anchor 297 530> mark @mark_top;
		pos base w <anchor 383 530> mark @mark_top;
		pos base x <anchor 246 0> mark @mark_bottom <anchor 264 531> mark @mark_top;
		pos base y <anchor 249 530> mark @mark_top;
	} mark_latn;
	lookupflag 0;
	script latn;
	lookup mark_latn;
	lookupflag 0;
### open feature 'mark' ###
### close feature 'mark' ###
} mark;

### feature:-1:mkmk ###
feature mkmk {
### open feature 'mkmk' ###
	lookup mkmk_DFLT_top {
		lookupflag UseMarkFilteringSet @mark_top;
		pos mark caroncomb <anchor 172 725> mark @mark_top;
	} mkmk_DFLT_top;
### close feature 'mkmk' ###
} mkmk;

The code looks OK. Could you send me the .glyphs file, too?

I didn’t asked before: Where are you testing? It Seems to work fine for me.

Well, darn, now it’s working for me too (Word, Pages, Mellel). I have a package installer that flushes the cache after the font install and then does a forced restart. Maybe I need to relook at that process. Sorry to bother you.

I usually don’t install fonts while working on it. I do a lot testing with FontGoggles. Only at the very end you do compatibility testing in different apps.