% \iffalse
%<dtx>\ProvidesFile{vnbase.dtx}[2003/11/01 v01.01 VNR.KTV.DTX.Base]
% \fi
%
% \section{Basic macros}
%
%    \begin{macrocode}
%<*vnbase>
%    \end{macrocode}
%
% §Þnh nghÜa tÊt c¶ c¸c macro ®­îc dïng bëi |VNR|.
%
% \subsection{Generic Macros}
%
% \danger
% V× |mfplain.mp| kh«ng ®­îc cËp nhËt cïng víi |plain.mf|,
% nªn ®Ó |MetaPost| cã thÓ lµm viÖc víi |ec| fonts,
% ta ph¶i cÇn c¸c dßng sau (chÐp tõ |plain.mf|).
% \endanger
%
%    \begin{macrocode}
%<*test>
vardef whatever = save ?; ? enddef;
def killtext text t = enddef;
%</test>
%    \end{macrocode}
%
%    \begin{macrocode}
if unknown exbase:
    input exbase;
fi;
%    \end{macrocode}
%
%    \begin{macrocode}
if unknown displaying:
    displaying := 0;
fi
%    \end{macrocode}
% Trong *exbase.mf*, macro *ecchar* ®­îc ®Þnh nghÜa bëi *|let ecchar=\;|*.
%    \begin{macrocode}
let vnchar = ecchar;
let cmchar = ecchar;
%    \end{macrocode}
%
% Load |T5| |encoding| vµ c¸c macro ®Þnh nghÜa c¸c hä ch÷ c¸i, hä dÊu.
%    \begin{macrocode}
input vncode;
%    \end{macrocode}
%
% \subsection{Test: Parameters}
%
% Parameter for |t5supp-encoding|.
%    \begin{macrocode}
%<*t5supp>
% get_acc_pos := 1;
% gen_t5_supp := 1;
% if known get_acc_pos or known gen_t5_supp:
    mag := 100.375;
% fi
%</t5supp>
%    \end{macrocode}
%
% *(KTV,2003/11/02):*
% ViÖc ®Æt *|defaultfont:="Times-Roman"|* sÏ sinh ra lçi
% (kh«ng t×m thÊy font |tfm|) t­¬ng øng.
% Xem thªm trong \href{../doc/vnr_bug_fix.dvi}{vnr_bug_fix}.
%
% *(KTV,2003/11/13):*
% Ph¶i dïng *|prologues:=1|* míi cã thÓ |merge| c¸c output t¹o bëi
% |MetaPost| b»ng |mpmergeps.py|.
% (Ch­a kiÓm tra ®iÒu nµy víi |mergemps.py|.)
%    \begin{macrocode}
%<*test>
% show_labels   := 1; % value passed in the `makefile'
% makeXbox      := 0; % value passed in the `makefile'
defaultscale    := 1;
prologues       := 1;
%defaultfont    := "Times-Roman";
if known black_proof:
    proofcolor  := .9999[white, black];
else:
    proofcolor  := .3[white, black];
fi
if known gensize:
        mag := 20/gensize;
else:   mag := 2; fi
if known no_labels:
    def penlabels(text _list) = enddef;
fi
%</test>
%    \end{macrocode}
%
% \subsection{Test: Letters}
%
% Danh s¸ch c¸c ch÷ c¸i ®­îc vÏ khi trong \tstmode.
% Muèn |test| ch÷ c¸i nµo th× chØ viÖc bá dÊu |%| ë tr­íc ch÷ ®ã.
% Cã thÓ thùc hiÖn c¸c phÐp g¸n, vÝ dô: *|test_grave:=1|*.
% \emph{L­u ý:} nh÷ng ch÷ c¸i ®­îc test sÏ gåm c¶ ch÷ hoa lÉn ch÷ th­êng.
% (Xem ®Þnh nghÜa cña *grave_fam*, *acute_fam*,... ë \lref{def:accent_fam},
% ®Þnh nghÜa cña *a_fam*, *d_fam*,... ë \lref{def:letter_fam}.)
%
% \begin{multicols}3
%    \begin{macrocode}
%<*test>
def testchars =
%<=def:testchars>
if known test_grave:
    grave_fam(,)
fi if known test_acute:
    acute_fam(,)
fi if known test_tilde:
    tilde_fam(,)
fi if known test_hook:
    hook_fam(,)
fi if known test_dot:
    dot_fam(,)
fi if known test_a:
    a_fam(,)
fi if known test_e:
    e_fam(,)
fi if known test_i:
    i_fam(,)
fi if known test_o:
    o_fam(,)
fi if known test_u:
    u_fam(,)
fi if known test_uhorn:
    uhorn_fam(,)
fi if known test_y:
    y_fam(,)
fi if known test_d:
    d_fam(,)
fi if known test_all_chars:
    full_fam(,)
fi
% a.acute_,
% a.dot_,
% a.grave_,
% a.hook_,
% a.tilde_,
% a.breve_,
% a.breve_.acute_,
% a.breve_.dot_,
% a.breve_.grave_,
% a.breve_.hook_,
% a.breve_.tilde_,
% a.circumflex_,
% a.circumflex_.acute_,
% a.circumflex_.dot_,
% a.circumflex_.grave_,
% a.circumflex_.hook_,
% a.circumflex_.tilde_,
% d.bar_,
% e.acute_,
% e.dot_,
% e.grave_,
% e.hook_,
% e.tilde_,
% e.circumflex_,
% e.circumflex_.acute_,
% e.circumflex_.dot_,
% e.circumflex_.grave_,
% e.circumflex_.hook_,
% e.circumflex_.tilde_,
% i.acute_,
% i.dot_,
% i.grave_,
% i.hook_,
% i.tilde_,
% o.acute_,
% o.dot_,
% o.grave_,
% o.hook_,
% o.tilde_,
% o.circumflex_,
% o.circumflex_.acute_,
% o.circumflex_.dot_,
% o.circumflex_.grave_,
% o.circumflex_.hook_,
% o.circumflex_.tilde_,
% o.horn_,
% o.horn_.acute_,
% o.horn_.dot_,
% o.horn_.grave_,
% o.horn_.hook_,
% o.horn_.tilde_,
% u.acute_,
% u.dot_,
% u.grave_,
% u.hook_,
% u.tilde_,
% u.horn_,
% u.horn_.acute_,
% u.horn_.dot_,
% u.horn_.grave_,
% u.horn_.hook_,
% u.horn_.tilde_,
% y.acute_,
% y.dot_,
% y.grave_,
% y.hook_,
% y.tilde_,
last
enddef;
%</test>
%    \end{macrocode}
% \end{multicols}
%
% \danger
% Ta thªm vµo danh s¸ch trªn ch÷ c¸i ¶o |last|. \emph{Môc ®Ých:}
% Khi dïng vßng lÆp |for| ®Ó duyÖt qua danh s¸ch
% |testchars|, ta ph¶i biÕt lóc nµo th× kÕt thóc danh s¸ch.
% Ch÷ c¸i ¶o |last| t¹o ®iÒu kiÖn ®Ó kiÓm tra.
% Nh­ vËy, |last| ph¶i lu«n ®­îc |test|:
% ta kh«ng ®­îc phÐp bá ®i |last| trong danh s¸ch nãi trªn.
% \endanger
%
%    \begin{macrocode}
%<test> C.l.last := C.u.last := 256;
%    \end{macrocode}
%
% \subsection{Test: Macros}
%
% \begin{macro}{used_char}
% Macro nµy kiÓm tra xem \meta{char} víi m· |_code| cã n»m trong
% danh s¸ch |testchars| hay kh«ng. NÕu cã, \meta{char} nµy sÏ ®­îc vÏ.
% ChØ trong \tstmode\ míi cã sù kiÓm tra nµy, cßn trong b¶n
% \meta{publish} cña |VNR-METAFONT| th× macro |used_char| ®­îc bá qua.
% Xem ®Þnh nghÜa cña macro |define_vnchar| (\lref{def:define_vnchar}).
%    \begin{macrocode}
%<*test>
vardef used_char(expr _code) =
%<=def:used_char>
    boolean _is_used;
    if not known test_all_chars:
        _is_used := false;
        forsuffixes $ = testchars:
            if _code = vn_code($):
                _is_used := true;
            fi;
        endfor;
    else:
        _is_used := true;
    fi;
    _is_used
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% Khai b¸o 14 biÕn kiÓu |BOOLEAN|.
% C¸c biÕn nµy ®­îc g¸n gi¸ trÞ ban ®Çu |FALSE|.
%
% \emph{VÝ dô:} biÕn |a_fam_used| cã gi¸ trÞ |TRUE| nÕu mét trong c¸c
% ch÷ c¸i |a|, |¸|, |µ|, |¶|, |·|, |¹| ®­îc |test|. L­u ý r»ng,
% c¸c ch÷ c¸i |a|, |¸|, |µ|, |¶|, |·|, |¹| ®­îc vÏ theo c¸ch \emph{t­¬ng
% tù} nhau, nªn ta chØ cÇn \emph{dïng mét biÕn} lµ |a_fam_used|:
% nÕu |a_fam_used| b»ng |TRUE|, th× ta sÏ |load| m· |MF| ®Ó vÏ c¸c
% ch÷ |a|, m· nµy ®Æt trong |vnlar|.
%
% Xem thªm ®Þnh nghÜa cña |input_lr_fam|, |input_ur_fam| bªn d­íi.
%
%    \begin{macrocode}
%<*test>
forsuffixes _u =
    A_fam_used, D_fam_used, E_fam_used, I_fam_used,
                O_fam_used, U_fam_used, Y_fam_used,
    a_fam_used, d_fam_used, e_fam_used, i_fam_used,
                o_fam_used, u_fam_used, y_fam_used:
    boolean _u;
    _u := false;
endfor;
%</test>
%    \end{macrocode}
%
% Gi¶ sö trong |test_char|, \meta{char} cã m· |_c| ®­îc \meta{test}.
% Khi ®ã, ta sÏ t×m xem \meta{char} nµy n»m trong hä nµo (|A_fam|,
% |e_fam|, v.v...). NÕu (vÝ dô) nã n»m trong hä |a_fam|, th× ta sÏ g¸n
% biÕn |a_fam_used| gi¸ trÞ |TRUE|.
%
% \begin{macro}{test_fam}
%
% Macro |test_fam| d­íi ®©y cã nhiÖm
% vô tr¶ lêi xem \meta{char} víi m· |_c| cã n»m trong hä |_f| hay kh«ng;
% nÕu cã th× g¸n |_u| b»ng |TRUE|. \emph{L­u ý:} c¸c \meta{char} (tiÕng
% ViÖt) chØ cã m· hoÆc nhá h¬n |32|, hoÆc lín h¬n |127|.
%
%    \begin{macrocode}
%<*test>
def test_fam(text _f, _u, _c) =
    n_ := 0;
    if not _u:
        forsuffixes $ = _f(,) 257:
            n_ := n_ + 1;
            if (($ < 32) or ($ > 127)) and ($ = C.u._c) or ($ = C.l._c):
                _u := true;
            fi
        endfor
    fi
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% B©y giê, ta duyÖt qua tÊt c¶ c¸c hä (ch÷ hoa) ®Ó xem |_c| thuéc hä nµo.
% Râ rµng, mçi \meta{char} chØ thuéc mét vµ chØ mét hä mµ th«i, nªn ta cã
% thÓ c¶i thiÖn viÖc duyÖt b»ng c¸ch dïng |if...elif...if|. (Nh­ng viÖc
% nµy kh«ng \emph{kinh tÕ}l¾m.)
%
% \begin{multicols}2
%    \begin{macrocode}
%<*test>
forsuffixes _c = testchars:
    test_fam(A_fam)(A_fam_used)(_c);
    test_fam(D_fam)(D_fam_used)(_c);
    test_fam(E_fam)(E_fam_used)(_c);
    test_fam(I_fam)(I_fam_used)(_c);
    test_fam(O_fam)(O_fam_used)(_c);
    test_fam(U_fam)(U_fam_used)(_c);
    test_fam(Y_fam)(Y_fam_used)(_c);
    test_fam(a_fam)(a_fam_used)(_c);
    test_fam(d_fam)(d_fam_used)(_c);
    test_fam(e_fam)(e_fam_used)(_c);
    test_fam(i_fam)(i_fam_used)(_c);
    test_fam(o_fam)(o_fam_used)(_c);
    test_fam(u_fam)(u_fam_used)(_c);
    test_fam(y_fam)(y_fam_used)(_c);
    test_fam(U_horn_fam)(U_fam_used)(_c);
    test_fam(u_horn_fam)(u_fam_used)(_c);
endfor
%</test>
%    \end{macrocode}
% \end{multicols}
%
% BiÕn |inpustr| ®­îc dïng trong 4 macro s¾p tíi.
%
%    \begin{macrocode}
%<test>string inputstr;
%    \end{macrocode}
%
% \begin{macro}{input_ur_fam}
% Xem hä ch÷ nµo ®­îc dïng th× |load| m· |MF| ®Ó vÏ hä t­¬ng øng.
% \up ë ®©y lµ hä c¸c ch÷ hoa.
%    \begin{macrocode}
%<*test>
def input_ur_fam =
    inputstr := "";
    if A_fam_used: inputstr := inputstr & "input vnuar; "; fi
    if D_fam_used: inputstr := inputstr & "input vnudr; "; fi
    if E_fam_used: inputstr := inputstr & "input vnuer; "; fi
    if I_fam_used: inputstr := inputstr & "input vnuir; "; fi
    if O_fam_used: inputstr := inputstr & "input vnuor; "; fi
    if U_fam_used: inputstr := inputstr & "input vnuur; "; fi
    if Y_fam_used: inputstr := inputstr & "input vnuyr; "; fi
    scantokens(inputstr);
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{input_lr_fam}
% |Load| m· vÏ c¸c ch÷ th­êng.
%    \begin{macrocode}
%<*test>
def input_lr_fam =
    inputstr := "";
    if a_fam_used: inputstr := inputstr & "input vnlar; "; fi
    if d_fam_used: inputstr := inputstr & "input vnldr; "; fi
    if e_fam_used: inputstr := inputstr & "input vnler; "; fi
    if i_fam_used: inputstr := inputstr & "input vnlir; "; fi
    if o_fam_used: inputstr := inputstr & "input vnlor; "; fi
    if u_fam_used: inputstr := inputstr & "input vnlur; "; fi
    if y_fam_used: inputstr := inputstr & "input vnlyr; "; fi
    scantokens(inputstr);
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{input_sc_fam}
% |Load| m· vÏ c¸c ch÷ |small-cap|.
%    \begin{macrocode}
%<*test>
def input_sc_fam =
    inputstr := "";
    if a_fam_used: inputstr := inputstr & "input vnuar; "; fi
    if d_fam_used: inputstr := inputstr & "input vnudr; "; fi
    if e_fam_used: inputstr := inputstr & "input vnuer; "; fi
    if i_fam_used: inputstr := inputstr & "input vnuir; "; fi
    if o_fam_used: inputstr := inputstr & "input vnuor; "; fi
    if u_fam_used: inputstr := inputstr & "input vnuur; "; fi
    if y_fam_used: inputstr := inputstr & "input vnuyr; "; fi
    scantokens(inputstr);
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{input_li_fam}
% |Load| m· vÏ c¸c ch÷ nghiªng.
%    \begin{macrocode}
%<*test>
def input_li_fam =
    inputstr := "";
    if a_fam_used: inputstr := inputstr & "input vnlai; "; fi
    if d_fam_used: inputstr := inputstr & "input vnldi; "; fi
    if e_fam_used: inputstr := inputstr & "input vnlei; "; fi
    if i_fam_used: inputstr := inputstr & "input vnlii; "; fi
    if o_fam_used: inputstr := inputstr & "input vnloi; "; fi
    if u_fam_used: inputstr := inputstr & "input vnlui; "; fi
    if y_fam_used: inputstr := inputstr & "input vnlyi; "; fi
    scantokens(inputstr);
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{bboxcolor}
% \begin{macro}{bbxorule}
% Macro |bboxrule| dïng ®Ó vÏ ®o¹n th¼ng nèi hai ®iÓm |w| vµ |z|,
% víi mµu lµ |bboxcolor| vµ kiÓu ®­êng th¼ng lµ |linecap|.
% \emph{L­u ý:} |linecap| lµ biÕn |internal| cña |MetaPOST|.
%
% \danger
% NÕu ta muèn t¹m thêi quªn ®i gi¸ trÞ cña mét biÕn |internal|, ë ®©y lµ
% biÕn |linecap|, th× dïng |interim| trong mét |group|. Sau |group| ®ã,
% gi¸ trÞ cò cña biÕn |internal| sÏ ®­îc phôc håi. §èi víi biÕn |external|,
% ta dïng hµm |save| thay v× |interim|.
% \endanger
%    \begin{macrocode}
%<*test>
def bboxcolor = red enddef;
def bboxrule(expr w,z) =
    begingroup
        interim linecap := squared;
        draw w..z
            withpen pencircle scaled (.4/bp_per_pixel)
            withcolor bboxcolor;
    endgroup
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{makebbox}
% VÏ bèn c¹nh cña h×nh ch÷ nhËt bao quanh \meta{h×nh vÏ}
% víi kÝch th­íc cña h×nh ch÷ nhËt b»ng kÝch th­íc cña \meta{h×nh vÏ}.
% \meta{H×nh vÏ} ë ®©y lµ \meta{char} hoÆc \meta{accent}.
%    \begin{macrocode}
%<*test>
def makebbox(text rule) =
    if known makeXbox:
        for x = 0,w:
            bboxrule((x,-d),(x,h)); endfor
        for y = 0,h,-d:
            bboxrule((0,y),(w,y)); endfor
    fi
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{makebox}
% VÏ l­íi gåm c¸c ®o¹n th¼ng ®i qua c¸c ®iÓm ®Æc biÖt.
% \danger
% Macro nµy dïng ®Ó kÕt thóc viÖc vÏ \meta{char},
% kh«ng dïng ®Ó kÕt thóc viÖc vÏ \meta{accent}.\\
% Cã thÓ xem chó thÝch vÒ macro nµy trong \mfb E/309/.
% \endanger
%    \begin{macrocode}
%<*test>
def makebox(text rule) =
%    \end{macrocode}
% VÏ b¶y (7) ®­êng th¼ng n»m ngang: mét ®­êng ®i qua gèc täa ®é;
% mét ®­êng ®i ë ®é s©u |body_depth| -- ®­êng nµy kh«ng thÓ thÊy ®­îc
% nÕu ta xem kÕt qu¶ do viÖc |merge| c¸c file "PS" t¹o bëi "MetaPost".
%    \begin{macrocode}
    for y = 0, (cap_height+acc_height),
            asc_height, body_height, x_height,
            bar_height, desc_depth ,-body_depth:
        rule((l,y),(r,y));
    endfor
%    \end{macrocode}
%    \begin{macrocode}
    for y = -3.5pt, 8.5pt, (x_height + acc_height):
        rule((l-4pt,y),(l-2pt,y));
    endfor
%    \end{macrocode}
% VÏ c¸c ®­êng th¼ng ®øng.
%    \begin{macrocode}
    for x=l,r:
        rule((x,-body_depth),(x,body_height));
    endfor
%    \end{macrocode}
% VÏ c¸c ®­êng th¼ng ®øng phô.
%    \begin{macrocode}
    for x = u*(1 + floor(l/u)) step u until r-1:
        rule((x,-body_depth),(x,body_height));
    endfor
    for x = 0.5w:
        rule((x,-body_depth - 1pt),
             (x,-body_depth - 1.5pt));
        rule((x, cap_height + acc_height + 1pt),
             (x, cap_height + acc_height + 1.5pt));
    endfor
%    \end{macrocode}
% VÏ thªm ®­êng th¼ng ®øng nÕu |charic <> 0|.
%    \begin{macrocode}
    if charic <> 0:
        rule((r + charic*pt,  h.o_),
             (r + charic*pt,.5h.o_));
    fi
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Test: enchar}
%
% \begin{macro}{endchar}
% Sau khi kÕt thóc viÖc vÏ mét \meta{char},
% ta vÏ h×nh ch÷ nhËt bao quanh \meta{char} ®ã (b»ng |makebbox|),
% vµ vÏ l­íi gåm c¸c ®­êng th¼ng ®Æc biÖt (b»ng |makebox|).
%
% \danger
% Xem trong |METAFONTBook| vÒ |proofrule|.
% \endanger
%    \begin{macrocode}
%<*test>
def endchar =
    scantokens extra_endchar;
%   if proofing > 0:
    if known makeXbox:
        makebox(proofrule);
        makebbox(proofrule);
    fi
    shipit;
    endgroup
enddef;
%</test>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Writting Shifting Information}
%
% \begin{macro}{abs_round}
%    \begin{macrocode}
%<*t5supp>
def abs_round(expr _e) =
    if _e < 0: ceiling(_e - .5)
    else:      floor(_e + .5)
    fi
enddef;
%</t5supp>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{write_shift_xy}
% Ghi ra *log* file th«ng tin vÒ |shift|; c¸c th«ng tin nµy ®­îc sö dông
% trong qu¸ tr×nh chuyÓn font *VNR* sang *type1* format. 
% Xem \href{../doc/vnr_type1.pdf}{vnr_type1.pdf} (appendix {\bf A})
% ®Ó biÕt thªm vai trß cña macro nµy.
%    \begin{macrocode}
%<*t5supp>
def write_shift_xy(suffix _l, _a)(expr _sx, _sy) =
    if known bp_per_pixel:
        message "CC " &
            if case_ = capital: "capital"
            elseif case_ = small: "small"
            else: "smallcap"
            fi & " " & str _l & " " & str _a & " " &
            decimal(abs_round(_sx*bp_per_pixel*10/designsize)) &  " " &
            decimal(abs_round(_sy*bp_per_pixel*10/designsize));
    fi
enddef;
%</t5supp>
%    \end{macrocode}
% \end{macro}
%
% \subsection{Miscellanea}
%
% BiÕn |case_| dïng lµm |switch| ®Ó x¸c ®Þnh kiÓu ch÷ hoa/th­êng/...
%    \begin{macrocode}
numeric case_;
small       := 0;
capital     := 1;
smallcap    := 2;
def set_lowercase =
    case_ := small;
    def vncase = l enddef;
enddef;
def set_uppercase =
    case_ := capital;
    def vncase = u enddef;
enddef;
def set_smallcap =
    case_ := smallcap;
    def vncase = l enddef;
enddef;
%    \end{macrocode}
%
% \begin{macro}{casename}
% Tªn ®Çy ®ñ cña ch÷ c¸i ®ang ®­îc
% |METAFONT| vÏ (chØ khi |testing| lµ \emph{unknown}).
% Cã thÓ thÊy c¸c tªn nµy trªn |terminal| vµ trong file |log|
% nÕu ch¹y |mf| víi |mode := proof|.
%    \begin{macrocode}
def casename expr _name =
%<*!test>
    "The " &
    if case_ = capital: "capital"
    elseif case_ = small: "small"
    else: "smallcap" fi
    & " letter " & _name
%</!test>
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{ifknown}
% This macro expands to |_b| if the suffix |_a| is \emph{unknown},
% and to |_a| itself in the other case.
% Macro nµy ®­îc dïng nhiÒu, khi ph¶i lùa chän c¸c biÕn t­¬ng øng
% víi c¸c dÊu. Xem mét vÝ dô ë \lref{use:ifknown}.
%    \begin{macrocode}
def ifknown(suffix _a)(expr _b) =
    if known _a: _a else: _b fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{tand}
% Hµm tÝnh |tangent| cña gãc |d| (tÝnh b»ng ®é, |d = degree|).
%    \begin{macrocode}
def tand(expr _d) =
    (sind(_d)/cosd(_d))
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{hp}
% Lµm trßn theo chiÒu ngang (|horizontal|).
%    \begin{macrocode}
def hp(expr _x) =
    hround(_x*hppp)
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{vp}
% Lµm trßn theo chiÒu ®øng (|vertical|).
%    \begin{macrocode}
def vp(expr _y) =
    vround(_y*vppp)
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Macro: begin, end}
%
% \begin{macro}{begin_pic}
%    \begin{macrocode}
def begin_pic(suffix _n) =
    begingroup
        clearxy;
        clearit;
        clearpen;
        picture vn.vncase._n.pic;
        vn.vncase._n.pic :=
        begingroup
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{end_pic}
%    \begin{macrocode}
def end_pic =
%    \end{macrocode}
%
% \danger
% Ta chØ cã thÓ dïng |makebbox| ë ®©y mµ th«i!
% \endanger
%
%    \begin{macrocode}
%<test>     makebbox(proofrule);
%    \end{macrocode}
%
%    \begin{macrocode}
            currentpicture
        endgroup;
    endgroup
enddef;
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
let end_accent   = end_pic;
let begin_letter = begin_pic;
let end_letter   = end_pic;
%    \end{macrocode}
%
% \begin{macro}{begin_accent}
%    \begin{macrocode}
def begin_accent(suffix _a) =
    begin_pic(_a);
    set_char_dimens(vn_width(_a), vn_height(_a), 0)
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Picture's Properties}
%
% Tõ \meta{h×nh vÏ} dïng ®Ó chØ \meta{picture} do |METAFONT|
% t¹o ra khi vÏ ch÷ c¸i \meta{char}, hoÆc dÊu \meta{accent}.
% Mçi \meta{h×nh vÏ} cã c¸c thuéc tÝnh sau ®©y:
% \begin{verbatim}
% code, pic, width, height, top, bot, depth,
% ic, left, right, gap, join_xp, join_x
% \end{verbatim}
%
% \begin{multicols}2
%    \begin{macrocode}
def vn_code(suffix _n) =
    C.vncase._n
enddef;
def vn_pic(suffix _n) =
    vn.vncase._n.pic
enddef;
def vn_width(suffix _n) =
    vn.vncase._n.w#
enddef;
def vn_height(suffix _n) =
    vn.vncase._n.h#
enddef;
def vn_top(suffix _n) =
    vn.vncase._n.top#
enddef;
def vn_depth(suffix _n) =
    vn.vncase._n.d#
enddef;
def vn_bot(suffix _n) =
    vn.vncase._n.bot#
enddef;
def vn_ic(suffix _n) =
    vn.vncase._n.ic#
enddef;
def vn_left_adj(suffix _n) =
    vn.vncase._n.left_adj#
enddef;
def vn_right_adj(suffix _n) =
    vn.vncase._n.right_adj#
enddef;
def vn_gap(suffix _n) =
    vn.vncase._n.gap#
enddef;
def vn_join_xp(suffix _n) =
    vn.vncase._n.join.x
enddef;
def vn_join_x(suffix _n) =
    vn.vncase._n.join.x#
enddef;
def vn_rt(suffix _n) =
    vn.vncase._n.rt#
enddef;
def vn_dot_shift_y(suffix _n) =
    vn.vncase._n.dot_shift.y#
enddef;
def vn_ac_top =
    vn.vncase.accent_top#
enddef;
def vn_double_ac_top =
    vn.vncase.double_accent_top#
enddef;
let vn_left_side = vn_join_x;
def vn_right_side(suffix _a) =
    (vn_width(_a) - vn_left_side(_a))
enddef;
def align_left(suffix _a, _b) =
    0
enddef;
def vn_align_join(suffix _a, _b) =
    (vn_join_x(_a) - vn_join_x(_b))
enddef;
def vn_align_right(suffix _a, _b) =
    (vn_width(_a) - vn_width(_b))
enddef;
%    \end{macrocode}
% \end{multicols}
%
% \subsection{Setting Macros}
%
% \begin{macro}{define_accent_dimens}
% X¸c ®Þnh c¸c kÝch th­íc cña mét dÊu (gåm cã |width|, |height|, |top|).
%    \begin{macrocode}
def define_accent_dimens(suffix _a)(expr _w, _h) =
    vn_width(_a)  := _w;
    vn_height(_a) := _h;
    vn_top(_a)    := vn_height(_a) + vn_letter_height# + vn_accent_gap#;
%    \end{macrocode}
% TÝnh l¹i gi¸ trÞ lín nhÊt cña |vn_max_ac_top#|.
%    \begin{macrocode}
    vn_max_ac_top# := max(vn_max_ac_top#, vn_top(_a));
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_char_dimens}
%    \begin{macrocode}
def set_char_dimens(expr _w, _h, _d) =
    charwd := _w;
    charht := _h;
    chardp := _d;
    w := hp(charwd);
    h := vp(charht);
    d := vp(chardp);
    charic := 0;
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_letter_dimens}
%    \begin{macrocode}
def set_letter_dimens(suffix _l)(expr _w, _h, _d, _ic, _lft, _rt) =
    set_char_dimens(_w, _h, _d);
    vn_width(_l)  := _w;
    vn_height(_l) := _h;
    vn_depth(_l)  := _d;
    vn_ic(_l)     := _ic;
    vn_left_adj(_l)  := _lft;
    vn_right_adj(_l) := _rt;
    adjust_fit(_lft, _rt);
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_ac_join}
%    \begin{macrocode}
def set_ac_join(suffix _a)(expr _xp, _x, _rt) =
    vn_join_xp(_a) := _xp;
    vn_join_x(_a)  := _x;
    vn_rt(_a)      := _rt;
%<*test>
    if known show_labels:
        makelabel("j", (vn_join_xp(_a), 0));
        makelabel("J", (hp(vn_join_x(_a)), 0));
        makelabel("r", (hp(vn_width(_a)), vp(vn_rt(_a))));
        makelabel("o", (0,0));
    fi;
%</test>
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_letter_join}
%    \begin{macrocode}
def set_letter_join(suffix _l)(expr _xp, _x) =
    vn_join_xp(_l) := _xp;
    vn_join_x(_l)  := _x;
%<*test>
    if known show_labels:
        makelabel("X", (vn_join_xp(_l),    vp(vn_height(_l))));
        makelabel("Y", (hp(vn_join_x(_l)), vp(vn_height(_l))));
    fi;
%</test>
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_adj_gap}
%    \begin{macrocode}
def set_adj_gap(suffix _l, _a) =
%<=use:ifknown>
    adj_gap# := ifknown(vn_gap(_l._a),
                        ifknown(vn_gap(_a), 0));
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_shift}
%    \begin{macrocode}
def set_shift(suffix _l, _a) =
    shift.y  := vp(vn_top(_a) - vn_height(_a))
                + ifknown(hook_shift.y._l._a,0)*u;
    shift.x  := get_join_xp(_l, _a) - vn_join_xp(_a)
                + slant*shift.y
                + ifknown(hook_shift.x.vncase._l._a,0)*u;
%    \end{macrocode}
%
%    \begin{macrocode}
    shift.y# := vn_top(_a) - vn_height(_a)
                + ifknown(hook_shift.y._l._a#,0)*u#;
    shift.x# := get_join_x(_l, _a) - vn_join_x(_a)
                + slant*shift.y#
                + ifknown(hook_shift.x.vncase._l._a#,0)*u#;
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_ic}
%    \begin{macrocode}
def set_ic(suffix _l, _a) =
    italcorr max(vn_ic(_l),
                 vn_width(_a) + shift.x#
                    + slant*(vn_rt(_a) + shift.y#)
                    - w# + .5u#);
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_lic}
%    \begin{macrocode}
def set_lic(suffix _l) =
    italcorr vn_ic(_l);
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_fit}
%    \begin{macrocode}
def set_fit(suffix _l) =
    adjust_fit(vn_left_adj(_l), vn_right_adj(_l));
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_dot_shift}
% to avoid error when calling |set_dot_shift(idot)|
%    \begin{macrocode}
C.l.idot.dot_ = C.u.idot.dot_ = 256;
%    \end{macrocode}
%
%    \begin{macrocode}
def set_dot_shift(suffix _l) =
    shift.y := - vp(ifknown(vn_dot_shift_y(_l), vn_bot(dot_)));
    shift.x := get_join_xp(_l, dot_) - vn_join_xp(dot_) + slant*shift.y;
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Getting Macros}
%
% \begin{macro}{get_join_xp}
%    \begin{macrocode}
def get_join_xp(suffix _l, _a) =
    ifknown(vn_join_xp(_l._a), vn_join_xp(_l))
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{get_join_x}
%    \begin{macrocode}
def get_join_x(suffix _l, _a) =
    ifknown(vn_join_x(_l._a), vn_join_x(_l))
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{get_top}
%    \begin{macrocode}
def get_top(suffix _a) =
%<=def:get_top>
    max(vn_top(_a) + adj_gap#,
        if vn_top(_a) <= vn_ac_top:
            vn_ac_top
        else:
            vn_double_ac_top
        fi)
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Pos Function}
%
% \begin{macro}{pos}
% Xem chó thÝch trong \mfb E/310/.
%    \begin{macrocode}
vardef pos@#(expr b,d) =
    if known b:
        if b <= currentbreadth:
                (x@#r - x@#l, y@#r - y@#l) = (eps,0) rotated d;
        else:   (x@#r - x@#l, y@#r - y@#l) = (b - currentbreadth, 0) rotated d;
        fi
    else:       (x@#r - x@#l, y@#r - y@#l) = (b - currentbreadth, 0) rotated d;
    fi
%    \end{macrocode}
% H×nh nh­ anh Thµnh nhÇm lÉn, khi dïng *|if known b ... else|*?
% Kh«ng! Quan s¸t file *log* (sau khi thªm *message ...* vµo trong *else:*)
% ta thÊy cã nhiÒu lÇn tr­êng hîp "else" x¶y ra... Xem xÐt mét sè tr­êng hîp
% gäi *pos*, ta thÊy: cã khi *|expr b|* lµ mét biÓu thøc,
% cã khi nã lµ mét biÕn. VÝ dô, khi vÏ *tilde* trong *vnaccent*,
% anh Thµnh ®· dïng\\\centerline{"pos1(vn_tilde_vair, theta + 90)"}
% Nh­ vËy lµ, hµm *pos* ®­îc ®Þnh nghÜa ë ®©y \emph{rÊt m¹nh}.
% Mét c©u hái ®Æt ra lµ, liÖu cã cÇn ph©n biÖt hai tr­êng hîp nh­ trªn?
% C©u tr¶ lêi lµ \emph{kh¼ng ®Þnh}.
% \up ý cña anh Thµnh lµ: nÕu *|expr b|* ®­îc dïng lµ mét biÕn, th× cÇn
% ph¶i khèng chÕ tr­êng hîp gi¸ trÞ cña biÕn ®ã ë d­íi ng­ìng cho phÐp!
%    \begin{macrocode}
    x@# = .5(x@#l + x@#r);
    y@# = .5(y@#l + y@#r)
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{vn_sl_shift}
%    \begin{macrocode}
def vn_sl_shift(suffix _a) =
%   .5slant*(adj_y# + vn_height(_a))
    0
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Drawing Letters and Accents}
%
% \begin{macro}{define_vnchar}
% \label{def:define_vnchar}
%
% Macro nµy nèi dÊu |_c| víi ch÷ |_c|, t¹o thµnh mét ch÷ c¸i
% tiÕng ViÖt. VÝ dô, nèi dÊu huyÒn víi ch÷ "a".
%
%    \begin{macrocode}
def define_vnchar(suffix _l, _a) =
%<=def:define_vnchar>
%<test> if used_char(vn_code(_l._a)):
    set_adj_gap(_l, _a);
    beginchar(vn_code(_l._a),
              vn_width(_l),
              get_top(_a),
              vn_depth(_l));
        set_shift(_l, _a);
        set_ic(_l, _a);
        set_fit(_l);
        currentpicture := vn_pic(_l);
        addto currentpicture also vn_pic(_a)
            shifted (shift.x, shift.y + vp(adj_gap#));
%<*t5supp>
        write_shift_xy(_l, _a)
           (shift.x + hp(vn_left_adj(_l)) + letter_fit,
            shift.y + vp(adj_gap#));
%</t5supp>
    endchar
%<test> fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_double_accent}
%    \begin{macrocode}
def define_double_accent(suffix _a, _b)(expr _adj_x, _adj_y) =
    shift.y# := _adj_y + vn_height(_a);
    shift.x# := _adj_x + slant*shift.y#;
    define_accent_dimens(_a._b, vn_width(_a), vn_height(_b) + shift.y#);
    begin_accent(_a._b);
    currentpicture := vn_pic(_a);
    addto currentpicture
        also vn_pic(_b) shifted (hp(shift.x#), vp(shift.y#));
%<*t5supp>
    write_shift_xy(_a, _b)(hp(shift.x#), vp(shift.y#));
%</t5supp>    
    set_ac_join(
        _a._b,
        vn_join_xp(_a),
        vn_join_x(_a),
        if vn_width(_a) + slant*vn_rt(_a)
                > vn_width(_b) + shift.x#
                  + slant*(vn_rt(_b) + shift.y#):
            vn_rt(_a)
        else:
            vn_rt(_b) + shift.y#
        fi);
    end_accent;
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_vnaccent}
%
% VÏ \meta{accent} |_a| víi m· |_c|.
% ChØ dïng víi |T5supp|.
% Xem c¸ch dïng trong *vnuacc* \lref{use:define_vnaccent}.
%
%    \begin{macrocode}
%<*t5supp>
def define_vnaccent(expr _c)(suffix _a) =
%<=def:define_vnaccent>
    beginchar(_c, vn_width(_a), vn_height(_a), 0);
        currentpicture := vn_pic(_a);
    endchar
enddef;
%</t5supp>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_vnchar_dot}
%
% Thªm dÊu nÆng vµo mét ch÷
%
%    \begin{macrocode}
def define_vnchar_dot(suffix _l) =
%<test> if used_char(vn_code(_l.dot_)):
%    \end{macrocode}
% Ta ph©n biÖt hai tr­êng hîp: ch÷ |Þ| (th­êng)
% vµ c¸c ch÷ kh¸c (víi dÊu nÆng).
%    \begin{macrocode}
    if (case_ = small) and (vn_code(_l.dot_) = vn_code(i.dot_)):
        beginchar(vn_code(i.dot_),
                  vn_width(idot),
                  vn_height(idot),
                  vn_bot(dot_));
            set_dot_shift(idot);
            set_lic(idot);
            set_fit(idot);
            currentpicture := vn_pic(idot);
    else:
        beginchar(vn_code(_l.dot_),
                  vn_width(_l),
                  vn_height(_l),
                  ifknown(vn_depth(_l.dot_),
                          max(vn_bot(dot_), vn_depth(_l))));
            set_dot_shift(_l);
            set_lic(_l);
            set_fit(_l);
            currentpicture := vn_pic(_l);
    fi
        addto currentpicture
            also vn_pic(dot_) shifted (shift.x, shift.y);
%<*t5supp>
        write_shift_xy(_l, dot_)
            (shift.x + hp(vn_left_adj(_l)) + letter_fit,
             shift.y);
%</t5supp>        
        endchar
%<test> fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_vnchar_dot_ac}
%
% Thªm dÊu vµ dÊu nÆng vµo mét ch÷ cã dÊu.
%
%    \begin{macrocode}
def define_vnchar_dot_ac(suffix _l, _a) =
%<test> if used_char(vn_code(_l._a.dot_)):
    set_adj_gap(_l, _a);
    beginchar(vn_code(_l._a.dot_),
              vn_width(_l),
              get_top(_a),
              max(vn_bot(dot_), vn_depth(_l)));
        set_shift(_l, _a);
        set_ic(_l, _a);
        set_fit(_l);
        currentpicture := vn_pic(_l);
        addto currentpicture
            also vn_pic(_a) shifted (shift.x, shift.y + vp(adj_gap#));
        set_dot_shift(_l);
        addto currentpicture
            also vn_pic(dot_) shifted (shift.x, shift.y);
%<*t5supp>
        write_shift_xy(_l._a, dot_)
            (shift.x + hp(vn_left_adj(_l)) + letter_fit, shift.y);
%</t5supp>    
    endchar
%<test> fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_vnchar_horn}
%
% VÏ r©u cho ch÷ |u| hoÆc |o|.
%
%    \begin{macrocode}
def define_vnchar_horn(suffix _l) =
%<test> if used_char(vn_code(_l.horn_)):
    select_horn(_l);
    set_shift_horn(_l);
    update_horn_width(_l);
    beginchar(vn_code(_l.horn_),
              updated_width#,
              vn_top(cur_horn_),
              vn_depth(_l));
        set_ic(_l, cur_horn_);
        set_fit(_l);
        select_letter_u(_l);
        addto currentpicture
            also vn_pic(cur_horn_) shifted (shift.x, shift.y);
    endchar
%<test> fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{select_horn}
%
% Chän r©u cña ch÷ |u| hay ch÷ |o|.
%
%    \begin{macrocode}
def select_horn(suffix _l) =
    if vn_code(_l.horn_) = vn_code(u.horn_):
            def cur_horn_ = uhorn_ enddef;
    else:   def cur_horn_ = ohorn_ enddef;
    fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{update_horn_width}
%    \begin{macrocode}
def update_horn_width(suffix _l) =
    _du := (shift.x + hp(vn_width(cur_horn_)))
           - (hp(vn_width(_l) + vn_left_adj(_l)
                + vn_right_adj(_l)) + 2letter_fit)
           - slant*(shift.y + vp(vn_height(cur_horn_)));
    updated_width# :=
        vn_width(_l)
        if _du > .5u:
            + .5u#*floor(_du/.5u)
        fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_shift_horn}
%    \begin{macrocode}
def set_shift_horn(suffix _l) =
    shift.y  := vp(vn_bot(cur_horn_));
    shift.x  := vn_join_xp(_l.horn_join)
                - vn_join_xp(cur_horn_) + slant*(shift.y);
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{select_letter_u}
%    \begin{macrocode}
def select_letter_u(suffix _l) =
%   test for the serif capital u letter with horn
    if serifs and (case_ <> small) and (vn_code(_l.horn_) = vn_code(u.horn_)):
%       use the modified "U" (without right part of the right serif)
        currentpicture := vn_pic(Uhorn)
    else:
        currentpicture := vn_pic(_l)
    fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_vnchar_horn_ac}
% set |cur_horn_| to |uhorn_| or |ohorn_| according to |_l|.
%    \begin{macrocode}
def define_vnchar_horn_ac(suffix _l, _a) =
%<test> if used_char(vn_code(_l.horn_._a)):
    select_horn(_l);
    set_adj_gap(_l, _a);
    set_shift_horn(_l);
    update_horn_width(_l);
    beginchar(vn_code(_l.horn_._a),
              updated_width#,
              get_top(_a),
              vn_depth(_l));
        set_ic(_l, cur_horn_);
        set_fit(_l);
        select_letter_u(_l);
        addto currentpicture also vn_pic(cur_horn_)
                             shifted (shift.x, shift.y);
        set_shift(_l.horn_, _a);
%       if serifs and (vn_code(_l.horn_._a) = vn_code(o.horn_.grave_)):
%           shift.x := shift.x + max(0, u - .3stem);
%       fi
        set_ic(_l, _a);
        addto currentpicture also vn_pic(_a)
                             shifted (shift.x, shift.y + vp(adj_gap#));
%<*t5supp>
        write_shift_xy(_l.horn_, _a)
            (shift.x + hp(vn_left_adj(_l)) + letter_fit,
             shift.y + vp(adj_gap#));
%</t5supp>
    endchar
%<test> fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{define_vnchar_horn}
%    \begin{macrocode}
def define_vnchar_horn_dot(suffix _l) =
%<test> if used_char(vn_code(_l.horn_.dot_)):
    select_horn(_l); % set cur_horn_ to uhorn_ or ohorn_ according to _l
    set_shift_horn(_l);
    update_horn_width(_l);
    beginchar(vn_code(_l.horn_.dot_),
              updated_width#,
              vn_top(cur_horn_),
              max(vn_bot(dot_), vn_depth(_l)));
        set_ic(_l, cur_horn_);
        set_fit(_l);
        select_letter_u(_l);
        addto currentpicture also vn_pic(cur_horn_)
                             shifted (shift.x, shift.y);
        set_dot_shift(_l);
        addto currentpicture also vn_pic(dot_)
                             shifted (shift.x, shift.y);
%<*t5supp>
        write_shift_xy(_l.horn_, dot_)
            (shift.x + hp(vn_left_adj(_l)) + letter_fit,
             shift.y);
%</t5supp>
    endchar
%<test> fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{hook_arck.r}
% |hook_arc| is based on |super_arc| from exbase.mf
%    \begin{macrocode}
vardef hook_arc.r(suffix $, $$)(expr _superness, _swap) =
    pair center, corner;
    if (y$ = y$r) or _swap:
        center = (x$$r, y$r);
        corner = (x$r, y$$r);
    else:
        center = (x$r, y$$r);
        corner = (x$$r, y$r);
    fi
    z$.r{corner - z$.r}
        ... _superness[center, corner]{z$$.r - z$.r}
        ... {z$$.r - corner}z$$.r
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{hook_arc.l}
%    \begin{macrocode}
vardef hook_arc.l(suffix $, $$)(expr _superness, _swap) =
    pair center, corner;
    if (y$ = y$r) or _swap:
        center = (x$$l, y$l);
        corner = (x$l, y$$l);
    else:
        center = (x$l, y$$l);
        corner = (x$$l, y$l);
    fi
    z$l{corner - z$l}
        ... _superness[center, corner]{z$$l - z$l}
        ... {z$$l - corner}z$$l
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{vn_hook_bulb}
% |vn_hook_bulb| is based on bulb from |exbase.mf|
%    \begin{macrocode}
def vn_hook_bulb(suffix $, $$, $$$) =
    z$$$r = z$$r;
    path_.l := z$l{x$$r - x$r, 0} ... {0, y$$r - y$r}z$$l;
    filldraw
        path.l -- z$$r{0, y$r - y$$r}
            ... {x$r - x$$r, 0}z$r -- cycle; % link
    path_.r := z$$$l{0, y$r - y$$r} .. z$$$r{0, y$$r - y$r}; % near - circle
    filldraw
        subpath(0, xpart(path_.r intersectiontimes path_.l))
            of path_.r
        -- z$$r{0, y$$r - y$r} .. cycle; % bulb
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{vn_draw_horn}
% \begin{verbatim}
%   ====4r===
%  =    1    =      z1r = z4r
% =           =     y2  = 1/3[y1, y3]
% =     4   22l
% =           =
%  =         =
%   ===4l====
%         ==
%       ==
%  3===
% \end{verbatim}
%
%    \begin{macrocode}
def vn_draw_horn(suffix _a)(expr _dotsize, _horn_stem, _horn_bot_theta) =
    cur_dotsize# := _dotsize;
    cur_stem# := _horn_stem;
    define_blacker_pixels(cur_dotsize, cur_stem);
%    \end{macrocode}
%    \begin{macrocode}
    if not square_dots:
        pickup crisp.nib;
        pos4(cur_dotsize, 90);
        top y4r = h;
        x4 = w - .5cur_dotsize;
        pos1(cur_stem, 90);
        pos2(cur_stem, 0);
        pos3(cur_stem, _horn_bot_theta - 90);
        z1r = z4r;
        rt x2r = hround(x4 + .5cur_dotsize) + 2eps;
        lft x3l = 0;
        bot y3r = 0;
        y2 = 1/3[y1, y3];
        y_ := ypart( (z1{right} ... z2{down} ... z3 )
                      intersectiontimes (z4l{right} .. {left}z4r) );
        if y_ < 0:
            y_ := 1;
        fi
%    \end{macrocode}
% Víi ®o¹n m· d­íi ®©y, ta t« ®­îc mét nöa h×nh trßn vµ mét tam gi¸c cong
% cã mét c¹nh lµ ®­êng kÝnh cña nöa h×nh trßn. Tam gi¸c nµy ®­îc chän
% dùa trªn tham sè |y_| ë trªn.
% {\ttfamily
% \begin{verbatim}
%     ooooo
%   ooooooox
%  ooooooooxx
% oooooooooxxx
% oooooooooxxxx
% oooooooooxxxxx
% ooooooooxxxxxxx
%  oooooooxxxxxx
%   ooooooxxxxx
%     ooooxxx
% \end{verbatim}
% }
%    \begin{macrocode}
        filldraw z4r{left}
            .. subpath (0, y_) of (z4l{right}.. {left}z4r)
            -- cycle;
%    \end{macrocode}
% \danger
% Tuy nhiªn, víi phÇn h×nh trßn ë trªn, khi ®­îc phãng to, c¸i r©u sÏ
% bÞ khuyÕt mét m¶nh.
%
% §Ó kh¾c phôc lçi nµy, anh Thµnh ®· thªm vµo mét chót,
% |--z2--cycle|, trong ®o¹n m· trªn. M¶nh khuyÕt b©y giê kh«ng cßn.
% Tuy nhiªn, c¸c font |typewriter| khi ®ã ®Òu bÞ lçi <<|strange path|>>.
% \emph{Lçi nµy xuÊt hiÖn trong bé |VNR| ngµy 2003/03/03
% (\href{http://vinux.sourceforge.net/vntex}{vinux.sourceforge.net/vntex}).}
% \endanger
%
% TiÕp theo, ta vÏ dÊu phÈy, thªm vµo h×nh ë trªn ®Ó t¹o r©u.
%    \begin{macrocode}
        filldraw stroke
            z1e{right} ... z2e{down} ... {left}z3e;
%    \end{macrocode}
% §Ó che ®i m¶nh khuyÕt ®ång thêi tr¸nh lçi ë trªn,
% ta cã thÓ viÕt m· riªng... ®Ó t¹o mét tam gi¸c ®ñ lín.
% C¸c ®Ønh cña tam gi¸c nµy lµ c¸c ®iÓm \meta{ngoµi cïng} cña r©u.
% Cho ®Õn ngµy "2003/11/30", miÕng v¸ nµy ch­a thÓ hiÖn thiÕu sãt nµo.
% C¸c font |typewriter| ®Òu tèt, nh­ng c¸c font |csc| th× vÉn\footnote{%
% §· kh¾c phôc lçi sau ®ã mét ngµy, còng víi viÖc viÕt l¹i |docstrip|.
% \emph{Nguyªn nh©n:} c¸c |guard| trong file
% *|vndriver.dtx|* lµ c¸c |nested| |guard|, vµ |docstrip.py| khi ®ã
% kh«ng thÓ hiÓu ®iÒu nµy.}...
% \danger
% CÇn xem l¹i |METAFONTbook|, xem thö tam gi¸c nµy liÖu cã ®Ønh *rÊt nhän*
% hay lµ *trßn* (nh­ khi dïng |draw|)? (\emph{Tr¶ lêi:} dïng |filldraw|
% th× chuyÖn nµy khái ph¶i lo....)
% \endanger
%    \begin{macrocode}
        filldraw z1r--z2r--z4l--cycle;
%    \end{macrocode}
%    \begin{macrocode}
%<test> penlabels(0, 1, 2, 3, 4);
        set_ac_join(_a, x3,
            .5cur_stem*sind(_horn_bot_theta),
            h# - .5cur_dotsize#);
%    \end{macrocode}
%    \begin{macrocode}
    else:
        pickup fine.nib;
        pos4(cur_dotsize, 90);
        top y4r = h;
        x4 = w - .5cur_dotsize;
        pos4'(cur_dotsize, 0);
        z4' = z4;
        dot(4', 4);  % squarish dot
        horn_join := max(fine.breadth, floor cur_stem);
        horn_bot := max(fine.breadth, floor .8cur_stem);
        pos0(horn_join, 0);
        pos1(horn_join, 0);
        pos2(horn_bot, 0);
        y0 = y4;
        y1 = y4l;
        x0r = x1r = x4'r;
        lft x2l = 0;
        bot y2r = 0;
        z2' = whatever[z1, z2];
        numeric _vn_bot_width;
        pos2'(_vn_bot_width, -90 + _horn_bot_theta);
        z2l = z2'l;
        filldraw stroke z0e -- z1e .. z2'e; % tail
%<test> penlabels(0, 1, 2', 3, 4);
        set_ac_join(_a, x2', 0, h#);
    fi
    vn_bot(_a) := vn_top(_a) - vn_height(_a);
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{set_horn_join}
%    \begin{macrocode}
def set_horn_join(suffix _l)(expr _pl, _pr) =
    select_horn(_l); % set cur_horn_ to uhorn_ or ohorn_ according to _l
    path bot_line;
    pair L, R;
    bot_line := (.5w, vp(vn_bot(cur_horn_))) -- (w, vp(vn_bot(cur_horn_)));
    L := point xpart(bot_line intersectiontimes _pl) of bot_line;
    R := point xpart(bot_line intersectiontimes _pr) of bot_line;
    set_ac_join(_l.horn_join, xpart .5[L, R], 0, 0);
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Oct031 Character}
%
% \begin{macro}{lig_CGQ_table}
%    \begin{macrocode}
def lig_CGQ_table(expr k) =
    "C" kern k, "G" kern k, "Q" kern k
enddef;
%    \end{macrocode}
%
%    \begin{macrocode}
def end_ligtable = 0 kern 0 enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{input_lig}
% define input_lig to generate only char oct"031" from excspl.mf
%    \begin{macrocode}
def input_lig suffix @# =
    let save_endchar = endchar;
    let endchar = lig_endchar;
    scantokens("input " & str @#);
    relax;
    let endchar = save_endchar;
enddef;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{lig_endchar}
%    \begin{macrocode}
def lig_endchar =
    if charcode = oct"031":
        save_endchar
    else:
        endgroup
    fi
enddef;
%    \end{macrocode}
% \end{macro}
%
% \subsection{Macro: generate}
%
% \begin{macro}{generate}
% File |vnr10.mf| sÏ |input| c¸c file |vnbase.mf| vµ |ecrm.mf|.
% §Õn l­ît m×nh, |ecrm| sÏ |input| driver lµ |exroman| b»ng c¸ch gäi
% *|generate exroman|* (®èi víi |ec|, |generate| chÝnh lµ |input|).
% {\tiny
% \begin{verbatim}
% 0: 0  *
% 1: 1  +- vnr10.mf
% 2: 2  |  +- vnbase.mf
% 3: 3  |  |  +- exbase.mf
% 4: 3  |  |  +- vncode.mf
% 5: 2  |  +- ecrm.mf
% 6: 3  |  |  +- null.mf
% 7: 3  |  |  +- vnroman.mf
%
% (See |doc/vnr10_tree_*.txt| for full detail)
% \end{verbatim}
% }
% §Ó thay thÕ |exroman| b»ng |driver| cña |VNR|, ta sÏ ®Þnh nghÜa l¹i
% |generate|, nhê vµo ®Æc ®iÓm: c¸c |driver| cña |ec| ®Òu b¾t ®Çu b»ng
% hai ký tù |ec|, vµ c¸c |driver| cña |VNR| (bao gåm \emph{vnroman},
% \emph{vncsc}, \emph{vntextit}) ®­îc b¾t ®Çu bëi |vn|.
%
% \danger
% Kh«ng thÓ hiÓu t¹i sao ph¶i dïng |scantokens("input null")|.
% NÕu kh«ng cã dßng nµy, th× tÊt c¶ c¸c file ®Òu ®­îc |input| mét
% c¸ch \emph{b×nh th­êng}, nh­ng kh«ng cã ch÷ nµo ®­îc vÏ c¶.
%
% T¹i sao anh Thµnh l¹i cã thÓ nghÜ ra chuyÖn thªm dßng nµy vµo?
% \emph{Qu¸ siªu!}
% \endanger
%    \begin{macrocode}
vardef generate @# =
    scantokens("input null");
    scantokens("input vn" & substring(2, length(str @#)) of str @#);
enddef;
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</vnbase>
%    \end{macrocode}
% \endinput
