%
% Example of luaTeX to use Level 0 ofm
% and "Kinsoku" by Yannis Haralambous
% (driver is dvipdfmx)
%
% luarml   UniJIS-UCS2-H Ryumin-Light
% luagbm   UniJIS-UCS2-H GothicBBB-Medium
% in cid-x.map for dvipdfmx
% or 
% luarml   UniJIS-UCS2-H KozMinProVI-Regular.otf
% luagbm   UniJIS-UCS2-H KozGoProVI-Medium.otf
% to embed OpenType fonts.
%

%
% If I don't use callback for define_font,
% time needed is extremely long. --ak
%
\pdfoutput0
%
% lua code
%
\directlua0{
callback.register('define_font',
function(name, size)
  f = font.read_tfm(name, size)
  return f
end)

table_le  = {[0x3008]=true, [0x300A]=true, [0x300C]=true,
             [0x300E]=true, [0x3010]=true, [0x3014]=true,
             [0x3016]=true, [0x3018]=true, [0x301A]=true,
             [0x301D]=true, [0xFF08]=true, [0xFF3B]=true,
             [0xFF5B]=true}

table_re  = {[0x3001]=true, [0x3002]=true, [0x3009]=true,
             [0x300B]=true, [0x300D]=true, [0x300F]=true,
             [0x3011]=true, [0x3015]=true, [0x3017]=true,
             [0x3019]=true, [0x301F]=true, [0xFF09]=true,
             [0xFF0C]=true, [0xFF0E]=true, [0xFF3D]=true,
             [0xFF5D]=true}

table_sk  = {[0x3041]=true, [0x3043]=true, [0x3045]=true,
             [0x3047]=true, [0x3049]=true, [0x3063]=true,
             [0x3083]=true, [0x3085]=true, [0x3087]=true,
             [0x3083]=true, [0x30A1]=true, [0x30A3]=true,
             [0x30A5]=true, [0x30A7]=true, [0x30A9]=true,
             [0x30C3]=true, [0x30E3]=true, [0x30E5]=true,
             [0x30E7]=true, [0x30EE]=true, [0x30F5]=true,
             [0x30F6]=true}

table_aux = {[0x3005]=true, [0x3006]=true, [0x301C]=true,
             [0x309D]=true, [0x309E]=true, [0x30FD]=true,
             [0x30FE]=true}

table_ll  = {[0x28]=true,   [0x5B]=true}

table_rl  = {[0x29]=true,   [0x5D]=true,   [0x21]=true,
             [0x2C]=true,   [0x2E]=true,   [0x3A]=true,
             [0x3B]=true,   [0x3F]=true}

function is_CJK(id)
  if ((id >= 12288 and id <= 55207) or (id >= 65280 and id <= 65504))
  then
    return true;
  else
    return false;
  end
end 

function is_CJK_le(id)
  return table_le[id]
end

function is_CJK_re(id)
  return table_re[id]
end

function is_CJK_karenb(id)
  return (is_CJK(id) and (not table_re[id]))
end

function is_CJK_ll(id)
  return table_ll[id]
end

function is_CJK_rl(id)
  return table_ll[id]
end

function is_CJK_ka(id)
  return (is_CJK(id) and (not (table_re[id] or table_le[id] or table_sk[id] or table_aux[id])))
end

function insert_penalty(head,t)
  n=node.new("penalty");
  n.penalty=10000;
  node.insert_after(head,t,n);
end

function insert_small_glue(head,t) 
  n=node.new("glue"); 
  gs=node.new("glue_spec"); 
  gs.width=0;
  gs.stretch=0.05 * font.fonts[t.font].size;
  gs.stretch_order=0;
  gs.shrink=0;
  gs.shrink_order=0;
  n.spec=gs;
  node.insert_after(head,t,n);
end

function insert_half_glue(head,t) 
  n=node.new("glue");
  gs=node.new("glue_spec");
  gs.width=-0.5 * font.fonts[t.font].size;
  gs.stretch=0.5 * font.fonts[t.font].size;
  gs.stretch_order=0;
  gs.shrink=0.05 * font.fonts[t.font].size;
  gs.shrink_order=0;
  n.spec=gs;
  node.insert_after(head,t,n);
end

function insert_double_half(head,t) 
  n=node.new("glue");
  gs=node.new("glue_spec");
  gs.width=-font.fonts[t.font].size;
  gs.stretch=font.fonts[t.font].size;
  gs.stretch_order=0;
  gs.shrink=0.05 * font.fonts[t.font].size;
  gs.shrink_order=0;
  n.spec=gs;
  node.insert_after(head,t,n);
end

function insert_abit_stretch(head,t) 
  n=node.new("glue");
  gs=node.new("glue_spec");
  gs.width=0.25 * font.fonts[t.font].size;
  gs.stretch=0.5 * font.fonts[t.font].size;
  gs.stretch_order=0;
  gs.shrink=0.05 * font.fonts[t.font].size;
  gs.shrink_order=0;
  n.spec=gs;
  node.insert_after(head,t,n);
end

callback.register('pre_linebreak_filter',
function(t,groupcode,glyphes)
  local node_id_glyph=node.id("glyph")
  local node_id_glue=node.id("glue")
  head = t
  for t in node.traverse(head)
  do
    if (node.has_attribute(t,kinsoku))
    then
      if (t.next and t.next.next and t.id == node_id_glyph and t.next.id == node_id_glue and t.next.next.id == node_id_glyph and is_CJK(t.char) and is_CJK(t.next.next.char)) 
      then
        l = t.next.next
        node.free(t.next)
        t.next = l
      end
      if (t.next and t.id == node_id_glyph and t.next.id == node_id_glyph)
      then
        if (is_CJK(t.next.char))
        then
          if (is_CJK_le(t.char))
          then
            insert_small_glue(head,t);
            insert_penalty(head,t); 
          elseif (is_CJK_re(t.char))
          then 
            if (is_CJK_karenb(t.next.char))
            then 
              insert_half_glue(head,t);
              insert_abit_stretch(head,t)
            else 
              insert_double_half(head,t);
              insert_abit_stretch(head,t)
            end
          elseif (is_CJK_ll(t.char))
          then
            if (is_CJK_karenb(t.next.char))
            then
              insert_small_glue(head,t);
              insert_penalty(head,t); 
            else
              insert_half_glue(head,t);
              insert_penalty(head,t);
            end
          else
            if (is_CJK_ka(t.next.char))
            then
              insert_small_glue(head,t);
            elseif (is_CJK_le(t.next.char))
            then
              insert_half_glue(head,t);
            else
              insert_small_glue(head,t);
              insert_penalty(head,t);
            end
          end
        elseif (is_CJK(t.char))
        then
          if (is_CJK_re(t.char))
          then 
            if (is_CJK_rl(t.next.char))
            then
              insert_half_glue(head,t);
              insert_penalty(head,t); 
            else
              insert_half_glue(head,t);
            end
          elseif (is_CJK_le(t.char) or is_CJK_rl(t.next.char))
          then
            insert_small_glue(head,t);
            insert_penalty(head,t);
          else
            insert_small_glue(head,t);
          end
        end
      end
    end
  end
  return true
end )
}

%
% TeX code
%
\def\newattribute#1#2{%
\expandafter\attributedef \csname#1\endcsname #2
\directlua0{#1 = #2 }}
\newattribute{kinsoku}{300}

\def\startkinsoku{\kinsoku1}
\def\stopkinsoku{\kinsoku-1} % -1 signals 'unset'
%
% present luaTeX dose not support Level 1 ofm
% luarml.ofm and luagbm.ofm are made from omrml.opl by H. Suzuki
% simply changing Level from 1 to 0
%
\font\ggl=luarml at 14pt
\font\ggt=luagbm at 16pt
\font\dflt=cmr10 at 14pt

\def\ki{\begingroup\startkinsoku\ggl}
\def\ko{\stopkinsoku\endgroup}
\def\kgi{\begingroup\startkinsoku\ggt}
\def\kgo{\stopkinsoku\endgroup}
%
\nopagenumbers
\parindent=1em
\baselineskip=20pt
\dflt
%
%
%
\centerline{%
\kgi
日本語版への序文
\kgo
}
\vskip 2ex
\ki
本書を執筆しているとき、私には、こういった内容の本が英語以外
への翻訳に値するものになるとはあまり考えませんでした。
書き終えたときには、私はこうも確信したものです
\ko ---
\ki
こんな本の翻訳はほとんど不可能だ！しかし、その予想に反し、今こうして
日本の皆さんが、ついにはこの本を翻訳しようというまでに
\ko \TeX{}
\ki
に関心を寄せてくださっていることを知り、驚くと同時に心から
うれしく思っています。何と言っても日本は、出版技術にかけては
最先端の水準を誇る技術先進国なのですから。

\ko \TeX{}
\ki
に先立つ研究を始めようとしていた頃、もしも私が日本に
住んでいたとしたら、そもそも、そんな研究が必要だとは、まずは
思いも及ばなかったことでしょう。おそらく
\ko \TeX{}
\ki
プロジェクトを始めることはなかったに違いありません。
それと言うのも、あれやこれや
と手を加えなければならないほどお粗末な印刷品質に煩わされるなど、
日本ではとても考えられなかったと思えるからです。
一連の仕事を終え、
\ko \TeX{}
\ki
を世に送り出した今、アメリカや
ヨーロッパのみならず、その際立った出版技術を誇る日本においても
\ko \TeX{}
\ki
が受け入れられつつあるということを聞くにつけ、
喜びが増す思いがします。この本の翻訳が作成されることで、
\ko \TeX{}
\ki
が世界中のあらゆる国々で使われ、美しい出版物を生み出すために
結構お役に立てるかもしれない、という希望も出てきました。

本書の現在の版では、バージョン
\ko 3.0
\ki
以降で使える
\ko \TeX{}
\ki
の大きな拡張についても説明してあります。新たな拡張を
\ko \TeX{}
\ki
に施したため、
\ko 8
\ki
ビットの文字セットすべてを扱え、また多くの
言葉を同時に組版できるようにもなりました。

\ko 15
\ki
年前、拙著「
\ko The Art of Computer Programming
\ki
」の日本語版に対して、私は序文を寄せました。そこに書いた結びの
言葉は、この本についてもまったく変わりありません。
ただ、いつになっても
\ko ``%
\ki
この翻訳を私自身が理解できる
には至らない
\ko ''%
\ki
のはまことに残念なのですが、私は、
大変優れた方々がこの本の翻訳に大きな力を注いでくださったことを
非常に栄誉に思い、その成果を日本の読者に皆さんが賞味
されることを願っています。
\ko
\bye
