Closed chenxiao445566 closed 2 years ago
通过 \CJKmove
移动基线是 undocumented method,是一个 quick-and-dirty hack,不建议使用。
请试着将 \newcommand*\CJKmovesymbol...\AtBeginDocument{\Large \CJKmove \sloppy}
这部分代码注释掉,jiazhu
默认设置的 ideohtratio=0.5
不需要修改、就是为竖排设置的。
中易仿宋的字身高是 85.9375%,用 RawFeature=vertical
进行竖排时,XeTeX 会帮忙自动开启字体本身的特性 vert
、vrt2
。但是,XeTeX 仍然是用横排的度量测量每个字(这是 XeTeX 引擎底层的 bug,没办法)。
这时候,你再用 \raise.29em\hbox{...}
将汉字抬高 29%,行内的汉字就会占据大约 115% 的高度,超过了夹注默认的行距 100%;夹注如果很长、需要折行,宏包内部是这么处理的:
% 夹注是一个三行的自然段,装着夹注内容的盒子大概长这样
第一行㊀㊁㊂㊃
㊄㊅第二行㊆㊇
㊈㊉剩余的夹注内容全部在第三行等着被折行
宏包接下来会尝试分离出两行的内容,更准确的说法是「分离出高度为 200% 的内容」。但因为第一行高到 115%,前两行加在一起就有 215%,取出两行内容就会溢出。所以,TeX 只会分离出第一行:
% 因为太高,只能分离出第一行,装进 \l__jiazhu_typeset_box
第一行㊀㊁㊂㊃
% 剩下的部分留在 \l__jiazhu_text_box 里面
㊄㊅第二行㊆㊇
㊈㊉剩余的夹注内容全部在第三行等着被折行
接下来的工作就是:
第一步里面的 repackage 会做底部对齐。第二步只会取出 ㊈㊉剩余的夹注内容全部在第三行等着被折行
这个部分,而丢掉了 ㊄㊅第二行㊆㊇
这个部分。
抬高 29%,并且设置夹注为三行,考虑一个跨三行正文的长夹注:
% Expected result:
㈩㈨㈦ ㈤㈢㊆ 正
︒︐㈧ ︙︙︙ 文
正 ︙︙㈠ ㊄㊂㊀
文 ㈥㈣㈡ ㊅㊃㊁
% Actual result:
㈩㈨㈦ ㈢㊆ 正
︒︐㈧ ︙︙ 文
正 ︙㈠ ㊂㊀
文 ㈣㈡ ㊃㊁
@chenxiao445566 我看你已经试过注释掉 \CJKmove
了,问题应该消失了吧。
我想多啰嗦几句:这个 xeCJK
+\raise.29em\hbox{...}
的办法,过去了这么多年,在我看来是颠倒主次、本末倒置的,可以算是我们简体中文TeX社区在摸索竖排过程中走的弯路。
横排的时候,各个厂家的字身高度不尽相同;竖排的时候,其实就根本没有这个问题,此时所有厂家的汉字皆被放置在基线对称的位置上。
既然可以竖排,就说明文本内容是以汉字为主的,而文本中出现的拉丁字母(英文)、数字必然是少量的。能够转正的英文(如缩写)、数字(如单位数或双位数的月份日期)都是正立着竖排下去,长一点的数字如四位数的年份会把阿拉伯数字改写成汉字然后也是正立着竖排下去。真正「侧躺九十度」的只是一些零散的英文单词。
所以,如果你要匹配这些侧躺英文单词跟汉字的关系,去做所谓的对齐,那么要移动的不应该是汉字、不应该是逐个逐个汉字去 \raise.29em
,动的应该是零散的英文单词,如 \lower.29em\hbox{English} \lower.29em\hbox{words}
。
顺便一提,这种「动英文、不动汉字」的方法是日文TeX社区的习惯做法。说到底还是因为人家到现在还经常用竖排、总结出了 best practice,我们简体中文社区不常用竖排、难免走弯路……
目前 \splittopskip
被设为零,可以扩大它,适当解决第一行过高的问题。分离的时候不再是分离出 n×\baselineskip
,而是分离出 \splittopskip
+(n−1)×\baselineskip
。
默认可以将 \splittopskip
设为 1.5\baselineskip
,应该够了。第一行实在是太高,就让用户自生自灭吧(其实用户可以自行滥用 \jiazhuset{format=\setlength\splittopskip{...}}
设置更大的值)。
用 \penalty0
+\vsplit\textbox to0pt
这个技巧,为夹注第一行的上方也加上 \splittopskip
。
...
\linespread{1}%
\splittopskip=\glueexpr\baselineskip*3/2\relax % <- 1.5\baselineskip
<user's code for format (a token list)>
...
\setbox\textbox=\vbox{%
\penalty0 % neat trick
\parshape <n+1>
<zero dim> <jiazhu line length> % line 1
...
<zero dim> <jiazhu line length> % line n
<zero dim> <max dim> % line n+1
<jiazhu content>
}%
\setbox0=\vsplit\textbox to0pt % neat trick
分离出 \splittopskip
+(n−1)×\baselineskip
。
\setbox\typesetbox=\vsplit\textbox
to\dimexpr\splittopskip+<n-1>\baselineskip\relax
修正分离出来的 \typesetbox
的高度。
\setbox\typesetbox=\vbox{%
\vskip-\splittopskip
\vskip<height of jiazhu ideographs>
\unvbox\typesetbox
}%
如果用了这种修正高度的方法,那就不需要支架了。
测试 \textbox
是否为空。若已空,则结束,返回正文;若不空,则
\setbox\textbox=\vbox{%
\penalty0
\parshape ...
\unhbox<the last line being carried over>
}%
\setbox0=\vsplit\textbox to0pt
然后返回第二步。
感谢各位大佬指点!
https://github.com/CTeX-org/ctex-kit/commit/e254c61a0f08f0c1f098d9bf5ab644697dd7b807 通过设置 \interlinepenalties
可以避免分离错误,但其实 \vsplit
不是必要的。我们可以在 \vbox
中通过 \prevgraf
和 \lastbox
获得相应信息,然后处理。当然,无论是使用 \vsplit
还是 \lastbox
,都要求 \vbox
垂直列上的内容比较规整,不能出现 whatsit
、mark
等结点。鉴于 jiazhu 的使用场景,我想这个要求并不过分。
请看图 竖排时,当夹注折行时,会有一部分丢失,如何解决? 代码如下