texjporg / tex-jp-build

Minimum source repository to build Japanese TeX processing tools
23 stars 6 forks source link

[upTeX+dvipdfmx] 異体字セレクタ、Unicode合成文字 #46

Open t-tk opened 6 years ago

t-tk commented 6 years ago

upTeX+dvipdfmx で異体字セレクタ等を使えるようにしたいと考えています。 しかし知らないこと不勉強なことも多く、どのくらい開発のハードルが高いのかも分かっていません。議論にお付き合いいただけると助かります。

実装案1,2のいずれにせよ、dvipdfmxの拡張は要りそうです。dvips+(distiller or ghostscript)の場合は分かりません。 実装案1は、最近実現したばかりのJFM拡張を利用します。IVSや仮名の濁音までは対応できそうです。反面、携帯電話の絵文字の一部"U+0023 U+20E3"のようにASCIIから始まるような場合は処理が困難です。 実装案2は、upTeXの既存の方法(入力はptexencで頑張る。upTeXエンジンはフォントの情報を持たずCJKのグリフ1個として処理する。dviwareはフォントに依存する処理を頑張る)と整合します。実装としては筋がよいと感じ、最終的にはここまで持って行きたいです。 とりあえず、実装案1でdvipdfmxの拡張をして、次に実装案2を進めるという2段階の開発でも良いかなと思います。 実装案2では、IVSのテーブルunicode.orgのIVDは巨大(2017-12-12現在29303字)なので、ptexencの中にハードコードすることは気が進まないなどの課題もあります。

Variation Selectorを扱うためには、'cmap' Subtable Format 14 を読み出せばよいそうです。 参考: appleのところ, microsoftのところ 現状のdvipdfmxには実装されていないようです。 内部のことは全然知らないのですが、tt_cmap.c に'cmap' Subtable Format 4, 12 を扱う部分があるのでそこを拡張すれば良いと想像しています。 しかし、dvipdfmxの中身はまるで判らないので私にとっては高い壁です。

何か、ご意見やアドバイスなどがあればお願いします。

aminophen commented 6 years ago

実装案1は、最近実現したばかりのJFM拡張を利用します。IVSや仮名の濁音までは対応できそうです。反面、携帯電話の絵文字の一部"U+0023 U+20E3"のようにASCIIから始まるような場合は処理が困難です。

簡単なコメントだけですが,検討なさっている通り,どこまでやるかで実装方法が変わりそうですね。

まず,絵文字,というのがどこまでなのかよくわかっていません。カラー絵文字を PDF に埋め込めるようにしたいという話なのでしょうか?

補足:カラー絵文字をサポートした既存エンジンとして pTeX-ng があり,これは upTeX に極めて似ているため,一定の参考にはなりそうです。

# 私の理解では,pTeX-ng は「upTeX + e-TeX の改変版で作った特殊な DVI」を「ライブラリ様式に再構成された dvipdfmx = libpdf」で PDF を直接出力するように見せているというモノ。

ただ,この場合は dvipdfmx 部分が主に freetype2 や libotf に新たに依存しています。ライブラリを増やして良ければ,案外簡単に実現できるのかもしれませんが,よくわかりません。

t-tk commented 6 years ago

私がupTeXの基本的な機能として拡張したいのは、「絵文字をグリフとして持っているフォントを使ってフォントとしてpdfに埋め込む」場合です。図形として埋め込むことは関心の外にあります。 Unicodeの絵文字は最近Unicodeの新版が出る度に増殖しているみたいで色々ですが、文字集合の候補として気になるのは

  1. 日本の携帯電話由来の絵文字 Ref.Wikipedia
  2. Macが絵文字に使っているEVS Ref.NAOIさんのところ
  3. その他 Ref.Wikipedia

イメージとしては、絵文字をグリフに持ちVS等を使って呼び出せるように実装されているフォントを用いて、そのフォントのUTF-8のシーケンスに合致したグリフをpdfに埋め込むようなことです。 pTeX-ng のことはよく判りませんが少し違うかもしれません。

Unicode のシーケンスで分類すると

  1. Unicodeの一つのコードポイントで表せるもの
  2. 「親文字」+VS
  3. 国旗: Regional indicator symbolsのコードポイントが2個並んだもの
  4. その他??

1は既に既存のupTeX環境で使えるはずです。2は漢字のVS=IVS と同様のやり方で対応出来るような気がします。 3は2とほぼ似ているような気がしますが判りません。4は存在するのかどうか判りません。 優先順位としては、まずはVS対応が先決と思っています。

t-tk commented 6 years ago

お勉強、備忘録を兼ねて書きます。 NAOIさんのところによると、JIS X 0213に含まれる「Unicodeでは文字合成で表す仮名」を合成済みグリフで出すには、OpenType の 'liga' フィーチャーまたは 'ccmp' フィーチャーを使うそうです。 最初に書いた目標を満たすのは、フォントの機能別にざっくりいうと

  1. Variation Selector, 'cmap' Subtable Format 14
  2. OpenType, GSUBの 'liga' フィーチャーまたは 'ccmp' フィーチャー

と纏められると思います。可変長のコードポイントの配列で表される塊を1つのグリフとして扱いたいという点では共通なので、その操作は共通で処理したい。 また、dviのset命令の列でその処理を実現しようとすると、dviwareが読み込んだ後に文字の切り出しや文字幅の取得等を適切に行うことが必要となり、煩雑な処理にならざるを得ない。 そうすると、更に別案として、XeTeXのやり方を少し真似した以下の案に傾いています。

改造量が多くdviwareの対応のための開発が重くなり、結果としてdvipdfmx以外では新仕様に追従困難になるかもしれない、拡張dvi命令を知らない従来のdviwareでは拡張dvi命令を含む新dviを丸っきり処理できなくなる、など短所もあります。 しかし、機能の分かりやすさやメンテナンス性は実装案3が一番よく、今はこれで行こうと思っています。 改造量が多く時間が掛かりそうです。 TeX Live 2018 には到底間に合わないことが分かったので、一旦止めて少しづつやろうかと考えています。

t-tk commented 6 years ago

IVSのテーブルunicode.orgのIVDは巨大(2017-12-12現在29303字)なので、ptexencの中にハードコードすることは気が進まないなどの課題もあります。

IVDのテーブルを調べてみたところ、 upTeX の内部コード(24bit)はまだ沢山領域が余っているので、 文字コード+異体字セレクタ情報を持つ内部コードとして比較的単純な割り当てでも充分まかなえることが分かりました。

異体字セレクタの種類が最多になっている文字は U+FFFF以下のBMPでは、U+9089 (邉) で U+E0100..E011F の32種類、 U+20000..2FFFF のSIPでは、U+20525 で U+E0100..E0108 の9種類でした。 なので、upTeXの内部コードとして例えば U+9089の IVS に 0x809089 〜 0x9F9089 を U+20525の IVS に 0xC00525 〜 0xC80525 を 割り当てればまかなえます。 IVS全体としては、例えば BMP の IVS を 0x800000 〜 0x9FFFFF に、SIP の IVS を 0xC00000 〜 0xC8FFFF に割り当てれば足ります。 今後IVDの大幅な拡張は無いと予想する上、将来の拡張を見越しても充分まかなえそうです。 変換式も単純になりptexencの改造も少々で済みそうです。 この方針で行こうと思います。

t-tk commented 1 year ago

2022年9月に Ideographic Variation Database の新版が出ていました。 http://www.unicode.org/ivd/data/2022-09-13/

31350 E0100; Adobe-Japan1; CID+19130 が追加されています。

なので計画を若干修正。 異体字セレクタの種類が最多になっている文字は U+FFFF以下のBMPでは、U+9089 (邉) で U+E0100..E011F の32種類、 U+20000..2FFFF のSIPでは、U+20525 で U+E0100..E0108 の9種類、 U+30000..3FFFF のTIPでは、U+31350 で U+E0100 の1種類、 なので、upTeXの内部コードとして例えば U+9089の IVS に 0x809089 〜 0x9F9089 を U+20525の IVS に 0xC00525 〜 0xC80525 を U+31350の IVS に 0xE01350 を 割り当てればまかなえます。

h-kitagawa commented 1 year ago

npTeX (#150) も考えたときに,どこまで「0x110000 以上の内部コード」を許容するかについて悩んでいます.#150 で h20y6m さんが

個人的には 0x110000 以上の 文字トークン は無いほうがいいと思います。 これが存在すると expl3 等に特別扱いしてもらう必要が出てきてしまいます。 (例えば文字列を UTF-16 の HEX 表記(PDF 文字列)に変換するとき 0x110000 以上の文字コードのトークンがあると困ったことになる。)

と書かれているように,仮に「0x110000 以上の文字トークン」を許さないことにすると……


t-tk さんの元コメント に便乗して,別の案を挙げてみます.

aminophen commented 1 year ago

0x110000 以上の文字トークン

現状の (e-)upTeX は 0x110000 以上は「文字ノードとしては存在するが,文字トークンとしては存在しない」で一貫しています(\kansujichar や \Uchar はトークン生成時に mod 0x110000 で落とす)。OTF パッケージ対策は文字ノードさえ出来れば良く,これで十分だったのでしょう。異体字セレクタだとそうはいかない,と言われると確かに…。

%#!euptex
% ノード
\chardef\X="112603 \show\X % => \char"112603
% トークン
\kansujichar1="112603 \showthe\kansujichar1 % => 9731 = "2603
\expandafter\show\kansuji1 % => kanji character ☃
\expandafter\show\Uchar"442603 % => kanji character ☃
\end

メモ: mod 0x110000 の処理は toUCS() あるいは toDVI() → 内部 Unicode の時 UPTEXtoUCS% UCS_MAX による。

h20y6m commented 1 year ago
  • \@tfor でトークンごとにループを回すとき,IVS が基底文字と異体字セレクタに分離してしまう.
    • XeTeX/LuaTeX において,l3text での対応状況はどうか?

書記素ごとにループする \text_map_function:nN/\text_map_inline:nn という関数があります。


異体字セレクタの種類が最多になっている文字は U+FFFF以下のBMPでは、U+9089 (邉) で U+E0100..E011F の32種類、

ここがちょっと気になっていています。 いまデジタル庁が文字情報基盤(MJ)を拡張した MJ+ というのを作っているそうです。(1万文字くらい追加されるらしい) どういった文字が追加されるのか、Unicodeにも登録されるされるのかよく分かりませんが、 もしIVDに異体字が追加された場合に足りなくなったりしないか心配です。

t-tk commented 1 year ago

コメントありがとうございます。 MJ+ というのは知りませんでした。 現行の MJ で既に漢字 58,862文字でこれらは既に戸籍統一文字、住民基本台帳ネットワークシステム統一文字を含んでいるとのこと、Unicode の基底文字もしくは IVS に定義されているとのことです。 MJ+ のこれから追加されるであろう文字とは、Unicodeにすでに登録されている文字と同定できず、Unicodeの包摂の範囲に入らず、辞書にも見出せず、読みや意味が不明だが人名など固有名詞に稀に使われている文字の積み残し、というイメージになると思います。なので、「辺邉邊」の異体字が増えるというような増え方は起きにくいように思います。

また、下記のように現計画の延長線上で、 U+0hhhhの ~VS80, U+2hhhhの ~VS64 は賄えると思います。 さらに、現計画の延長から外れた符号化をしてもよいと思います。

絵文字の肌の色とか顔の向きとか、謎かつ予測不可能な進化についていくことは難しそうですが。

◇SVS
40hhhh  U+0hhhh U+0FE00 (VS01)
41hhhh  U+0hhhh U+0FE01 (VS02)
42hhhh  U+0hhhh U+0FE02 (VS03) (現状の最大値)
...
4Ehhhh  U+0hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
4Fhhhh  U+0hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

5Ehhhh  U+1hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
5Fhhhh  U+1hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

60hhhh  U+2hhhh U+0FE00 (VS01)
61hhhh  U+2hhhh U+0FE01 (VS02) (現状の最大値)
62hhhh  U+2hhhh U+0FE02 (VS03)
...
6Ehhhh  U+2hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
6Fhhhh  U+2hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

7xxxxx  未定義

◇IVS
80hhhh  U+0hhhh U+E0100 (VS17)
81hhhh  U+0hhhh U+E0101 (VS18)
82hhhh  U+0hhhh U+E0102 (VS19)
...
9Dhhhh  U+0hhhh U+E011D (VS46)
9Ehhhh  U+0hhhh U+E011E (VS47)
9Fhhhh  U+0hhhh U+E011F (VS48) (現状の最大値) (一応ここまで可能ということにしておくか)

Axxxxx  未定義  (U+0hhhhの ~VS64 の余地あり)
Bxxxxx  未定義  (U+0hhhhの ~VS80 の余地あり)

C0hhhh  U+2hhhh U+E0100 (VS17)
C1hhhh  U+2hhhh U+E0101 (VS18)
C2hhhh  U+2hhhh U+E0102 (VS19)
...
C6hhhh  U+2hhhh U+E0106 (VS23)
C7hhhh  U+2hhhh U+E0107 (VS24)
C8hhhh  U+2hhhh U+E0108 (VS25) U+2xxxxの(現状の最大値)
...
CFhhhh  U+2hhhh U+E010F (VS32) (一応ここまで可能ということにしておくか)

Dxxxxx  未定義  (U+2hhhhの ~VS48 の余地あり)

E0hhhh  U+3hhhh U+E0100 (VS17) (U+3xxxxの現状の最大値)
...
EFhhhh  U+3hhhh U+E010F (VS32) (一応ここまで可能ということにしておくか)

Fxxxxx  未定義

◇註
きっと将来も現れないが
U+0hhhh の VS48超え
U+0hhhh の VS64超え
U+2hhhh の VS32超え
U+3hhhh の SVS
も余地がありそう。
zr-tex8r commented 1 year ago

少し気になったのですが、VS付の文字について、 「upTeXとnpTeXでエンジン内の実装方法を同じにする」 あるいは 「そのような文字を扱うTeX言語コードの実装がupTeXとnpTeXで共通に使える」 必要はあるのでしょうか。 現在存在する機能(それを扱う既存のTeX言語のソフトウェアが存在する)ではないので、その必要性はそこまで強くないと思います。

t-tk commented 1 year ago

「そのような文字を扱うTeX言語コードの実装がupTeXとnpTeXで共通に使える」 必要はあるのでしょうか。

私は必要ないと思います。 もし npTeX が XeTeX ベースに進むのでしたら、IVSは XeTeX で既に実現されているはずなのでそれと同様にする方が自然だしメンテナンス性もよくなると思います。

h20y6m commented 10 months ago

https://github.com/texjporg/tex-jp-build/issues/155 で 'cmap' Subtable Format 14 を読んで VS に対応するのをやったのでこちらも少し実験してみています。

  • DVI には内部コードをそのまま set3"809089で出力し,dvipdfmx で頑張る

が VF を作れば疑似的に実験できそうだったので、IVD_Sequences.txtを元に Unicode 私用面に Adobe-Japan1(0xF0000+CID)と Moji_Joho(0x100000+MJ番号)の異体字を 0x800000--0xFFFFFF にマップするVFを生成するスクリプトを作ってみました。

実際にやってみると dvipdfmx:fatal: Invalid char: 9343113 のようなエラーなってしまいます。 dvipdfmx では JFM の最大文字コードは 0x10FFFF 固定にしているためのようです。これを単純に 0xFFFFFF に拡張すれば読めるようにはなりますが、dvipdfmx では文字コードから CHARTYPE を取得するためにルックアップテーブルを使用していて(CHARTYPE が 0 以外を含む JFM の場合)、これのメモリ使用量が約 4.4 MiB から約 64 MiB に増大してしまいます。和文多書体などであっという間に数百 MiB になってしまうので、そのあたりも改良が必要になってきそうです。(tfm.c の jfm_make_charmap

また、実際に VS 付きの文字コードからグリフを検索する方法ですが、VS を使う場合フォント map は CMap として unicode を指定する場合の処理になるのではないかと思います(CIDに変換するわけにはいかないと思うので)。 この場合、最初にフォントの cmap テーブルから UCS4 → CID/GID 変換する CMap を生成して set3 等の DVI 命令の処理ではこの CMap を利用して CID/GID に変換し出力しているようです(つまりフォントから自動的生成した CMap を指定したようなイメージで DVI 命令の処理は普通の CMap を指定したときとほぼ共通のよう)。(tt_cmap.c の otf_load_Unicode_CMap) UCS4 (4バイト)なのでここに Subtable Format 14 から VS 用の変換を 0x400000--0xFFFFFF で入れてやれば割と簡単にできそうではあります。(ただ、Unicode として不正な値を入れるのがちょっとやな感じなので、基底文字+VSの 8バイトのシーケンスにしたい気もする……) あと、フォントに該当の異体字がなかったときは基底の字体フォールバックしたい気がします。(pdfdev.c の handle_multibyte_string でゴニョゴニョすればできるだろうか?) dvipdfmx の和文文字出力は DVI (or VF) の文字コードを CMap で PDF に書き込む CID/GID に変換して出力する仕組みのようなので、これにうまく合わせられると改造量が減らせそうではあります。

それから、ToUnicode CMap をちゃんと作るのも必要になります。たぶん cmap Subtable Format 4/12 から逆引きで作っているのですが(たぶん tt_cmap.c の otf_create_ToUnicode_stream)、どのあたりをいじれば Format 14 の VS の情報追加できるのか追いきれていません。 また、ToUnicode CMap に VS 付きで入れるべきなのか(あるいは VS を入れてはいけないのか)もよくわかっていません。


【追記】 とりあえず動いている実験コードを https://github.com/h20y6m/tex-jp-build/tree/dvipdfmx_uvs_experiment_1 に置いておきます。(ただ、この実装だとフォントに異体字がなかったときのフォールバックは無理そうなんですよねぇ……)

t-tk commented 8 months ago

https://github.com/h20y6m/tex-jp-build/tree/dvipdfmx_uvs_experiment_1 を拝借しつつ、触り始めています。 とりあえず、

dvipdfmx では JFM の最大文字コードは 0x10FFFF 固定にしているためのようです。これを単純に 0xFFFFFF に拡張

この問題ですが、 https://github.com/texjporg/tex-jp-build/commit/4ed80319febb9a1204ba8d286e39be207cb0b6dd でよいように思います。 前提として、0x110000 以上の文字トークンは、defaultの全角グリフしか使わない、文字毎に設定したりしない、ということです。 ちょっと気になったのは、OTF パッケージで使っている 0x110000 ~ 0x140000 あたりで半角幅があったりしたのはどうだったか?

t-tk commented 8 months ago

いろいろ検討した結果、文字コードは以前の構想と少し変えました。以下で確定のつもりです。

内部トークンの文字コード ::
SVS: 0xC00000..0xFFFFFF の3byteで表現
IVS: 0x400000..0xBFFFFF の3byteで表現

DVIの文字コード ::
SVS: 0xC00000..0xFFFFFF の3byte を set3 で出力、内部トークンと同じ符号
IVS: 0x01000000..0x02F3FFFF の4byte を set4 で出力、uptex出力時に符号を変換

SVSは3byteなので JFMのグリフをchartype 0番以外に設定可能。
IVSはJFMで chartype 0番の全角グリフを想定。

DVIの文字コードでは、 0x3FFFF でマスクして得られる下位 18 bit が基底文字の Unicodeスカラー値に等しい。
SVS,IVSの異体字セレクタの部分をそれより上の上位bitで表現している。

◇SVS
内部トークン DVIコード 文字の順に
C0hhhh  ##C0hhhh  U+0hhhh U+0FE00 (VS01)
C4hhhh  ##C4hhhh  U+0hhhh U+0FE01 (VS02)
C8hhhh  ##C8hhhh  U+0hhhh U+0FE02 (VS03) (現状の最大値)
CChhhh  ##CChhhh  U+0hhhh U+0FE03 (VS04)
...
F8hhhh  ##F8hhhh  U+0hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
FChhhh  ##FChhhh  U+0hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

C1hhhh  ##C1hhhh  U+1hhhh U+0FE00 (VS01)
C5hhhh  ##C5hhhh  U+1hhhh U+0FE01 (VS02)
C9hhhh  ##C9hhhh  U+1hhhh U+0FE02 (VS03)
...
F9hhhh  ##F9hhhh  U+1hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
FDhhhh  ##FDhhhh  U+1hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

C2hhhh  ##C2hhhh  U+2hhhh U+0FE00 (VS01)
C6hhhh  ##C6hhhh  U+2hhhh U+0FE01 (VS02) (現状の最大値)
CAhhhh  ##CAhhhh  U+2hhhh U+0FE02 (VS03)
...
FAhhhh  ##FAhhhh  U+2hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
FEhhhh  ##FEhhhh  U+2hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

◇IVS
(VS17..VS32) U+2hhhhの現状最大はVS25, U+3hhhhの現状最大はVS17
(VS33..VS48) U+0hhhhの現状最大はVS48
(VS49..VS64) まだ無い
(VS65..VS80) まだ無い

内部トークン DVIコード 文字の順に
40hhhh  0100hhhh  U+0hhhh U+E0100 (VS17)
41hhhh  0110hhhh  U+0hhhh U+E0101 (VS18)
42hhhh  0120hhhh  U+0hhhh U+E0102 (VS19)
...
5Dhhhh  02d0hhhh  U+0hhhh U+E011D (VS46)
5Ehhhh  02e0hhhh  U+0hhhh U+E011E (VS47)
5Fhhhh  02f0hhhh  U+0hhhh U+E011F (VS48) (U+0xxxxの現状の最大値) (現状ここまで可能)

6xxxxx  未定義  (U+0hhhhの ~VS64 の余地あり)
7xxxxx  未定義  (U+0hhhhの ~VS80 の余地あり)

80hhhh  0102hhhh  U+2hhhh U+E0100 (VS17)
81hhhh  0112hhhh  U+2hhhh U+E0101 (VS18)
82hhhh  0122hhhh  U+2hhhh U+E0102 (VS19)
...
86hhhh  0162hhhh  U+2hhhh U+E0106 (VS23)
87hhhh  0172hhhh  U+2hhhh U+E0107 (VS24)
88hhhh  0182hhhh  U+2hhhh U+E0108 (VS25) (U+2xxxxの現状の最大値)
...
8Fhhhh  01f2hhhh  U+2hhhh U+E010F (VS32) (現状ここまで可能)

9xxxxx  未定義  (U+2hhhhの ~VS48 の余地あり)

A0hhhh  0103hhhh  U+3hhhh U+E0100 (VS17) (U+3xxxxの現状の最大値)
...
AFhhhh  01f3hhhh  U+3hhhh U+E010F (VS32) (現状ここまで可能)

Bxxxxx  未定義

◇註
現状定義されている漢字のSVS,IVSはカバーできている。
きっと将来も現れないが
U+0hhhh の VS48超え
U+0hhhh の VS64超え
U+2hhhh の VS32超え
U+3hhhh の SVS
も余地がありそう。
t-tk commented 8 months ago

現在の試作品はこちらです。 https://github.com/texjporg/tex-jp-build/commit/2cee45aa4e5d76d39019da371003a7ffdc9f1c58

実際にやってみると dvipdfmx:fatal: Invalid char: 9343113 のようなエラーなってしまいます。

ここは解消しています。

dvipdfmx では JFM の最大文字コードは 0x10FFFF 固定にしているためのようです。これを単純に 0xFFFFFF に拡張すれば読めるようにはなりますが、dvipdfmx では文字コードから CHARTYPE を取得するためにルックアップテーブルを使用していて(CHARTYPE が 0 以外を含む JFM の場合)、これのメモリ使用量が約 4.4 MiB から約 64 MiB に増大してしまいます。

現状のコードは、最大 U+10FFFF までは JFM を参照、それ以上の文字コードは chartype 0番を参照になっていると思います。ルックアップテーブルは巨大化していません。まだまだ節約の余地はあるのは確かです。

また、実際に VS 付きの文字コードからグリフを検索する方法 ... (tt_cmap.c の otf_load_Unicode_CMap) UCS4 (4バイト)なのでここに Subtable Format 14 から VS 用の変換を 0x400000--0xFFFFFF で入れてやれば割と簡単にできそうではあります。(ただ、Unicode として不正な値を入れるのがちょっとやな感じなので、

今回の案では、VSの値 + ユニコードスカラー値の正規の値、という組み合わせの独自の4byteのバイナリーコードで扱うことになります。 「Unicode として不正」とまではいえないコードだと思うので、「やな感じ」は和らぐと思います。

基底文字+VSの 8バイトのシーケンスにしたい気もする……) あと、フォントに該当の異体字がなかったときは基底の字体フォールバックしたい気がします。(pdfdev.c の handle_multibyte_string でゴニョゴニョすればできるだろうか?)

現状のテストではまだフォールバック機能はありませんが、DVIコードから簡単に基底文字が得られるので、フォントの検索結果を見てからフォールバックする機能の実装は容易と思います。

それから、ToUnicode CMap をちゃんと作るのも必要になります。たぶん cmap Subtable Format 4/12 から逆引きで作っているのですが(たぶん tt_cmap.c の otf_create_ToUnicode_stream)、どのあたりをいじれば Format 14 の VS の情報追加できるのか追いきれていません。 また、ToUnicode CMap に VS 付きで入れるべきなのか(あるいは VS を入れてはいけないのか)もよくわかっていません。

この辺はよく分からないのでノーコメントです。

【追記】 とりあえず動いている実験コードを https://github.com/h20y6m/tex-jp-build/tree/dvipdfmx_uvs_experiment_1 に置いておきます。

非常に参考になっています。ありがとうございます。

t-tk commented 8 months ago

3byte の内部トークンの文字コードから 4byteのDVIコードへの変換は、ptexencの中で、DVI出力の直前に行っています。 dviware 側で基底文字、異体字セレクタを取得する計算は単純になるので、dviware側の実装は容易になると思います。 今まで set3 まで対応できている dviwareを今回の 4byte コードに拡張する改造は容易になるとみています。

現状の試作品は、uptex で \kchar"C09083 のように内部トークンのコードを指定すればとりあえずの入力は出来ています。 今後、uptex側で buffer での UTF-8 の多バイト文字2個(基底文字 + VS) から内部トークンへ変換する仕組みを検討するつもりです。

テストを dvipdfm-x/dvipdfmx-upjf.test に追加しています。Haranoaji, IPAmj明朝 を使ってupLaTeX (\kchar使用)のソースから予定通りの出力結果が得られています。

t-tk commented 7 months ago

いろいろ検討した結果、文字コードを再び変えました。今度こそ確定のつもりです。

内部トークンの文字コード ::
SVS: 0x400000..0x7FFFFF の3byteで表現
IVS: 0x800000..0xFFFFFF の3byteで表現

DVIの文字コード ::
SVS: 0x400000..0x7FFFFF の3byte を set3 で出力、内部トークンと同じ符号
IVS(VS48まで): 0x800000..0xFFFFFF の3byte を set3 で出力、内部トークンと同じ符号
IVS(VS256まで): 0x01000000..0x100FFFFF の4byte を set4 で出力、uptex出力時に符号を変換
VS48超えはまだ定義されていないので当面3byteの範囲で収まる。

SVSは3byteなので JFMのグリフをchartype 0番以外に設定可能。
IVS(VS48まで)は3byteなので JFMのグリフをchartype 0番以外に設定可能。しかし、chartype 0番の全角グリフを想定。
IVS(VS256まで)はJFMで chartype 0番の全角グリフを想定。

DVIの文字コードでは、 0x3FFFF でマスクして得られる下位 18 bit が基底文字の Unicodeスカラー値に等しい。
SVS,IVSの異体字セレクタの部分をそれより上の上位bitで表現している。

◇SVS
内部トークン DVIコード 文字の順に
40hhhh  ##40hhhh  U+0hhhh U+0FE00 (VS01)
44hhhh  ##44hhhh  U+0hhhh U+0FE01 (VS02)
48hhhh  ##48hhhh  U+0hhhh U+0FE02 (VS03) (現状の最大値)
4Chhhh  ##4Chhhh  U+0hhhh U+0FE03 (VS04)
...
78hhhh  ##78hhhh  U+0hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
7Chhhh  ##7Chhhh  U+0hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

41hhhh  ##41hhhh  U+1hhhh U+0FE00 (VS01)
45hhhh  ##45hhhh  U+1hhhh U+0FE01 (VS02)
49hhhh  ##49hhhh  U+1hhhh U+0FE02 (VS03)
...
79hhhh  ##79hhhh  U+1hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
7Dhhhh  ##7Dhhhh  U+1hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

42hhhh  ##42hhhh  U+2hhhh U+0FE00 (VS01)
46hhhh  ##46hhhh  U+2hhhh U+0FE01 (VS02) (現状の最大値)
4Ahhhh  ##4Ahhhh  U+2hhhh U+0FE02 (VS03)
...
7Ahhhh  ##7Ahhhh  U+2hhhh U+0FE0E (VS15) (emoji-sequencesに現れる)
7Ehhhh  ##7Ehhhh  U+2hhhh U+0FE0F (VS16) (emoji-sequencesに現れる)

◇IVS
(VS17..VS32) U+2hhhhの現状最大はVS25, U+3hhhhの現状最大はVS17
(VS33..VS48) U+0hhhhの現状最大はVS48
(VS49..VS64) まだ無い
(VS65..VS80) まだ無い

内部トークン DVIコード 文字の順に
80hhhh  ##80hhhh  U+0hhhh U+E0100 (VS17)
84hhhh  ##84hhhh  U+0hhhh U+E0101 (VS18)
88hhhh  ##88hhhh  U+0hhhh U+E0102 (VS19)
...
F4hhhh  ##F4hhhh  U+0hhhh U+E011D (VS46)
F8hhhh  ##F8hhhh  U+0hhhh U+E011E (VS47)
FChhhh  ##FChhhh  U+0hhhh U+E011F (VS48) (U+0xxxxの現状の最大値) (現状ここまで可能)

82hhhh  ##82hhhh  U+2hhhh U+E0100 (VS17)
87hhhh  ##87hhhh  U+2hhhh U+E0101 (VS18)
8Ahhhh  ##8Ahhhh  U+2hhhh U+E0102 (VS19)
...
9Ahhhh  ##9Ahhhh  U+2hhhh U+E0106 (VS23)
9Ehhhh  ##9Ehhhh  U+2hhhh U+E0107 (VS24)
A2hhhh  ##A2hhhh  U+2hhhh U+E0108 (VS25) (U+2xxxxの現状の最大値)
...
BEhhhh  ##BEhhhh  U+2hhhh U+E010F (VS32) (現状ここまで可能)

83hhhh  ##83hhhh  U+3hhhh U+E0100 (VS17) (U+3xxxxの現状の最大値)
...
BFhhhh  ##BFhhhh  U+3hhhh U+E010F (VS32) (現状ここまで可能)

◇註
現状定義されている漢字のSVS,IVSはカバーできている。
きっと将来も現れないが
U+0hhhh の VS48超え
U+0hhhh の VS64超え
U+2hhhh の VS32超え
U+3hhhh の SVS
も余地がありそう。
t-tk commented 7 months ago

{,e}uptex の方は、kcatcode 20 modifier を新設しました。

基底文字 + modifier の順に入力バッファに現れた場合、内部トークンに変換する際に基底文字のトークンの文字コードを、今回の 3バイトの内部トークンの文字コードに書き換える。 内部トークンからバッファに書き戻す際には、基底文字 + modifier のUTF-8の文字列に書き換える。 基底文字 + modifier の合成ができなかった場合には modifier は普通のCJK文字のように扱われる。

例えば、<U+8279 U+FE00> の文字は、以下のどれでも出力可能。

`\kchar"408279`
 `\kchar"8279\kchar"FE00`
`艹︀`
`\Uchar"8279\Uchar"FE00`
t-tk commented 7 months ago

実装についてまとめます。

t-tk commented 6 months ago

upTeX の改造量が多めで少し不安もありますが、私の手元で想定通り動いているようなので ptexenc 1.5.0, upTeX ver 1.35, updvitype etc p240427, dviout-util 20240427, dvipdfmx 20240427 として TeX Live svn にコミットしました。 r71091 r71092 r71093 r71094

お気づきの点があればお知らせください。

t-tk commented 6 months ago

omfonts ver 2.2 r71118

h20y6m commented 6 months ago

begin-end の対応がずれていたのを https://github.com/texjporg/tex-jp-build/commit/320633cb07a13b73082a0c29ced8cdbe053adf41 で修正しました。 和文フォント未設定で和文文字ノードが作られたときに未初期化メモリを読んで内容次第でクラッシュしていました。 (pLaTeX カーネルで和文フォント未設定で和文文字ノードが作られていたようです→ https://github.com/texjporg/platex/commit/36cd846a93e49e958eee9f96025b9f54330222a6

h20y6m commented 6 months ago

まだ全然理解できていませんが、

という理解であっていますか?

TeX 言語から見た時の変化は

ほかにありますか?

t-tk commented 6 months ago

コメントありがとうございます。 以下は、こうしたつもり、こうなっているはず、ということです。違ったらご指摘お願いします。

これは yes です。ただし、以前からこれは同じだったはず。

少し書き足しました。

これは yes です。以前からと同じですが、0x408279 に意味があるところに今回新規のところと思います。

\Ucharの周辺のコードは意図して触ったつもりはありませんが、そのようになっていると思います。

これは yes です。そのように意図しています。

これは、あまり考えていなかったのですが差し支えありますか?

t-tk commented 5 months ago

変体仮名を upTeX 1.35 + dvipdfmx 20240427 + Noto Hentaigana font v1.000 で試しています。 横組みは想定通りできていますが、縦組みはなぜかずれます。原因の切り分けは未だです。

image


IPAmj明朝フォントだとずれませんでした。Noto Hentaigana fontの所為?

image

h20y6m commented 5 months ago

kcatcode=20 が追加された

これについては以下のパッケージが影響を受けそうなので TL2025 までに対応してもらう必要がありそうです。

(kcatcode=20 が有効かどうかの判定方法は? \uptexversion?)

  • \Uchar, \Ucharcat"220000 以上を指定したときに2トークンに展開されるようになった。
    • \kansujichar + \kansuji でも同様のことがおこる。

これは、あまり考えていなかったのですが差し支えありますか?

これらの展開結果が2トークンになるのはちょっとびっくりする結果かもしれません。 とはいえ意図的に 0x110000 以上の文字コードを使うことはないと思うので問題にはならないとは思います。


変体仮名を upTeX 1.35 + dvipdfmx 20240427 + Noto Hentaigana font v1.000 で試しています。 横組みは想定通りできていますが、縦組みはなぜかずれます。原因の切り分けは未だです。

IPAmj明朝フォントだとずれませんでした。Noto Hentaigana fontの所為?

Noto Hentaigana font は vmtx を持っていないみたいなので縦組みはダメそうですね。 (Ascender+Descender が 1.437em なのでその分の字幅がずれている?)

t-tk commented 5 months ago

Noto Hentaigana font は vmtx を持っていないみたいなので縦組みはダメそうですね。

これには軽い衝撃を受けました。 Noto serif CJKの記事を見ると、Noto font 自体が縦組みをサポートしない方針ということはなさそうですし、 Unicodeの縦組みのproperty The Vertical_Orientation Property (vo) VerticalOriantation.txtを見ても、変体仮名が平仮名片仮名と違っているわけでもなさそうです。 サポートしてほしいものです。

aminophen commented 4 months ago

全然追いつけていませんが,dviasm で 0x110000 以上の文字コードを扱えなかったので https://github.com/aminophen/dviasm/commit/1cd3ef2504dafa6a2b3f176ba5e39b91b78f8283 で対応してみました(まだテスト中…)。

t-tk commented 3 weeks ago

upTeX本体は upTeX u1.35 として TeX Live svnにコミット。r72531 uptex-base は 2024-10-12 としてCTANに投稿済み。

uptex-fonts は TeX Live 2025 コードフリーズの時期を狙ってCTANに投稿し、TL2025以降に入るようにする予定。