summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2019-05-02 21:10:43 +0000
committerKarl Berry <karl@freefriends.org>2019-05-02 21:10:43 +0000
commit8c5676efab90bcd994e66dd4c3ef5e64da0cb38d (patch)
tree5289f9b7c7ad9eda0590e9021a0201c7fffa1cc5 /Master/texmf-dist/tex/luatex
parent030b6070c99b9d787a0395499d75854156d46099 (diff)
luatexko (2may19)
git-svn-id: svn://tug.org/texlive/trunk@50924 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r--Master/texmf-dist/tex/luatex/luatexko/luatexko-core.sty506
-rw-r--r--Master/texmf-dist/tex/luatex/luatexko/luatexko-normalize.lua13
-rw-r--r--Master/texmf-dist/tex/luatex/luatexko/luatexko-uhc2utf8.lua40
-rw-r--r--Master/texmf-dist/tex/luatex/luatexko/luatexko.lua3182
-rw-r--r--Master/texmf-dist/tex/luatex/luatexko/luatexko.sty1101
5 files changed, 2061 insertions, 2781 deletions
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko-core.sty b/Master/texmf-dist/tex/luatex/luatexko/luatexko-core.sty
deleted file mode 100644
index 5572bc4ff06..00000000000
--- a/Master/texmf-dist/tex/luatex/luatexko/luatexko-core.sty
+++ /dev/null
@@ -1,506 +0,0 @@
-% luatexko-core.sty
-%
-% Copyright (c) 2013-2019 Dohyun Kim <nomos at ktug org>
-% Soojin Nam <jsunam at gmail com>
-%
-% This work may be distributed and/or modified under the
-% conditions of the LaTeX Project Public License, either version 1.3c
-% of this license or (at your option) any later version.
-% The latest version of this license is in
-% http://www.latex-project.org/lppl.txt
-% and version 1.3c or later is part of all distributions of LaTeX
-% version 2006/05/20 or later.
-
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname selectfont\endcsname\relax
- \input luaotfload.sty
- \ifcsname ifpdf\endcsname\else \input ifpdf.sty \fi
- \catcode`@ = 11
-\else
- \ProvidesPackage{luatexko-core}[2019/03/24 v1.23 Typesetting Korean with LuaTeX]
- \RequirePackage{luaotfload}[2016/04/21]
- \RequirePackage{ifpdf}
-\fi
-
-\ifdefined\fontid\else
- \let\fontid\luatexfontid % latex 2015/10/01
-\fi
-\ifdefined\newattribute\else % luaotfload 2.6
- \let\newattribute\newluatexattribute
- \let\unsetattribute\unsetluatexattribute
- \let\scantextokens\luatexscantextokens
- \let\luaescapestring\luatexluaescapestring
-\fi
-\ifdefined\pdfliteral\else % luatex 0.87
- \protected\def\pdfliteral{\pdfextension literal}
-\fi
-
-%% make hangul catcode 12
-\count@"1100
-\loop \catcode\count@ 12
- \ifnum\count@<"115F \advance\count@\@ne \repeat
-\count@"3131
-\loop \catcode\count@ 12
- \ifnum\count@<"318E \advance\count@\@ne \repeat
-\count@"A960
-\loop \catcode\count@ 12
- \ifnum\count@<"A97C \advance\count@\@ne \repeat
-\count@"AC00
-\loop \catcode\count@ 12
- \ifnum\count@<"D7A3 \advance\count@\@ne \repeat
-
-%% attributes
-\newattribute\finemathattr \finemathattr\tw@ % finemath on by default
-\newattribute\cjtypesetattr
-\newattribute\dotemphattr
-\newattribute\autojosaattr
-\newattribute\luakorubyattr \chardef\luakorubyattrnum\the\allocationnumber
-\newattribute\hangulfntattr
-\newattribute\hanjafntattr
-\newattribute\fallbackfntattr
-\newattribute\hangulpunctsattr
-
-%% load lua modules
-\directlua{require "luatexko"}
-
-%% japanese/chinese/pre-modern
-\protected\def\japanese{\frenchspacing\cjtypesetattr\@ne \parindent1em }
-\protected\def\Schinese{\frenchspacing\cjtypesetattr\tw@ \parindent2em }
-\protected\def\Tchinese{\frenchspacing\cjtypesetattr\thr@@\parindent2em }
-\let\chinese\Schinese
-% korean in japanese/chinese env.
-\protected\def\korean{\unsetattribute\cjtypesetattr}
-
-% inhibitglue
-\protected\def\inhibitglue{{\unsetattribute\cjtypesetattr\hskip\z@skip}}
-
-%% auto josa
-\def\josaignoreparens{\afterassignment\josa@ignore@parens\count@}
-\def\josa@ignore@parens{%
- \ifcase\count@ \chardef\josa@attr@level\@ne
- \else \chardef\josa@attr@level\tw@
- \fi
-}
-\josaignoreparens=\z@
-
-\protected\def\은{{\autojosaattr\josa@attr@level 은}}
-\let\는\은
-
-\protected\def\을{{\autojosaattr\josa@attr@level 을}}
-\let\를\을
-
-\protected\def\와{{\autojosaattr\josa@attr@level 와}}
-\let\과\와
-
-\protected\def\가{{\autojosaattr\josa@attr@level 가}}
-\protected\def\이{{\autojosaattr\josa@attr@level 이}}
-\protected\def\라{\이라}
-
-\protected\def\으{{\autojosaattr\josa@attr@level 으}}
-\protected\def\로{\으로}
-
-%% dot-emphasis
-\def\dotemphraise{0.4em }
-\unless\ifdefined\bfseries\let\bfseries\bf\fi
-\def\dotemphchar{\bfseries ^^^^02d9}
-\newcount\luakodotemphcnt \luakodotemphcnt\z@
-\protected\def\dotemph#1{{%
- \ifnum\luakodotemphcnt > 65535 \luakodotemphcnt\z@ \fi
- \global\advance\luakodotemphcnt\@ne
- \setbox\z@\hbox{\raise\dotemphraise\hbox{\dotemphchar}}\ht\z@\z@\dp\z@\z@
- \directlua{luatexko.dotemphnode[\the\luakodotemphcnt] = node.copy_list(tex.box[0])}%
- \dotemphattr\luakodotemphcnt #1}}
-
-%% ruby : ruby.sty by Lemberg is excellent; but
-%% it doesn't match well with luatexko, so implemented anew
-%% with plain tex support and enhanced features.
-\def\rubysize{0.6} % size of ruby compared to base character
-\def\rubysep{0.1ex} % distance between base character and ruby
-% users can define \rubyfont : eg. \font\rubyfont={foo:+ruby}
-\newif\ifruby@overlap
-\let\rubyoverlap\ruby@overlaptrue
-\let\rubynooverlap\ruby@overlapfalse
-\rubyoverlap % ruby may protrude over adjacent chars
-\newcount\luakorubyattrcnt\luakorubyattrcnt\z@
-\protected\def\ruby#1#2{%
- \ifnum\luakorubyattrcnt > 65535 \luakorubyattrcnt\z@ \fi
- \global\advance\luakorubyattrcnt\@ne
- \begingroup
- \setbox\z@\hbox attr\luakorubyattrnum\luakorubyattrcnt{% base character
- \vrule width\z@ height.88em depth\z@\relax #1}%
- \setbox\tw@\hbox{% ruby
- \ifdefined\rubyfont \rubyfont \fi
- \ifcsname selectfont\endcsname % latex
- \dimen@\dimexpr\rubysize em\relax
- \fontsize\dimen@\dimen@\selectfont
- \else % plain
- \luatexko@resize@font\font\resized@font\font\rubysize
- \ifdefined\hangul@font
- \luatexko@resize@font\hangulfont{}\hangul@font\rubysize
- \fi
- \ifdefined\hanja@font
- \luatexko@resize@font\hanjafont{}\hanja@font\rubysize
- \fi
- \ifdefined\fallback@font
- \luatexko@resize@font\fallbackfont{}\fallback@font\rubysize
- \fi
- \fi #2}\ht\tw@\z@\dp\tw@\z@
- \directlua{%
- luatexko.rubynode[\the\luakorubyattrcnt] = {
- node.copy_list(tex.box[2]),
- \number\numexpr\dimexpr\rubysep\relax\relax,
- \ifruby@overlap true\else false\fi}}%
- \leavevmode\box\z@
- \endgroup}
-
-\unless\ifcsname selectfont\endcsname
-% font resize under plain tex
-\begingroup\edef\x{\endgroup
- \def\noexpand\rem@vesizepart##1\detokenize{ at}##2\noexpand\end{##1}}\x
-\def\luatexko@resize@font#1#2#3#4{%
- \begingroup
- \edef\x@{\noexpand\rem@vesizepart\fontname#3\detokenize{ at}\noexpand\end}%
- \edef\y@{\endgroup#1\noexpand#2 \x@\space at#4\dimexpr\fontdimen6 #3\relax}%
- \y@#2}
-\fi
-
-% xxruby: consecutive ruby annotations
-\protected\def\xxruby#1#2{%
- \begingroup\def\basestr{#1}\def\rubystr{#2}\luako@xxrubyxx\endgroup
-}
-\def\luako@xxrubyxx{%
- \ifx\empty\basestr\else
- \expandafter\luako@ruby@get@base@char\basestr\end
- \expandafter\luako@ruby@get@ruby@char\rubystr\end
- \ruby\basechar\rubychar
- \expandafter\luako@xxrubyxx
- \fi
-}
-\def\luako@ruby@get@base@char#1#2\end{\def\basechar{#1}\def\basestr{#2}}
-\def\luako@ruby@get@ruby@char#1#2\end{\def\rubychar{#1}\def\rubystr{#2}}
-
-%% vertical typesetting
-%% EXPERIMENTAL code
-\def\luatexko@vertical{%
- \ifnum\cjtypesetattr<\@ne
- \cjtypesetattr\z@ % korean-vertical
- \spaceskip 0.5em plus 0.15em minus 0.06em
- \parindent 1em
- \fi
-}
-\protected\def\vertical#1{%
- \leavevmode
- \setbox\z@\vbox\bgroup
- \hsize#1\relax
- \luatexko@vertical
- \everypar{}%
- \leftskip\z@
- \rightskip\z@ }
-\protected\def\endvertical{\egroup\luatexkorotatebox\z@\box\z@}
-\protected\def\luatexkorotatebox#1{%
- \ifvbox#1\count@\@ne\else\count@\z@\fi
- \dimen@\wd#1\dimen@ii\dimexpr\ht#1+\dp#1\relax
- \setbox#1\ifnum\count@=\@ne
- \vbox to\dimen@\bgroup\hbox to\dimen@ii\bgroup\hfil\else
- \hbox to\dimen@ii\bgroup\vbox to\dimen@\bgroup\fi
- \wd#1\z@ \ht#1\z@ \dp#1\z@
- \luatexko@rotate@clockwise{\box#1}%
- \ifnum\count@=\@ne\egroup\vfil\else\vfil\egroup\hfil\fi\egroup}
-\def\luatexko@rotate@clockwise#1{%
- \ifpdf\pdfliteral{q 0 -1 1 0 0 0 cm}#1\pdfliteral{Q}%
- \else\special{pdf:btrans rotate -90}#1\special{pdf:etrans}%
- \fi
-}
-
-% do not veticalize headline/footline
-\ifcsname selectfont\endcsname % latex
- \def\verticaltypesetting{%
- \maxdepth\z@ \luatexko@vertical
- \dimen@\textwidth \textwidth\textheight \textheight\dimen@
- \edef\@outputpage{\unexpanded{\luatexkorotatebox\@outputbox
- \textwidth\textheight}\unexpanded\expandafter{\@outputpage}}}
-\else % plain
- \def\verticaltypesetting{%
- \dimen@\hsize\hsize\vsize\vsize\dimen@
- \edef\plainoutput{\unexpanded{\dimen@\hsize\hsize\vsize\vsize\dimen@}%
- \unexpanded\expandafter{\plainoutput}}%
- \def\pagebody{\setbox\z@\vbox to\hsize{\boxmaxdepth=\maxdepth
- \pagecontents}\luatexkorotatebox\z@\box\z@}%
- \maxdepth\z@ \luatexko@vertical}
-\fi
-
-% horizontal box inside vertical typesetting
-\protected\def\horizontal#1{%
- \setbox\z@\vbox\bgroup
- \ifnum\cjtypesetattr<\@ne
- \unsetattribute\cjtypesetattr
- \spaceskip\fontdimen2\font
- plus\fontdimen3\font
- minus\fontdimen4\font
- \fi
- \hsize#1\relax
- \everypar{}%
- \leftskip\z@
- \rightskip\z@
- \parindent\z@
-}
-\protected\def\endhorizontal{\egroup\luatexkounrotatebox\z@\box\z@}
-\protected\def\luatexkounrotatebox#1{%
- \leavevmode
- \vbox to\wd#1\bgroup
- \vfill
- \hbox to\dimexpr\ht#1+\dp#1\bgroup
- \wd#1\z@\ht#1\z@\dp#1\z@
- \luatexko@rotate@counterclockwise{\box#1}%
- \hfill
- \egroup
- \egroup
-}
-\def\luatexko@rotate@counterclockwise#1{%
- \ifpdf\pdfliteral{q 0 1 -1 0 0 0 cm}#1\pdfliteral{Q}%
- \else \special{pdf:btrans rotate 90}#1\special{pdf:etrans}%
- \fi
-}
-
-%% underline using post_linebreak_filter
-%% ulem doesn't work well with luatexko;
-%% especially linebreak does not occur inside cjk words.
-\def\ulinewidth{0.04em }
-\def\ulinedown {0.24em }
-\newcount\luakoulineboxcnt\luakoulineboxcnt\z@
-\chardef\luako@uline@level\z@ % for nested uline
-\def\luako@nested@ulinedown{% must be used in a group
- \ifcase\luako@uline@level\else
- \edef\ulinedown{\the\dimexpr\ulinedown+0.1em\relax}%
- \fi
- \chardef\luako@uline@level\@ne}
-\def\luako@uline@code@common{%
- \begingroup
- \ifnum\luakoulineboxcnt > 65535 \luakoulineboxcnt\z@ \fi
- \global\advance\luakoulineboxcnt\@ne
- \count@\luakoulineboxcnt
- \leavevmode}
-\protected\def\ulineluatexko#1{%
- \luako@uline@code@common
- \luako@nested@ulinedown
- \dimen@\dimexpr\ulinedown+\ulinewidth\relax
- \dimen@ii-\dimexpr\ulinedown\relax
- \setbox\z@\hbox{\vrule width\z@ height\dimen@ii depth\dimen@}%
- \directlua{ luatexko.uline_boundary(\the\count@,tex.box[0].head) }%
- #1\relax
- \directlua{ luatexko.uline_boundary(\the\count@) }%
- \endgroup}
-\let\uline\ulineluatexko
-\protected\def\sout#1{{\def\ulinedown{-0.5ex-\ulinewidth/2}\ulineluatexko{#1}}}
-\protected\def\uuline#1{\ulineluatexko{\ulineluatexko{#1}}}
-% ulem with arbitray box
-\protected\def\markoverwith#1#2{%
- \luako@uline@code@common
- \setbox\z@\hbox{#1}%
- \directlua{ luatexko.uline_boundary(\the\count@,tex.box[0]) }%
- #2\relax
- \directlua{ luatexko.uline_boundary(\the\count@) }%
- \endgroup}
-\protected\def\uwave{\ifx\ltxko@sixly\undefined \font\ltxko@sixly=lasy6 \fi
- \markoverwith{\lower4\p@\hbox{\ltxko@sixly\char58}}}
-\protected\def\xout {\markoverwith{\hbox to.35em{/\hss}}}
-\protected\def\dashuline#1{\begingroup
- \luako@nested@ulinedown
- \markoverwith{\kern.125em\vtop{\kern\ulinedown
- \hrule width.3em height\z@ depth\ulinewidth}\kern.125em}{#1}\endgroup}
-\protected\def\dotuline#1{\begingroup
- \luako@nested@ulinedown
- \dimen@\dimexpr\ulinedown+0.1ex\relax
- \markoverwith{\lower\dimen@\hbox{\kern.1em .\kern.04em}}{#1}\endgroup}
-
-%% hangul font -- core
-\def\luatexko@hangul@selectfont{%
- \ifdefined\hangul@font
- \begingroup
- \let\luatexko@hangul@selectfont\relax
- \let\luatexko@hanja@selectfont\relax
- \let\luatexko@fallback@selectfont\relax
- \hangul@font
- \expandafter\expandafter\expandafter
- \endgroup
- \expandafter\hangulfntattr\fontid\font\relax
- \fi
-}
-\def\luatexko@hanja@selectfont{%
- \ifdefined\hanja@font
- \begingroup
- \let\luatexko@hangul@selectfont\relax
- \let\luatexko@hanja@selectfont\relax
- \let\luatexko@fallback@selectfont\relax
- \hanja@font
- \expandafter\expandafter\expandafter
- \endgroup
- \expandafter\hanjafntattr\fontid\font\relax
- \fi
-}
-\def\luatexko@fallback@selectfont{%
- \ifdefined\fallback@font
- \begingroup
- \let\luatexko@hangul@selectfont\relax
- \let\luatexko@hanja@selectfont\relax
- \let\luatexko@fallback@selectfont\relax
- \fallback@font
- \expandafter\expandafter\expandafter
- \endgroup
- \expandafter\fallbackfntattr\fontid\font\relax
- \fi
-}
-
-% user interface for plain tex
-\protected\def\hangulfont
- {\afterassignment\luatexko@hangul@selectfont\font\hangul@font}
-\protected\def\hanjafont
- {\afterassignment\luatexko@hanja@selectfont \font\hanja@font }
-\protected\def\fallbackfont
- {\afterassignment\luatexko@fallback@selectfont\font\fallback@font}
-
-%% hangul in math mode -- general
-\def\setmathhangulblock#1#2{%
- \count@="#1
- \loop
- \Umathcode\count@ = 7 \symmathhangul \count@
- \ifnum\count@<"#2
- \advance\count@\@ne
- \repeat}
-\unless\ifcsname selectfont\endcsname
- % for plain; see luatexko.sty for latex
- \newfam\symmathhangul
- \def\setmathhangulfont#1#{\setmathhangul@font@}
- \def\setmathhangul@font@#1{%
- \font\tenhangul = "#1" at 10pt
- \font\sevenhangul = "#1" at 7pt
- \font\fivehangul = "#1" at 5pt
- \textfont\symmathhangul = \tenhangul
- \scriptfont\symmathhangul = \sevenhangul
- \scriptscriptfont\symmathhangul = \fivehangul}
- \setmathhangulblock{AC00}{D7A3}
-\fi
-
-%% hangul normalization
-\def\luatexhangulnormalize{\directlua{require "luatexko-normalize"}%
- \afterassignment\luatexh@ngulnorm@lize\count@}
-\def\luatexh@ngulnorm@lize{%
- \ifcase\count@ % 0: none
- \directlua{ luatexkonormalize.unload() }%
- \or % 1: nfc
- \directlua{ luatexkonormalize.compose() }%
- \else % 2: nfd
- \directlua{ luatexkonormalize.decompose() }%
- \fi}
-
-%% uhc to utf8
-\def\luatexuhcinputencoding{\directlua{require "luatexko-uhc2utf8"}%
- \afterassignment\luatexuhcinput@ncoding\count@}
-\def\luatexuhcinput@ncoding{%
- \ifcase\count@
- \directlua{ luatexkouhc2utf8.stopconvert() }%
- \else
- \directlua{ luatexkouhc2utf8.startconvert() }%
- \fi}
-
-%% uhc file names
-\def\luatexuhcfilenames{\directlua{require "luatexko-uhc2utf8"}%
- \afterassignment\luatexuhcfilen@mes\count@}
-\def\luatexuhcfilen@mes{%
- \ifcase\count@
- \directlua{ luatexkouhc2utf8.stop_uhc_filename() }%
- \else
- \directlua{ luatexkouhc2utf8.start_uhc_filename() }%
- \fi}
-
-%% use hangul font for hangul chars
-\def\hangulfontforhangul{\afterassignment\h@ngul@fontforh@ngul\count@}
-\let\hangulbyhangulfont\hangulfontforhangul
-\def\h@ngul@fontforh@ngul{%
- \ifcase\count@
- \directlua{ luatexko.hangulfontforhangul = false }%
- \else
- \directlua{ luatexko.hangulfontforhangul = true }%
- \fi}
-
-%% use hanja font for hanja chars
-\def\hanjafontforhanja{\afterassignment\h@nj@fontforh@nj@\count@}
-\let\hanjabyhanjafont\hanjafontforhanja
-\def\h@nj@fontforh@nj@{%
- \ifcase\count@
- \directlua{ luatexko.hanjafontforhanja = false }%
- \else
- \directlua{ luatexko.hanjafontforhanja = true }%
- \fi}
-
-% latin punctuations typeset with hangul fonts
-\def\hangulpunctuations{\afterassignment\h@ngulpunctu@tions\count@}
-\def\h@ngulpunctu@tions{%
- \ifcase\count@
- \unsetattribute\hangulpunctsattr
- \else
- \hangulpunctsattr\@ne
- \fi
-}
-\def\registerpunctuations#1{\registerpunctu@tions#1,*,}
-\def\registerpunctu@tions#1,{%
- \ifx\empty#1\empty
- \expandafter\registerpunctu@tions
- \else\ifx*#1\else
- \directlua{ luatexko.hangulpunctuations[\number#1]=true }
- \expandafter\expandafter\expandafter\registerpunctu@tions
- \fi\fi
-}
-\def\unregisterpunctuations#1{\unregisterpunctu@tions#1,*,}
-\def\unregisterpunctu@tions#1,{%
- \ifx\empty#1\empty
- \expandafter\unregisterpunctu@tions
- \else\ifx*#1\else
- \directlua{ luatexko.hangulpunctuations[\number#1]=nil }
- \expandafter\expandafter\expandafter\unregisterpunctu@tions
- \fi\fi
-}
-
-% Actual Text: beware that #2 should not be divided into separate pages.
-% \actualtext* variant inserts space char from phvr8r. see accsupp manual
-\protected\def\actualtext#1#{%
- \ifx\empty#1\empty
- \expandafter\actualtext@\expandafter!%
- \else
- \expandafter\actualtext@\expandafter*%
- \fi
-}
-\def\actualtext@{%
- \begingroup
- \catcode`\\=12 \catcode`\$=12 \catcode`\&=12 \catcode`\#=12
- \catcode`\^=12 \catcode`\_=12 \catcode`\~=12 %catcode`\%=12
- \actualtext@@
-}
-\def\actualtext@@#1#2{%
- \endgroup
- \luatexko@pdfspecial{/Span<</ActualText\directlua{
- luatexko.actualtext("\luaescapestring{\detokenize{#2}}")
- }>>BDC}%
- \scantextokens{#2}%
- \ifx*#1%
- \begingroup
- \ifdefined\actualtext@spacefont\else
- \global\font\actualtext@spacefont=phvr8r\relax
- \fi
- \setbox\z@\hbox{\actualtext@spacefont\char32}%
- \wd\z@\z@\ht\z@\z@\dp\z@\z@
- \leavevmode\copy\z@
- \endgroup
- \fi
- \luatexko@pdfspecial{EMC}%
-}
-\def\luatexko@pdfspecial#1{%
- \ifpdf\pdfliteral page{#1}%
- \else\special{pdf:content #1}%
- \fi
-}
-
-%% 말줄임표
-\def\hellipsis{^^^^2026^^^^2026}
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko-normalize.lua b/Master/texmf-dist/tex/luatex/luatexko/luatexko-normalize.lua
index b791a2497ff..895ee5b60c3 100644
--- a/Master/texmf-dist/tex/luatex/luatexko/luatexko-normalize.lua
+++ b/Master/texmf-dist/tex/luatex/luatexko/luatexko-normalize.lua
@@ -13,8 +13,8 @@
luatexbase.provides_module({
name = "luatexko-normalize",
- version = "1.23",
- date = "2019/03/24",
+ version = "2.0",
+ date = "2019/05/01",
author = "Dohyun Kim, Soojin Nam",
description = "Hangul normalization",
license = "LPPL v1.3+",
@@ -408,7 +408,6 @@ local byte = unicodeutf8.byte
local char = unicodeutf8.char
local find = unicodeutf8.find
local concat = table.concat
-local floor = math.floor
local add_to_callback = luatexbase.add_to_callback
local remove_from_callback = luatexbase.remove_from_callback
@@ -426,15 +425,15 @@ end
local syllable2jamo = function(s)
s = byte(s) - 0xac00
local t = {}
- t[1] = char(floor(s / 588) + 0x1100)
- t[2] = char(floor(s % 588 / 28) + 0x1161)
+ t[1] = char(s // 588 + 0x1100)
+ t[2] = char(s % 588 // 28 + 0x1161)
local jong = s % 28
t[3] = jong > 0 and char(jong + 0x11a7) or nil
return concat(t)
end
local hanguldecompose = function(buffer)
- return gsub(buffer, "[가-힣]", syllable2jamo)
+ return gsub(buffer, "[\234\176\128-\237\158\163]", syllable2jamo)
end
local function hanjanormalize(c)
@@ -457,7 +456,7 @@ local function jamo2cjamojung(c,t)
end
local hangulcompose = function(buffer)
- buffer = gsub(buffer, "[가-힣]"..jong, hanguldecompose)
+ buffer = gsub(buffer, "[\234\176\128-\237\158\163]"..jong, hanguldecompose)
buffer = gsub(buffer, "("..ncho..")("..njung..")("..jong.."?)", jamo2syllable)
buffer = gsub(buffer,
"([\225\132\128-\225\133\153])\225\133\160", jamo2cjamocho)
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko-uhc2utf8.lua b/Master/texmf-dist/tex/luatex/luatexko/luatexko-uhc2utf8.lua
index 70150f346ea..d23de4bc968 100644
--- a/Master/texmf-dist/tex/luatex/luatexko/luatexko-uhc2utf8.lua
+++ b/Master/texmf-dist/tex/luatex/luatexko/luatexko-uhc2utf8.lua
@@ -13,8 +13,8 @@
luatexbase.provides_module({
name = "luatexko-uhc2utf8",
- version = "1.23",
- date = "2019/03/24",
+ version = "2.0",
+ date = "2019/05/01",
author = "Dohyun Kim, Soojin Nam",
description = "UHC (CP949) input encoding",
license = "LPPL v1.3+",
@@ -24,12 +24,12 @@ luatexkouhc2utf8 = luatexkouhc2utf8 or {}
local luatexkouhc2utf8 = luatexkouhc2utf8
local format = string.format
+local utf8len = utf8.len
require "unicode"
local unicodeutf8 = unicode.utf8
local ugsub = unicodeutf8.gsub
local ubyte = unicodeutf8.byte
local uchar = unicodeutf8.char
-local floor = math.floor
local kpse_find_file = kpse.find_file
local add_to_callback = luatexbase.add_to_callback
local remove_from_callback = luatexbase.remove_from_callback
@@ -58,38 +58,10 @@ end
local t_uhc2ucs = t_uhc2ucs or get_uhc_uni_table()
-local function not_utf8lowbyte(t)
- for _,v in ipairs(t) do
- -- rough checking
- if v < 0x80 or v > 0xBF then return true end
- end
- return false
-end
-
local uhc_to_utf8 = function(buffer)
if not buffer then return end
- -- check if buffer is already utf-8; better solution?
- local i, buflen = 1, buffer:len()+1
- while i < buflen do
- local a = buffer:byte(i)
- if a < 0x80 then
- i = i + 1
- elseif a < 0xC2 then
- break
- elseif a < 0xE0 then
- if not_utf8lowbyte({buffer:byte(i+1)}) then break end
- i = i + 2
- elseif a < 0xF0 then
- if not_utf8lowbyte({buffer:byte(i+1,i+2)}) then break end
- i = i + 3
- elseif a < 0xF5 then
- if not_utf8lowbyte({buffer:byte(i+1,i+3)}) then break end
- i = i + 4
- else
- break
- end
- end
- if i == buflen then return nil end
+ -- check if buffer is already utf-8
+ if utf8len(buffer) then return nil end
-- now convert to utf8
buffer = buffer:gsub("([\129-\253])([\65-\254])",
function(a, b)
@@ -128,7 +100,7 @@ local function utf8_to_uhc (name)
function(u)
local c = t_ucs2uhc[ubyte(u)]
if c then
- return format("%c%c", floor(c/256), c%256)
+ return format("%c%c", c//256, c%256)
end
end)
return name
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua b/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
index 73acf5a4291..01a274bfeda 100644
--- a/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
+++ b/Master/texmf-dist/tex/luatex/luatexko/luatexko.lua
@@ -1,7 +1,7 @@
-- luatexko.lua
--
--- Copyright (c) 2013-2019 Dohyun Kim <nomos at ktug org>
--- Soojin Nam <jsunam at gmail com>
+-- Copyright (c) 2013-2019 Dohyun Kim <nomos at ktug org>
+-- Soojin Nam <jsunam at gmail com>
--
-- This work may be distributed and/or modified under the
-- conditions of the LaTeX Project Public License, either version 1.3c
@@ -13,1902 +13,1307 @@
luatexbase.provides_module {
name = 'luatexko',
- date = '2019/04/06',
- version = '1.24',
- description = 'Korean linebreaking and font-switching',
+ date = '2019/05/01',
+ version = '2.0',
+ description = 'typesetting Korean with LuaTeX',
author = 'Dohyun Kim, Soojin Nam',
license = 'LPPL v1.3+',
}
-luatexko = luatexko or {}
-local luatexko = luatexko
-
-local dotemphnode,rubynode = {},{}
-luatexko.dotemphnode = dotemphnode
-luatexko.rubynode = rubynode
-
-local stringbyte = string.byte
-local stringchar = string.char
-local stringformat = string.format
-local mathfloor = math.floor
-local tex_round = tex.round
-local tex_sp = tex.sp
-local texcount = tex.count
-local fontdefine = font.define
-
-local kpse_find_file = kpse.find_file
-
-local fontdata = fonts.hashes.identifiers
-
-local finemathattr = luatexbase.attributes.finemathattr
-local cjtypesetattr = luatexbase.attributes.cjtypesetattr
-local dotemphattr = luatexbase.attributes.dotemphattr
-local autojosaattr = luatexbase.attributes.autojosaattr
-local luakorubyattr = luatexbase.attributes.luakorubyattr
-local hangulfntattr = luatexbase.attributes.hangulfntattr
-local hanjafntattr = luatexbase.attributes.hanjafntattr
-local fallbackfntattr = luatexbase.attributes.fallbackfntattr
-local hangulpunctsattr = luatexbase.attributes.hangulpunctsattr
-local luakoglueattr = luatexbase.new_attribute("luakoglueattr")
-local luakounicodeattr = luatexbase.new_attribute("luakounicodeattr")
-local luakoulineattr = luatexbase.new_attribute("luakoulineattr")
-
-local function warn (...)
- return luatexbase.module_warning("luatexko", stringformat(...))
+luatexko = luatexko or {}
+local luatexko = luatexko
+
+local dimensions = node.dimensions
+local end_of_math = node.end_of_math
+local getglue = node.getglue
+local getnext = node.getnext
+local getprev = node.getprev
+local getproperty = node.getproperty
+local has_attribute = node.has_attribute
+local has_glyph = node.has_glyph
+local insert_after = node.insert_after
+local insert_before = node.insert_before
+local nodecopy = node.copy
+local nodecount = node.count
+local nodefree = node.free
+local nodeid = node.id
+local nodenew = node.new
+local noderemove = node.remove
+local nodeslide = node.slide
+local nodesubtype = node.subtype
+local nodewrite = node.write
+local rangedimensions = node.rangedimensions
+local setglue = node.setglue
+local setproperty = node.setproperty
+local unset_attribute = node.unset_attribute
+
+local fontcurrent = font.current
+local fontfonts = font.fonts
+local fontgetfont = font.getfont
+local getparameters = font.getparameters
+
+local texcount = tex.count
+local texround = tex.round
+local texset = tex.set
+local texsp = tex.sp
+
+local stringformat = string.format
+
+local tableconcat = table.concat
+local tableinsert = table.insert
+
+local add_to_callback = luatexbase.add_to_callback
+local attributes = luatexbase.attributes
+local call_callback = luatexbase.call_callback
+local create_callback = luatexbase.create_callback
+local module_warning = luatexbase.module_warning
+local new_user_whatsit = luatexbase.new_user_whatsit
+local new_user_whatsit_id = luatexbase.new_user_whatsit_id
+local registernumber = luatexbase.registernumber
+
+local function warning (...)
+ return module_warning("luatexko", stringformat(...))
+end
+
+local dirid = nodeid"dir"
+local discid = nodeid"disc"
+local glueid = nodeid"glue"
+local glyphid = nodeid"glyph"
+local hlistid = nodeid"hlist"
+local kernid = nodeid"kern"
+local mathid = nodeid"math"
+local penaltyid = nodeid"penalty"
+local ruleid = nodeid"rule"
+local vlistid = nodeid"vlist"
+local whatsitid = nodeid"whatsit"
+local literal_whatsit = nodesubtype"pdf_literal"
+local user_whatsit = nodesubtype"user_defined"
+local directmode = 2
+local fontkern = 0
+local userkern = 1
+local italcorr = 3
+local lua_number = 100
+local lua_value = 108
+local spaceskip = 13
+local xleaders = 102
+local nohyphen = registernumber"l@nohyphenation" or -1 -- verbatim
+
+local hangulfontattr = attributes.luatexkohangulfontattr
+local hanjafontattr = attributes.luatexkohanjafontattr
+local fallbackfontattr = attributes.luatexkofallbackfontattr
+local autojosaattr = attributes.luatexkoautojosaattr
+local classicattr = attributes.luatexkoclassicattr
+local dotemphattr = attributes.luatexkodotemphattr
+local rubyattr = attributes.luatexkorubyattr
+
+local vert_classic = 1
+local SC_classic = 2
+
+local function is_hanja (c)
+ return (c >= 0x3400 and c <= 0xA4C6)
+ or (c >= 0xF900 and c <= 0xFAD9)
+ or (c >= 0x20000 and c <= 0x2FFFD)
+ or (c >= 0x2E81 and c <= 0x2FD5)
end
-local function add_to_callback (name, func, desc, pos)
- local t = {{func, desc}}
- if pos then
- for i,v in ipairs(luatexbase.callback_descriptions(name)) do
- if i >= pos then
- t[#t+1] = {luatexbase.remove_from_callback(name, v)}
- end
- end
- end
- for i,v in ipairs(t) do
- luatexbase.add_to_callback(name, v[1], v[2])
- end
+local function is_hangul (c)
+ return (c >= 0xAC00 and c <= 0xD7A3)
+end
+
+local function is_chosong (c)
+ return (c >= 0x1100 and c <= 0x115F)
+ or (c >= 0xA960 and c <= 0xA97C)
+end
+
+local function is_jungsong (c)
+ return (c >= 0x1160 and c <= 0x11A7)
+ or (c >= 0xD7B0 and c <= 0xD7C6)
+end
+
+local function is_jongsong (c)
+ return (c >= 0x11A8 and c <= 0x11FF)
+ or (c >= 0xD7CB and c <= 0xD7FB)
end
-local glue_type_space = 13
-local kern_type_itlc = 3
-
-local discnode = node.id("disc")
-local gluenode = node.id("glue")
-local glyphnode = node.id("glyph")
-local mathnode = node.id("math")
-local hlistnode = node.id("hlist")
-local vlistnode = node.id("vlist")
-local kernnode = node.id("kern")
-local penaltynode = node.id("penalty")
-local rulenode = node.id("rule")
-local whatsitnode = node.id("whatsit")
-local user_whatsit = node.subtype("user_defined")
-local n_copy_list = node.copy_list
-
-local nodedirect = node.direct
-local d_getdisc = nodedirect.getdisc
-local d_todirect = nodedirect.todirect
-local d_tonode = nodedirect.tonode
-local d_has_field = nodedirect.has_field
-local d_copy_node = nodedirect.copy
-local d_getid = nodedirect.getid
-local d_getfield = nodedirect.getfield
-local d_setfield = nodedirect.setfield
-local d_getsubtype = nodedirect.getsubtype
-local d_setsubtype = nodedirect.setsubtype
-local d_getchar = nodedirect.getchar
-local d_setchar = nodedirect.setchar
-local d_getfont = nodedirect.getfont
-local d_getlist = nodedirect.getlist
-local d_setlist = nodedirect.setlist
-local d_getnext = nodedirect.getnext
-local d_setnext = nodedirect.setnext
-local d_getprev = nodedirect.getprev
-local d_setprev = nodedirect.setprev
-local d_setleader = nodedirect.setleader
-local d_getglue = nodedirect.getglue
-local d_setglue = nodedirect.setglue
-local d_has_attribute = nodedirect.has_attribute
-local d_set_attribute = nodedirect.set_attribute
-local d_unset_attribute = nodedirect.unset_attribute
-local d_traverse = nodedirect.traverse
-local d_traverse_id = nodedirect.traverse_id
-local d_insert_before = nodedirect.insert_before
-local d_insert_after = nodedirect.insert_after
-local d_remove_node = nodedirect.remove
-local d_nodenew = nodedirect.new
-local d_nodecount = nodedirect.count
-local d_end_of_math = nodedirect.end_of_math
-local d_nodetail = nodedirect.slide -- tail seems to be no good
-local d_nodedimensions = nodedirect.dimensions
-local d_nodefree = nodedirect.free
-local d_nodewrite = nodedirect.write
-local d_node_zero_glue = nodedirect.is_zero_glue
-
-local emsize = 655360
-
-local cjkclass = {
- [0x2018] = 1, -- ‘
- [0x201C] = 1, -- “
- [0x2329] = 1, -- 〈
- [0x3008] = 1, -- 〈
- [0x300A] = 1, -- 《
- [0x300C] = 1, -- 「
- [0x300E] = 1, -- 『
- [0x3010] = 1, -- 【
- [0x3014] = 1, -- 〔
- [0x3016] = 1, -- 〖
- [0x3018] = 1, -- 〘
- [0x301A] = 1, -- 〚
- [0x301D] = 1, -- 〝
- [0xFE17] = 1, -- ︗
- [0xFE35] = 1, -- ︵
- [0xFE37] = 1, -- ︷
- [0xFE39] = 1, -- ︹
- [0xFE3B] = 1, -- ︻
- [0xFE3D] = 1, -- ︽
- [0xFE3F] = 1, -- ︿
- [0xFE41] = 1, -- ﹁
- [0xFE43] = 1, -- ﹃
- [0xFE47] = 1, -- ﹇
- [0xFF08] = 1, -- (
- [0xFF3B] = 1, -- [
- [0xFF5B] = 1, -- {
- [0xFF5F] = 1, -- ⦅
- [0xFF62] = 1, -- 「 half
- [0x2019] = 2, -- ’
- [0x201D] = 2, -- ”
- [0x232A] = 2, -- 〉
- [0x3001] = 2, -- 、
- [0x3009] = 2, -- 〉
- [0x300B] = 2, -- 》
- [0x300D] = 2, -- 」
- [0x300F] = 2, -- 』
- [0x3011] = 2, -- 】
- [0x3015] = 2, -- 〕
- [0x3017] = 2, -- 〗
- [0x3019] = 2, -- 〙
- [0x301B] = 2, -- 〛
- [0x301E] = 2, -- 〞
- [0x301F] = 2, -- 〟
- [0xFE10] = 2, -- ︐
- [0xFE11] = 2, -- ︑
- [0xFE18] = 2, -- ︘
- [0xFE36] = 2, -- ︶
- [0xFE38] = 2, -- ︸
- [0xFE3A] = 2, -- ︺
- [0xFE3C] = 2, -- ︼
- [0xFE3E] = 2, -- ︾
- [0xFE40] = 2, -- ﹀
- [0xFE42] = 2, -- ﹂
- [0xFE44] = 2, -- ﹄
- [0xFE48] = 2, -- ﹈
- [0xFF09] = 2, -- )
- [0xFF0C] = 2, -- ,
- [0xFF3D] = 2, -- ]
- [0xFF5D] = 2, -- }
- [0xFF60] = 2, -- ⦆
- [0xFF63] = 2, -- 」 half
- [0xFF64] = 2, -- 、 half
- [0x00B7] = 3, -- ·
- [0x30FB] = 3, -- ・
- [0xFF1A] = 3, -- :
- [0xFF1B] = 3, -- ;
- [0xFF65] = 3, -- ・ half
- [0x3002] = 4, -- 。
- [0xFE12] = 4, -- ︒
- [0xFF0E] = 4, -- .
- [0xFF61] = 4, -- 。 half
- [0x2015] = 5, -- ―
- [0x2025] = 5, -- ‥
- [0x2026] = 5, -- …
- [0xFE19] = 5, -- ︙
- [0xFE30] = 5, -- ︰
- [0xFE31] = 5, -- ︱
- [0xFE15] = 6, -- ︕
- [0xFE16] = 6, -- ︖
- [0xFF01] = 6, -- !
- [0xFF1F] = 6, -- ?
+local hangul_tonemark = {
+ [0x302E] = true, [0x302F] = true,
}
-local inhibitxspcode = setmetatable({
- [0x002D] = 0, -- - hyphen minus
- [0x003C] = 0, -- <
- [0x003E] = 1, -- >
- [0x00B0] = 1, -- °
- [0x2032] = 1, -- ′
- [0x2033] = 1, -- ″
- [0x25CC] = 2, -- dotted circle
- [0x3012] = 2, -- 〒
- [0x301C] = 0, -- 〜
- [0xFE14] = 1, -- ︔
- [0xFF1B] = 1, -- ;
- [0xFFE5] = 0, -- ¥
-},{
- __index = function (_,c)
- if cjkclass[c] == 1 then
- return 2
- elseif cjkclass[c] == 2 or cjkclass[c] == 4 or cjkclass[c] == 6 then
- return 1
- elseif cjkclass[c] == 5 then
- return 0
- end
- end
-})
+local function is_unicode_vs (c)
+ return (c >= 0xFE00 and c <= 0xFE0F)
+ or (c >= 0xE0100 and c <= 0xE01EF)
+end
-local postbreakpenalty = setmetatable({
- [0x0023] = 500,
- [0x0024] = 500,
- [0x0025] = 500,
- [0x0026] = 500,
- [0x0028] = 10000,
- [0x003C] = 10000, -- <
- [0x005B] = 10000,
- [0x0060] = 10000,
- [0x007B] = 10000, -- {
- [0x00AB] = 10000, -- «
- [0x2013] = 50, -- en-dash
- [0x2014] = 50, -- em-dash
- [0xFF03] = 200,
- [0xFF04] = 200,
- [0xFF05] = 200,
- [0xFF06] = 200,
- [0xFF40] = 10000, -- `
-},{
- __index = function (_,c)
- if cjkclass[c] == 1 then
- return 10000
- end
+local function is_cjk_combining (c)
+ return (c >= 0x302A and c <= 0x302F)
+ or (c >= 0x3099 and c <= 0x309C)
+ or (c >= 0xFF9E and c <= 0xFF9F)
+ or is_unicode_vs(c)
+end
+
+local function is_noncjkletter (c)
+ return (c >= 0x30 and c <= 0x39)
+ or (c >= 0x41 and c <= 0x5A)
+ or (c >= 0x61 and c <= 0x7A)
+ or (c >= 0xC0 and c <= 0xD6)
+ or (c >= 0xD8 and c <= 0xF6)
+ or (c >= 0xF8 and c <= 0x10FC)
+ or (c >= 0x1200 and c <= 0x1FFE)
+ or (c >= 0xA4D0 and c <= 0xA877)
+ or (c >= 0xAB01 and c <= 0xABBF)
+ or (c >= 0xFB00 and c <= 0xFDFD)
+ or (c >= 0xFE70 and c <= 0xFEFC)
+end
+
+local function is_kana (c)
+ return (c >= 0x3041 and c <= 0x3096)
+ or (c >= 0x30A1 and c <= 0x30FA)
+ or (c >= 0x31F0 and c <= 0x31FF)
+ or (c >= 0xFF66 and c <= 0xFF6F)
+ or (c >= 0xFF71 and c <= 0xFF9D)
+ or c == 0x309F or c == 0x30FF
+ or (c >= 0x1B000 and c <= 0x1B16F)
+end
+
+local function is_hangul_jamo (c)
+ return is_hangul(c)
+ or is_chosong(c)
+ or is_jungsong(c)
+ or is_jongsong(c)
+ or (c >= 0x3131 and c <= 0x318E)
+end
+
+local stretch_f, shrink_f = 5/100, 3/100 -- should be consistent for ruby
+
+local function get_font_data (fontid)
+ return fontgetfont(fontid) or fontfonts[fontid] or {}
+end
+
+local function get_en_size (f)
+ local pm
+ if type(f) == "number" then
+ pm = getparameters(f)
+ elseif type(f) == "table" then
+ pm = f.parameters
end
-})
+ return pm and pm.quad and pm.quad/2 or 327680
+end
-local prebreakpenalty = setmetatable({
- [0x0021] = 10000,
- [0x0022] = 10000,
- [0x0027] = 10000,
- [0x0029] = 10000,
- [0x002A] = 5000, -- 500, -- *
- [0x002B] = 5000, -- 500, -- +
- [0x002C] = 10000,
- [0x002D] = 10000,
- [0x002E] = 10000,
- [0x002F] = 5000, -- 500, -- /
- [0x003A] = 10000,
- [0x003B] = 10000,
- [0x003E] = 10000, -- >
- [0x003F] = 10000,
- [0x005D] = 10000,
- [0x007D] = 10000, -- }
- [0x00B4] = 10000, -- ´
- [0x00BB] = 10000, -- »
- [0x2013] = 10000, -- –
- [0x2014] = 10000, -- —
- [0x2025] = 5000, -- 250, -- ‥
- [0x2026] = 5000, -- 250, -- …
- [0x2212] = 5000, -- 200, -- − minus sign
- [0x3005] = 10000, -- 々
- [0x301C] = 10000, -- 〜
- [0x3035] = 10000, -- 〵
- [0x303B] = 10000, -- 〻
- [0x3041] = 150,
- [0x3043] = 150,
- [0x3045] = 150,
- [0x3047] = 150,
- [0x3049] = 150,
- [0x3063] = 150,
- [0x3083] = 150,
- [0x3085] = 150,
- [0x3087] = 150,
- [0x308E] = 150,
- [0x3095] = 150,
- [0x3096] = 150,
- [0x309B] = 10000, -- ゛
- [0x309C] = 10000, -- ゜
- [0x309D] = 10000, -- ゝ
- [0x309E] = 10000, -- ゞ
- [0x30A0] = 10000, -- ゠
- [0x30A1] = 150,
- [0x30A3] = 150,
- [0x30A5] = 150,
- [0x30A7] = 150,
- [0x30A9] = 150,
- [0x30C3] = 150,
- [0x30E3] = 150,
- [0x30E5] = 150,
- [0x30E7] = 150,
- [0x30EE] = 150,
- [0x30F5] = 150,
- [0x30F6] = 150,
- [0x30FC] = 10000, -- ー
- [0x30FD] = 10000, -- ヽ
- [0x30FE] = 10000, -- ヾ
- [0xFE13] = 10000, -- ︓
- [0xFE14] = 10000, -- ︔
- [0xFE19] = 5000, -- 250, -- ︙
- [0xFE30] = 5000, -- 250, -- ︰
- [0xFE32] = 10000, -- ︲
- [0xFF0B] = 5000, -- 200, -- +
- [0xFF1D] = 5000, -- 200, -- =
- [0xFF9E] = 10000, -- ゙
- [0xFF9F] = 10000, -- ゚
-},{
- __index = function (_,c)
- if cjkclass[c] and cjkclass[c] > 1 then
- return 10000
- end
+local function char_in_font(fontdata, char)
+ if type(fontdata) == "number" then
+ fontdata = get_font_data(fontdata)
end
-})
+ if fontdata.characters then
+ return fontdata.characters[char]
+ end
+end
-local xspcode = {
- [0x0027] = 2,
- [0x0028] = 1,
- [0x0029] = 2,
- [0x002C] = 2,
- [0x002E] = 2,
- [0x003B] = 2,
- [0x005B] = 1,
- [0x005D] = 2,
- [0x0060] = 1,
-}
+local function option_in_font (fontdata, optionname)
+ if type(fontdata) == "number" then
+ fontdata = get_font_data(fontdata)
+ end
+ if fontdata.shared then
+ return fontdata.shared.features[optionname]
+ end
+end
-local cjk_glue_spec = { [0] =
--- 한자 ( ) · . — ? 한글 초성 중종성 latin
-{[0] = nil, {.5,.5}, nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, --한자
-{[0] = nil, nil, nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, -- (
-{[0] = {.5,.5}, {.5,.5}, nil, {.25,.25},nil, {.5,.5}, {.5,.5}, {.25,.25},{.25,.25},{.25,.25},{.5,.5}, }, -- )
-{[0] = {.25,.25},{.25,.25},{.25,.25},{.5,.25}, {.25,.25},{.25,.25},{.25,.25},{.25,.25},{.25,.25},{.25,.25},{.25,.25},}, -- ·
-{[0] = {.5,0}, {.5,0}, nil, {.75,.25},nil, {.5,0}, {.5,0}, {.5,0}, {.5,0}, {.5,0}, {.5,0}, }, -- .
-{[0] = nil, {.5,.5}, nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, -- —
-{[0] = {.5,.5}, {.5,.5}, nil, {.25,.25},nil, nil, nil, {.5,.5}, {.5,.5}, {.5,.5}, {.5,.5}, }, -- ?
---
-{[0] = nil, {.25,.25},nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, --한글
-{[0] = nil, {.25,.25},nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, --초성
-{[0] = nil, {.25,.25},nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, --중종성
-{[0] = nil, {.5,.5}, nil, {.25,.25},nil, nil, nil, nil, nil, nil, nil, }, --latin
-}
+local function my_node_props (n)
+ local t = getproperty(n)
+ if not t then
+ t = {}
+ setproperty(n, t)
+ end
+ t.luatexko = t.luatexko or {}
+ return t.luatexko
+end
-local latin_fullstop = {
- [0x2e] = 1, -- .
- -- [0x21] = 2, -- !
- -- [0x2c] = 2, -- ,
- -- [0x3f] = 2, -- ?
- -- [0x2026] = 1, -- \ldots
-}
+-- font fallback
-local hangulpunctuations = luatexko.hangulpunctuations or {
+local force_hangul = {
[0x21] = true, -- !
[0x27] = true, -- '
[0x28] = true, -- (
[0x29] = true, -- )
[0x2C] = true, -- ,
- -- [0x2D] = true, -- -
[0x2E] = true, -- .
[0x3A] = true, -- :
[0x3B] = true, -- ;
- [0x3C] = true, -- <
- [0x3E] = true, -- >
[0x3F] = true, -- ?
- [0x5B] = true, -- [
- [0x5D] = true, -- ]
[0x60] = true, -- `
- [0x7B] = true, -- {
- [0x7D] = true, -- }
- [0xB7] = true, -- periodcentered
- -- [0x2014] = true, -- emdash
- -- [0x2015] = true, -- horizontal bar
- [0x2018] = true, -- quoteleft
- [0x2019] = true, -- quoteright
- [0x201C] = true, -- quotedblleft
- [0x201D] = true, -- quotedblright
- [0x2026] = true, -- ellipsis
+ [0xB7] = true, -- ·
+ [0x2014] = true, -- —
+ [0x2015] = true, -- ―
+ [0x2018] = true, -- ‘
+ [0x2019] = true, -- ’
+ [0x201C] = true, -- “
+ [0x201D] = true, -- ”
+ [0x2026] = true, -- …
[0x203B] = true, -- ※
}
-luatexko.hangulpunctuations = hangulpunctuations
-
-local josa_list = {
- -- 리을, 중성, 종성
- [0xAC00] = {0xC774, 0xAC00, 0xC774}, -- 가 = 이, 가, 이
- [0xC740] = {0xC740, 0xB294, 0xC740}, -- 은 = 은, 는, 은
- [0xC744] = {0xC744, 0xB97C, 0xC744}, -- 을 = 을, 를, 을
- [0xC640] = {0xACFC, 0xC640, 0xACFC}, -- 와 = 과, 와, 과
- [0xC73C] = {-1, -1, 0xC73C}, -- 으(로) = , , 으
- [0xC774] = {0xC774, -1, 0xC774}, -- 이(라) = 이, , 이
-}
-
-local josa_code = {
- [0x30] = 3, -- 0
- [0x31] = 1, -- 1
- [0x33] = 3, -- 3
- [0x36] = 3, -- 6
- [0x37] = 1, -- 7
- [0x38] = 1, -- 8
- [0x4C] = 1, -- L
- [0x4D] = 3, -- M
- [0x4E] = 3, -- N
- [0x6C] = 1, -- l
- [0x6D] = 3, -- m
- [0x6E] = 3, -- n
- [0xFB02] = 1, -- fl
- [0xFB04] = 1, -- ffl
- ng = 3,
- ap = 3,
- up = 3,
- at = 3,
- et = 3,
- it = 3,
- ot = 3,
- ut = 3,
- ok = 3,
- ic = 3,
- le = 1,
- ime = 3,
- ine = 3,
- ack = 3,
- ick = 3,
- oat = 2,
- TEX = 3,
- -- else 2
-}
-
-local function d_get_gluenode (...)
- local g = d_nodenew(gluenode)
- d_setglue(g, ...)
- return g
-end
-
-local function d_get_penaltynode (n)
- local p = d_nodenew(penaltynode)
- d_setfield(p,"penalty", n or 0)
- return p
-end
+luatexko.forcehangulchars = force_hangul
-local function d_get_kernnode (n)
- local k = d_nodenew(kernnode,1)
- d_setfield(k,"kern", n or 0)
- return k
-end
+local forcehf_f, forcehf_id = new_user_whatsit("forcehf","luatexko")
-local function d_get_rulenode (w,h,d)
- local r = d_nodenew(rulenode)
- d_setfield(r,"width", w or 0)
- d_setfield(r,"height", h or 0)
- d_setfield(r,"depth", d or 0)
- return r
+local function update_force_hangul (value)
+ local what = forcehf_f()
+ what.type = lua_value -- function
+ what.value = value
+ nodewrite(what)
end
+luatexko.updateforcehangul = update_force_hangul
-local function d_make_luako_glue(...)
- local glue = d_get_gluenode(...)
- d_set_attribute(glue,luakoglueattr,1)
- return glue
-end
-
-local function is_cjk_k (c)
- return (c >= 0x2E80 and c <= 0x9FFF )
- or (c >= 0xF900 and c <= 0xFAFF )
- or (c >= 0xFE10 and c <= 0xFE1F )
- or (c >= 0xFE30 and c <= 0xFE4F )
- or (c >= 0xFF00 and c <= 0xFFEF )
- or (c >= 0x20000 and c <= 0x2FFFD)
- or c == 0x00B0 or c == 0x2015
- -- or c == 0x2018 or c == 0x2019
- -- or c == 0x201C or c == 0x201D
- or c == 0x2026 or c == 0x2032
- or c == 0x2033
-end
+local active_processes = {}
-local function is_hanja (c)
- return (c >= 0x3400 and c <= 0x9FFF )
- or (c >= 0xF900 and c <= 0xFAFF )
- or (c >= 0x20000 and c <= 0x2FFFD)
-end
+local char_font_options ={
+ interhangul = {},
+ interlatincjk = {},
+ intercharacter = {},
+ hangulspaceskip = {},
+ tonemarkwidth = {},
+}
-local function is_hangul (c)
- return (c >= 0xAC00 and c <= 0xD7A3)
+local function hangul_space_skip (curr, newfont)
+ if curr.lang ~= nohyphen then
+ local n = getnext(curr)
+ if n and n.id == glueid and n.subtype == spaceskip then
+ local params = getparameters(curr.font)
+ local oldwd, oldst, oldsh, oldsto, oldsho = getglue(n)
+ if oldwd == params.space
+ and oldst == params.space_stretch
+ and oldsh == params.space_shrink
+ and oldsto == 0
+ and oldsho == 0 then -- not user's spaceskip
+
+ local newwd = char_font_options.hangulspaceskip[newfont]
+ if newwd == nil then
+ local newsp = nodecopy(curr)
+ newsp.char, newsp.font = 32, newfont
+ newsp = nodes.simple_font_handler(newsp)
+ newwd = newsp and newsp.width or false
+ if newwd then
+ newwd = { texround(newwd), texround(newwd/2), texround(newwd/3) }
+ end
+ char_font_options.hangulspaceskip[newfont] = newwd
+ if newsp then
+ nodefree(newsp)
+ end
+ end
+ if newwd then
+ setglue(n, newwd[1], newwd[2], newwd[3])
+ end
+ end
+ end
+ end
end
-local function is_chosong (c)
- return (c >= 0x1100 and c <= 0x115F)
- or (c >= 0xA960 and c <= 0xA97C)
-end
+local function process_fonts (head)
+ local curr = head
+ while curr do
+ local id = curr.id
+ if id == glyphid then
+ local props = my_node_props(curr)
+ if not props.unicode then
+
+ local c = curr.char
+
+ if is_unicode_vs(c) then
+ local p = getprev(curr)
+ if p.id == glyphid and curr.font ~= p.font then
+ hangul_space_skip(curr, p.font)
+ curr.font = p.font
+ end
-local function is_jungjongsong (c)
- return (c >= 0x1160 and c <= 0x11FF)
- or (c >= 0xD7B0 and c <= 0xD7Fb)
- or c == 0x302E or c == 0x302F -- tone marks
-end
+ else
+ local hf = has_attribute(curr, hangulfontattr) or false
+ local hjf = has_attribute(curr, hanjafontattr) or false
+ local fontdata = get_font_data(curr.font)
+ local format = fontdata.format
+ local no_legacy = format == "opentype" or format == "truetype"
+ if hf and no_legacy and force_hangul[c] and curr.lang ~= nohyphen then
+ curr.font = hf
+ elseif hf and luatexko.hangulbyhangulfont and is_hangul_jamo(c) then
+ hangul_space_skip(curr, hf)
+ curr.font = hf
+ elseif hjf and luatexko.hanjabyhanjafont and is_hanja(c) then
+ hangul_space_skip(curr, hjf)
+ curr.font = hjf
+ elseif not char_in_font(fontdata, c) then
+ local fbf = has_attribute(curr, fallbackfontattr) or false
+ for _,f in ipairs{ hf, hjf, fbf } do
+ if f and char_in_font(f, c) then
+ hangul_space_skip(curr, f)
+ curr.font = f
+ break
+ end
+ end
+ end
+ end
-local function is_unicode_vs (c)
- return (c >= 0xFE00 and c <= 0xFE0F )
- or (c >= 0xE0100 and c <= 0xE01EF)
-end
+ if not active_processes.reorderTM
+ and hangul_tonemark[c]
+ and option_in_font(curr.font, "script") == "hang" then
+ luatexko.activate("reorderTM") -- activate reorderTM here
+ active_processes.reorderTM = true
+ end
-local function get_cjk_class (ch, cjtype)
- if ch then
- if is_hangul(ch) then return 7 end -- hangul = 7
- if is_chosong(ch) then return 8 end -- jamo LC = 8
- if is_jungjongsong(ch) then return 9 end -- jamo VL, TC, TM = 9
- local c = is_cjk_k(ch) and 0 or 10 -- hanja = 0; latin = 10
- if cjkclass[ch] then c = cjkclass[ch] end -- cjkclass 1 .. 6
- if cjtype then
- if cjtype == 2 and
- (ch == 0xFF1F or ch == 0xFF01 or ch == 0xFF1A or ch == 0xFF1B) then
- c = 4 -- simplified chinese ? !
+ props.unicode = c
end
- else
- if ch == 0x2018 or ch == 0x2019 or ch == 0x201C or ch == 0x201D then
- c = 10 -- korean “ ” ‘ ’
+ elseif id == mathid then
+ curr = end_of_math(curr)
+ elseif id == whatsitid
+ and curr.subtype == user_whatsit
+ and curr.user_id == forcehf_id
+ and curr.type == lua_value then
+
+ local value = curr.value
+ if type(value) == "function" then
+ value()
end
end
- return c
+ curr = getnext(curr)
end
+ return head
end
-local type1fonts = {}
-
-local function get_font_table (fid)
- if fid then
- if fontdata[fid] then
- return fontdata[fid]
- elseif type1fonts[fid] then
- return type1fonts[fid]
- else
- return font.fonts[fid]
- end
- end
-end
+-- linebreak
-local function get_font_char (fid, chr)
- local f = get_font_table(fid)
- return chr and f and f.characters and f.characters[chr]
-end
+local intercharclass = { [0] =
+ { [0] = nil, {1,1}, nil, {.5,.5} },
+ { [0] = nil, nil, nil, {.5,.5} },
+ { [0] = {1,1}, {1,1}, nil, {.5,.5}, nil, {1,1}, {1,1} },
+ { [0] = {.5,.5},{.5,.5},{.5,.5},{1,.5}, {.5,.5},{.5,.5},{.5,.5} },
+ { [0] = {1,0}, {1,0}, nil, {1.5,.5},nil, {1,0}, {1,0} },
+ { [0] = nil, {1,1}, nil, {.5,.5} },
+ { [0] = {1,1}, {1,1}, nil, {.5,.5} },
+}
-local function get_font_emsize(fid)
- local f = get_font_table(fid)
- return (f and f.parameters and f.parameters.quad) or emsize
+local charclass = setmetatable({
+ [0x2018] = 1, [0x201C] = 1, [0x2329] = 1, [0x3008] = 1,
+ [0x300A] = 1, [0x300C] = 1, [0x300E] = 1, [0x3010] = 1,
+ [0x3014] = 1, [0x3016] = 1, [0x3018] = 1, [0x301A] = 1,
+ [0x301D] = 1, [0xFE17] = 1, [0xFE35] = 1, [0xFE37] = 1,
+ [0xFE39] = 1, [0xFE3B] = 1, [0xFE3D] = 1, [0xFE3F] = 1,
+ [0xFE41] = 1, [0xFE43] = 1, [0xFE47] = 1, [0xFF08] = 1,
+ [0xFF3B] = 1, [0xFF5B] = 1, [0xFF5F] = 1, [0xFF62] = 1,
+ --
+ [0x2019] = 2, [0x201D] = 2, [0x232A] = 2, [0x3001] = 2,
+ [0x3009] = 2, [0x300B] = 2, [0x300D] = 2, [0x300F] = 2,
+ [0x3011] = 2, [0x3015] = 2, [0x3017] = 2, [0x3019] = 2,
+ [0x301B] = 2, [0x301E] = 2, [0x301F] = 2, [0xFE10] = 2,
+ [0xFE11] = 2, [0xFE18] = 2, [0xFE36] = 2, [0xFE38] = 2,
+ [0xFE3A] = 2, [0xFE3C] = 2, [0xFE3E] = 2, [0xFE40] = 2,
+ [0xFE42] = 2, [0xFE44] = 2, [0xFE48] = 2, [0xFF09] = 2,
+ [0xFF0C] = 2, [0xFF3D] = 2, [0xFF5D] = 2, [0xFF60] = 2,
+ [0xFF63] = 2, [0xFF64] = 2,
+ --
+ [0x00B7] = 3, [0x30FB] = 3, [0xFF1A] = 3, [0xFF1B] = 3,
+ [0xFF65] = 3,
+ --
+ [0x3002] = 4, [0xFE12] = 4, [0xFF0E] = 4, [0xFF61] = 4,
+ --
+ [0x2015] = 5, [0x2025] = 5, [0x2026] = 5, [0xFE19] = 5,
+ [0xFE30] = 5, [0xFE31] = 5,
+ --
+ [0xFE15] = 6, [0xFE16] = 6, [0xFF01] = 6, [0xFF1F] = 6,
+}, { __index = function() return 0 end })
+
+local SC_charclass = setmetatable({
+ [0xFF01] = 4, [0xFF1A] = 4, [0xFF1B] = 4, [0xFF1F] = 4,
+}, { __index = function(_,c) return charclass[c] end })
+
+local vert_charclass = setmetatable({
+ [0xFF1A] = 5, -- 0xFE13
+ [0xFF1B] = 5, -- 0xFE14
+}, { __index = function(_,c) return charclass[c] end })
+
+local function get_char_class (c, classic)
+ if classic == vert_classic then
+ return vert_charclass[c]
+ elseif classic == SC_classic then
+ return SC_charclass[c]
+ end
+ return charclass[c]
+end
+
+local breakable_after = setmetatable({
+ [0x21] = true, [0x22] = true, [0x25] = true, [0x27] = true,
+ [0x29] = true, [0x2C] = true, [0x2D] = true, [0x2E] = true,
+ [0x3A] = true, [0x3B] = true, [0x3E] = true, [0x3F] = true,
+ [0x5D] = true, [0x7D] = true, [0x7E] = true, [0xBB] = true,
+ [0x2013] = true, [0x2014] = true, [0x25A1] = true, [0x25CB] = true,
+ [0x2E80] = true, [0x3003] = true, [0x3005] = true, [0x3007] = true,
+ [0x301C] = true, [0x3035] = true, [0x303B] = true, [0x303C] = true,
+ [0x309D] = true, [0x309E] = true, [0x30A0] = true, [0x30FC] = true,
+ [0x30FD] = true, [0x30FE] = true, [0xFE13] = true, [0xFE14] = true,
+ [0xFE32] = true, [0xFE50] = true, [0xFE51] = true, [0xFE52] = true,
+ [0xFE54] = true, [0xFE55] = true, [0xFE57] = true, [0xFE57] = true,
+ [0xFE58] = true, [0xFE5A] = true, [0xFE5C] = true, [0xFE5E] = true,
+ [0xFF1E] = true, [0xFF5E] = true, [0xFF70] = true,
+},{ __index = function (_,c)
+ return (is_hangul_jamo(c) and not is_chosong(c))
+ or is_noncjkletter(c)
+ or is_hanja(c)
+ or is_cjk_combining(c)
+ or is_kana(c)
+ or charclass[c] >= 2
+end })
+luatexko.breakableafter = breakable_after
+
+local breakable_before = setmetatable({
+ [0x28] = true, [0x3C] = true, [0x5B] = true, [0x60] = true,
+ [0x7B] = true, [0xAB] = true, [0x25A1] = true, [0x25CB] = true,
+ [0x3007] = true, [0xFE59] = true, [0xFE5B] = true, [0xFE5D] = true,
+ [0xFF1C] = true,
+ -- small kana
+ [0x3041] = 1000, [0x3043] = 1000, [0x3045] = 1000, [0x3047] = 1000,
+ [0x3049] = 1000, [0x3063] = 1000, [0x3083] = 1000, [0x3085] = 1000,
+ [0x3087] = 1000, [0x308E] = 1000, [0x3095] = 1000, [0x3096] = 1000,
+ [0x30A1] = 1000, [0x30A3] = 1000, [0x30A5] = 1000, [0x30A7] = 1000,
+ [0x30A9] = 1000, [0x30C3] = 1000, [0x30E3] = 1000, [0x30E5] = 1000,
+ [0x30E7] = 1000, [0x30EE] = 1000, [0x30F5] = 1000, [0x30F6] = 1000,
+ [0x31F0] = 1000, [0x31F1] = 1000, [0x31F2] = 1000, [0x31F3] = 1000,
+ [0x31F4] = 1000, [0x31F5] = 1000, [0x31F6] = 1000, [0x31F7] = 1000,
+ [0x31F8] = 1000, [0x31F9] = 1000, [0x31FA] = 1000, [0x31FB] = 1000,
+ [0x31FC] = 1000, [0x31FD] = 1000, [0x31FE] = 1000, [0x31FF] = 1000,
+ [0xFF67] = 1000, [0xFF68] = 1000, [0xFF69] = 1000, [0xFF6A] = 1000,
+ [0xFF6B] = 1000, [0xFF6C] = 1000, [0xFF6D] = 1000, [0xFF6E] = 1000,
+ [0xFF6F] = 1000, [0x1B150] = 1000, [0x1B151] = 1000, [0x1B152] = 1000,
+ [0x1B164] = 1000, [0x1B165] = 1000, [0x1B166] = 1000, [0x1B167] = 1000,
+},{ __index = function(_,c)
+ return (is_hangul_jamo(c) and not is_jungsong(c) and not is_jongsong(c))
+ or is_hanja(c)
+ or is_kana(c)
+ or charclass[c] == 1
end
+})
+luatexko.breakablebefore = breakable_before
+
+local allowbreak_false_nodes = {
+ [hlistid] = true,
+ [vlistid] = true,
+ [ruleid] = true,
+ [discid] = true,
+ [glueid] = true,
+ [penaltyid] = true,
+}
-local function get_font_feature (fid, name)
- local f = get_font_table(fid)
- return f and f.shared and f.shared.features and f.shared.features[name]
+local function is_blocking_node (curr)
+ local id, subtype = curr.id, curr.subtype
+ return allowbreak_false_nodes[id] or (id == kernid and subtype == userkern)
end
-local function get_char_boundingbox(fid, chr)
- local f = get_font_table(fid)
- local glbox = f and f.shared
- glbox = glbox and glbox.rawdata
- glbox = glbox and glbox.descriptions
- glbox = glbox and glbox[chr] and glbox[chr].boundingbox
- if glbox then
- local factor, bbox = f.parameters and f.parameters.factor or 655.36, {}
- for i,v in ipairs(glbox) do
- bbox[i] = v * factor
+local function ruby_char_font (rb)
+ local n, c, f = has_glyph(rb.list), 0, 0
+ if n then
+ c, f = my_node_props(n).unicode or n.char, n.font or 0
+ if is_chosong(c) or hangul_tonemark[c] then
+ c = 0xAC00
end
- return bbox
end
+ return c, f
end
-local function d_get_unicode_char(curr)
- local uni = d_getchar(curr) or 0
- if (uni > 0xFF and uni < 0xE000) or (uni > 0xF8FF and uni < 0xF0000) then
- return uni -- no pua. no nanumgtm
- end
- if uni < 0xE000 or (uni > 0xF8FF and uni < 0xF0000) then -- no pua
- local uchr = get_font_char(d_getfont(curr), uni)
- uchr = uchr and uchr.tounicode
- uchr = uchr and uchr:sub(1,4) -- seems ok for old hangul
- if uchr then return tonumber(uchr,16) end
+local function get_actualtext (curr)
+ local actual = my_node_props(curr).startactualtext
+ if type(actual) == "table" then
+ return actual[0], actual[1], actual[#actual]
end
- local uatt = d_has_attribute(curr, luakounicodeattr)
- if uatt then return uatt end
- return uni
end
-local function d_get_hlist_char_first (hlist)
- local curr = d_getlist(hlist)
- while curr do
- local currid = d_getid(curr)
- if currid == glyphnode then
- local c,f = d_get_unicode_char(curr), d_getfont(curr)
- if c then return c,f end
- elseif currid == hlistnode or currid == vlistnode then
- local c,f = d_get_hlist_char_first(curr)
- if c then return c,f end
- elseif currid == gluenode then
- if not d_node_zero_glue(curr) then return end
+local function goto_end_actualtext (curr)
+ local n = getnext(curr)
+ while n do
+ if n.id == whatsitid
+ and n.mode == directmode
+ and my_node_props(n).endactualtext then
+ curr = n
+ break
end
- curr = d_getnext(curr)
+ n = getnext(n)
end
+ return curr
end
-local function d_get_hlist_char_last (hlist,c,f)
- local curr = d_nodetail(d_getlist(hlist))
- while curr do
- local currid = d_getid(curr)
- if currid == glyphnode then
- c, f = d_get_unicode_char(curr), d_getfont(curr)
- if c and not is_unicode_vs(c) then break end -- bypass VS
- elseif currid == hlistnode or currid == vlistnode then
- c, f = d_get_hlist_char_last(curr)
- if c then break end
- elseif currid == gluenode then
- if not d_node_zero_glue(curr) then break end
+local function fontdata_opt_dim (fd, optname)
+ local dim = option_in_font(fd, optname)
+ if dim then
+ local m, u = dim:match"(.+)(e[mx])%s*$"
+ if m and u then
+ if u == "em" then
+ dim = m * fd.parameters.quad
+ else
+ dim = m * fd.parameters.x_height
+ end
+ else
+ dim = texsp(dim)
end
- curr = d_getprev(curr)
+ return dim
end
- return c, f
end
-----------------------------
--- cjk linebreak and spacing
-----------------------------
-local function kanjiskip (head,curr)
- d_insert_before(head,curr,d_make_luako_glue(0, emsize*0.1, emsize*0.02))
-end
-
-local function xkanjiskip (head,curr)
- if d_has_attribute(curr,finemathattr) == 0 then -- ttfamily
- kanjiskip(head,curr)
- else
- d_insert_before(head,curr,d_make_luako_glue(0.25*emsize, emsize*0.15, emsize*0.06))
+local function get_font_opt_dimen (fontid, option_name)
+ local fop_t = char_font_options[option_name]
+ local dim = fop_t and fop_t[fontid]
+ if dim == nil then
+ local fd = get_font_data(fontid)
+ dim = fontdata_opt_dim(fd, option_name)
+ if dim then
+ fop_t[fontid] = dim -- cache
+ else
+ fop_t[fontid] = false
+ end
end
+ return dim
end
-local function interhangulskip (head,curr,currfont,prevfont,was_penalty)
- local width = 0
- local interhangul = get_font_feature(currfont, "interhangul")
- if interhangul and currfont == prevfont then
- width = tex_sp(interhangul)
- end
- if not was_penalty then
- d_insert_before(head,curr,d_get_penaltynode(50))
+local function insert_glue_before (head, curr, par, br, brb, classic, ict, dim)
+ local pn = nodenew(penaltyid)
+ if not br then
+ pn.penalty = 10000
+ elseif type(brb) == "number" then
+ pn.penalty = brb
+ elseif par and nodecount(glyphid, curr) <= 2 then
+ pn.penalty = 1000 -- supress orphan
+ else
+ pn.penalty = 50
end
- d_insert_before(head,curr,d_make_luako_glue(width, emsize*0.04, emsize*0.02))
-end
-local function interhanjaskip (head,curr,was_penalty)
- if not was_penalty then
- d_insert_before(head,curr,d_get_penaltynode(50))
+ dim = dim or 0
+ local gl = nodenew(glueid)
+ local en = get_en_size(curr.font)
+ if ict then
+ en = classic and en or en/4
+ setglue(gl, en * ict[1] + dim, nil, en * ict[2])
+ else
+ setglue(gl, dim, en * stretch_f, en * shrink_f)
end
- d_insert_before(head,curr,d_make_luako_glue(0, emsize*0.04, emsize*0.02))
-end
-local function koreanlatinskip (head,curr,currfont,prevfont,was_penalty)
- local width = 0 -- default: 0em
- if (d_has_attribute(curr,finemathattr) or 0) > 0 then -- not ttfamily
- local latincjk = get_font_feature(currfont, "interlatincjk")
- if not latincjk then
- latincjk = get_font_feature(prevfont, "interlatincjk")
- end
- if latincjk then
- width = tex_sp(latincjk)
- end
- end
- if not was_penalty then
- d_insert_before(head,curr,d_get_penaltynode(50))
- end
- d_insert_before(head,curr,d_make_luako_glue(width, emsize*0.04, emsize*0.02))
+ head = insert_before(head, curr, pn)
+ return insert_before(head, curr, gl)
end
-local function cjk_insert_nodes(head,curr,currchar,currfont,prevchar,prevfont,was_penalty)
- local currentcjtype = d_has_attribute(curr,cjtypesetattr)
- local p = get_cjk_class(prevchar, currentcjtype)
- local c = get_cjk_class(currchar, currentcjtype)
- ---[[raise latin puncts
- if d_getid(curr) == glyphnode and (d_has_attribute(curr,finemathattr) or 0) > 0 and c < 10 then -- not ttfamily
- local nn, raise = d_getnext(curr), nil
- while nn do
- local nnid = d_getid(nn)
- if nnid == glyphnode and latin_fullstop[d_getchar(nn)] then
- if not raise then
- raise = get_font_feature(currfont, "punctraise")
- raise = raise and tex_sp(raise)
- end
- if raise then
- local yoff = d_getfield(nn,"yoffset") or 0
- d_setfield(nn,"yoffset", yoff + raise)
- end
- nn = d_getnext(nn)
- elseif nnid == kernnode then
- nn = d_getnext(nn)
- else
- break
- end
- end
- end
- --raise latin puncts]]
- if c == 5 and p == 5 then -- skip ------ ......
- return currchar,currfont
- end
- if p and p < 10 and prebreakpenalty[currchar] then
- was_penalty = true
- d_insert_before(head,curr,d_get_penaltynode(prebreakpenalty[currchar]))
- elseif c and c < 10 and postbreakpenalty[prevchar] then
- was_penalty = true
- d_insert_before(head,curr,d_get_penaltynode(postbreakpenalty[prevchar]))
- end
- ---[[ kern is a breakpoint if followed by a glue: protrusion and compress_fullwidth_punctuations
- if (c and c == 1) or (p and p >= 2 and p <= 6) then was_penalty = true end
- --]]
- if p and c then
- if currentcjtype then
- if cjk_glue_spec[p] and cjk_glue_spec[p][c] then
- local width = emsize * cjk_glue_spec[p][c][1]
- local stretch = 0
- local shrink = emsize * cjk_glue_spec[p][c][2]
- d_insert_before(head,curr,d_make_luako_glue(width, stretch, shrink))
- elseif p < 10 and c < 9 then -- break between chosong and chosong
- kanjiskip(head,curr)
- elseif (p < 10 and c == 10) or (p == 10 and c < 10) then
- if xspcode[currchar] then
- if xspcode[currchar] % 2 == 1 then
- xkanjiskip(head,curr)
- end
- elseif xspcode[prevchar] then
- if xspcode[prevchar] > 1 then
- xkanjiskip(head,curr)
- end
- elseif inhibitxspcode[currchar] then -- 3, 2
- if inhibitxspcode[currchar] > 1 then
- xkanjiskip(head,curr)
- end
- elseif inhibitxspcode[prevchar] then -- 3, 1
- if inhibitxspcode[prevchar] % 2 == 1 then
- xkanjiskip(head,curr)
- end
- else
- xkanjiskip(head,curr)
- end
- end
- else
- if (p < 10 and c == 10) or (p == 10 and c < 10) then
- if xspcode[currchar] then
- if xspcode[currchar] % 2 == 1 then
- koreanlatinskip(head,curr,currfont,prevfont,was_penalty)
- end
- elseif xspcode[prevchar] then
- if xspcode[prevchar] > 1 then
- koreanlatinskip(head,curr,currfont,prevfont,was_penalty)
- end
- elseif inhibitxspcode[currchar] then -- 3, 2
- if inhibitxspcode[currchar] > 1 then
- koreanlatinskip(head,curr,currfont,prevfont,was_penalty)
- end
- elseif inhibitxspcode[prevchar] then -- 3, 1
- if inhibitxspcode[prevchar] % 2 == 1 then
- koreanlatinskip(head,curr,currfont,prevfont,was_penalty)
- end
- else
- koreanlatinskip(head,curr,currfont,prevfont,was_penalty)
- end
- elseif cjk_glue_spec[p] and cjk_glue_spec[p][c] then
- koreanlatinskip(head,curr,currfont,prevfont,was_penalty)
- elseif p == 7 and c == 7 then
- interhangulskip(head,curr,currfont,prevfont,was_penalty)
- elseif p < 10 and c < 9 then -- break between chosong and chosong
- interhanjaskip(head,curr,was_penalty)
- end
+local function maybe_linebreak (head, curr, pc, pcl, cc, gomun, fid, par)
+ local ccl = get_char_class(cc, gomun)
+ if pc and cc and curr.lang ~= nohyphen then
+ local ict = intercharclass[pcl][ccl]
+ local brb = breakable_before[cc]
+ local br = brb and breakable_after[pc]
+ local dim = get_font_opt_dimen(fid, "intercharacter")
+ if ict or br or dim and (pcl >= 1 or ccl >= 1) then
+ head = insert_glue_before(head, curr, par, br, brb, gomun, ict, dim)
end
end
- return currchar,currfont
+ return head, cc, ccl
end
-local function cjk_spacing_linebreak (head)
- local prevchar,prevfont,was_penalty,prevfine = nil,nil,nil,nil
- local curr = head
+local function process_linebreak (head, par)
+ local curr, pc, pcl = head, false, 0
while curr do
- local currfine = d_has_attribute(curr,finemathattr)
- if currfine then
- local currid = d_getid(curr)
- if currid == gluenode then
- prevchar,prevfont,prevfine = nil,nil,nil
- d_unset_attribute(curr,finemathattr)
- elseif currid == glyphnode then
- local currfont = d_getfont(curr)
- emsize = get_font_emsize(currfont)
- local uni = d_get_unicode_char(curr)
- if uni and not is_unicode_vs(uni) then -- bypass VS
- if prevfine and prevfine > 0 and currfine == 0 then
- d_set_attribute(curr, finemathattr, 1)
- end
- prevchar,prevfont = cjk_insert_nodes(head,curr,uni,currfont,prevchar,prevfont,was_penalty)
- prevfine = currfine
- end
- d_unset_attribute(curr,finemathattr)
- elseif currid == mathnode then
- local currchar = 0
- local currsurround, currsubtype = d_getfield(curr,"surround"), d_getsubtype(curr)
- if currsurround and currsurround > 0 then
- currchar = 0x4E00
- end
- if currsubtype == 0 then
- cjk_insert_nodes(head,curr,currchar,nil,prevchar,prevfont,was_penalty)
- curr = d_end_of_math(curr)
- if not curr then break end
- prevchar,prevfont,prevfine = currchar,nil,nil
- end
- d_unset_attribute(curr,finemathattr)
- elseif currid == hlistnode or currid == vlistnode then
- local firstchr, firstfid = d_get_hlist_char_first(curr)
- if firstchr then
- cjk_insert_nodes(head,curr,firstchr,firstfid,prevchar,prevfont,was_penalty)
- end
- prevchar,prevfont = d_get_hlist_char_last(curr,prevchar,prevfont)
- if d_getlist(curr) then prevfine = nil end -- empty box preserves prevfine.
- d_unset_attribute(curr,finemathattr)
- end
- was_penalty = currid == penaltynode
- else
- if d_getid(curr) == glyphnode and prevfine and prevfine > 0 then -- fitst glyph in verb
- d_set_attribute(curr, finemathattr, 1)
- cjk_insert_nodes(head,curr,0,nil,prevchar,prevfont,was_penalty)
- d_unset_attribute(curr,finemathattr)
- prevchar,prevfont,prevfine = 0,nil,nil -- treat \verb as latin character.
+ local id = curr.id
+ if id == glyphid then
+ local cc = my_node_props(curr).unicode or curr.char
+ local gomun = has_attribute(curr, classicattr)
+
+ head, pc, pcl = maybe_linebreak(head, curr, pc, pcl, cc, gomun, curr.font, par)
+
+ elseif id == hlistid and has_attribute(curr, rubyattr) then
+ local cc, fi = ruby_char_font(curr) -- rubybase
+ local gomun = has_attribute(curr, classicattr)
+ head, pc, pcl = maybe_linebreak(head, curr, pc, pcl, cc, gomun, fi, par)
+
+ elseif id == whatsitid and curr.mode == directmode then
+ local glyf, cc, fin = get_actualtext(curr)
+ if cc and fin and glyf then
+ local gomun = has_attribute(glyf, classicattr)
+ head = maybe_linebreak(head, curr, pc, pcl, cc, gomun, glyf.font, par)
+ pc, pcl, curr = fin, 0, goto_end_actualtext(curr)
end
+
+ elseif id == mathid then
+ pc, pcl, curr = 0x30, 0, end_of_math(curr)
+ elseif id == dirid then
+ pc, pcl = curr.dir:sub(1,1) == "-" and 0x30, 0 -- pop dir
+ elseif is_blocking_node(curr) then
+ pc, pcl = false, 0
end
- curr = d_getnext(curr)
+ curr = getnext(curr)
end
+ return head
end
-------------------------------------
--- remove japanese/chinese spaceskip
-------------------------------------
-local function remove_cj_spaceskip (head)
- local curr, prevfont = head, nil
+-- compress punctuations
+
+local function process_glyph_width (head)
+ local curr = head
while curr do
- local currid,currsubtype = d_getid(curr), d_getsubtype(curr)
- if currid == mathnode and currsubtype == 0 then
- curr = d_end_of_math(curr)
- elseif currid == gluenode and currsubtype == glue_type_space then -- do not touch on xspaceskip for now
- local cjattr = d_has_attribute(curr,cjtypesetattr)
- local prv, nxt = d_getprev(curr), d_getnext(curr)
- if cjattr and cjattr > 0 and prv and nxt then
- local prevclass, prevchar, nextclass
- local prvid, nxtid = d_getid(prv), d_getid(nxt)
- if prvid == hlistnode or prvid == vlistnode then
- prevclass = get_cjk_class(d_get_hlist_char_last(prv), cjattr)
- else
- -- what is this strange kern before \text??
- if prvid == kernnode and d_getfield(prv,"kern") == 0 then
- prv = d_getprev(prv)
+ local id = curr.id
+ if id == glyphid then
+ if curr.lang ~= nohyphen
+ and option_in_font(curr.font, "compresspunctuations") then
+
+ local cc = my_node_props(curr).unicode or curr.char
+ local gomun = has_attribute(curr, classicattr)
+ local class = get_char_class(cc, gomun)
+ if (gomun or cc < 0x2000 or cc > 0x202F) -- exclude general puncts
+ and class >= 1 and class <= 4 then
+
+ local gpos
+ if class ~= 1 then
+ gpos = getnext(curr)
+ else
+ gpos = getprev(curr)
end
- if prvid == glyphnode then
- prevchar, prevfont = d_getchar(prv), d_getfont(prv)
- if is_unicode_vs(prevchar) then prv = d_getprev(prv) end -- bypass VS
- prevclass = get_cjk_class(d_get_unicode_char(prv), cjattr)
+ gpos = gpos and gpos.id == kernid and gpos.subtype == fontkern
+
+ if not gpos then
+ local wd = get_en_size(curr.font) - curr.width
+ if wd ~= 0 then
+ local k = nodenew(kernid) -- fontkern (subtype 0) is default
+ k.kern = class == 3 and wd/2 or wd
+ if class == 1 then
+ head = insert_before(head, curr, k)
+ elseif class == 2 or class == 4 then
+ head, curr = insert_after(head, curr, k)
+ else
+ local k2 = nodecopy(k)
+ head = insert_before(head, curr, k)
+ head, curr = insert_after(head, curr, k2)
+ end
+ end
end
end
- if nxtid == glyphnode then
- nextclass = get_cjk_class(d_get_unicode_char(nxt), cjattr)
- elseif nxtid == hlistnode or nxtid == vlistnode then
- nextclass = get_cjk_class(d_get_hlist_char_first(nxt), cjattr)
- end
- if (prevclass and prevclass < 10) or (nextclass and nextclass < 10) then
- d_remove_node(head,curr)
- d_nodefree(curr)
- curr = nxt
- end
end
+ elseif id == mathid then
+ curr = end_of_math(curr)
end
- curr = d_getnext(curr)
+ curr = getnext(curr)
end
+ return head
end
-----------------------------------
--- compress fullwidth punctuations
-----------------------------------
-local function check_next_halt_kern (head, curr)
- -- glyph halt_kern glue -> glyph halt_kern rule glue
- local nn = d_getnext(curr)
- if nn and d_getid(nn) == kernnode and d_getnext(nn) then
- d_insert_after(head, nn, d_get_rulenode(0))
- end
+-- interhangul & interlatincjk
+
+local function is_cjk (c)
+ return is_hangul_jamo(c)
+ or is_hanja(c)
+ or is_cjk_combining(c)
+ or is_kana(c)
+ or charclass[c] >= 1
+ or (rawget(breakable_before, c) and c >= 0x2000)
+ or (rawget(breakable_after, c) and c >= 0x2000)
end
-local function check_prev_halt_kern (head, curr)
- local pn = d_getprev(curr)
- if pn and d_getid(pn) == kernnode and d_getprev(pn) then
- -- glue halt_kern glyph -> glue rule halt_kern glyph
- head = d_insert_before(head, pn, d_get_rulenode(0))
- elseif pn and d_getid(pn) == gluenode and d_has_attribute(pn, luakoglueattr) then
- -- halt_kern ko_glue glyph -> ko_glue rule halt_kern glyph
- local ppn = d_getprev(pn)
- if d_getid(ppn) == kernnode then
- head = d_remove_node(head, ppn)
- head = d_insert_before(head, curr, ppn)
- head = d_insert_before(head, ppn, d_get_rulenode(0))
+local function do_interhangul_option (head, curr, pc, c, fontid, par)
+ local cc = (is_hangul(c) or is_chosong(c)) and 1 or 0
+
+ if cc*pc == 1 and curr.lang ~= nohyphen then
+ local dim = get_font_opt_dimen(fontid, "interhangul")
+ if dim then
+ head = insert_glue_before(head, curr, par, true, true, false, false, dim)
end
end
- return head
+
+ return head, cc
end
-local function compress_fullwidth_punctuations (head)
- for curr in d_traverse_id(glyphnode,head) do
- local currfont, currchar = d_getfont(curr), d_getchar(curr)
- local cjtype = d_has_attribute(curr, cjtypesetattr)
- local uni = d_get_unicode_char(curr)
- local class = uni and get_cjk_class(uni, cjtype or 0) -- include U+201C ...
- local chr = get_font_char(currfont, currchar)
- if chr and class and class >= 1 and class <= 4 then
- local halt_on = get_font_feature(currfont,'halt') or get_font_feature(currfont,'vhal')
- local width = d_getfield(curr,"width") or 655360
- emsize = get_font_emsize(currfont)
- local ensize = emsize/2
- local oneoften = emsize/10
- local bbox = get_char_boundingbox(currfont, currchar)
- bbox = bbox or {ensize-oneoften, ensize-oneoften, ensize+oneoften, ensize+oneoften}
- if class == 2 or class == 4 then
- local wd
- if get_font_feature(currfont,'vertical') then
- wd = ensize<width and ensize-width or 0
- else
- wd = (bbox[3] < ensize) and ensize-width or bbox[3]-width+oneoften
- if not cjtype and wd > 0 then wd = 0 end
- end
- if chr.right_protruding then
- -- kern is a breakpoint if followed by a glue
- if not halt_on then
- d_insert_after(head, curr, d_get_kernnode(wd))
- end
- else
- if halt_on then
- check_next_halt_kern(head, curr)
- else
- d_insert_after(head, curr, d_get_rulenode(wd))
- end
- end
- elseif class == 1 then
- local wd
- if get_font_feature(currfont,'vertical') then
- wd = ensize<width and ensize-width or 0
- else
- wd = (width-bbox[1] < ensize) and ensize-width or -bbox[1]+oneoften
- if not cjtype and wd > 0 then wd = 0 end
- end
- if chr.left_protruding then
- if not halt_on then
- head = d_insert_before(head, curr, d_get_kernnode(wd))
- end
- else
- if halt_on then
- head = check_prev_halt_kern(head, curr)
- else
- head = d_insert_before(head, curr, d_get_rulenode(wd))
- end
- end
- elseif class == 3 then
- local lwd, rwd
- local quarter, thirdquarter, halfwd = ensize/2, ensize*1.5, width/2
- if get_font_feature(currfont,'vertical') then
- rwd = quarter<halfwd and quarter-halfwd or 0
- lwd = rwd
- else
- rwd = (bbox[3] < thirdquarter) and quarter-halfwd or bbox[3]-width
- lwd = (width-bbox[1] < thirdquarter) and quarter-halfwd or -bbox[1]
- end
- if chr.left_protruding then
- if not halt_on then
- head = d_insert_before(head, curr, d_get_kernnode(lwd))
- end
- else
- if halt_on then -- there's already penalty 10000
- head = check_prev_halt_kern(head, curr)
- else
- head = d_insert_before(head, curr, d_get_rulenode(lwd))
- end
- end
- if chr.right_protruding then
- if not halt_on then
- d_insert_after (head, curr, d_get_kernnode(rwd))
- end
- else
- if halt_on then
- check_next_halt_kern(head, curr)
- else
- d_insert_after (head, curr, d_get_rulenode(rwd))
- end
- end
+local function process_interhangul (head, par)
+ local curr, pc = head, 0
+ while curr do
+ local id = curr.id
+ if id == glyphid then
+ local c = my_node_props(curr).unicode or curr.char
+ head, pc = do_interhangul_option(head, curr, pc, c, curr.font, par)
+
+ if is_chosong(c) then
+ pc = 0
+ elseif is_jungsong(c) or is_jongsong(c) or hangul_tonemark[c] then
+ pc = 1
end
- end
- end
- return head -- should be returned!
-end
-------------------------------
--- ruby: pre-linebreak routine
-------------------------------
-local function spread_ruby_box(head,extrawidth)
- local to_free = {}
- for curr in d_traverse_id(gluenode,head) do
- local wd = d_getglue(curr) or 0
- if d_has_attribute(curr,luakoglueattr) then
- d_setglue(curr, wd + extrawidth)
- else
- head = d_insert_before(head,curr,d_get_kernnode(wd+extrawidth))
- head = d_remove_node(head,curr)
- to_free[#to_free + 1] = curr
+ elseif id == hlistid and has_attribute(curr, rubyattr) then
+ local c, fi = ruby_char_font(curr)
+ head, pc = do_interhangul_option(head, curr, pc, c, fi, par)
+
+ elseif id == whatsitid and curr.mode == directmode then
+ local glyf, c = get_actualtext(curr)
+ if c and glyf then
+ head = do_interhangul_option(head, curr, pc, c, glyf.font, par)
+ pc, curr = 1, goto_end_actualtext(curr)
+ end
+
+ elseif id == mathid then
+ pc, curr = 0, end_of_math(curr)
+ elseif is_blocking_node(curr) or id == dirid then
+ pc = 0
end
- end
- if #to_free > 0 then
- for _,v in ipairs(to_free) do d_nodefree(v) end
+ curr = getnext(curr)
end
return head
end
-local function spread_ruby_base_box (head)
- for curr in d_traverse_id(hlistnode,head) do
- local attr = d_has_attribute(curr,luakorubyattr)
- local rubyoverlap = attr and rubynode[attr][3]
- if attr and not rubyoverlap then
- local ruby = d_todirect(rubynode[attr][1])
- local currwidth, rubywidth = d_getfield(curr,"width"), d_getfield(ruby,"width")
- if ruby and rubywidth > currwidth then
- local basehead = d_getlist(curr)
- local numofglues = d_nodecount(gluenode,basehead)
- local extrawidth = (rubywidth - currwidth)/(numofglues + 1)
- if numofglues > 0 then
- basehead = spread_ruby_box(basehead,extrawidth)
- end
- local leading = d_get_kernnode(extrawidth/2)
- d_setfield(curr,"width", rubywidth)
- d_setnext(leading, basehead)
- d_setlist(curr, leading)
- end
+local function do_interlatincjk_option (head, curr, pc, pf, c, cf, par)
+ local cc = (is_cjk(c) and 1) or (is_noncjkletter(c) and 2) or 0
+ local brb = cc == 2 or breakable_before[c] -- numletter != br_before
+
+ if brb and cc*pc == 2 and curr.lang ~= nohyphen then
+ local fontid = cc == 1 and cf or pf
+ local dim = get_font_opt_dimen(fontid, "interlatincjk")
+ if dim then
+ head = insert_glue_before(head, curr, par, true, brb, false, false, dim)
end
end
+
+ return head, cc, cf
end
-local function get_ruby_side_width (basewidth,rubywidth,adjacent)
- local width,margin = (rubywidth-basewidth)/2, 0
- if adjacent then
- if d_getid(adjacent) == glyphnode then
- local uni = d_get_unicode_char(adjacent)
- if is_unicode_vs(uni) then -- bypass VS
- uni = d_get_unicode_char(d_getprev(adjacent))
+local function process_interlatincjk (head, par)
+ local curr, pc, pf = head, 0, 0
+ while curr do
+ local id = curr.id
+ if id == glyphid then
+ local c = my_node_props(curr).unicode or curr.char
+ head, pc, pf = do_interlatincjk_option(head, curr, pc, pf, c, curr.font, par)
+ pc = breakable_after[c] and pc or 0
+
+ elseif id == hlistid and has_attribute(curr, rubyattr) then
+ local c, cf = ruby_char_font(curr)
+ head, pc, pf = do_interlatincjk_option(head, curr, pc, pf, c, cf, par)
+
+ elseif id == whatsitid and curr.mode == directmode then
+ local glyf, c = get_actualtext(curr)
+ if c and glyf then
+ head, pc, pf = do_interlatincjk_option(head, curr, pc, pf, c, glyf.font, par)
+ curr = goto_end_actualtext(curr)
end
- if not is_hanja(uni) then
- width = (rubywidth-basewidth-emsize)/2
- if width > 0 then
- margin = emsize/2
- else
- width,margin = 0,(rubywidth-basewidth)/2
- end
+
+ elseif id == mathid then
+ if pc == 1 then
+ head = do_interlatincjk_option(head, curr, pc, pf, 0x30, pf, par)
end
- end
- end
- return width,margin
-end
+ pc, curr = 2, end_of_math(curr)
-local function get_ruby_side_kern (head)
- for curr in d_traverse_id(hlistnode,head) do
- local attr = d_has_attribute(curr,luakorubyattr)
- local rubyoverlap = attr and rubynode[attr][3]
- if rubyoverlap then
- local currwidth = d_getfield(curr,"width")
- local basewidth = currwidth
- local ruby = d_todirect(rubynode[attr][1])
- local rubywidth = d_getfield(ruby,"width")
- if currwidth < rubywidth then
- local _,fid = d_get_hlist_char_first(curr)
- emsize = get_font_emsize(fid)
- local leftwidth,leftmargin = get_ruby_side_width(basewidth,rubywidth,d_getprev(curr))
- if leftwidth > 0 then
- currwidth = currwidth + leftwidth
- d_setfield(curr,"width", currwidth)
- end
- if leftmargin > 0 then
- rubynode[attr].leftmargin = leftmargin
- end
- local rightwidth,rightmargin = get_ruby_side_width(basewidth,rubywidth,d_getnext(curr))
- if rightwidth > 0 then
- currwidth = currwidth + rightwidth
- d_setfield(curr,"width", currwidth)
- end
- if rightmargin > 0 then
- rubynode[attr].rightmargin = rightmargin
- end
- rubynode[attr].rightshift = rightwidth - leftwidth
- local totalspace = leftwidth+rightwidth
- if totalspace > 0 then
- local currhead = d_getlist(curr)
- local numofglues = d_nodecount(gluenode,currhead)
- local extrawidth = totalspace/(numofglues + 1)
- if numofglues > 0 then
- currhead = spread_ruby_box(currhead,extrawidth)
- end
- local leading = d_get_kernnode(extrawidth*(leftwidth/totalspace))
- d_setnext(leading, currhead)
- d_setlist(curr, leading)
- end
+ elseif id == dirid then
+ if pc == 1 and curr.dir:sub(1,1) == "+" then
+ head = do_interlatincjk_option(head, curr, pc, pf, 0x30, pf, par)
+ pc = 0
end
- end
- end
-end
-local function zero_width_rule_with_dir (head,curr,before)
- local rule = d_get_rulenode(0)
- d_setfield(rule,"dir", d_getfield(curr,"dir"))
- if before then
- head = d_insert_before(head,curr,rule)
- else
- d_insert_after(head,curr,rule)
+ elseif is_blocking_node(curr) then
+ pc = 0
+ end
+ curr = getnext(curr)
end
return head
end
-local function no_ruby_at_margin(head)
- for curr in d_traverse_id(hlistnode,head) do
- local attr = d_has_attribute(curr,luakorubyattr)
- if attr then
- local margin = rubynode[attr].leftmargin
- if margin then
- head = d_insert_before(head,curr,d_get_kernnode(-margin))
- head = zero_width_rule_with_dir(head,curr,true) -- before
- head = d_insert_before(head,curr,d_get_kernnode(margin))
- end
- margin = rubynode[attr].rightmargin
- if margin then
- local nn = d_getnext(curr)
- if nn then
- local nnid = d_getid(nn)
- if nnid == gluenode then
- d_insert_after(head,curr,d_get_kernnode(-margin))
- head = zero_width_rule_with_dir(head,curr)
- d_insert_after(head,curr,d_get_kernnode(margin))
- elseif nnid == penaltynode and d_getfield(nn,"penalty") < 10000 then
- d_insert_after(head,nn,d_get_kernnode(-margin))
- head = zero_width_rule_with_dir(head,curr)
- d_insert_after(head,curr,d_get_kernnode(margin))
+-- remove classic spaces
+
+local function process_remove_spaces (head)
+ local curr, opt_name, to_free = head, "removeclassicspaces", {}
+ while curr do
+ local id = curr.id
+ if id == glueid then
+ if curr.subtype == spaceskip and has_attribute(curr, classicattr) then
+
+ for k, v in pairs{ p = getprev(curr), n = getnext(curr) } do
+ local ok
+ while v do
+ local vid = v.id
+ if vid ~= whatsitid -- skip whatsit or kern except userkern
+ and ( vid ~= kernid or v.subtype == userkern ) then
+
+ local vchar, vfont
+ if vid == glyphid and v.lang ~= nohyphen then
+ vchar, vfont = v.char, v.font
+ elseif vid == hlistid and has_attribute(v, rubyattr) then
+ vchar, vfont = ruby_char_font(v)
+ end
+ if vchar and vfont and option_in_font(vfont, opt_name) then
+ ok = is_cjk(vchar)
+ end
+
+ break
+ end
+ v = k == "p" and getprev(v) or getnext(v)
+ end
+ if ok then
+ head = noderemove(head, curr)
+ tableinsert(to_free, curr)
+ break
end
end
end
+ elseif id == mathid then
+ curr = end_of_math(curr)
end
+ curr = getnext(curr)
end
+ for _,v in ipairs(to_free) do nodefree(v) end
return head
end
-------------------------------
--- discourage character orphan
-------------------------------
-local function inject_char_widow_penalty (head,curr,uni,cjattr)
- if uni and prebreakpenalty[uni] ~= 10000 then
- local class = get_cjk_class(uni, cjattr)
- if class and class < 9 then
- local pv = cjattr and 500 or 5000
- local np = d_getprev(curr)
- if np and d_getid(np) == rulenode then
- curr = np; np = d_getprev(curr)
- end
- if np and d_getid(np) == gluenode then
- curr = np; np = d_getprev(curr)
+-- josa
+
+local josa_table = {
+ -- 리을, 중성, 종성
+ [0xAC00] = {0xC774, 0xAC00, 0xC774}, -- 가 = 이, 가, 이
+ [0xC740] = {0xC740, 0xB294, 0xC740}, -- 은 = 은, 는, 은
+ [0xC744] = {0xC744, 0xB97C, 0xC744}, -- 을 = 을, 를, 을
+ [0xC640] = {0xACFC, 0xC640, 0xACFC}, -- 와 = 과, 와, 과
+ [0xC73C] = {nil, nil, 0xC73C}, -- 으(로) = , , 으
+ [0xC774] = {0xC774, nil, 0xC774}, -- 이(라) = 이, , 이
+}
+
+local josa_code = setmetatable({
+ [0x30] = 3, [0x31] = 1, [0x33] = 3, [0x36] = 3,
+ [0x37] = 1, [0x38] = 1, [0x4C] = 1, [0x4D] = 3,
+ [0x4E] = 3, [0x6C] = 1, [0x6D] = 3, [0x6E] = 3,
+ [0x2160] = 1, [0x2162] = 3, [0x2165] = 3, [0x2166] = 1,
+ [0x2167] = 1, [0x2169] = 3, [0x216A] = 1, [0x216C] = 3,
+ [0x216D] = 3, [0x216E] = 3, [0x216F] = 3, [0x2170] = 1,
+ [0x2172] = 3, [0x2175] = 3, [0x2176] = 1, [0x2177] = 1,
+ [0x2179] = 3, [0x217A] = 1, [0x217C] = 3, [0x217D] = 3,
+ [0x217E] = 3, [0x217F] = 3, [0x2460] = 1, [0x2462] = 3,
+ [0x2465] = 3, [0x2466] = 1, [0x2467] = 1, [0x2469] = 3,
+ [0x246A] = 1, [0x246C] = 3, [0x246F] = 3, [0x2470] = 1,
+ [0x2471] = 1, [0x2473] = 3, [0x2474] = 1, [0x2476] = 3,
+ [0x2479] = 3, [0x247A] = 1, [0x247B] = 1, [0x247D] = 3,
+ [0x247E] = 1, [0x2480] = 3, [0x2483] = 3, [0x2484] = 1,
+ [0x2485] = 1, [0x2487] = 3, [0x2488] = 1, [0x248A] = 3,
+ [0x248D] = 3, [0x248E] = 1, [0x248F] = 1, [0x2491] = 3,
+ [0x2492] = 1, [0x2494] = 3, [0x2497] = 3, [0x2498] = 1,
+ [0x2499] = 1, [0x249B] = 3, [0x24A7] = 1, [0x24A8] = 3,
+ [0x24A9] = 3, [0x24C1] = 1, [0x24C2] = 3, [0x24C3] = 3,
+ [0x24DB] = 1, [0x24DC] = 3, [0x24DD] = 3, [0x3139] = 1,
+ [0x3203] = 1, [0x3263] = 1, [0xFF10] = 3, [0xFF11] = 1,
+ [0xFF13] = 3, [0xFF16] = 3, [0xFF17] = 1, [0xFF18] = 1,
+ [0xFF2C] = 1, [0xFF2D] = 3, [0xFF2E] = 3, [0xFF4C] = 1,
+ [0xFF4D] = 3, [0xFF4E] = 3,
+},{ __index = function(_,c)
+ if is_hangul(c) then
+ c = (c - 0xAC00) % 28 + 0x11A7
+ end
+ if is_chosong(c) then
+ return c == 0x1105 and 1 or 3
+ elseif is_jungsong(c) then
+ return c ~= 0x1160 and 2
+ elseif is_jongsong(c) then
+ return c == 0x11AF and 1 or 3
+ elseif (is_noncjkletter(c) and c <= 0x7A )
+ or (c >= 0x2160 and c <= 0x217F) -- roman
+ or (c >= 0x2460 and c <= 0x24E9) -- ①
+ or (c >= 0x314F and c <= 0x3163) or (c >= 0x3187 and c <= 0x318E) -- ㅏ
+ or (c >= 0x320E and c <= 0x321E) -- ㈎
+ or (c >= 0x326E and c <= 0x327F) -- ㉮
+ or (c >= 0xFF10 and c <= 0xFF19) -- 0
+ or (c >= 0xFF21 and c <= 0xFF3A) -- A
+ or (c >= 0xFF41 and c <= 0xFF5A) -- a
+ then return 2
+ elseif (c >= 0x3131 and c <= 0x314E) or (c >= 0x3165 and c <= 0x3186) -- ㄱ
+ or (c >= 0x3200 and c <= 0x320D) -- ㈀
+ or (c >= 0x3260 and c <= 0x326D) -- ㉠
+ then return 3
+ end
+end })
+
+local ignore_parens = false
+
+local function prevjosacode (n, parenlevel)
+ local parenlevel, josacode = parenlevel or 0
+ while n do
+ local id = n.id
+ if id == glyphid then
+ local c = my_node_props(n).unicode or n.char -- beware hlist/vlist
+ if ignore_parens and c == 0x29 then
+ parenlevel = parenlevel + 1
+ elseif ignore_parens and c == 0x28 then
+ parenlevel = parenlevel - 1
+ elseif parenlevel <= 0 then
+ josacode = josa_code[c]
+ if josacode then break end
end
- if np and d_getid(np) == penaltynode then
- curr = np
- local currpenalty = d_getfield(curr,"penalty")
- if currpenalty < pv and currpenalty > 0 then -- bypass \\ case
- d_setfield(curr,"penalty", pv)
- end
- elseif curr and d_getid(curr) == gluenode then
- head, curr = d_insert_before(head,curr,d_get_penaltynode(pv))
+ elseif id == hlistid or id == vlistid then
+ local list = n.list
+ if list then
+ josacode, parenlevel = prevjosacode(nodeslide(list), parenlevel)
+ if josacode then break end
end
end
+ n = getprev(n)
end
- return curr
+ return josacode, parenlevel
end
-local function discourage_char_widow (head,curr)
+local function process_josa (head)
+ local curr, tofree = head, {}
while curr do
- if curr == head then return end
- local currid = d_getid(curr)
- if currid == glyphnode then
- emsize = get_font_emsize(d_getfont(curr))
- local remwd = d_nodedimensions(curr)
- if remwd > 2*emsize then return end
- local cjattr = d_has_attribute(curr,cjtypesetattr)
- local uni = d_get_unicode_char(curr)
- curr = inject_char_widow_penalty(head,curr,uni,cjattr)
- elseif currid == hlistnode and currid == vlistnode then
- local remwd = d_nodedimensions(curr)
- local uni,fid = d_get_hlist_char_first(curr)
- emsize = get_font_emsize(fid)
- if remwd > 2*emsize then return end
- local cjattr = d_has_attribute(curr,cjtypesetattr)
- curr = inject_char_widow_penalty(head,curr,uni,cjattr)
+ local id = curr.id
+ if id == glyphid then
+ local autojosaattr = has_attribute(curr, autojosaattr)
+ if autojosaattr then
+ local cc = curr.char
+ if cc == 0xC774 then
+ local n = getnext(curr)
+ if n and n.char and is_hangul(n.char) then
+ else
+ cc = 0xAC00
+ end
+ end
+ local t = josa_table[cc]
+ if t then
+ ignore_parens = autojosaattr > 0
+ cc = t[prevjosacode(getprev(curr)) or 3]
+ if cc then
+ curr.char = cc
+ else
+ head = noderemove(head, curr)
+ tableinsert(tofree, curr)
+ end
+ end
+ unset_attribute(curr, autojosaattr)
+ end
+ elseif id == mathid then
+ curr = end_of_math(curr)
end
- curr = d_getprev(curr)
+ curr = getnext(curr)
end
+ for _,v in ipairs(tofree) do nodefree(v) end
+ return head
end
----------------------------
--- automatic josa selection
----------------------------
-local function syllable2jamo (code)
- local code = code - 0xAC00
- local L = 0x1100 + mathfloor(code / 588)
- local V = 0x1161 + mathfloor((code % 588) / 28)
- local T = 0x11A7 + code % 28
- if T == 0x11A7 then T = nil end
- return L, V, T
-end
+-- dotemph
-local function number2josacode (n)
- n = n % 10 + stringbyte("0")
- if josa_code[n] then return josa_code[n] end
- return nil -- 2
-end
+local dotemphbox = {}
+luatexko.dotemphbox = dotemphbox
-local function latin2josacode (n)
- n = n + stringbyte("a")
- if josa_code[n] then return josa_code[n] end
- return nil -- 2
+local function process_dotemph (head, tofree)
+ local curr, outer, tofree = head, not tofree, tofree or {}
+ while curr do
+ local id = curr.id
+ if id == glyphid then
+ local dotattr = has_attribute(curr, dotemphattr)
+ if dotattr then
+ local c = my_node_props(curr).unicode or curr.char
+ if is_hangul(c) or is_hanja(c) or is_chosong(c) or is_kana(c) then
+ local currwd = curr.width
+ if currwd >= get_en_size(curr.font) then
+ local box = nodecopy(dotemphbox[dotattr])
+ local shift = (currwd - box.width)/2
+ if shift ~= 0 then
+ local list = box.list
+ local k = nodenew(kernid)
+ k.kern = shift
+ box.list = insert_before(list, list, k)
+ end
+ box.width = 0
+ head = insert_before(head, curr, box)
+ tofree[dotattr] = true
+ end
+ end
+ unset_attribute(curr, dotemphattr)
+ end
+ elseif id == hlistid then
+ local list = curr.list
+ if list then
+ curr.list, tofree = process_dotemph(list, tofree)
+ end
+ end
+ curr = getnext(curr)
+ end
+ if outer then
+ for k in pairs(tofree) do nodefree(dotemphbox[k]) end
+ end
+ return head, tofree
end
-for c = 0x2160, 0x216B do -- Ⅰ
- josa_code[c] = number2josacode(c - 0x215F)
-end
-for c = 0x2170, 0x217B do -- ⅰ
- josa_code[c] = number2josacode(c - 0x216F)
-end
-for c = 0x2460, 0x2473 do -- ①
- josa_code[c] = number2josacode(c - 0x245F)
-end
-for c = 0x2474, 0x2487 do -- ⑴
- josa_code[c] = number2josacode(c - 0x2473)
-end
-for c = 0x2488, 0x249B do -- ⒈
- josa_code[c] = number2josacode(c - 0x2487)
-end
-for c = 0x249C, 0x24B5 do -- ⒜
- josa_code[c] = latin2josacode(c - 0x249C)
-end
-for c = 0x24B6, 0x24CF do -- Ⓐ
- josa_code[c] = latin2josacode(c - 0x24B6)
-end
-for c = 0x24D0, 0x24E9 do -- ⓐ
- josa_code[c] = latin2josacode(c - 0x24D0)
-end
-for c = 0x3131, 0x314E do -- ㄱ
- josa_code[c] = 3
-end
-josa_code[0x3139] = 1 -- ㄹ
-for c = 0x3165, 0x3186 do
- josa_code[c] = 3
-end
-for c = 0x3200, 0x320D do -- ㈀
- josa_code[c] = 3
-end
-josa_code[0x3203] = 1 -- ㈃
-for c = 0x3260, 0x327F do -- ㉠
- josa_code[c] = 3
-end
-josa_code[0x3263] = 1 -- ㉣
-for c = 0xFF10, 0xFF19 do -- 0
- josa_code[c] = number2josacode(c - 0xFF10)
-end
-for c = 0xFF21, 0xFF3A do -- A
- josa_code[c] = latin2josacode(c - 0xFF21)
-end
-for c = 0xFF41, 0xFF5A do -- a
- josa_code[c] = latin2josacode(c - 0xFF41)
-end
+-- uline
-local function jamo2josacode(code)
- if code and code > 0x11A7 then
- if code == 0x11AF then return 1 end
- return 3
- end
- return 2
-end
+local uline_f, uline_id = new_user_whatsit("uline","luatexko")
+local no_uline_id = new_user_whatsit_id("no_uline","luatexko")
-local function get_hanja_hangul_table (table,file,init)
- local i = 0
- local file = kpse_find_file(file)
- if not file then return table end
- file = io.open(file, "r")
- if not file then return table end
- while true do
- local d = file:read("*number")
- if not d then break end
- table[init + i] = d
- i = i + 1
+local function ulboundary (i, n)
+ local what = uline_f()
+ if n then
+ what.type = lua_value -- table
+ what.value = { i, nodecopy(n) }
+ else
+ what.type = lua_number
+ what.value = i
end
- file:close()
- return table
+ nodewrite(what)
end
+luatexko.ulboundary = ulboundary
-local hanja2hangul
-local function initialize_hanja2hangul ()
- hanja2hangul = {}
- hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanja_hangul.tab",0x4E00)
- hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanjaexa_hangul.tab",0x3400)
- hanja2hangul = get_hanja_hangul_table(hanja2hangul,"hanjacom_hangul.tab",0xF900)
-end
+local white_nodes = {
+ [glueid] = true,
+ [penaltyid] = true,
+ [kernid] = true,
+ [whatsitid] = true,
+}
--- 1 : 리을, 2 : 중성, 3 : 종성
-local function get_josacode (prevs)
- local code = prevs[1] -- last char
- if not code then return 2 end
- if is_hangul(code) then -- hangul syllable
- local _, _, T = syllable2jamo(code)
- return jamo2josacode(T)
- end
- if is_jungjongsong(code) then return jamo2josacode(code) end
- if (code >= 0x3400 and code <= 0x9FA5)
- or (code >= 0xF900 and code <= 0xFA2D) then
- if not hanja2hangul then initialize_hanja2hangul() end
- local _, _, T = syllable2jamo(hanja2hangul[code])
- return jamo2josacode(T)
- end
- -- latin
- if prevs[1] < 0x80
- and prevs[2] and prevs[2] < 0x80
- and prevs[3] and prevs[3] < 0x80 then
- local liii = stringchar(prevs[3], prevs[2], prevs[1])
- if josa_code[liii] then return josa_code[liii] end
+function skip_white_nodes (n, ltr)
+ local nextnode = ltr and getnext or getprev
+ while n do
+ if not white_nodes[n.id] then break end
+ n = nextnode(n)
+ end
+ return n
+end
+
+local function draw_uline (head, curr, parent, t, final)
+ local start, list = t.start or head, t.list
+ start = skip_white_nodes(start, true)
+ nodeslide(start) -- to get correct getprev.
+ curr = skip_white_nodes(curr)
+ if getnext(curr) then curr = getnext(curr) end
+ local len = parent and rangedimensions(parent, start, curr)
+ or dimensions(start, curr) -- it works?!
+ if len and len ~= 0 then
+ local g = nodenew(glueid)
+ setglue(g, len)
+ g.subtype = xleaders
+ g.leader = final and list or nodecopy(list)
+ local k = nodenew(kernid)
+ k.kern = -len
+ head = insert_before(head, start, g)
+ head = insert_before(head, start, k)
end
- if prevs[1] < 0x80
- and prevs[2] and prevs[2] < 0x80 then
- local lii = stringchar(prevs[2], prevs[1])
- if josa_code[lii] then return josa_code[lii] end
- end
- if josa_code[code] then return josa_code[code] end
- return 2
+ return head
end
-local function get_josaprevs(curr,josaprev,ignoreparens,halt)
- if type(halt) ~= "number" then halt = 0 end
+local function process_uline (head, parent, ulitems, level)
+ local curr, ulitems, level = head, ulitems or {}, level or 0
while curr do
- local currid = d_getid(curr)
- if currid == glyphnode then
- local chr = d_get_unicode_char(curr)
- -- ignore chars inside parentheses (KTS workshop 2013.11.09)
- if ignoreparens and chr == 0x29 then -- right parenthesis
- halt = halt + 1
- elseif ignoreparens and chr == 0x28 then -- left parenthesis
- halt = halt - 1
- elseif xspcode[chr]
- or inhibitxspcode[chr]
- or prebreakpenalty[chr]
- or postbreakpenalty[chr]
- or is_unicode_vs(chr) -- bypass VS
- or chr == 0x302E -- tone mark
- or chr == 0x302F then -- tone mark
- --skip
- elseif halt <= 0 then
- josaprev[#josaprev + 1] = chr
+ local id = curr.id
+ if id == whatsitid
+ and curr.subtype == user_whatsit
+ and curr.user_id == uline_id then
+
+ local value = curr.value
+ if curr.type == lua_value then
+ local count, list = value[1], value[2]
+ ulitems[count] = { start = curr, list = list, level = level }
+ elseif ulitems[value] then
+ head = draw_uline(head, curr, parent, ulitems[value], true)
+ ulitems[value] = nil
end
- elseif currid == hlistnode or currid == vlistnode then
- josaprev = get_josaprevs(d_nodetail(d_getlist(curr)),josaprev,ignoreparens,halt)
- end
- if #josaprev == 3 then break end
- curr = d_getprev(curr)
- end
- return josaprev
-end
-local function korean_autojosa (head)
- local to_free = {}
- for curr in d_traverse_id(glyphnode,head) do
- local josaattr = d_has_attribute(curr,autojosaattr)
- if josaattr and d_has_attribute(curr,finemathattr) then
- local ignoreparens = josaattr > 1 and true or false
- local josaprev = {}
- josaprev = get_josaprevs(d_getprev(curr),josaprev,ignoreparens)
- local josacode = get_josacode(josaprev)
- local thischar = d_get_unicode_char(curr)
- if thischar == 0xC774 then
- local nn, nc = d_getnext(curr)
- if nn and d_getid(nn) == glyphnode then
- nc = d_get_unicode_char(nn)
- end
- if nc and nc >= 0xAC00 and nc <= 0xD7A3 then
- d_setchar(curr, josa_list[0xC774][josacode])
- else
- d_setchar(curr, josa_list[0xAC00][josacode])
- end
- elseif thischar and josa_list[thischar] then
- d_setchar(curr, josa_list[thischar][josacode])
+ curr.user_id = no_uline_id -- avoid multiple run
+ elseif id == hlistid then
+ local list = curr.list
+ if list then
+ curr.list, ulitems = process_uline(list, curr, ulitems, level+1)
end
end
- if d_getchar(curr) < 0 then
- d_remove_node(head,curr)
- to_free[#to_free + 1] = curr
- end
- end
- if #to_free > 0 then
- for _,v in ipairs(to_free) do d_nodefree(v) end
+ curr = getnext(curr)
end
-end
-
-------------------------------
--- switch to hangul/hanja font
-------------------------------
-local function hangulspaceskip (engfont, hfontid, glue)
- local eng = engfont.parameters
- if not eng then return end
- local gsp, gst, gsh, gsto, gsho = d_getglue(glue)
- if gsto ~= 0 or gsho ~= 0 then return end
- local esp, est, esh = eng.space, eng.space_stretch, eng.space_shrink
- esp = esp and tex_round(esp)
- est = est and tex_round(est)
- esh = esh and tex_round(esh)
- if esp == gsp and est == gst and esh == gsh then else return end
- local hf = get_font_table(hfontid)
--- if hf and hf.encodingbytes == 2 then else return end
- return gsp, hf
-end
-local function virtual_unifont (prefix,size)
- local data = {
- name = prefix.."vf",
- type = "virtual",
- fonts = {},
- characters = {},
- }
- local fonts = data.fonts
- local chars = data.characters
- for index = 0, 255 do
- local name = string.format(prefix.."%02x", index)
- if kpse_find_file(name,"tfm") then
- local tfm = font.read_tfm(name, size)
- data.parameters = data.parameters or tfm.parameters
- fonts[#fonts+1] = { name=name, size=size }
- local fid = #fonts
- local zro = 256 * index
- for i,v in pairs(tfm.characters) do
- local slot = zro + i
- chars[slot] = v
- chars[slot].commands = { { "slot", fid, i } }
- end
+ curr = nodeslide(head)
+ for i, t in pairs(ulitems) do
+ if level == t.level then
+ head = draw_uline(head, curr, parent, t)
+ t.start = nil
end
end
- return data
+ return head, ulitems
end
-local function nanumtype1font(curr)
- local currchar, currfont = d_getchar(curr), d_getfont(curr)
- if currchar > 0xFFFF then return end
- local fnt_t = get_font_table(currfont)
- if not fnt_t then return end
- local family = (d_has_attribute(curr,finemathattr) or 0) > 1 and not is_hanja(currchar) and "nanummj" or "nanumgt"
- local series = fnt_t.shared and
- fnt_t.shared.rawdata and
- fnt_t.shared.rawdata.metadata and
- fnt_t.shared.rawdata.metadata.pfmweight
- if series then
- series = series > 500 and "b" or "m"
- else
- series = fnt_t.name:find("^cmb") and "b" or "m"
- end
- local shape = fnt_t.parameters.slant > 0 and "o" or ""
- local prefix = stringformat("%s%s%s",family,series,shape)
- local fsize = fnt_t.size or 655360
- local fspec = stringformat("%s@%d",prefix,fsize)
- local fontid = type1fonts[fspec]
- if fontid == nil then -- bypass false
- local fontdata = virtual_unifont(prefix, fsize)
- fontid = fontdata and fontdefine(fontdata)
- if fontid then
- type1fonts[fspec] = fontid
- type1fonts[fontid] = fontdata
- else
- type1fonts[fspec] = false
- end
- end
- return fontid
-end
+-- ruby
+
+local rubybox = {}
+luatexko.rubybox = rubybox
-local function font_substitute(head)
+local function process_ruby_pre_linebreak (head)
local curr = head
while curr do
- local currid = d_getid(curr)
- if currid == glyphnode then
- local currchar, currfont = d_getchar(curr), d_getfont(curr)
- if currchar then
- if is_unicode_vs(currchar) then -- ideograph variation selectors
- local prev = d_getprev(curr)
- local prevfont = d_getid(prev) == glyphnode and d_getfont(prev)
- if prevfont ~= currfont then
- d_setfield(curr, "font", prevfont) -- sync font
- end
- else
- local myfontchar, forcehangul, forcehanja
- local eng = currfont and get_font_table(currfont)
- if eng and eng.encodingbytes and eng.encodingbytes == 2 -- exclude type1
- and hangulpunctuations[currchar] and d_has_attribute(curr, hangulpunctsattr)
- and (d_has_attribute(curr, finemathattr) or 0) > 0 -- not ttfamily
- and not get_font_char(currfont, 0xAC00) then -- exclude hangul font
- else
- if luatexko.hangulfontforhangul or luatexko.hanjafontforhanja then
- local uni = d_get_unicode_char(curr)
- uni = uni and get_cjk_class(uni) or 10
- if uni < 7 then
- forcehanja = luatexko.hanjafontforhanja
- elseif uni < 10 then
- forcehangul = luatexko.hangulfontforhangul
- end
- end
- if not forcehangul and not forcehanja then
- myfontchar = get_font_char(currfont, currchar)
- end
- end
- if not myfontchar then
- local hangul = d_has_attribute(curr, hangulfntattr)
- local hanja = d_has_attribute(curr, hanjafntattr)
- local fallback = d_has_attribute(curr, fallbackfntattr)
- local ftable = {hangul, hanja, fallback}
- if forcehanja then ftable = {hanja, hangul, fallback} end
- local fid
- for i = 1,3 do
- fid = ftable[i]
- myfontchar = fid and get_font_char(fid, currchar)
- if myfontchar then break end
- end
- if not myfontchar and not hangulpunctuations[currchar] then
- fid = nanumtype1font(curr)
- myfontchar = fid and get_font_char(fid, currchar)
- end
- if myfontchar then
- d_setfield(curr,"font",fid)
- --- charraise option charraise
- local charraise = get_font_feature(fid, "charraise")
- if charraise then
- charraise = tex_sp(charraise)
- local curryoffset = d_getfield(curr,"yoffset") or 0
- d_setfield(curr,"yoffset", charraise + curryoffset)
- end
- ---
- local nxt = d_getnext(curr)
- local nxtid = nxt and d_getid(nxt)
- if nxtid == glyphnode and is_unicode_vs(d_getchar(nxt)) then
- nxt = d_getnext(nxt)
- nxtid = nxt and d_getid(nxt)
- end
- if eng and nxtid then
- local nxtsubtype = d_getsubtype(nxt)
- -- adjust next glue by hangul font space
- if nxtid == gluenode and nxtsubtype == glue_type_space and get_font_char(fid,32) then
- local oldwd, ft = hangulspaceskip(eng, fid, nxt)
- if oldwd and ft then
- local newwd = ft.space_char_width
- if not newwd then
- local newsp = d_tonode(d_copy_node(curr))
- newsp.char = 32
- newsp = nodes.simple_font_handler(newsp)
- newwd = newsp and newsp.width
- ft.space_char_width = newwd
- node.free(newsp)
- end
- if newwd and oldwd ~= newwd then
- d_setglue(nxt, newwd, newwd/2, newwd/3)
- end
- end
- -- adjust next italic correction kern
- elseif nxtid == kernnode and nxtsubtype == kern_type_itlc and d_getfield(nxt,"kern") == 0 then
- local ksl = get_font_table(fid).parameters.slant
- if ksl and ksl > 0 then
- d_setfield(nxt,"kern", myfontchar.italic or 0)
- end
- end
- end
- end
+ local id = curr.id
+ if id == hlistid then
+ local rubyid = has_attribute(curr, rubyattr)
+ if rubyid then
+ local ruby_t = rubybox[rubyid]
+ if ruby_t[3] then -- rubyoverlap
+ local side = (ruby_t[1].width - curr.width)/2
+ if side > 0 then -- ruby is wide
+ local k, r = nodenew(kernid), nodenew(ruleid)
+ k.subtype, k.kern = userkern, -side
+ r.width, r.height, r.depth = side, 0, 0
+ local k2, r2 = nodecopy(k), nodecopy(r)
+ head = insert_before(head, curr, k)
+ head = insert_before(head, curr, r)
+ head, curr = insert_after(head, curr, r2)
+ head, curr = insert_after(head, curr, k2)
end
+ ruby_t[3] = false
end
end
- elseif currid == mathnode then
- if d_getsubtype(curr) == 0 then
- curr = d_end_of_math(curr)
- end
- elseif currid == discnode then
- local pre, post, replace = d_getdisc(curr)
- if pre then font_substitute(pre) end
- if post then font_substitute(post) end
- if replace then font_substitute(replace) end
+ elseif id == mathid then
+ curr = end_of_math(curr)
end
- curr = d_getnext(curr)
- end
-end
-
------------------------------
--- reserve unicode code point
------------------------------
-local function assign_unicode_codevalue (head)
- for curr in d_traverse_id(glyphnode, head) do
- d_set_attribute(curr, luakounicodeattr, d_getchar(curr))
+ curr = getnext(curr)
end
+ return head
end
------------------------------
--- reorder hangul tone marks
------------------------------
-local function reorderTM (head)
- local curr, todo = head, nil
+local function process_ruby_post_linebreak (head)
+ local curr = head
while curr do
- local nid = d_getid(curr)
- if nid == glyphnode then
- local uni = d_get_unicode_char(curr)
- if uni == 0x302E or uni == 0x302F then
- local tmgl = get_font_char(d_getfont(curr), uni)
- local tmwidth = tmgl and tmgl.width or 0
- if todo then
- if tmwidth > 0 then
- local tm = curr
- head, curr = d_remove_node(head, curr)
- d_setprev(tm, nil) -- prev might survive!
- head = d_insert_before(head, todo, tm)
- curr = d_getprev(curr)
- end
- elseif get_font_char(d_getfont(curr), 0x25CC) then
- local u25CC = d_copy_node(curr)
- d_setchar(u25CC, 0x25CC)
- if tmwidth > 0 then
- head, curr = d_insert_after(head, curr, u25CC)
- else
- head = d_insert_before(head, curr, u25CC)
+ if curr.id == hlistid then
+ local rubyid = has_attribute(curr, rubyattr)
+ if rubyid then
+ local ruby_t = rubybox[rubyid]
+ local ruby = ruby_t and ruby_t[1]
+ if ruby then
+ local side = (curr.width - ruby.width)/2
+ if side ~= 0 then
+ local list = ruby.list
+ local k = nodenew(kernid)
+ k.kern = side
+ ruby.list = insert_before(list, list, k)
end
+ ruby.width = 0
+ ruby.shift = -(curr.height + ruby_t[2]) -- rubysep
+ head = insert_before(head, curr, ruby)
end
- todo = nil
- elseif is_hangul(uni) or is_chosong(uni) or uni == 0x25CC then
- todo = curr
- elseif is_jungjongsong(uni) then
+ ruby_t = nil
+ unset_attribute(curr, rubyattr)
else
- todo = nil
+ local list = curr.list
+ if list then
+ curr.list = process_ruby_post_linebreak(list)
+ end
end
- elseif nid == kernnode then
- else
- todo = nil
end
- curr = d_getnext(curr)
+ curr = getnext(curr)
end
return head
end
-----------------------------------
--- add to callback : pre-linebreak
-----------------------------------
-
-add_to_callback("hpack_filter", function(head)
- head = d_todirect(head)
- assign_unicode_codevalue(head)
- korean_autojosa(head)
- remove_cj_spaceskip(head)
- font_substitute(head)
- return d_tonode(head)
-end, 'luatexko.hpack_filter_first', 1)
-
-add_to_callback('hpack_filter', function(head)
- head = d_todirect(head)
- if texcount["luakorubyattrcnt"]>0 then get_ruby_side_kern(head) end
- cjk_spacing_linebreak(head)
- if texcount["luakorubyattrcnt"]>0 then spread_ruby_base_box(head) end
- head = compress_fullwidth_punctuations(head)
- -- head = no_ruby_at_margin(head)
- head = reorderTM(head)
- return d_tonode(head)
-end, 'luatexko.hpack_filter')
-
-add_to_callback('pre_linebreak_filter', function(head)
- head = d_todirect(head)
- assign_unicode_codevalue(head)
- korean_autojosa(head)
- remove_cj_spaceskip(head)
- font_substitute(head)
- return d_tonode(head)
-end, 'luatexko.pre_linebreak_filter_first', 1)
-
-add_to_callback('pre_linebreak_filter', function(head)
- head = d_todirect(head)
- if texcount["luakorubyattrcnt"]>0 then get_ruby_side_kern(head) end
- cjk_spacing_linebreak(head)
- if texcount["luakorubyattrcnt"]>0 then spread_ruby_base_box(head) end
- head = compress_fullwidth_punctuations(head)
- discourage_char_widow(head, d_nodetail(head))
- if texcount["luakorubyattrcnt"]>0 then head = no_ruby_at_margin(head) end
- head = reorderTM(head)
- return d_tonode(head)
-end, 'luatexko.pre_linebreak_filter')
-
-
---------------------------
--- dot emphasis (드러냄표)
---------------------------
-local function after_linebreak_dotemph (head, to_free)
- local outer = not to_free
- to_free = to_free or {}
- for curr in d_traverse(head) do
- local currid = d_getid(curr)
- if currid == hlistnode then -- hlist may be nested!!!
- d_setlist(curr, after_linebreak_dotemph(d_getlist(curr), to_free))
- elseif currid == glyphnode then
- local attr = d_has_attribute(curr,dotemphattr)
- if attr and attr > 0 then
- local cc = get_cjk_class(d_get_unicode_char(curr))
- if cc and (cc == 0 or cc == 7 or cc == 8) then
- local basewd = d_getfield(curr,"width") or 0
- if cc == 8 then -- check next char for old hangul jung/jongseong
- local nn = d_getnext(curr)
- while nn do
- if d_getid(nn) ~= glyphnode then break end
- local uni = d_get_unicode_char(nn)
- local nc = get_cjk_class(uni)
- if nc and nc == 9 and uni ~= 0x302E and uni ~= 0x302F then
- basewd = basewd + (d_getfield(nn,"width") or 0)
- else
- break
- end
- nn = d_getnext(nn)
- end
- end
- local dbox = d_todirect(dotemphnode[attr])
- local d = d_copy_node(dbox)
- local dwidth = d_getfield(d,"width")
- local dot = d_get_kernnode(basewd/2-dwidth/2)
- d_setnext(dot, d_getlist(d))
- d_setlist(d, dot)
- d_setfield(d,"width", 0)
- head = d_insert_before(head,curr,d)
- to_free[dbox] = true
- end
- d_unset_attribute(curr,dotemphattr)
- end
- end
- end
- if outer then
- for k in pairs(to_free) do d_nodefree(k) end
+-- reorder tone marks
+
+local function conv_tounicode (uni)
+ if uni < 0x10000 then
+ return stringformat("%04X", uni)
+ else -- surrogate
+ uni = uni - 0x10000
+ local high = uni // 0x400 + 0xD800
+ local low = uni % 0x400 + 0xDC00
+ return stringformat("%04X%04X", high, low)
end
- return head
end
--------------------------------
--- ruby: post-linebreak routine
--------------------------------
-local function after_linebreak_ruby (head)
- for curr in d_traverse_id(hlistnode,head) do
- after_linebreak_ruby(d_getlist(curr)) -- hlist may be nested!!!
- local attr = d_has_attribute(curr,luakorubyattr)
- if attr then
- local ruby = rubynode[attr] and d_todirect(rubynode[attr][1])
- if ruby then
- local currwidth, rubywidth = d_getfield(curr,"width"), d_getfield(ruby,"width")
- local currheight = d_getfield(curr,"height")
- if rubywidth < currwidth then
- local rubyhead = d_getlist(ruby)
- local numofglues = d_nodecount(gluenode,rubyhead)
- local extrawidth = (currwidth - rubywidth)/(numofglues + 1)
- d_setfield(ruby,"width", currwidth - extrawidth/2)
- if numofglues > 0 then
- d_setlist(ruby, spread_ruby_box(rubyhead,extrawidth))
- end
- else
- local right = rubynode[attr].rightshift or 0
- d_setfield(ruby,"width", currwidth + (rubywidth-currwidth+right)/2)
- end
- d_setfield(ruby,"shift", -currheight-rubynode[attr][2])
- d_insert_after(head,curr,ruby)
- d_insert_after(head,curr,d_get_kernnode(-d_getfield(ruby,"width")))
- end
- rubynode[attr] = nil
- d_unset_attribute(curr,luakorubyattr)
+local function pdfliteral_direct_actual (syllable)
+ local data
+ if syllable then
+ local t = {}
+ for _,v in ipairs(syllable) do
+ tableinsert(t, conv_tounicode(v))
end
+ data = stringformat("/Span<</ActualText<FEFF%s>>>BDC", tableconcat(t))
+ else
+ data = "EMC"
+ end
+ local what = nodenew(whatsitid, literal_whatsit)
+ what.mode = directmode
+ what.data = data
+ if syllable then
+ my_node_props(what).startactualtext = syllable
+ else
+ my_node_props(what).endactualtext = true
end
+ return what
end
----------------------
--- underline emphasis
----------------------
-
-local uline_start_id = luatexbase.new_whatsit("luako_uline_start")
-local uline_stop_id = luatexbase.new_whatsit("luako_uline_stop")
-local function uline_boundary (num, list)
- local n = d_nodenew(whatsitnode, user_whatsit)
- d_setfield(n, "user_id", list and uline_start_id or uline_stop_id)
- d_setfield(n, "type", 110) -- node list
- d_setfield(n, "value", n_copy_list(list))
- d_set_attribute(n, luakoulineattr, num)
- d_nodewrite(n)
+local function get_tonemark_width (curr, uni)
+ local fontid = curr.font
+ local hwidth = char_font_options.tonemarkwidth[fontid]
+ if not hwidth then
+ -- check horizontal width; vertical width is mostly non-zero
+ local fontdata = get_font_data(fontid)
+ local shared = fontdata.shared or {}
+ local rawdata = shared.rawdata or {}
+ local descriptions = rawdata.descriptions or {}
+ local description = descriptions[uni] or {}
+ hwidth = description.width or 0
+ char_font_options.tonemarkwidth[fontid] = hwidth
+ end
+ return hwidth
end
-luatexko.uline_boundary = uline_boundary
-local skippable = {
- [gluenode ] = true,
- [penaltynode] = true,
- [kernnode ] = true,
- [whatsitnode] = true,
-}
-local function draw_underline(head,curr,glueset,gluesign,glueorder,ubox,start)
- start = start or head
- while start do
- if not skippable[d_getid(start)] then break end
- start = d_getnext(start)
- end
+local function process_reorder_tonemarks (head)
+ local curr = head
while curr do
- local p = d_getprev(curr)
- if not skippable[d_getid(p)] then break end
- curr = p
- end
- local width = d_nodedimensions(glueset,gluesign,glueorder,start,curr)
- if width and width > 0 then
- local glue = d_get_gluenode(width)
- d_setsubtype(glue, 101) -- cleaders
- d_setleader(glue, d_copy_node(ubox))
- head = d_insert_before(head, start, glue)
- head = d_insert_before(head, start, d_get_kernnode(-width))
- end
- return head
-end
+ local id = curr.id
+ if id == glyphid and option_in_font(curr.font, "script") == "hang" then
+ local fontdata = get_font_data(curr.font)
+ local uni = my_node_props(curr).unicode or curr.char
+ if is_hangul(uni) or is_chosong(uni) or uni == 0x25CC then
+
+ local syllable = { [0]=curr, uni }
+
+ local n = getnext(curr)
+ while n do
+ local nid = n.id
+ if nid == glyphid then
+ local u = my_node_props(n).unicode or n.char
+ if is_jungsong(u)
+ or is_jongsong(u)
+ or hangul_tonemark[u] then
+ tableinsert(syllable, u)
+ curr, uni = n, u
+ else
+ break
+ end
+ elseif nid ~= kernid or n.subtype == userkern then
+ break
+ end
+ n = getnext(n)
+ end
+
+ if #syllable > 1
+ and hangul_tonemark[uni]
+ and get_tonemark_width(curr, uni) ~= 0 then
+
+ local ini, fin = syllable[0], curr
+ local actual = pdfliteral_direct_actual(syllable)
+ local endactual = pdfliteral_direct_actual()
+ head = insert_before(head, ini, actual)
+ head, curr = insert_after(head, curr, endactual)
-local function after_linebreak_underline(head,glueorder,glueset,gluesign,ulstart,level)
- ulstart, level = ulstart or {}, level or 0
-
- for curr in d_traverse(head) do
- local currid = d_getid(curr)
- if currid == hlistnode then
- local newhead
- newhead, ulstart = after_linebreak_underline(
- d_getlist(curr),
- d_getfield(curr,"glue_order"),
- d_getfield(curr,"glue_set"),
- d_getfield(curr,"glue_sign"),
- ulstart,
- level+1)
- d_setlist(curr, newhead)
- elseif currid == whatsitnode and d_getsubtype(curr) == user_whatsit then
- local attr = d_has_attribute(curr, luakoulineattr)
- local whatsit_type = d_getfield(curr, "type")
- if attr and whatsit_type == 110 then
- local user_id = d_getfield(curr, "user_id")
- if user_id == uline_start_id then
- local list = d_getfield(curr, "value")
- ulstart[attr] = { start = curr, list = list, level = level }
- elseif user_id == uline_stop_id and ulstart[attr] then
- local ubox, start = ulstart[attr].list, ulstart[attr].start
- head = draw_underline(head,curr,glueset,gluesign,glueorder,ubox,start)
- ulstart[attr] = nil
+ head = noderemove(head, fin)
+ head = insert_before(head, ini, fin)
end
- d_unset_attribute(curr,luakoulineattr)
- end
- end
- end
- local curr = d_nodetail(head)
- for i, v in pairs(ulstart) do
- local ubox, start = v.list, v.start
- if ubox and level == v.level then
- head = draw_underline(head,curr,glueset,gluesign,glueorder,ubox,start)
- ulstart[i].start = nil
- end
- end
+ elseif hangul_tonemark[uni] -- isolated tone mark
+ and char_in_font(fontdata, 0x25CC) then
+
+ local dotcircle = nodecopy(curr)
+ dotcircle.char = 0x25CC
+ if get_tonemark_width(curr, uni) ~= 0 then
+ local actual = pdfliteral_direct_actual{ [0]=curr, uni }
+ local endactual = pdfliteral_direct_actual()
+ head = insert_before(head, curr, actual)
+ head, curr = insert_after(head, curr, dotcircle)
+ head, curr = insert_after(head, curr, endactual)
+ else
+ head = insert_before(head, curr, dotcircle)
+ end
+ end
+ elseif id == whatsitid
+ and curr.mode == directmode
+ and my_node_props(curr).startactualtext then
- return head, ulstart
-end
+ curr = goto_end_actualtext(curr)
------------------------------------
--- add to callback : post-linebreak
------------------------------------
-add_to_callback('vpack_filter', function(head)
- head = d_todirect(head)
- if texcount["luakodotemphcnt"]>0 then head = after_linebreak_dotemph(head) end
- if texcount["luakorubyattrcnt"]>0 then after_linebreak_ruby(head) end
- if texcount["luakoulineboxcnt"]>0 then head = after_linebreak_underline(head) end
- return d_tonode(head)
-end, 'luatexko.vpack_filter')
-
-add_to_callback('hpack_filter', function(head, groupcode)
- if groupcode == "align_set" then
- head = d_todirect(head)
- if texcount["luakodotemphcnt"]>0 then head = after_linebreak_dotemph(head) end
- if texcount["luakorubyattrcnt"]>0 then after_linebreak_ruby(head) end
- if texcount["luakoulineboxcnt"]>0 then head = after_linebreak_underline(head) end
- head = d_tonode(head)
+ elseif id == mathid then
+ curr = end_of_math(curr)
+ end
+ curr = getnext(curr)
end
return head
-end, 'luatexko.hpack_filter.postlinebreak')
+end
+-- vertical font
-------------------------------------
--- vertical typesetting: EXPERIMENTAL
-------------------------------------
local streamreader = utilities.files
local openfile = streamreader.open
local closefile = streamreader.close
@@ -1919,7 +1324,7 @@ local readfixed = streamreader.readfixed4
local readshort = streamreader.readinteger2
local setpos = streamreader.setposition
-local function getotftables (f, subfont)
+local function get_otf_tables (f, subfont)
if f then
local sfntversion = readstring(f,4)
if sfntversion == "ttcf" then
@@ -1953,7 +1358,7 @@ local function getotftables (f, subfont)
end
end
-local function readmaxp (f, t)
+local function read_maxp (f, t)
if f and t then
setpos(f, t.offset)
return {
@@ -1963,7 +1368,7 @@ local function readmaxp (f, t)
end
end
-local function readvhea (f, t)
+local function read_vhea (f, t)
if f and t then
setpos(f, t.offset)
return {
@@ -1988,7 +1393,7 @@ local function readvhea (f, t)
end
end
-local function readvmtx (f, t, numofheights, numofglyphs)
+local function read_vmtx (f, t, numofheights, numofglyphs)
if f and t and numofheights and numofglyphs then
setpos(f, t.offset)
local vmtx = {}
@@ -2010,96 +1415,93 @@ local function readvmtx (f, t, numofheights, numofglyphs)
end
end
-local tsbtable
+local tsb_font_data = {}
local function get_tsb_table (filename, subfont)
subfont = tonumber(subfont) or 1
local key = stringformat("%s::%s", filename, subfont)
- if tsbtable[key] then
- return tsbtable[key]
+ if tsb_font_data[key] then
+ return tsb_font_data[key]
end
local f = openfile(filename, true) -- true: zero-based
if f then
local vmtx
- local tables = getotftables(f, subfont)
+ local tables = get_otf_tables(f, subfont)
if tables then
- local vhea = readvhea(f, tables.vhea)
+ local vhea = read_vhea(f, tables.vhea)
local numofheights = vhea and vhea.numheights
- local maxp = readmaxp(f, tables.maxp)
+ local maxp = read_maxp(f, tables.maxp)
local numofglyphs = maxp and maxp.numglyphs
- vmtx = readvmtx(f, tables.vmtx, numofheights, numofglyphs)
+ vmtx = read_vmtx(f, tables.vmtx, numofheights, numofglyphs)
end
closefile(f)
- tsbtable[key] = vmtx
+ tsb_font_data[key] = vmtx
return vmtx
end
end
-local function cjk_vertical_font (vf)
- if not vf.shared then return end
- if not vf.shared.features then return end
- if not vf.shared.features["vertical"] then return end
- if vf.type == "virtual" then return end
-
- local subfont = vf.specification and vf.specification.sub
- local tsbtable = get_tsb_table(vf.filename, subfont)
- if not tsbtable then
- warn("%s does not have vertical metric info", vf.fontname)
+local function process_vertical_font (fontdata)
+ local subfont = fontdata.specification and fontdata.specification.sub
+ local tsb_tab = get_tsb_table(fontdata.filename, subfont)
+ if not tsb_tab then
+ warning("Vertical metrics table (vmtx) not found in the font\n"..
+ "`%s'", fontdata.fontname)
return
end
- local params = vf.parameters or {}
- local shared = vf.shared or {}
- local quad = params.quad or 655360
- local ascender = params.ascender or quad*0.8
- local descender = params.descender or quad*0.2
- local factor = params.factor or 655.36
- local xheight = params.x_height or quad/2
- local goffset = xheight/2 - quad/2
- local descriptions = shared.rawdata and shared.rawdata.descriptions
- local spbp = 65536*(7227/7200)
- for i,v in pairs(vf.characters) do
- local dsc = descriptions[i]
- local gl = v.index
- local tsb_gl = tsbtable and tsbtable[gl]
- local vw = tsb_gl and tsb_gl.ht; vw = vw and vw * factor or quad
- local tsb = tsb_gl and tsb_gl.tsb
- local bb4 = dsc and dsc.boundingbox and dsc.boundingbox[4]
- local asc = bb4 and tsb and (bb4+tsb)*factor or ascender
- local hw = v.width or quad
- local offset = hw/2 + goffset
- local vh = hw > 0 and hw or 0
- asc = asc/spbp; offset = offset/spbp
+ local shared = fontdata.shared or {}
+ local descriptions = shared.rawdata and shared.rawdata.descriptions or {}
+ local parameters = fontdata.parameters or {}
+ local scale = parameters.factor or 655.36
+ local quad = parameters.quad or 655360
+ local ascender = parameters.ascender or quad*0.8
+ local goffset = fontdata_opt_dim(fontdata, "charraise")
+ if not goffset then
+ goffset = (parameters.x_height or quad/2) / 2
+ end
+ for i,v in pairs(fontdata.characters) do
+ local voff = goffset - (v.width or 0)/2
+ local bbox = descriptions[i] and descriptions[i].boundingbox or {0,0,0,0}
+ local gid = v.index
+ local tsb = tsb_tab[gid].tsb
+ local hoff = tsb and (bbox[4] + tsb) * scale or ascender
v.commands = {
- {'special', stringformat('pdf:q 0 1 -1 0 %.3f %.3f cm', asc, -offset)},
- {'push'},
- {'char', i},
- {'pop'},
- {'special', 'pdf:Q'},
+ { "down", -voff },
+ { "right", hoff },
+ { "pdf", "q 0 1 -1 0 0 0 cm" },
+ { "push" },
+ { "char", i },
+ { "pop" },
+ { "pdf", "Q" },
}
- v.width = vw
- v.height = vh*(ascender/quad)
- v.depth = vh*(descender/quad)
- v.italic = nil
+ local vw = tsb_tab[gid].ht
+ v.width = vw and vw * scale or quad
+ local ht = bbox[3] * scale + voff
+ local dp = bbox[1] * scale + voff
+ v.height = ht > 0 and ht or nil
+ v.depth = dp < 0 and -dp or nil
end
- --- vertical gpos
- local res = vf.resources or {}
- if res.verticalgposhack then
- return -- avoid multiple running
+ local spacechar = char_in_font(fontdata, 32)
+ if spacechar then
+ parameters.space = spacechar.width
+ parameters.space_stretch = spacechar.width/2
+ parameters.space_shrink = spacechar.width/2
end
+
+ local res = fontdata.resources or {}
local fea = shared.features or {}
- fea.kern = nil -- only for horizontal typesetting
+ fea.kern = nil -- only for horizontal writing
fea.vert = true -- should be activated by default
local seq = res.sequences or {}
for _,v in ipairs(seq) do
local fea = v.features or {}
if fea.vhal or fea.vkrn or fea.valt or fea.vpal or fea.vert then
if v.type == "gpos_single" then
- for _,vv in pairs(v.steps or{}) do
- local cover = vv.coverage or {}
- for iii,vvv in pairs(cover) do
+ for _,vv in pairs(v.steps or {}) do
+ for _,vvv in pairs(vv.coverage or {}) do
if type(vvv) == "table" and #vvv == 4 then
- cover[iii] = { -vvv[2], vvv[1], vvv[4], vvv[3], 0 }
+ vvv[1], vvv[2], vvv[3], vvv[4], vvv[5] =
+ -vvv[2], vvv[1], vvv[4], vvv[3], 0 -- last 0 to avoid multiple run
end
end
end
@@ -2107,10 +1509,10 @@ local function cjk_vertical_font (vf)
for _,vv in pairs(v.steps or {}) do
for _,vvv in pairs(vv.coverage or {}) do
for _,vvvv in pairs(vvv) do
- for iiiii,vvvvv in pairs(vvvv) do
+ for _,vvvvv in pairs(vvvv) do
if type(vvvvv) == "table" and #vvvvv == 4 then
- -- last 0 to avoid multiple round
- vvvv[iiiii] = { -vvvvv[2], vvvvv[1], vvvvv[4], vvvvv[3], 0 }
+ vvvvv[1], vvvvv[2], vvvvv[3], vvvvv[4], vvvvv[5] =
+ -vvvvv[2], vvvvv[1], vvvvv[4], vvvvv[3], 0
end
end
end
@@ -2119,72 +1521,228 @@ local function cjk_vertical_font (vf)
end
end
end
- res.verticalgposhack = true
end
-local otffeatures = fonts.constructors.newfeatures("otf")
-otffeatures.register {
- name = "vertical",
- description = "vertical typesetting",
- initializers = {
- node = function (tfmdata,value)
- if value and not tsbtable then
- tsbtable = {}
- add_to_callback("luaotfload.patch_font",cjk_vertical_font,"luatexko.vertical_virtual_font")
+-- charraise
+
+local function process_charriase_font (fontdata)
+ local raise = fontdata_opt_dim(fontdata, "charraise")
+ if raise then
+ local shared = fontdata.shared or {}
+ local descriptions = shared.rawdata and shared.rawdata.descriptions or {}
+ local scale = fontdata.parameters.factor or 655.36
+ for i, v in pairs( fontdata.characters ) do
+ v.commands = {
+ {"down", -raise },
+ {"char", i},
+ }
+ local bbox = descriptions[i] and descriptions[i].boundingbox or {0,0,0,0}
+ local ht = bbox[4] * scale + raise
+ local dp = bbox[2] * scale + raise
+ v.height = ht > 0 and ht or nil
+ v.depth = dp < 0 and -dp or nil
+ end
+ end
+end
+
+-- fake italic correctioin
+
+local function process_fake_slant_corr (head) -- for font fallback
+ local curr = head
+ while curr do
+ local id = curr.id
+ if id == kernid then
+ if curr.subtype == italcorr and curr.kern == 0 then
+ local p = getprev(curr)
+ while p do -- skip jungsong/jongsong
+ if p.id == glyphid and p.width < get_en_size(p.font) then
+ local c = my_node_props(p).unicode or p.char
+ if not is_jungsong(c) and not is_jongsong(c) then
+ break
+ end
+ elseif p.id == whatsitid
+ and p.mode == directmode
+ and my_node_props(p).endactualtext then -- skip
+ else
+ break
+ end
+ p = getprev(p)
+ end
+ if p.id == glyphid then
+ local fontdata = get_font_data(p.font)
+ if fontdata.slant and fontdata.slant > 0 then
+ local italic = char_in_font(fontdata, p.char).italic
+ if italic then
+ curr.kern = italic
+ end
+ end
+ end
end
+ elseif id == mathid then
+ curr = end_of_math(curr)
end
- }
-}
+ curr = getnext(curr)
+ end
+ return head
+end
-------------------------------------
--- no embedding
-------------------------------------
-local function dontembedthisfont (tfmdata, value)
- if value == "no" then
- fonts.constructors.dontembed[tfmdata.properties.filename] = 1
+local function process_fake_slant_font (fontdata)
+ local fsl = fontdata.slant
+ if fsl and fsl > 0 then
+ fsl = fsl/1000
+ local params = fontdata.parameters or {}
+ params.slant = (params.slant or 0) + fsl*65536 -- slant per point
+ local scale = params.factor or 655.36
+ local shared = fontdata.shared or {}
+ local descriptions = shared.rawdata and shared.rawdata.descriptions or {}
+ for i, v in pairs(fontdata.characters) do
+ local bbox = descriptions[i] and descriptions[i].boundingbox or {0,0,0,0}
+ local italic = (v.height or 0) * fsl - (v.width or 0) + bbox[3]*scale
+ if italic > 0 then
+ v.italic = italic
+ end
+ end
end
end
-otffeatures.register {
- name = "embedding",
- description = "dont embed this font",
- initializers = {
- base = dontembedthisfont,
- node = dontembedthisfont,
- }
+-- wrap up
+
+local pass_fun = function(...) return ... end
+create_callback("luatexko_pre_hpack", "data", pass_fun)
+create_callback("luatexko_pre_prelinebreak", "data", pass_fun)
+create_callback("luatexko_post_hpack", "data", pass_fun)
+create_callback("luatexko_post_prelinebreak", "data", pass_fun)
+
+add_to_callback("hpack_filter", function(h)
+ h = process_fonts(h)
+ h = call_callback("luatexko_pre_hpack", h)
+ h = call_callback("luatexko_post_hpack", h)
+ return process_linebreak(h)
+end, "luatexko.hpack_filter.pre_rendering", 1)
+
+add_to_callback("pre_linebreak_filter", function(h)
+ h = process_fonts(h)
+ h = call_callback("luatexko_pre_prelinebreak", h, true)
+ h = call_callback("luatexko_post_prelinebreak", h, true)
+ return process_linebreak(h, true)
+end, "luatexko.pre_linebreak_filter.pre_rendering", 1)
+
+local font_opt_procs = {
+ removeclassicspaces = {
+ luatexko_pre_hpack = process_remove_spaces,
+ luatexko_pre_prelinebreak = process_remove_spaces,
+ },
+ interhangul = {
+ luatexko_post_hpack = process_interhangul,
+ luatexko_post_prelinebreak = process_interhangul,
+ },
+ interlatincjk = {
+ luatexko_post_hpack = process_interlatincjk,
+ luatexko_post_prelinebreak = process_interlatincjk,
+ },
+ compresspunctuations = {
+ hpack_filter = process_glyph_width,
+ pre_linebreak_filter = process_glyph_width,
+ },
+ slant = {
+ hpack_filter = process_fake_slant_corr,
+ pre_linebreak_filter = process_fake_slant_corr,
+ },
}
-------------------------------------
--- italic correction for fake-slant font
-------------------------------------
-local function fakeslant_itlc (tfmdata)
- local slfactor = tfmdata.parameters.slantfactor
- if slfactor and slfactor > 0 then else return end
- tfmdata.parameters.slant = slfactor * 65536
- local chrs = tfmdata.characters
- for i,v in pairs(chrs) do
- local italic = v.height * slfactor
- if italic > 0 then
- chrs[i].italic = italic
+local function process_patch_font (fontdata)
+ for name, procs in pairs( font_opt_procs ) do
+ if not active_processes[name] and option_in_font(fontdata, name) then
+ for cbnam, cbfun in pairs( procs ) do
+ add_to_callback(cbnam, cbfun, "luatexko."..cbnam.."."..name)
+ end
+ active_processes[name] = true
end
end
-end
-add_to_callback("luaotfload.patch_font", fakeslant_itlc, "luatexko.fakeslant_itlc")
-
-------------------------------------
--- Actual Text
-------------------------------------
-local function actualtext (str)
- local t = {}
- for uni in string.utfvalues(str) do
- if uni < 0x10000 then
- t[#t+1] = stringformat("%04X",uni)
- else -- surrogate
- uni = uni - 0x10000
- t[#t+1] = stringformat("%04X%04X", uni/0x400+0xD800, uni%0x400+0xDC00)
+ if not active_processes.expansion
+ and option_in_font(fontdata, "expansion") then
+ texset("global", "adjustspacing", 2)
+ active_processes.expansion = true
+ end
+
+ if option_in_font(fontdata, "protrusion") then
+ if not active_processes.protrusion then
+ texset("global", "protrudechars", 2)
+ active_processes.protrusion = true
+ end
+ if not active_processes[fontdata.fontname] and
+ option_in_font(fontdata, "compresspunctuations") then
+ warning("Both `compresspunctuations' and `protrusion' are\n"..
+ "enabled for the font `%s'.\n"..
+ "Beware that this could result in bad justifications.\n",
+ fontdata.fontname)
+ active_processes[fontdata.fontname] = true
end
end
- tex.sprint(stringformat("<FEFF%s>", table.concat(t)))
+
+ if option_in_font(fontdata, "vertical") then
+ process_vertical_font(fontdata)
+ elseif option_in_font(fontdata, "charraise") then
+ process_charriase_font(fontdata)
+ end
+
+ if option_in_font(fontdata, "slant") then
+ process_fake_slant_font(fontdata)
+ end
+end
+
+add_to_callback("luaotfload.patch_font", process_patch_font,
+"luatexko.patch_font")
+
+local auxiliary_procs = {
+ dotemph = {
+ hpack_filter = process_dotemph,
+ vpack_filter = process_dotemph,
+ },
+ uline = {
+ hpack_filter = process_uline,
+ vpack_filter = process_uline,
+ },
+ ruby = {
+ pre_linebreak_filter = process_ruby_pre_linebreak,
+ hpack_filter = process_ruby_post_linebreak,
+ vpack_filter = process_ruby_post_linebreak,
+ },
+ autojosa = {
+ luatexko_pre_hpack = process_josa,
+ luatexko_pre_prelinebreak = process_josa,
+ },
+ reorderTM = {
+ luatexko_pre_hpack = process_reorder_tonemarks,
+ luatexko_pre_prelinebreak = process_reorder_tonemarks,
+ },
+}
+
+local function activate (name)
+ for cbnam, cbfun in pairs( auxiliary_procs[name] ) do
+ local fun
+ if cbnam == "hpack_filter" then
+ fun = function(h, gc)
+ if gc == "align_set" then
+ h = cbfun(h)
+ end
+ return h
+ end
+ else
+ fun = function(h)
+ h = cbfun(h)
+ return h
+ end
+ end
+ add_to_callback(cbnam, fun, "luatexko."..cbnam.."."..name)
+ end
+end
+luatexko.activate = activate
+
+-- default hangul font
+
+local function current_has_hangul_chars (cnt)
+ texcount[cnt] = char_in_font(fontcurrent(), 0xAC00) and 1 or 0
end
-luatexko.actualtext = actualtext
+luatexko.currenthashangulchars = current_has_hangul_chars
diff --git a/Master/texmf-dist/tex/luatex/luatexko/luatexko.sty b/Master/texmf-dist/tex/luatex/luatexko/luatexko.sty
index a54b14ade60..d575a0ce1df 100644
--- a/Master/texmf-dist/tex/luatex/luatexko/luatexko.sty
+++ b/Master/texmf-dist/tex/luatex/luatexko/luatexko.sty
@@ -1,7 +1,7 @@
% luatexko.sty
%
-% Copyright (c) 2013-2019 Dohyun Kim <nomos at ktug org>
-% Soojin Nam <jsunam at gmail com>
+% Copyright (c) 2013-2019 Dohyun Kim <nomos at ktug org>
+% Soojin Nam <jsunam at gmail com>
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
@@ -11,450 +11,707 @@
% and version 1.3c or later is part of all distributions of LaTeX
% version 2006/05/20 or later.
-\ifx\luatexkocatcodeofatchar\undefined\else\endinput\fi % no multiple loading
-
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname selectfont\endcsname\relax % plain tex
- \edef\luatexkocatcodeofatchar{\catcode`@=\the\catcode`@}
- \input luatexko-core.sty
- %\hangulfont{name:NanumGothic:interlatincjk=0.125em} at 10pt
- %\setmathhangulfont{NanumGothic}
- \luatexkocatcodeofatchar
- \expandafter\endinput
-\fi
-
-\ProvidesPackage{luatexko}[2019/04/06 v1.24 Typesetting Korean with LuaLaTeX]
-
-\ifdefined\adjustspacing\else % luatex < 0.87
- \let\adjustspacing\pdfadjustspacing
- \let\protrudechars\pdfprotrudechars
+\ifdefined\luatexkohangulfontattr \endinput\fi
+\ifdefined\selectfont
+ \ProvidesPackage{luatexko}[2019/05/01 v2.0 typesetting Korean with LuaTeX]
+ \RequirePackage{luatexbase}
+ \RequirePackage{fontspec}
+\else
+ \input luatexbase.sty
+ \input luaotfload.sty
+ \chardef\luatexkoatcatcode=\catcode`\@
+ \catcode`\@=11
\fi
-
-%% package options
-\newif\if@hangul
-\newif\if@hanja
-\newif\if@luatexko@loadfontspec\@luatexko@loadfontspectrue
-\DeclareOption{hangul}{\@hangultrue}
-\DeclareOption{hanja}{\@hangultrue\@hanjatrue}
-\DeclareOption{unfonts}{}
-\DeclareOption{nofontspec}{\@luatexko@loadfontspecfalse}
-\ProcessOptions\relax
-
-\if@luatexko@loadfontspec
- \RequirePackage{fontspec}[2018/07/30]
+\protected\def\pdfliteral{\pdfextension literal}
+\newattribute\luatexkohangulfontattr
+\newattribute\luatexkohanjafontattr
+\newattribute\luatexkofallbackfontattr
+\newattribute\luatexkoautojosaattr
+\newattribute\luatexkoclassicattr
+\newattribute\luatexkodotemphattr
+\newattribute\luatexkorubyattr \chardef\luatexkorubyalloc\allocationnumber
+\directlua{ require"luatexko.lua" }
+% classic
+\protected\def\typesetclassic{\luatexkoclassicattr\z@\parindent1em }
+\protected\def\typesetvertical{\luatexkoclassicattr\@ne\parindent1em }
+\protected\def\typesetmodern{\unsetattribute\luatexkoclassicattr}
+\protected\def\inhibitglue{\hskip\z@skip}
+\protected\def\Schinese{\luatexkoclassicattr\tw@\parindent2em }
+\protected\def\Tchinese{\luatexkoclassicattr\thr@@\parindent2em } % +halt
+\let\korean\typesetmodern \let\japanese\typesetclassic \let\chinese\Schinese
+% josa
+\count@"AC00
+\loop
+ \catcode\count@ 12
+ \ifnum\count@<"D7A3 \advance\count@\@ne \repeat
+\newcount\josaignoreparens
+\def\luatexkojosaactivate{%
+ \ifx\luatexkojosaactive\relax
+ \else
+ \directlua{ luatexko.activate("autojosa") }%
+ \global\let\luatexkojosaactive\relax
+ \fi
+ \luatexkoautojosaattr\josaignoreparens }
+\protected\def\은{\begingroup\luatexkojosaactivate 은\endgroup}
+\let\는\은
+\protected\def\을{\begingroup\luatexkojosaactivate 을\endgroup}
+\let\를\을
+\protected\def\와{\begingroup\luatexkojosaactivate 와\endgroup}
+\let\과\와
+\protected\def\가{\begingroup\luatexkojosaactivate 가\endgroup}
+\protected\def\이{\begingroup\luatexkojosaactivate 이\endgroup}
+\protected\def\라{\이라}
+\protected\def\으{\begingroup\luatexkojosaactivate 으\endgroup}
+\protected\def\로{\으로}
+% force hangul font
+\def\luatexkotoks@appendchars#1,{%
+ \ifx\empty#1\empty
+ \expandafter\luatexkotoks@appendchars
+ \else
+ \ifx*#1\else
+ \expandafter\ifx\expandafter\empty\the\toks@\empty
+ \etoksapp0{\number#1}%
+ \else
+ \etoksapp0{,\number#1}%
+ \fi
+ \expandafter\expandafter\expandafter\luatexkotoks@appendchars
+ \fi
+ \fi }
+\def\luatexkodoluacode#1{\directlua{
+ \ifhmode luatexko.updateforcehangul(function() \fi
+ #1
+ \ifhmode end) \fi }}
+\protected\def\registerpunctuations#1{%
+ \toks@{}\luatexkotoks@appendchars#1,*,\luatexkodoluacode{
+ local t = luatexko.forcehangulchars
+ for _,v in ipairs{\the\toks@} do t[v]=true end }}
+\let\registerhangulpunctuations\registerpunctuations
+\protected\def\unregisterpunctuations#1{%
+ \toks@{}\luatexkotoks@appendchars#1,*,\luatexkodoluacode{
+ local t = luatexko.forcehangulchars
+ for _,v in ipairs{\the\toks@} do t[v]=nil end }}
+\let\unregisterhangulpunctuations\unregisterpunctuations
+\protected\def\hangulpunctuations{%
+ \afterassignment\luatexkohangulpunctuations\count@ }
+\def\luatexkohangulpunctuations{\luatexkodoluacode{
+ local t = luatexko.forcehangulchars
+ for i in pairs(t) do t[i]=\ifcase\count@ false \else true \fi end }}
+\protected\def\registerbreakableafter#1{%
+ \toks@{}\luatexkotoks@appendchars#1,*,\luatexkodoluacode{
+ local t = luatexko.breakableafter
+ for _,v in ipairs{\the\toks@} do t[v]=true end }}
+\protected\def\registerbreakablebefore#1{%
+ \toks@{}\luatexkotoks@appendchars#1,*,\luatexkodoluacode{
+ local t = luatexko.breakablebefore
+ for _,v in ipairs{\the\toks@} do t[v]=true end }}
+\protected\def\hangulbyhangulfont{%
+ \afterassignment\luatexkohangulbyhangulfont\count@ }
+\def\luatexkohangulbyhangulfont{\luatexkodoluacode{
+ luatexko.hangulbyhangulfont=\ifcase\count@ false \else true \fi }}
+\protected\def\hanjabyhanjafont{%
+ \afterassignment\luatexkohanjabyhanjafont\count@ }
+\def\luatexkohanjabyhanjafont{\luatexkodoluacode{
+ luatexko.hanjabyhanjafont=\ifcase\count@ false \else true \fi }}
+% dotemph
+\newcount\luatexkodotemphcount
+\def\dotemphraise{1ex }
+\unless\ifdefined\bfseries\let\bfseries\bf\fi
+\def\dotemphchar{\bfseries\char"02D9 }
+\protected\def\dotemph#1{%
+ \global\advance\luatexkodotemphcount\@ne
+ \begingroup
+ \setbox\z@\hbox{\raise\dotemphraise\hbox{\dotemphchar}}%
+ \directlua{
+ if \the\luatexkodotemphcount == 1 then luatexko.activate("dotemph") end
+ luatexko.dotemphbox[\the\luatexkodotemphcount] = node.copy(tex.box[0].list)
+ }\luatexkodotemphattr\luatexkodotemphcount #1%
+ \endgroup }
+% uline
+\newcount\luatexkoulinecount
+\def\ulinedown{0.5ex }\def\ulinewidth{0.04em }
+\protected\def\markoverwith#1#2{%
+ \global\advance\luatexkoulinecount\@ne
+ \begingroup
+ \count@\luatexkoulinecount
+ \ifx\luatexkoulinerunning\relax
+ \edef\ulinedown{\the\dimexpr\ulinedown+\ulinewidth+.15ex\relax}\fi
+ \let\luatexkoulinerunning\relax
+ \leavevmode
+ \setbox\z@\hbox{#1}%
+ \directlua{
+ if \the\luatexkoulinecount == 1 then luatexko.activate("uline") end
+ luatexko.ulboundary(\the\count@, tex.box[0].list)
+ }#2\directlua{
+ luatexko.ulboundary(\the\count@)
+ }\endgroup }
+\protected\def\uline{\markoverwith{%
+ \vrule width\z@ height-\ulinedown depth\dimexpr\ulinedown+\ulinewidth\relax }}
+\protected\def\dashuline{\markoverwith{%
+ \hbox{\kern.125em
+ \vrule width.3em height-\ulinedown depth\dimexpr\ulinedown+\ulinewidth\relax
+ \kern.125em }}}
+\protected\def\dotuline{\markoverwith{%
+ \lower\dimexpr\ulinedown+.1ex\relax\hbox{\kern.07em .\kern.07em }}}
+\protected\def\uuline#1{\uline{\uline{#1}}}
+\protected\def\sout#1{\begingroup
+ \def\ulinedown{-.5\dimexpr\ulinewidth+1ex\relax}%
+ \uline{#1}\endgroup}
+\protected\def\xout{\markoverwith{\hbox to.4em{\hss/\hss}}}
+\protected\def\uwave{\font\luatexkofontsixly=lasy6\relax
+ \markoverwith{\lower4\p@\hbox{\luatexkofontsixly\char58}}}
+% ruby
+\def\rubysize{0.6} % size of ruby compared to base chars
+\def\rubysep{0.2ex} % distance between base chars and ruby
+\def\luatexkostretchfactor{.0125} % .5em/20/2 is hard coded.
+\newif\ifruby@overlap
+\let\rubyoverlap\ruby@overlaptrue
+\let\rubynooverlap\ruby@overlapfalse
+\rubyoverlap % ruby may hangover neighboring chars
+\newcount\luatexkorubycount
+\def\luatexkorubybasehbox{\hbox attr\luatexkorubyalloc=\luatexkorubycount}
+\protected\def\ruby#1#2{%
+ \global\advance\luatexkorubycount\@ne
+ \begingroup
+ \leavevmode
+ \setbox\z@\luatexkorubybasehbox{% base
+ \vrule width\z@ height 2ex depth\z@ #1}%
+ \setbox\tw@\hbox{% ruby
+ \ifdefined\rubyfont \rubyfont \fi
+ \ifdefined\selectfont % <- latex
+ \dimen@\dimexpr\rubysize em\relax
+ \fontsize\dimen@\dimen@\selectfont
+ \fi
+ #2}%
+ \hbadness\@M % supress underfull warning
+ \dimen@ii\dimexpr\rubysize em\relax % ruby font size
+ \ifdim\wd\z@ < \wd\tw@ % ruby is wider
+ \ifruby@overlap
+ \dimen@\dimexpr\wd\tw@-\wd\z@-\dimen@ii\relax % overhang .5 rubysize
+ \ifdim\dimen@ > \z@
+ \setbox\z@\luatexkorubybasehbox spread\dimen@{%
+ \hskip\z@ plus \luatexkostretchfactor em\relax
+ \unhbox\z@
+ \hskip\z@ plus \luatexkostretchfactor em\relax }%
+ \fi
+ \else
+ \setbox\z@\luatexkorubybasehbox to\wd\tw@{%
+ \hskip\z@ plus \luatexkostretchfactor em\relax
+ \unhbox\z@
+ \hskip\z@ plus \luatexkostretchfactor em\relax }%
+ \fi
+ \else
+ \ifdim\rubysize\wd\z@ > 2\wd\tw@ % ruby is far shorter
+ \setbox\tw@\hbox to\wd\z@{%
+ \hskip\dimen@ii\relax
+ \unhbox\tw@
+ \hskip\dimen@ii\relax }%
+ \else
+ \setbox\tw@\hbox to\wd\z@{%
+ \hskip\z@ plus \luatexkostretchfactor \dimen@ii\relax
+ \unhbox\tw@
+ \hskip\z@ plus \luatexkostretchfactor \dimen@ii\relax }%
+ \fi
+ \fi
+ \directlua{
+ if \the\luatexkorubycount == 1 then luatexko.activate("ruby") end
+ luatexko.rubybox[\the\luatexkorubycount] = {
+ node.copy(tex.box[2]),
+ \number\numexpr\dimexpr\rubysep\relax\relax,
+ \ifruby@overlap true\else false\fi, }}%
+ \box\z@
+ \endgroup }
+\protected\def\xxruby#1#2{%
+ \begingroup\def\basestr{#1}\def\rubystr{#2}\luatexkoxxruby\endgroup }
+\def\luatexkoxxruby{%
+ \ifx\empty\basestr\else
+ \expandafter\luatexkogetrubybasechar\basestr\end
+ \expandafter\luatexkogetrubyrubychar\rubystr\end
+ \ruby\basechar\rubychar
+ \expandafter\luatexkoxxruby
+ \fi }
+\def\luatexkogetrubybasechar#1#2\end{\def\basechar{#1}\def\basestr{#2}}
+\def\luatexkogetrubyrubychar#1#2\end{\def\rubychar{#1}\def\rubystr{#2}}
+% vertical writing
+\protected\def\vertical#1{%
+ \leavevmode
+ \setbox\z@\vbox\bgroup
+ \hsize#1\relax
+ \typesetvertical }
+\protected\def\endvertical{%
+ \egroup
+ \luatexkorotatebox\z@
+ \box\z@ }
+\protected\def\luatexkorotatebox#1{%
+ \setbox#1\hbox to\dimexpr\ht#1+\dp#1{%
+ \hfil
+ \vbox to\wd#1{%
+ \wd#1\z@ \ht#1\z@ \dp#1\z@
+ \pdfliteral{q 0 -1 1 0 0 0 cm}\box#1\pdfliteral{Q}%
+ \vfil }}}
+% horizontal box inside vertical writing
+\protected\def\horizontal#1{%
+ \leavevmode
+ \setbox\z@\vbox\bgroup
+ \hsize#1\relax
+ \typesetmodern }
+\protected\def\endhorizontal{%
+ \egroup
+ \luatexkounrotatebox\z@
+ \box\z@ }
+\protected\def\luatexkounrotatebox#1{%
+ \setbox#1\hbox to\dimexpr\ht#1+\dp#1{%
+ \vbox to\wd#1{%
+ \vfil
+ \wd#1\z@ \ht#1\z@ \dp#1\z@
+ \pdfliteral{q 0 1 -1 0 0 0 cm}\box#1\pdfliteral{Q}}%
+ \hfil }}
+% do not veticalize headline/footline
+\ifdefined\selectfont
+ \def\verticaltypesetting{%
+ \maxdepth\z@ \typesetvertical
+ \dimen@\textwidth \textwidth\textheight \textheight\dimen@
+ \edef\@outputpage{\unexpanded{\luatexkorotatebox\@outputbox
+ \textwidth\textheight}\unexpanded\expandafter{\@outputpage}}}
+\else
+ \def\verticaltypesetting{%
+ \dimen@\hsize \hsize\vsize \vsize\dimen@
+ \edef\plainoutput{\unexpanded{\dimen@\hsize \hsize\vsize \vsize\dimen@}%
+ \unexpanded\expandafter{\plainoutput}}%
+ \def\pagebody{\setbox\z@\vbox to\hsize{\boxmaxdepth=\maxdepth
+ \pagecontents}\luatexkorotatebox\z@\box\z@}%
+ \maxdepth\z@ \typesetvertical }
\fi
-
-\RequirePackage{luatexko-core}
-
-\if@luatexko@loadfontspec
- %% fontspec Korean options
- \newfontfeature{YetHangul}{script=hang}
- \newfontfeature{InterHangul}{interhangul=#1}
- \newfontfeature{InterLatinCJK}{interlatincjk=#1}
- \newfontfeature{PunctRaise}{punctraise=#1}
- \newfontfeature{CharRaise}{charraise=#1}
- \newfontfeature{NoEmbed}{embedding=no}
- \aliasfontfeature{NoEmbed}{NoEmbedding}
- \newfontfeature{protrusion}{protrusion=#1}
- \newfontfeature{expansion}{expansion=#1}
- \ExplSyntaxOn
- \DeclareDocumentCommand \newhangulfontfeature {mmmm}
- {
- \keys_define:nn { fontspec }
- {
- #1 .code:n =
- {
- \keys_set:nn { fontspec } { #2 = {##1} } #4
- },
- #1 .default:n = {#3}
- }
- }
- \newhangulfontfeature{Protrusion}{protrusion}{default}
- {\aftergroup\protrudechars\aftergroup\tw@}
- \newhangulfontfeature{Expansion}{expansion}{default}
- {\aftergroup\adjustspacing\aftergroup\tw@}
- %% default font features
- \cs_set_eq:NN \defaulthangulfontfeatures \defaultfontfeatures
- \cs_set_eq:NN \defaulthanjafontfeatures \defaultfontfeatures
- \cs_set_eq:NN \defaultfallbackfontfeatures \defaultfontfeatures
- \defaultfontfeatures
- [
- \serifhangul@font, \serifhanja@font, \seriffallback@font,
- \sanshangul@font, \sanshanja@font, \sansfallback@font,
- ]
- {Ligatures=TeX}
- %% macros for Korean fonts
- \DeclareDocumentCommand \setmainhangulfont { O{} m O{} }
- {
- \setfontfamily \serifhangul@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \rmdefault
- {
- \cs_set_eq:NN \hangul@font \serifhangul@font
- \luatexko@hangul@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setmainhanjafont { O{} m O{} }
- {
- \setfontfamily \serifhanja@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \rmdefault
- {
- \cs_set_eq:NN \hanja@font \serifhanja@font
- \luatexko@hanja@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setmainfallbackfont { O{} m O{} }
- {
- \setfontfamily \seriffallback@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \rmdefault
- {
- \cs_set_eq:NN \fallback@font \seriffallback@font
- \luatexko@fallback@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setsanshangulfont { O{} m O{} }
- {
- \setfontfamily \sanshangul@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \sfdefault
- {
- \cs_set_eq:NN \hangul@font \sanshangul@font
- \luatexko@hangul@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setsanshanjafont { O{} m O{} }
- {
- \setfontfamily \sanshanja@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \sfdefault
- {
- \cs_set_eq:NN \hanja@font \sanshanja@font
- \luatexko@hanja@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setsansfallbackfont { O{} m O{} }
- {
- \setfontfamily \sansfallback@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \sfdefault
- {
- \cs_set_eq:NN \fallback@font \sansfallback@font
- \luatexko@fallback@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setmonohangulfont { O{} m O{} }
- {
- \setfontfamily \monohangul@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \ttdefault
- {
- \cs_set_eq:NN \hangul@font \monohangul@font
- \luatexko@hangul@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setmonohanjafont { O{} m O{} }
- {
- \setfontfamily \monohanja@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \ttdefault
- {
- \cs_set_eq:NN \hanja@font \monohanja@font
- \luatexko@hanja@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \setmonofallbackfont { O{} m O{} }
- {
- \setfontfamily \monofallback@font [#1,#3] {#2}
- \str_if_eq_x:nnT \familydefault \ttdefault
- {
- \cs_set_eq:NN \fallback@font \monofallback@font
- \luatexko@fallback@selectfont
- }
- \ignorespaces
- }
- \DeclareDocumentCommand \newhangulfontfamily { m O{} m O{} }
- {
- \exp_args:Nc \setfontfamily { luatexkofont@ \token_to_str:N #1 } [#2,#4] {#3}
- \DeclareRobustCommand #1
- {
- \cs_set_eq:Nc \hangul@font { luatexkofont@ \token_to_str:N #1 }
- \luatexko@hangul@selectfont
- }
- }
- \DeclareDocumentCommand \newhanjafontfamily { m O{} m O{} }
- {
- \exp_args:Nc \setfontfamily { luatexkofont@ \token_to_str:N #1 } [#2,#4] {#3}
- \DeclareRobustCommand #1
- {
- \cs_set_eq:Nc \hanja@font { luatexkofont@ \token_to_str:N #1 }
- \luatexko@hanja@selectfont
- }
- }
- \DeclareDocumentCommand \newfallbackfontfamily { m O{} m O{} }
- {
- \exp_args:Nc \setfontfamily { luatexkofont@ \token_to_str:N #1 } [#2,#4] {#3}
- \DeclareRobustCommand #1
- {
- \cs_set_eq:Nc \fallback@font { luatexkofont@ \token_to_str:N #1 }
- \luatexko@fallback@selectfont
- }
- }
- \DeclareDocumentCommand \newhangulfontface { m O{} m O{} }
- {
- \exp_args:Nc \newfontface { luatexkofont@ \token_to_str:N #1 } [#2,#4] {#3}
- \DeclareRobustCommand #1
- {
- \cs_set_eq:Nc \hangul@font { luatexkofont@ \token_to_str:N #1 }
- \luatexko@hangul@selectfont
- }
- }
- \DeclareDocumentCommand \newhanjafontface { m O{} m O{} }
- {
- \exp_args:Nc \newfontface { luatexkofont@ \token_to_str:N #1 } [#2,#4] {#3}
- \DeclareRobustCommand #1
- {
- \cs_set_eq:Nc \hanja@font { luatexkofont@ \token_to_str:N #1 }
- \luatexko@hanja@selectfont
- }
- }
- \DeclareDocumentCommand \newfallbackfontface { m O{} m O{} }
- {
- \exp_args:Nc \newfontface { luatexkofont@ \token_to_str:N #1 } [#2,#4] {#3}
- \DeclareRobustCommand #1
- {
- \cs_set_eq:Nc \fallback@font { luatexkofont@ \token_to_str:N #1 }
- \luatexko@fallback@selectfont
- }
- }
- \DeclareDocumentCommand \hangulfontspec { O{} m O{} }
- {
- \setfontfamily \hangul@font [#1,#3] {#2}
- \luatexko@hangul@selectfont
- \ignorespaces
- }
- \cs_set_eq:NN \adhochangulfont \hangulfontspec
- \DeclareDocumentCommand \hanjafontspec { O{} m O{} }
- {
- \setfontfamily \hanja@font [#1,#3] {#2}
- \luatexko@hanja@selectfont
- \ignorespaces
- }
- \cs_set_eq:NN \adhochanjafont \hanjafontspec
- \DeclareDocumentCommand \fallbackfontspec { O{} m O{} }
- {
- \setfontfamily \fallback@font [#1,#3] {#2}
- \luatexko@fallback@selectfont
- \ignorespaces
- }
- \cs_set_eq:NN \adhocfallbackfont \fallbackfontspec
- \DeclareDocumentCommand \addhangulfontfeature { m }
- {
- \group_begin:
- \cs_if_exist:NT \hangul@font { \hangul@font }
- \addfontfeature {#1}
- \use:x
- {
- \group_end:
- \exp_not:N \tl_set:Nn \exp_not:N \hangul@font
- {
- \exp_not:N \fontfamily { \f@family } \exp_not:N \selectfont
- }
- }
- \luatexko@hangul@selectfont
- \ignorespaces
- }
- \cs_set_eq:NN \addhangulfontfeatures \addhangulfontfeature
- \DeclareDocumentCommand \addhanjafontfeature { m }
- {
- \group_begin:
- \cs_if_exist:NT \hanja@font { \hanja@font }
- \addfontfeature {#1}
- \use:x
- {
- \group_end:
- \exp_not:N \tl_set:Nn \exp_not:N \hanja@font
- {
- \exp_not:N \fontfamily { \f@family } \exp_not:N \selectfont
- }
- }
- \luatexko@hanja@selectfont
- \ignorespaces
- }
- \cs_set_eq:NN \addhanjafontfeatures \addhanjafontfeature
- \DeclareDocumentCommand \addfallbackfontfeature { m }
- {
- \group_begin:
- \cs_if_exist:NT \fallback@font { \fallback@font }
- \addfontfeature {#1}
- \use:x
- {
- \group_end:
- \exp_not:N \tl_set:Nn \exp_not:N \fallback@font
- {
- \exp_not:N \fontfamily { \f@family } \exp_not:N \selectfont
- }
- }
- \luatexko@fallback@selectfont
- \ignorespaces
- }
- \cs_set_eq:NN \addfallbackfontfeatures \addfallbackfontfeature
- % hangul math font command
- \DeclareDocumentCommand \setmathhangulfont { O{} m O{} }
+% hangul normalize
+\def\luatexhangulnormalize{%
+ \directlua{require"luatexko-normalize"}%
+ \afterassignment\luatexkohangulnormalize\count@}
+\def\luatexkohangulnormalize{%
+ \ifcase\count@ \directlua{ luatexkonormalize.unload() }% 0: none
+ \or \directlua{ luatexkonormalize.compose() }% 1: nfc
+ \else \directlua{ luatexkonormalize.decompose() }% 2: nfd
+ \fi }
+% convert uhc to utf8
+\def\luatexuhcinputencoding{%
+ \directlua{require"luatexko-uhc2utf8"}%
+ \afterassignment\luatexkouhcinputencoding\count@}
+\def\luatexkouhcinputencoding{%
+ \ifcase\count@ \directlua{ luatexkouhc2utf8.stopconvert() }%
+ \else \directlua{ luatexkouhc2utf8.startconvert() }%
+ \fi}
+% actualtext not provided
+\protected\def\actualtext#1#{\luatexkoactualtext}
+\def\luatexkoactualtext#1{#1}
+% math hangul
+\def\setmathhangulblock#1#2{%
+ \count@="#1
+ \loop
+ \Umathcode\count@ = 7 \symmathhangul\count@
+ \ifnum\count@<"#2 \advance\count@\@ne \repeat}
+% font fallback
+\newif\ifluatexkoselectfontrunning
+\def\luatexkohangulselectfont{%
+ \ifluatexkoselectfontrunning \else
+ \ifdefined\luatexkohangulfont
+ \begingroup
+ \luatexkoselectfontrunningtrue
+ \luatexkohangulfont
+ \expandafter\expandafter\expandafter\endgroup
+ \expandafter\luatexkohangulfontattr\fontid\font\relax
+ \fi
+ \fi }
+\def\luatexkohanjaselectfont{%
+ \ifluatexkoselectfontrunning \else
+ \ifdefined\luatexkohanjafont
+ \begingroup
+ \luatexkoselectfontrunningtrue
+ \luatexkohanjafont
+ \expandafter\expandafter\expandafter\endgroup
+ \expandafter\luatexkohanjafontattr\fontid\font\relax
+ \fi
+ \fi }
+\def\luatexkofallbackselectfont{%
+ \ifluatexkoselectfontrunning \else
+ \ifdefined\luatexkofallbackfont
+ \begingroup
+ \luatexkoselectfontrunningtrue
+ \luatexkofallbackfont
+ \expandafter\expandafter\expandafter\endgroup
+ \expandafter\luatexkofallbackfontattr\fontid\font\relax
+ \fi
+ \fi }
+% plain
+\ifdefined\selectfont\else
+ \protected\def\hangulfont{%
+ \afterassignment\luatexkohangulselectfont\font\luatexkohangulfont}
+ \protected\def\hanjafont{%
+ \afterassignment\luatexkohanjaselectfont\font\luatexkohanjafont}
+ \protected\def\fallbackfont{%
+ \afterassignment\luatexkofallbackselectfont\font\luatexkofallbackfont}
+ \newfam\symmathhangul
+ \protected\def\setmathhangulfonts#1#2#3{% font identifiers
+ \ifnum\Umathcharfam"AC00=\symmathhangul\else
+ \setmathhangulblock{AC00}{D7A3}%
+ \fi
+ \textfont\symmathhangul=#1\relax
+ \scriptfont\symmathhangul=#2\relax
+ \scriptscriptfont\symmathhangul=#3\relax }
+ \protected\def\mathhangulfont{%
+ \afterassignment\luatexkosetmathhangulfonts\font\textmathhangul}
+ \def\luatexkosetmathhangulfonts{%
+ \toks@\expandafter{\directlua{
+ local n = string.gsub("\fontname\textmathhangul", " at .+", "")
+ tex.sprint(n) }}%
+ \dimen@\fontdimen 6 \textmathhangul
+ \font\scriptmathhangul= {\the\toks@} at .7\dimen@
+ \font\scriptscriptmathhangul = {\the\toks@} at .5\dimen@
+ \setmathhangulfonts\textmathhangul\scriptmathhangul\scriptscriptmathhangul}
+ \catcode`\@=\luatexkoatcatcode
+\endinput\fi
+% latex
+\RequirePackage{everysel}
+\EverySelectfont{%
+ \ifx\f@encoding\UTFencname
+ \luatexkohangulselectfont
+ \luatexkohanjaselectfont
+ \luatexkofallbackselectfont
+ \fi }
+\protected\def\fontfamily#1{\edef\f@family{#1}% redefine \fontfamily
+ \ifx\f@encoding\UTFencname
+ \ifluatexkoselectfontrunning \else
+ \ifx\f@family\rmdefault
+ \let\luatexkohangulfont\luatexkomainhangulfont
+ \let\luatexkohanjafont\luatexkomainhanjafont
+ \let\luatexkofallbackfont\luatexkomainfallbackfont
+ \else\ifx\f@family\sfdefault
+ \let\luatexkohangulfont\luatexkosanshangulfont
+ \let\luatexkohanjafont\luatexkosanshanjafont
+ \let\luatexkofallbackfont\luatexkosansfallbackfont
+ \else\ifx\f@family\ttdefault
+ \let\luatexkohangulfont\luatexkomonohangulfont
+ \let\luatexkohanjafont\luatexkomonohanjafont
+ \let\luatexkofallbackfont\luatexkomonofallbackfont
+ \fi\fi\fi
+ \fi\fi }
+% fontspec-like
+\ExplSyntaxOn
+\DeclareDocumentCommand \setmainhangulfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomainhangulfamily { Ligatures=TeX, #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkomainhangulfont
+ {
+ \fontfamily \luatexkomainhangulfamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \rmdefault
+ {
+ \cs_set_eq:NN \luatexkohangulfont \luatexkomainhangulfont
+ \luatexkohangulselectfont
+ }
+ \ignorespaces
+}
+\DeclareDocumentCommand \setsanshangulfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkosanshangulfamily { Ligatures=TeX, #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkosanshangulfont
+ {
+ \fontfamily \luatexkosanshangulfamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \sfdefault
+ {
+ \cs_set_eq:NN \luatexkohangulfont \luatexkosanshangulfont
+ \luatexkohangulselectfont
+ }
+ \ignorespaces
+}
+\DeclareDocumentCommand \setmonohangulfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomonohangulfamily { #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkomonohangulfont
+ {
+ \fontfamily \luatexkomonohangulfamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \ttdefault
+ {
+ \cs_set_eq:NN \luatexkohangulfont \luatexkomonohangulfont
+ \luatexkohangulselectfont
+ }
+ \ignorespaces
+}
+\DeclareDocumentCommand \newhangulfontfamily { m O{} m O{} }
+{
+ \fontspec_set_family:cnn { luatexko_user_family_ \cs_to_str:N #1 } { #2, #4 } { #3 }
+ \DeclareRobustCommand #1
+ {
+ \tl_set:Nn \luatexkohangulfont
{
- \fontspec_set_family:Nnn \luatexko@math@hangul@family {#1,#3} {#2}
+ \exp_args:Nc \fontfamily { luatexko_user_family_ \cs_to_str:N #1 } \selectfont
}
-%% fontspec 2018
-\RenewDocumentCommand \setmainfont { O{} m O{} }
+ \luatexkohangulselectfont
+ }
+ \ignorespaces
+}
+\DeclareDocumentCommand \newhangulfontface { m O{} m O{} }
+{
+ \newhangulfontfamily #1 { #3 } [ BoldFont={}, ItalicFont={}, SmallCapsFont={}, #2, #4 ]
+}
+\DeclareDocumentCommand \hangulfontspec { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkohangulfontfamily { #1, #3 } { #2 }
+ \tl_set:Nn \luatexkohangulfont
{
- \__fontspec_main_setmainfont:nn {#1,#3} {#2}
- \protected\edef\rmfamily{
- \unexpanded{\luatexko@serif@fonts}
- \unexpanded\expandafter{\rmfamily}
- }
- \ignorespaces
+ \fontfamily \luatexkohangulfontfamily \selectfont
+ }
+ \luatexkohangulselectfont
+ \ignorespaces
+}
+\DeclareDocumentCommand \setmainhanjafont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomainhanjafamily { Ligatures=TeX, #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkomainhanjafont
+ {
+ \fontfamily \luatexkomainhanjafamily \selectfont
}
-\RenewDocumentCommand \setsansfont { O{} m O{} }
+ \str_if_eq_x:nnT \familydefault \rmdefault
{
- \__fontspec_main_setsansfont:nn {#1,#3} {#2}
- \protected\edef\sffamily{
- \unexpanded{\luatexko@sans@fonts}
- \unexpanded\expandafter{\sffamily}
- }
- \ignorespaces
+ \cs_set_eq:NN \luatexkohanjafont \luatexkomainhanjafont
+ \luatexkohanjaselectfont
}
-\RenewDocumentCommand \setmonofont { O{} m O{} }
+ \ignorespaces
+}
+\DeclareDocumentCommand \setsanshanjafont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkosanshanjafamily { Ligatures=TeX, #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkosanshanjafont
{
- \__fontspec_main_setmonofont:nn {#1,#3} {#2}
- \protected\edef\ttfamily{
- \unexpanded{\luatexko@mono@fonts}
- \unexpanded\expandafter{\ttfamily}
+ \fontfamily \luatexkosanshanjafamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \sfdefault
+ {
+ \cs_set_eq:NN \luatexkohanjafont \luatexkosanshanjafont
+ \luatexkohanjaselectfont
+ }
+ \ignorespaces
+}
+\DeclareDocumentCommand \setmonohanjafont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomonohanjafamily { #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkomonohanjafont
+ {
+ \fontfamily \luatexkomonohanjafamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \ttdefault
+ {
+ \cs_set_eq:NN \luatexkohanjafont \luatexkomonohanjafont
+ \luatexkohanjaselectfont
+ }
+ \ignorespaces
+}
+\DeclareDocumentCommand \newhanjafontfamily { m O{} m O{} }
+{
+ \fontspec_set_family:cnn { luatexko_user_family_ \cs_to_str:N #1 } { #2, #4 } { #3 }
+ \DeclareRobustCommand #1
+ {
+ \tl_set:Nn \luatexkohanjafont
+ {
+ \exp_args:Nc \fontfamily { luatexko_user_family_ \cs_to_str:N #1 } \selectfont
}
- \ignorespaces
+ \luatexkohanjaselectfont
}
-\cs_set_eq:NN \setromanfont \setmainfont
- \ExplSyntaxOff
-\fi
-
-\RequirePackage{everysel}
-\EverySelectfont{%
- \luatexko@hangul@selectfont
- \luatexko@hanja@selectfont
- \luatexko@fallback@selectfont
+ \ignorespaces
+}
+\DeclareDocumentCommand \newhanjafontface { m O{} m O{} }
+{
+ \newhanjafontfamily #1 { #3 } [ BoldFont={}, ItalicFont={}, SmallCapsFont={}, #2, #4 ]
+}
+\DeclareDocumentCommand \hanjafontspec { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkohanjafontfamily { #1, #3 } { #2 }
+ \tl_set:Nn \luatexkohanjafont
+ {
+ \fontfamily \luatexkohanjafontfamily \selectfont
+ }
+ \luatexkohanjaselectfont
+ \ignorespaces
}
-% serif : finemathattr = 2
-% sans : finemathattr = 1
-% tt : finemathattr = 0
-% verbatim : finemathattr = nil
-\def\luatexko@serif@fonts{%
- \let\hangul@font\serifhangul@font
- \let\hanja@font\serifhanja@font
- \let\fallback@font\seriffallback@font
- \finemathattr\tw@
+\DeclareDocumentCommand \setmainfallbackfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomainfallbackfamily { Ligatures=TeX, #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkomainfallbackfont
+ {
+ \fontfamily \luatexkomainfallbackfamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \rmdefault
+ {
+ \cs_set_eq:NN \luatexkofallbackfont \luatexkomainfallbackfont
+ \luatexkofallbackselectfont
+ }
+ \ignorespaces
}
-\def\luatexko@sans@fonts{%
- \let\hangul@font\sanshangul@font
- \let\hanja@font\sanshanja@font
- \let\fallback@font\sansfallback@font
- \finemathattr\@ne
+\DeclareDocumentCommand \setsansfallbackfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkosansfallbackfamily { Ligatures=TeX, #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkosansfallbackfont
+ {
+ \fontfamily \luatexkosansfallbackfamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \sfdefault
+ {
+ \cs_set_eq:NN \luatexkofallbackfont \luatexkosansfallbackfont
+ \luatexkofallbackselectfont
+ }
+ \ignorespaces
}
-\def\luatexko@mono@fonts{%
- \let\hangul@font\monohangul@font
- \let\hanja@font\monohanja@font
- \let\fallback@font\monofallback@font
- \finemathattr\z@
+\DeclareDocumentCommand \setmonofallbackfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomonofallbackfamily { #1, #3 } { #2 }
+ \DeclareRobustCommand \luatexkomonofallbackfont
+ {
+ \fontfamily \luatexkomonofallbackfamily \selectfont
+ }
+ \str_if_eq_x:nnT \familydefault \ttdefault
+ {
+ \cs_set_eq:NN \luatexkofallbackfont \luatexkomonofallbackfont
+ \luatexkofallbackselectfont
+ }
+ \ignorespaces
}
-
-\protected\edef\rmfamily{%
- \unexpanded{\luatexko@serif@fonts}\unexpanded\expandafter{\rmfamily}}
-\protected\edef\sffamily{%
- \unexpanded{\luatexko@sans@fonts}\unexpanded\expandafter{\sffamily}}
-\protected\edef\ttfamily{%
- \unexpanded{\luatexko@mono@fonts}\unexpanded\expandafter{\ttfamily}}
-\edef\verbatim@font{\unexpanded\expandafter{\verbatim@font
- \unsetattribute\finemathattr}}
-
-\AtBeginDocument{
-\unless\ifdefined\serifhangul@font\let\serifhangul@font\sanshangul@font\fi
-\unless\ifdefined\sanshangul@font \let\sanshangul@font\serifhangul@font\fi
-\unless\ifdefined\monohangul@font \let\monohangul@font\sanshangul@font \fi
-\unless\ifdefined\serifhangul@font\unless\ifdefined\sanshangul@font
- \hangulpunctuations=0 % nanumtype1
-\fi\fi
-% don't forget to redefine \normalfont
-\expandafter\ifx\familydefault\rmdefault
- \protected\edef\normalfont{%
- \unexpanded{\luatexko@serif@fonts}\unexpanded\expandafter{\normalfont}}
- % and current hangul font
- \luatexko@serif@fonts
-\else\expandafter\ifx\familydefault\sfdefault
- \protected\edef\normalfont{%
- \unexpanded{\luatexko@sans@fonts}\unexpanded\expandafter{\normalfont}}
- \luatexko@sans@fonts
-\else
- \protected\edef\normalfont{%
- \unexpanded{\luatexko@mono@fonts}\unexpanded\expandafter{\normalfont}}
- \luatexko@mono@fonts
-\fi\fi
-\let\reset@font\normalfont
-% reset hangul font
-\selectfont
-% for hyperref
-\@ifpackageloaded{hyperref}{\pdfstringdefDisableCommands{%
- \let\dotemph\@firstofone
- \let\ruby\@firstoftwo
- \let\uline\@firstofone
- \let\sout\@firstofone
- \let\uuline\@firstofone
- \let\xout\@firstofone
- \let\uwave\@firstofone
- \let\dashuline\@firstofone
- \let\dotuline\@firstofone
- \let\actualtext\@firstofone
- \let\inhibitglue\empty
- \def\는{는}%
- \def\은{은}%
- \def\을{을}%
- \def\를{를}%
- \def\와{와}%
- \def\과{과}%
- \def\가{가}%
- \def\이{이}%
- \def\라{라}%
- \def\으{으}%
- \def\로{로}%
- }}{}
+\DeclareDocumentCommand \newfallbackfontfamily { m O{} m O{} }
+{
+ \fontspec_set_family:cnn { luatexko_user_family_ \cs_to_str:N #1 } { #2, #4 } { #3 }
+ \DeclareRobustCommand #1
+ {
+ \tl_set:Nn \luatexkofallbackfont
+ {
+ \exp_args:Nc \fontfamily { luatexko_user_family_ \cs_to_str:N #1 } \selectfont
+ }
+ \luatexkofallbackselectfont
+ }
+ \ignorespaces
}
-
-\if@luatexko@loadfontspec
- %% hangul in math --- latex
- \AtBeginDocument{
- \begingroup
- \unless\ifdefined\luatexko@math@hangul@family
- \ifdefined\hangul@font \hangul@font \fi
- \xdef\luatexko@math@hangul@family{\f@family}%
- \fi
- \endgroup
- \DeclareSymbolFont{mathhangul}%
- \f@encoding\luatexko@math@hangul@family\mddefault\updefault
- \ifcsname\f@encoding/\luatexko@math@hangul@family/\bfdefault/\updefault\endcsname
- \SetSymbolFont{mathhangul}{bold}%
- \f@encoding\luatexko@math@hangul@family\bfdefault\updefault
- \fi
+\DeclareDocumentCommand \newfallbackfontface { m O{} m O{} }
+{
+ \newfallbackfontfamily #1 { #3 } [ BoldFont={}, ItalicFont={}, SmallCapsFont={}, #2, #4 ]
+}
+\DeclareDocumentCommand \fallbackfontspec { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkofallbackfontfamily { #1, #3 } { #2 }
+ \tl_set:Nn \luatexkofallbackfont
+ {
+ \fontfamily \luatexkofallbackfontfamily \selectfont
+ }
+ \luatexkofallbackselectfont
+ \ignorespaces
+}
+\DeclareDocumentCommand \setmathhangulfont { O{} m O{} }
+{
+ \fontspec_set_family:Nnn \luatexkomathhangulfamily { #1, #3 } { #2 }
+ \DeclareSymbolFont { mathhangul }
+ \g_fontspec_encoding_tl \luatexkomathhangulfamily \mddefault \updefault
+ \int_compare:nNnF { \Umathcharfam"AC00 } = { \symmathhangul }
+ {
\setmathhangulblock{AC00}{D7A3}
}
-\fi
-
+ \ignorespaces
+}
+\ExplSyntaxOff
+\let\adhochangulfont\hangulfontspec
+\let\adhochanjafont\hanjafontspec
+\let\adhocfallbackfont\fallbackfontspec
+% interhangul, interlatincjk, charraise
+\protected\def\addhangulfontfeature#1{%
+ \begingroup
+ \ifdefined\luatexkohangulfont \luatexkohangulfont \fi
+ \addfontfeature{#1}%
+ \edef\x{\endgroup
+ \def\noexpand\luatexkohangulfont{%
+ \noexpand\fontfamily{\f@family}\noexpand\selectfont}}\x
+ \luatexkohangulselectfont
+ \ignorespaces}
+\let\addhangulfontfeatures\addhangulfontfeature
+\protected\def\addhanjafontfeature#1{%
+ \begingroup
+ \ifdefined\luatexkohanjafont \luatexkohanjafont \fi
+ \addfontfeature{#1}%
+ \edef\x{\endgroup
+ \def\noexpand\luatexkohanjafont{%
+ \noexpand\fontfamily{\f@family}\noexpand\selectfont}}\x
+ \luatexkohanjaselectfont
+ \ignorespaces}
+\let\addhanjafontfeatures\addhanjafontfeature
+\protected\def\addfallbackfontfeature#1{%
+ \begingroup
+ \ifdefined\luatexkofallbackfont \luatexkofallbackfont \fi
+ \addfontfeature{#1}%
+ \edef\x{\endgroup
+ \def\noexpand\luatexkofallbackfont{%
+ \noexpand\fontfamily{\f@family}\noexpand\selectfont}}\x
+ \luatexkofallbackselectfont
+ \ignorespaces}
+\let\addfallbackfontfeatures\addfallbackfontfeature
+\newfontfeature{InterHangul}{interhangul=#1}
+\newfontfeature{InterLatinCJK}{interlatincjk=#1}
+\newfontfeature{CharRaise}{charraise=#1}
+\newfontfeature{RemoveClassicSpaces}{+removeclassicspaces}
+\newfontfeature{CompressPunctuations}{+compresspunctuations}
+\newfontfeature{Expansion}{expansion=\ifx\empty#1\empty default\else #1\fi }
+\newfontfeature{Protrusion}{protrusion=\ifx\empty#1\empty default\else #1\fi }
+\newfontfeature{InterCharacter}{intercharacter=#1}
+% italic correction
+\def\nocorrlist{,.^^^^3001^^^^3002^^^^ff0c^^^^ff0e^^^^ff61^^^^ff64}
+% package options
+\newif\if@hangul
+\newif\if@hanja
+\DeclareOption{hangul}{\@hangultrue}
+\DeclareOption{hanja}{\@hangultrue\@hanjatrue}
+\ProcessOptions\relax
+% default hangul font
+\AtBeginDocument{
+ \ifdefined\luatexkomainhangulfont\else
+ \begingroup\rmfamily
+ \directlua{ luatexko.currenthashangulchars(255) }\expandafter\endgroup
+ \ifnum\count@=\z@
+ \setmainhangulfont{UnBatang}[Script=Hangul,Language=Korean]\fi\fi
+ \ifdefined\luatexkosanshangulfont\else
+ \begingroup\sffamily
+ \directlua{ luatexko.currenthashangulchars(255) }\expandafter\endgroup
+ \ifnum\count@=\z@
+ \setsanshangulfont{UnDotum}\fi\fi
+ \ifdefined\luatexkomonohangulfont\else
+ \begingroup\ttfamily
+ \directlua{ luatexko.currenthashangulchars(255) }\expandafter\endgroup
+ \ifnum\count@=\z@
+ \let\luatexkomonohangulfont\luatexkosanshangulfont\fi\fi
+ \@ifpackageloaded{hyperref}{\pdfstringdefDisableCommands{%
+ \let\ruby\@firstoftwo \let\xxruby\@firstoftwo
+ \let\dotemph\@firstofone
+ \let\markoverwith\@secondoftwo
+ \let\uline\@firstofone \let\sout\@firstofone
+ \let\uuline\@firstofone \let\xout\@firstofone
+ \let\uwave\@firstofone \let\dashuline\@firstofone
+ \let\dotuline\@firstofone
+ \let\typesetclassic\empty \let\typesetmodern\empty
+ \let\inhibitglue\empty
+ \let\hangulpunctuations\count@
+ \let\registerpunctuations\@gobble \let\unregisterpunctuations\@gobble
+ \let\registerhangulpunctuations\@gobble
+ \let\unregisterhangulpunctuations\@gobble
+ \let\registerbreakableafter\@gobble \let\registerbreakablebefore\@gobble
+ \let\hangulbyhangulfont\count@ \let\hanjabyhanjafont\count@
+ \let\addhangulfontfeature\@gobble \let\addhangulfontfeatures\@gobble
+ \let\addhanjafontfeature\@gobble \let\addhanjafontfeatures\@gobble
+ \let\addfallbackfontfeature\@gobble \let\addfallbackfontfeatures\@gobble
+ \def\는{는}\def\은{은}\def\을{을}\def\를{를}\def\와{와}\def\과{과}%
+ \def\가{가}\def\이{이}\def\라{라}\def\으{으}\def\로{로}%
+ \def\hellipsis{...}}}{}
+ \if@hangul \RequirePackage{konames-utf}\fi
+}
+% misc
\RequirePackage{kolabels-utf}
+\protected\def\hellipsis{\char"2026\char"2026 }
\if@hangul
- \AtBeginDocument{\RequirePackage{konames-utf}}
\linespread{1.3888}
\footnotesep=1.3888\footnotesep
\skip\footins=\glueexpr\skip\footins/72*100\relax
- \hangulpunctuations=1
\frenchspacing
\fi
-
\endinput