Open DamienRobert opened 4 years ago
For instance here is my Latin Modern Sans
fontspec file.
With this patch I am able to comment all Slanted
features and still have the correct sl->it
substitutions.
\defaultfontfeatures[Latin Modern Sans]{
Ligatures={TeX},
UprightFont = {*/R},
SmallCapsFont = {Latin Modern Roman Caps},
ItalicFeatures = { SmallCapsFont = {Latin Modern Roman Caps/I} },
BoldFeatures = { SmallCapsFeatures = { FakeBold=4 } },
BoldItalicFeatures = {
SmallCapsFont = {Latin Modern Roman Caps/I},
SmallCapsFeatures = { FakeBold=4 } },
SlantedFont={Latin Modern Sans/I},
BoldSlantedFont={Latin Modern Sans/BI},
SlantedFeatures = { SmallCapsFont = {Latin Modern Roman Caps/I} },
BoldSlantedFeatures = {
SmallCapsFont = {Latin Modern Roman Caps/I},
SmallCapsFeatures = { FakeBold=4 } },
FontFace = {b}{n}{Font = {Latin Modern Sans/B}},
FontFace = {b}{it}{Font = {Latin Modern Sans/BI}},
FontFace = {b}{sl}{Font = {Latin Modern Sans/BI}},
FontFace = {sbc}{n}{Font = {Latin Modern Sans Demi Cond/B}},
FontFace = {sbc}{it}{Font = {Latin Modern Sans Demi Cond/BI}},
FontFace = {sbc}{sl}{Font = {Latin Modern Sans Demi Cond/BI}},
}
I just pushed a new version that also set up a bx/scsl -> bx/scit
substitution, and correct the
bx/scit -> b/scit
substitution (previously it would substitute to b/it
instead).
Thanks! Code changes looks great so far. I can't look into detail right now but will merge once I've wrapped my head around a test file. Before I take a look, does it make sense to you that \fontshape{slsc}\selectfont
doesn't work but `\textsl{\textsc{...}}`` does?
It depends on the LaTeX version.
From version 2020-02, LaTeX has a new fontaxe like feature, where we can combine several shapes and setup fallbacks. For your example, the \DeclareFontShapeChangeRule {sl}{sc} {scsl} {scit}
applies, we are in sl
mode and we request an sc
, so the new mode should be scsl
, with a fallback to scit
if scsl
does not exist.
When we directly ask for a scsl
shape, since there is no \DeclareFontShapeChangeRule
for it, the standard nfss fallback of 'n' kicks in.
This could be corrected directly at the latex level by adding suitable DeclareFontShapeChangeRule {n}{scsl} {scsl} {scit}
DeclareFontShapeChangeRule {it}{scsl} {scsl} {scit}
... rules. By the way it is a bit painful that the current LaTeX api does not provide a convenient way to ask for scit
as a fallback for scsl
whatever the current shape we are in now.
In versions prior to 2020-02-02
, a \textsl{\textsc{...}}
would set up a sc
shape, to get a scsl
shape we would need to ask for it directly. (Fontspec patches \textsc
so that it asks for a scsl
shape first, but since it does not exists it fallsback to sc
and we are back to the standard LaTeX situation.)
Note that there is a similar fallback to 'b' for the 'bx' series:
\DeclareFontSeriesChangeRule {m}{bx} {bx} {b}
\DeclareFontSeriesChangeRule {b}{bx} {bx} {b} %<-----
\DeclareFontSeriesChangeRule {c}{bx} {bx} {b} %<-----
\DeclareFontSeriesChangeRule {ec}{bx} {bx} {b} %<-----
\DeclareFontSeriesChangeRule {sc}{bx} {bx} {b} %<-----
\DeclareFontSeriesChangeRule {l}{bx} {bx} {b} %<-----
And a it
fallback for the sl
shape:
\DeclareFontShapeChangeRule {n}{sl} {sl} {it}
\DeclareFontShapeChangeRule {it}{sl} {sl} {it}
Now it gets tricky. With the current way fontspec does things, it processes custom FontFace
first before processing the m/n
, b/n
, m/it
, m/sl
, b/it
, b/sl
faces (in this order, cf \@@_set_faces
).
When fontspec set up a face, it also set up the sc
shape, the sl
shape if the shape is it
, and the bx
weight if the weight is b
. This is not a problem for sl
since the sl
calls are after the it
calls, but this is a problem for bx
.
For instance in my LatinModernRoman
fontspec file, I want
BoldFont = {* Demi/B},
BoldItalicFont = {* Demi/BI},
FontFace = {bx}{n}{Font = {*/B}},
FontFace = {bx}{it}{Font = {*/BI}},
because that is also what tulmr.fd
does.
But since the FontFace
is processed first, the automatic bx -> b
substitution set up by fontspec when it process the bold font erases my custom bx
FontFace.
Indeed, patching DeclareFontShape
to add logging, I get:
LaTeX Info: DeclareFontShape: TU/LatinModernRoman(0)/bx/n=<->"LatinModernRoman/B
:mode=node;script=latn;language=dflt;+tlig;" () on input line 81.
LaTeX Info: DeclareFontShape: TU/LatinModernRoman(0)/bx/n=<->ssub*LatinModernRom
an(0)/b/n () on input line 81.
There are two solutions:
\@@_DeclareFontShape
in \@@_declare_shapes_bx
that checks first if the bx
weight exists (by testing if the csname #1/#2/#3/#4
exists) and in this case do nothing.2020-02
) use the existing bx -> b
and sl -> it
fallbacks and remove
\@@_declare_shape_slanted
and \@@_declare_shapes_bx
.Now here are a few more tricky situations:
sl -> it
substitution set up by fontspec, if a user wants to setup both a
eg l/sl
FontFace and a l/it
FontFace, then the order mater, the l/sl
FontFace has to be put afterwards so that it does not get overwritten by the l/it
one.
Once again this could be solved by checking first for an existing sl
shape before doing the substitution, or by relying on the new LaTeX fallback.\@@_merge_shape:n
is somewhat redundant with the new LaTeX version.
Here is what really happens with \textsl{\textsc{...}}
: first \@@_merge_shape:n
kicks in, combine the sl
shape with the existing sc
shape and checks if the scsl
shape exists. Since it does not it fallsback to \fontshape{sl}
where the new LaTeX shape substitution now kicks in.\sishape
, since it calls \fontshape{\scitdefault}
, ie it directly sets scit
, the existing scit -> scsl
fallback does not kick in (LaTeX set up both way fallbacks scit <-> scsl
). This could be solved by calling \fontshape{\scdefault}\fontshape{\itdefault}
instead (or better on the LaTeX side by extending \DeclareFontShapeChangeRule
to have a global scit -> scsl
fallback).(The new push simply correct the commit message, I was using itsc
instead of scit
...)
A few last thoughts on this subject of bx->b
substitution (this is unrelated to the pr itself, sorry I probably should have made a separate bug report):
bx/m
and bx/it
are defined, then \fontseries{bx}\fontshape{sc}
will give bx/m
but \fontshape{sc}\fontseries{bx}
will give b/sc
. On the other hand it is not clear which would be best anyway.FontFace
definitions after the setup of the normal font, italic font and so on, rather than before like it is currently the case, so that bx
fontfaces are not overwritten is not quite possible because of the automatic sc
handling. For instance setting up an m/ui
shape (like in lmr) would also set up the m/sc
shape and we would not want to overwrite the normal m/sc
font.sc
font, we cannot rely on the new latex behavior anyway because it is not simply a substitution. But this mean that a user setting up a sb/sc
fontshape before a sb/n
fontshape will have it overwritten. So I wonder if checking first if the sc
shape exists before overwriting it could help. The problem from this approach is that \addfontfeatures
rely on being able to overwrite existing shape settings...So unfortunately I don't see any easy solution to solve all corner cases. What I currently do is patch fontspec
to remove the sl->it
and bx->b
substitutions and rely instead on the LaTeX 2020-02 fallbacks, patch LaTeX to add globals scsl -> scit
and bx->b
substitutions (rather than only the specific existing ones), and be careful in my fontface declarations order for small caps fonts...
Thanks much for all the careful work here. FWIW I am more than happy that any new code in fontspec assumes a 2020 version of LaTeX. I’m in the middle of a busy period at work but I hope I can look at this code sometime soon...
Ok, so if we are allowed to assume LaTeX 2020, then my feeling is that the best would simply to remove \@@_declare_shape_{slanted,bx}
and let the new LaTeX's fallback work their substitutions instead.
In this case this pull-request that correct some bugs for both these functions is no longer needed ;)
I am happy to provide another pull request that does this if you agree. As I argued (too lengthy) above, this is not the perfect solution but imho the least worse one. Maybe you have better ideas than me!
Anyway there is no hurry, meanwhile I am happy with simply patching fontspec in fontspec.cfg
:)
If a slanted font is not provided, fontspec setup automatic
sl -> it
substitutions in\@@_declare_shape_slanted:nn
. But if a small caps font was provided, anitsc
shape is defined but there is no correspondingslsc -> itsc
substitution.Fix this by adapting the code of
\@@_declare_shape_slanted:nn
into\@@_declare_shapes_smcaps:nn
.Status
FOR DISCUSSION (but should be ready)
Todos
Minimal example demonstrating the new/fixed functionality