From 35af52eac70a27ef9b0e7bc01d508a6995431f2e Mon Sep 17 00:00:00 2001 From: Luigi Scarso Date: Sun, 16 Apr 2017 21:13:23 +0000 Subject: fix kpse call (thank to A. Kakuto) git-svn-id: svn://tug.org/texlive/trunk@43848 c570f23f-e606-0410-a88d-b1316a301751 --- .../source/texk/web2c/mfluadir/mfluatrap/mflua.lua | 2857 ++++++++++++++++++++ .../web2c/mfluadir/mfluatrap/mflua_svg_backend.lua | 538 ++++ .../web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua | 743 +++++ 3 files changed, 4138 insertions(+) create mode 100644 Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua create mode 100644 Build/source/texk/web2c/mfluadir/mfluatrap/mflua_svg_backend.lua create mode 100644 Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua (limited to 'Build/source') diff --git a/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua b/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua new file mode 100644 index 00000000000..96b5c511c1d --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua @@ -0,0 +1,2857 @@ +local function PRINTDBG(s) end +local function chMF(t,k) if t[k] then print(k.." already inserted") os.exit(1) end end + +PRINTDBG("mflua.lua") + +-------------------------------------------------------------------------------- +-- +-- kpse +-- +-------------------------------------------------------------------------------- +-- "new" +-- "set_program_name" +-- "init_prog" +-- "readable_file" +-- "find_file" +-- "expand_path" +-- "expand_var" +-- "expand_braces" +-- "var_value" +-- "show_path" +-- "lookup" +-- "version" +-- "default_texmfcnf" + + +-------------------------------------------------------------------------------- +-- +-- These are hardcoded into mflua.MFbuiltin table: +-- +-------------------------------------------------------------------------------- +MFbuiltin = mflua.MFbuiltin or {} +-- function: link +-- function: info +-- function: x_coord +-- function: y_coord +-- function: left_type +-- function: right_type +-- function: left_x +-- function: left_y +-- function: right_x +-- function: right_y +-- function: n_sin_cos +-- +-- function: LUAGLOBALGET_boundary_char +-- function: LUAGLOBALGET_char_code +-- function: LUAGLOBALGET_char_dp +-- function: LUAGLOBALGET_char_dx +-- function: LUAGLOBALGET_char_dy +-- function: LUAGLOBALGET_char_ext +-- function: LUAGLOBALGET_char_ht +-- function: LUAGLOBALGET_char_ic +-- function: LUAGLOBALGET_char_wd +-- function: LUAGLOBALGET_cur_edges +-- function: LUAGLOBALGET_cur_exp +-- function: LUAGLOBALGET_cur_pen +-- function: LUAGLOBALGET_designsize +-- function: LUAGLOBALGET_fillin +-- function: LUAGLOBALGET_granularity +-- function: LUAGLOBALGET_hppp +-- function: LUAGLOBALGET_mem_top +-- function: LUAGLOBALGET_octant +-- function: LUAGLOBALGET_turning_check +-- function: LUAGLOBALGET_vppp +-- function: LUAGLOBALGET_x_offset +-- function: LUAGLOBALGET_y_offset + +-- +-- It's handy to have them as local +-- + +local link = MFbuiltin.link +local info = MFbuiltin.info +local x_coord = MFbuiltin.x_coord +local y_coord = MFbuiltin.y_coord +local left_type = MFbuiltin.left_type +local right_type = MFbuiltin.right_type +local left_x = MFbuiltin.left_x +local left_y = MFbuiltin.left_y +local right_x = MFbuiltin.right_x +local right_y = MFbuiltin.right_y +local n_sin_cos = MFbuiltin.n_sin_cos + + + +-------------------------------------------------------------------------------- +-- Global table mflua. +-- Important subtable: +-- * mflua.MFbuiltin that stores the hardwired functions; +-- * mflua.MF that stores some constants from MetaFont, as also some functions +-- from PascalWEB rewritten in Lua (almost 1:1 translation). +-- Use them with care ! +-------------------------------------------------------------------------------- + +mflua = mflua or {} +mflua.MF = mflua.MF or {} + + +-------------------------------------------------------------------------------- +-- +-- As in MetaFont: +-- +-------------------------------------------------------------------------------- + +local min_quarterword = 0 --{smallest allowable value in a |quarterword|} +local max_quarterword = 255 --{largest allowable value in a |quarterword|} +local min_halfword = 0 --{smallest allowable value in a |halfword|} +local max_halfword = 65535 --{largest allowable value in a |halfword|} + +local mem_min = 0 -- {smallest index in the |mem| array, must not be less than |min_halfword|} + +local quarter_unit = 2^14 -- {$2^{14}$, represents 0.250000} +local half_unit = 2^15 -- {$2^{15}$, represents 0.50000} +local three_quarter_unit = 3*(2^14) -- {$3\cdot2^{14}$, represents 0.75000} +local unity = 2^16 -- {$2^{16}$, represents 1.00000} +local two = 2^17 -- {$2^{17}$, represents 2.00000} +local three = 2^16+2^16 -- {$2^{17}+2^{16}$, represents 3.00000} + + +chMF(mflua.MF,min_quarterword);mflua.MF.min_quarterword = min_quarterword +chMF(mflua.MF,max_quarterword);mflua.MF.max_quarterword = max_quarterword +chMF(mflua.MF,min_halfword);mflua.MF.min_halfword = min_halfword +chMF(mflua.MF,max_halfword);mflua.MF.max_halfword = max_halfword +chMF(mflua.MF,mem_min);mflua.MF.mem_min = mem_min +chMF(mflua.MF,quarter_unit);mflua.MF.quarter_unit = quarter_unit +chMF(mflua.MF,half_unit);mflua.MF.half_unit = half_unit +chMF(mflua.MF,three_quarter_unit);mflua.MF.three_quarter_unit = three_quarter_unit +chMF(mflua.MF,unity);mflua.MF.unity = unity +chMF(mflua.MF,two);mflua.MF.two = two +chMF(mflua.MF,three);mflua.MF.three = three + + + +-- @ Given integers |x| and |y|, not both zero, the |n_arg| function +-- returns the |angle| whose tangent points in the direction $(x,y)$. +-- This subroutine first determines the correct octant, then solves the +-- problem for |0<=y<=x|, then converts the result appropriately to +-- return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|. +-- (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of +-- |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.) + +-- The octants are represented in a ``Gray code,'' since that turns out +-- to be computationally simplest. + +negate_x=1 +negate_y=2 +switch_x_and_y=4 +first_octant=1 +second_octant=first_octant+switch_x_and_y +third_octant=first_octant+switch_x_and_y+negate_x +fourth_octant=first_octant+negate_x +fifth_octant=first_octant+negate_x+negate_y +sixth_octant=first_octant+switch_x_and_y+negate_x+negate_y +seventh_octant=first_octant+switch_x_and_y+negate_y +eighth_octant=first_octant+negate_y + + +local negate_x=1 +local negate_y=2 +local switch_x_and_y=4 +local first_octant=1 +local second_octant=first_octant+switch_x_and_y +local third_octant=first_octant+switch_x_and_y+negate_x +local fourth_octant=first_octant+negate_x +local fifth_octant=first_octant+negate_x+negate_y +local sixth_octant=first_octant+switch_x_and_y+negate_x+negate_y +local seventh_octant=first_octant+switch_x_and_y+negate_y +local eighth_octant=first_octant+negate_y + +chMF(mflua.MF,negate_x);mflua.MF.negate_x = negate_x +chMF(mflua.MF,negate_y);mflua.MF.negate_y = negate_y +chMF(mflua.MF,switch_x_and_y);mflua.MF.switch_x_and_y = switch_x_and_y +chMF(mflua.MF,first_octant);mflua.MF.first_octant = first_octant +chMF(mflua.MF,second_octant);mflua.MF.second_octant = second_octant +chMF(mflua.MF,third_octant);mflua.MF.third_octant = third_octant +chMF(mflua.MF,fourth_octant);mflua.MF.fourth_octant = fourth_octant +chMF(mflua.MF,fifth_octant);mflua.MF.fifth_octant = fifth_octant +chMF(mflua.MF,sixth_octant);mflua.MF.sixth_octant = sixth_octant +chMF(mflua.MF,seventh_octant);mflua.MF.seventh_octant = seventh_octant +chMF(mflua.MF,eighth_octant);mflua.MF.eighth_octant = eighth_octant + + +local octant_dir = {} +octant_dir[first_octant]="ENE-1" +octant_dir[second_octant]="NNE-2" +octant_dir[third_octant]="NNW-3" +octant_dir[fourth_octant]="WNW-4" +octant_dir[fifth_octant]="WSW-5" +octant_dir[sixth_octant]="SSW-6" +octant_dir[seventh_octant]="SSE-7" +octant_dir[eighth_octant]="ESE-8" + +chMF(mflua.MF,octant_dir);mflua.MF.octant_dir = octant_dir + +-- @ Finally we come to the last steps of |make_spec|, when boundary nodes +-- are inserted between cubics that move in different octants. The main +-- complication remaining arises from consecutive cubics whose octants +-- are not adjacent; we should insert more than one octant boundary +-- at such sharp turns, so that the envelope-forming routine will work. +-- For this purpose, conversion tables between numeric and Gray codes for +-- octants are desirable. +-- @= +-- @!octant_number:array[first_octant..sixth_octant] of 1..8; +-- @!octant_code:array[1..8] of first_octant..sixth_octant; + +local octant_code = {} +octant_code[1]=first_octant; +octant_code[2]=second_octant; +octant_code[3]=third_octant; +octant_code[4]=fourth_octant; +octant_code[5]=fifth_octant; +octant_code[6]=sixth_octant; +octant_code[7]=seventh_octant; +octant_code[8]=eighth_octant; +chMF(mflua.MF,octant_code);mflua.MF.octant_code = octant_code + + +local octant_number = {} +for k=1, 8 do octant_number[octant_code[k]]=k; end +chMF(mflua.MF,octant_number);mflua.MF.octant_number = octant_number + + +-- It is convenient to define a \.{WEB} macro |t_of_the_way| such that +-- |t_of_the_way(a)(b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|. +-- @d t_of_the_way_end(#)==#,t@=)@> +-- @d t_of_the_way(#)==#-take_fraction@=(@>#-t_of_the_way_end +-- +-- TO implement !! +-- function t_of_the_way(a,b,t) +-- return take_fraction(a-b,t) +-- end + +local endpoint = 0 -- {|left_type| at path beginning and |right_type| at path end} +local knot_node_size = 7 -- {number of words in a knot node} */ + +local left_curl=left_x -- {curl information when entering this knot} +local left_given=left_x -- {given direction when entering this knot} +local left_tension=left_y -- {tension information when entering this knot} +local right_curl=right_x -- {curl information when leaving this knot} +local right_given=right_x -- {given direction when leaving this knot} +local right_tension=right_y -- {tension information when leaving this knot} +local explicit =1 -- {|left_type| or |right_type| when control points are known} +local given = 2 -- {|left_type| or |right_type| when a direction is given} +local curl = 3 -- {|left_type| or |right_type| when a curl is desired} +local open = 4 -- {|left_type| or |right_type| when \MF\ should choose the direction} + +local right_octant=right_x -- {the octant code before a transition} +local left_octant=left_x -- {the octant after a transition} +local right_transition=right_y -- {the type of transition} +local left_transition=left_y -- {ditto, either |axis| or |diagonal|} +local axis=0 -- {a transition across the $x'$- or $y'$-axis} +local diagonal=1 -- {a transition where $y'=\pm x'$} + +local mem_top = MFbuiltin.mem_top() +local sentinel= mem_top --{end of sorted lists} +local null = mem_min -- {the null pointer} +local knil=info -- {inverse of the |link| field, in a doubly linked list} +local zero_w=4 +local void=null+1 + +local zero_field=4096 -- {amount added to coordinates to make them positive} + + +chMF(mflua.MF,endpoint);mflua.MF.endpoint = endpoint +chMF(mflua.MF,knot_node_size);mflua.MF.knot_node_size = knot_node_size + +chMF(mflua.MF,left_curl);mflua.MF.left_curl = left_curl +chMF(mflua.MF,left_given);mflua.MF.left_given = left_given +chMF(mflua.MF,left_tension);mflua.MF.left_tension = left_tension +chMF(mflua.MF,right_curl);mflua.MF.right_curl = right_curl +chMF(mflua.MF,right_given);mflua.MF.right_given = right_given +chMF(mflua.MF,right_tension);mflua.MF.right_tension = right_tension +chMF(mflua.MF,explicit);mflua.MF.explicit = explicit +chMF(mflua.MF,given);mflua.MF.given = given +chMF(mflua.MF,curl);mflua.MF.curl = curl +chMF(mflua.MF,open);mflua.MF.open = open + +chMF(mflua.MF,right_octant);mflua.MF.right_octant = right_octant +chMF(mflua.MF,left_octant);mflua.MF.left_octant = left_octant +chMF(mflua.MF,right_transition);mflua.MF.right_transition = right_transition +chMF(mflua.MF,left_transition);mflua.MF.left_transition = left_transition +chMF(mflua.MF,axis);mflua.MF.axis = axis +chMF(mflua.MF,diagonal);mflua.MF.diagonal = diagonal + +chMF(mflua.MF,mem_top);mflua.MF.mem_top = mem_top +chMF(mflua.MF,sentinel);mflua.MF.sentinel = sentinel +chMF(mflua.MF,null);mflua.MF.null = null +chMF(mflua.MF,knil);mflua.MF.knil = knil +chMF(mflua.MF,zero_w);mflua.MF.zero_w = zero_w +chMF(mflua.MF,void);mflua.MF.void = void + +chMF(mflua.MF,zero_field);mflua.MF.zero_field = zero_field + + +-- @d incr(#) == #:=#+1 {increase a variable by unity} +local function incr(p) + return p+1 +end +chMF(mflua.MF,incr);mflua.MF.incr = incr + +-- decr(#) == #:=#-1 {decrease a variable by unity} +local function decr(p) + return p-1 +end +chMF(mflua.MF,decr);mflua.MF.decr = decr + +-- double(#) == #:=#+# {multiply a variable by two} +local function double(p) + return 2*p +end +chMF(mflua.MF,double);mflua.MF.double = double + + + +-- @ An array of digits in the range |0..9| is printed by |print_the_digs|. +-- @= +-- procedure print_the_digs(@!k:eight_bits); +-- {prints |dig[k-1]|$\,\ldots\,$|dig[0]|} +-- begin while k>0 do +-- begin decr(k); print_char("0"+dig[k]); +-- end; +-- end; +local function print_the_digs(k,dig) + local res = '' + while k > 0 do + k=k-1 + res= res .. dig[k+1] + end + return res +end +chMF(mflua.MF,print_the_digs);mflua.MF.print_the_digs = print_the_digs + + +-- @= +-- procedure print_int(@!n:integer); {prints an integer in decimal form} +-- var k:0..23; {index to current digit; we assume that $|n|<10^{23}$} +-- @!m:integer; {used to negate |n| in possibly dangerous cases} +-- begin k:=0; +-- if n<0 then +-- begin print_char("-"); +-- if n>-100000000 then negate(n) +-- else begin m:=-1-n; n:=m div 10; m:=(m mod 10)+1; k:=1; +-- if m<10 then dig[0]:=m +-- else begin dig[0]:=0; incr(n); +-- end; +-- end; +-- end; +-- repeat dig[k]:=n mod 10; n:=n div 10; incr(k); +-- until n=0; +-- print_the_digs(k); +-- end; +local function print_int(n) -- {prints an integer in decimal form} + local k -- 0..23; {index to current digit; we assume that $|n|<10^{23}$} + local m -- {used to negate |n| in possibly dangerous cases} + local dig = {} + local done + local res + local sign='' + k=0 + if n<0 then + --begin print_char("-"); + sign='-' + if n>-100000000 + then + n=-n + else + m=-1-n; n=math.floor(m/10) ; m=math.fmod(m,10)+1; k=1; + if m<10 + then + dig[1]=m + else + dig[1]=0; n=n+1 + end + end + end + done=false + while not done do + dig[k+1]=math.fmod(n,10); n=math.floor(n/10); k=k+1; + if n==0 then done=true end + end + res = print_the_digs(k,dig) + return sign .. res +end +chMF(mflua.MF,print_int);mflua.MF.print_int = print_int + + + +-- @= +-- procedure print_scaled(@!s:scaled); {prints scaled real, rounded to five +-- digits} +-- var @!delta:scaled; {amount of allowable inaccuracy} +-- begin if s<0 then +-- begin print_char("-"); negate(s); {print the sign, if negative} +-- end; +-- print_int(s div unity); {print the integer part} +-- s:=10*(s mod unity)+5; +-- if s<>5 then +-- begin delta:=10; print_char("."); +-- repeat if delta>unity then +-- s:=s+@'100000-(delta div 2); {round the final digit '} +-- print_char("0"+(s div unity)); s:=10*(s mod unity); delta:=delta*10; +-- until s<=delta; +-- end; +-- end; +local function print_scaled(s) + local delta + local res = '' + local done + if s== nil then print("\nWarning: print_scale called with nil argument."); return res end + if s<0 then + res = '-' + s=-s + end + res = res .. print_int(math.floor(s/unity)) -- {print the integer part} + s=10*(math.fmod(s,unity))+5 + if s ~= 5 then + delta=10; res = res .. '.' + done = false + while not done do + if delta>unity then + s=s+half_unit-(math.floor(delta/2)) -- {round the final digit} + end + res = res .. math.floor(s/unity); s=10*math.fmod(s,unity); delta=delta*10; + if s<=delta then done = true end + end; + end + return res +end +chMF(mflua.MF,print_scaled);mflua.MF.print_scaled = print_scaled + + + +-- @= +-- procedure print_two(@!x,@!y:scaled); {prints `|(x,y)|''} +-- begin print_char("("); print_scaled(x); print_char(","); print_scaled(y); +-- print_char(")"); +-- end; +local function print_two(x,y) -- {prints `|(x,y)|'} + local res + -- debug + -- print("print_two(x,y)",x,y) + res = '(' .. print_scaled(x) .. ',' .. print_scaled(y) .. ')' + return res +end +chMF(mflua.MF,print_two);mflua.MF.print_two = print_two + +-- procedure unskew(@!x,@!y:scaled;@!octant:small_number); +-- begin case octant of +-- first_octant: set_two(x+y)(y); +-- second_octant: set_two(y)(x+y); +-- third_octant: set_two(-y)(x+y); +-- fourth_octant: set_two(-x-y)(y); +-- fifth_octant: set_two(-x-y)(-y); +-- sixth_octant: set_two(-y)(-x-y); +-- seventh_octant: set_two(y)(-x-y); +-- eighth_octant: set_two(x+y)(-y); +-- end; {there are no other cases} +-- end; +local function unskew ( x , y , octant ) + local curx,cury + if octant == 1 then + curx = x + y ; + cury = y ; + elseif octant == 5 then + curx = y ; + cury = x + y ; + elseif octant == 6 then + curx = -y ; + cury = x + y ; + elseif octant == 2 then + curx = -x - y ; + cury = y ; + elseif octant == 4 then + curx = -x - y ; + cury = -y ; + elseif octant == 8 then + curx = -y ; + cury = -x - y ; + elseif octant == 7 then + curx = y ; + cury = -x - y ; + elseif octant == 3 then + curx = x + y ; + cury = -y ; + end + return curx,cury +end +chMF(mflua.MF,unskew);mflua.MF.unskew = unskew + +-- print_two_true(#)==unskew(#,octant); print_two(cur_x,cur_y) +local function print_two_true(x,y,octant) + local cur_x,cur_y ,res + cur_x,cur_y = unskew ( x , y , octant ) + res = print_two(cur_x,cur_y) + return res +end +chMF(mflua.MF,print_two_true);mflua.MF.print_two_true = print_two_true +-- +-- Debug only +-- +-- function mflua_print_path(h) +-- print("mflua_print_path") +-- local p,q +-- local res +-- local done +-- local done1 +-- local f +-- done = false +-- done1 = false +-- p = h +-- res = '' +-- while not done do +-- q = link(p) +-- if (p==0) or (q==0) then +-- res = "???" +-- -- do something with res -- +-- return 0 +-- end +-- res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res) +-- if right_type(p) == endpoint then +-- if left_type(p)== open then print("{open?}") end -- {can't happen} +-- if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error} +-- done1 = true -- goto done1; +-- elseif right_type(p) == explicit then +-- -- begin "@" +-- res = res .. "..controls " .. print_two(right_x(p),right_y(p)) .. " and "; +-- if left_type(q) ~= explicit then print("??") -- {can't happen} +-- else res = res .. print_two(left_x(q),left_y(q)); +-- done1 = true -- goto done1; +-- end +-- -- end "@" +-- elseif right_type(p) == open then +-- -- begin "@" +-- if (left_type(p) ~= explicit) and (left_type(p)~=open) then +-- res = res .. "{open?}" -- {can't happen} +-- end +-- -- end "@" +-- elseif (right_type(p) == curl) or (right_type(p) == given) then +-- -- @ A curl of 1 is shown explicitly, so that the user sees clearly that +-- -- \MF's default curl is present. +-- -- begin @= +-- if left_type(p)==open then res = res .. "??" end -- {can't happen} +-- if right_type(p)==curl then +-- res = res .. "{curl ".. print_scaled(right_curl(p)) +-- else n_sin_cos(right_given(p)); res = res .."{" +-- res = res .. print_scaled(n_cos) .. "," .. print_scaled(n_sin) +-- end +-- res = res .."}" +-- -- end @= +-- else res = res .. "???" -- {can't happen} +-- end +-- if not done1 then -- mimic label done 1 +-- if left_type(q)~=explicit then res = res .. "..control?" -- {can't happen} +-- else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then +-- -- begin "@;" +-- res = res .. "..tension " +-- if right_tension(p)<0 then res = res .. "atleast" end +-- res = res .. print_scaled(math.abs(right_tension(p))) +-- if right_tension(p) ~= left_tension(q) then +-- res = res .. " and " +-- if left_tension(q)<0 then res = res .. "atleast" end +-- res = res .. print_scaled(math.abs(left_tension(q))) +-- end +-- end -- "@;" +-- end +-- end --- LABEL: done1 +-- -- begin @= +-- p = q +-- res = res .. " .." +-- if left_type(p)==given then +-- n_sin_cos(left_given(p)); res = res .. "{" +-- res = res .. print_scaled(n_cos); res = res .. ","; +-- res = res .. print_scaled(n_sin); res = res .. "}"; +-- else if left_type(p)==curl then +-- res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}"; +-- end; +-- end +-- -- end @= +-- -- end "@" +-- if p == h then done =true end +-- end +-- if left_type(h) ~= endpoint then +-- res = res .. "cycle" +-- else +-- res = res +-- end +-- -- do something with res -- +-- return res +-- end + + + +-- n_max(#)==link(#+1) {maximum row number present, plus |zero_field|} +local function n_max(p) + return link(p+1) +end +chMF(mflua.MF,n_max);mflua.MF.n_max = n_max + + +-- sorted_loc(#)==#+1 {where the |sorted| link field resides} +local function sorted_loc(p) + return p+1 +end +chMF(mflua.MF,sorted_loc);mflua.MF.sorted_loc = sorted_loc + + +-- @d sorted(#)==link(sorted_loc(#)) {beginning of the list of sorted edge weights} +local function sorted(p) + return link(sorted_loc(p)) +end +chMF(mflua.MF,sorted);mflua.MF.sorted = sorted + + +-- @d unsorted(#)==info(#+1) {beginning of the list of unsorted edge weights} +local function unsorted(p) + return info(p+1) +end +chMF(mflua.MF,unsorted);mflua.MF.unsorted = unsorted + +-- @d ho(#)==#-min_halfword +-- {to take a sixteen-bit item from a halfword} +-- See mf.ch +-- ho(#) == # +local function ho(p) + return p +end +chMF(mflua.MF,ho);mflua.MF.ho = ho +-- +-- @d m_offset(#)==info(#+3) {translation of $m$ data in edge-weight nodes} +-- +function m_offset(p) + return info(p+3) +end + + + +-- @ @= +-- procedure print_weight(@!q:pointer;@!x_off:integer); +-- var @!w,@!m:integer; {unpacked weight and coordinate} +-- @!d:integer; {temporary data register} +-- begin d:=ho(info(q)); w:=d mod 8; m:=(d div 8)-m_offset(cur_edges); +-- if file_offset>max_print_line-9 then print_nl(" ") +-- else print_char(" "); +-- print_int(m+x_off); +-- while w>zero_w do +-- begin print_char("+"); decr(w); +-- end; +-- while wzero_w do + --print(tostring(print_int(m+x_off)) .. " w=" .. w.. " " .. zero_w .. " " .. (w-zero_w)) + res = res .. "+" ; w=decr(w); + end + while w" + res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res) + if right_type(p) == endpoint then + if left_type(p)== open then print("{open?}") end -- {can't happen} + if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error} + done1 = true -- goto done1; + elseif right_type(p) == explicit then + -- begin "@" + res = res .. "..controls " .. print_two(right_x(p),right_y(p)) .. " and "; + if left_type(q) ~= explicit then print("??") -- {can't happen} + else res = res .. print_two(left_x(q),left_y(q)); + done1 = true -- goto done1; + end + -- end "@" + elseif right_type(p) == open then + -- begin "@" + if (left_type(p) ~= explicit) and (left_type(p)~=open) then + res = res .. "{open?}" -- {can't happen} + end + -- end "@" + elseif (right_type(p) == curl) or (right_type(p) == given) then + -- @ A curl of 1 is shown explicitly, so that the user sees clearly that + -- \MF's default curl is present. + -- begin @= + if left_type(p)==open then res = res .. "??" end -- {can't happen} + if right_type(p)==curl then + res = res .. "{curl ".. print_scaled(right_curl(p)) + else n_sin_cos(right_given(p)); res = res .."{" + res = res .. print_scaled(n_cos) .. "," .. print_scaled(n_sin) + end + res = res .."}" + -- end @= + else res = res .. "???" -- {can't happen} + end + if not done1 then -- mimic label done 1 + if left_type(q)~=explicit then res = res .. "..control?" -- {can't happen} + else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then + -- begin "@;" + res = res .. "..tension " + if right_tension(p)<0 then res = res .. "atleast" end + res = res .. print_scaled(math.abs(right_tension(p))) + if right_tension(p) ~= left_tension(q) then + res = res .. " and " + if left_tension(q)<0 then res = res .. "atleast" end + res = res .. print_scaled(math.abs(left_tension(q))) + end + end -- "@;" + end + end --- LABEL: done1 + -- begin @= + p = q + res = res .. " .." + if left_type(p)==given then + n_sin_cos(left_given(p)); res = res .. "{" + res = res .. print_scaled(n_cos); res = res .. ","; + res = res .. print_scaled(n_sin); res = res .. "}"; + else if left_type(p)==curl then + res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}"; + end; + end + -- end @= + -- end "@" + if p == h then done =true end + end + if left_type(h) ~= endpoint then res = res .. "cycle" end + -- do something with res -- + res = "%%Print path\n" .. "drawoptions(withcolor black withpen pencircle scaled 1pt);\n" .. "draw " .. res .. " ;\n" + --print(res) + -- local index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + -- local char = mflua.chartable[index] or {} + -- char['char_wd'] = print_scaled(MFbuiltin.char_wd()) + -- char['char_ht'] = print_scaled(MFbuiltin.char_ht()) + -- char['char_dp'] = print_scaled(MFbuiltin.char_dp()) + -- char['char_ic'] = print_scaled(MFbuiltin.char_ic()) + -- char['res'] = char['res'] or "" + -- char['res'] = char['res'] .. res + -- mflua.chartable[index] = char +end + + +-- @ The |print_edges| subroutine gives a symbolic rendition of an edge +-- structure, for use in `\&{show}\' commands. A rather terse output +-- format has been chosen since edge structures can grow quite large. + +-- @= +-- @t\4@>@@;@/ +-- procedure print_edges(@!s:str_number;@!nuline:boolean;@!x_off,@!y_off:integer); +-- var @!p,@!q,@!r:pointer; {for list traversal} +-- @!n:integer; {row number} +-- begin +-- mflua_printedges(s,nuline,x_off,y_off); +-- print_diagnostic("Edge structure",s,nuline); +-- p:=knil(cur_edges); n:=n_max(cur_edges)-zero_field; +-- while p<>cur_edges do +-- begin q:=unsorted(p); r:=sorted(p); +-- if(q>void)or(r<>sentinel) then +-- begin print_nl("row "); print_int(n+y_off); print_char(":"); +-- while q>void do +-- begin print_weight(q,x_off); q:=link(q); +-- end; +-- print(" |"); +-- while r<>sentinel do +-- begin print_weight(r,x_off); r:=link(r); +-- end; +-- end; +-- p:=knil(p); decr(n); +-- end; +-- end_diagnostic(true); +-- end; +local function printedges(s,nuline,x_off,y_off) + PRINTDBG("printedges") + local p,q,r -- for list traversal + local n=0 -- row number + local cur_edges = MFbuiltin.cur_edges() + local res ='' + local y = {} + local xr = {} + local xq = {} + local f, start_row, end_row ,start_row_1, end_row_1 + local edge + local w,w_integer,row_weight,xoff + local chartable = mflua.chartable + local index + local char + p = knil(cur_edges) + n = n_max(cur_edges)-zero_field + while p ~= cur_edges do + xq = {}; xr = {} + q=unsorted(p); r=sorted(p) + if(q>void)or(r~=sentinel) then + res = "mflua row " .. print_int(n+y_off) ..":" + while (q>void) do + w, w_integer,xoff = print_weight(q,x_off) + xq[#xq+1] = {xoff,w_integer} + res = res .. w; q=link(q); + end + res = res .. " |" + while r~=sentinel do + w,w_integer,xoff = print_weight(r,x_off) + xr[#xr+1]= {xoff,w_integer} + res = res .. w .. ' '; r=link(r) + end + y[#y+1] = {print_int(n+y_off),xq,xr} + end + -- print(res) + p=knil(p);n=decr(n); + end + -- + -- local management of y, xq, xr + -- + --f = mflua.print_specification.outfile1 + index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + char = chartable[index] or {} + --print("#xq=".. #xq) + for i,v in ipairs(y) do + xq,xr = v[2],v[3] + -- for j=1, #xq, 2 do end ?? + row_weight=0 + for j=1, #xr, 1 do + local xb = xr[j][1] + local xwb = xr[j][2] + row_weight=row_weight+xwb + xr[j][3]=row_weight + --print(v[1],xr[j][1],xr[j][2],xr[j][3]) + end + end + char['edges'] = char['edges'] or {} + char['edges'][#char['edges']+1] = {y,x_off,y_off} + + char['pre_res'] = char['pre_res'] or "" + for i,v in ipairs(y) do + xq,xr = v[2],v[3] + -- for j=1, #xq, 2 do end ?? + row_weight=0 + char['pre_res'] = char['pre_res'] .. "%% print edges " .. v[1] .. "\n" + for j=1, #xr-1, 1 do + local xb,xe = xr[j][1],xr[j+1][1] + local xsb,xse = xr[j][3],xr[j+1][3] + res = "" + if xsb>0 then + local color = {'0.7white','0.5white','0.4white'} + local col = color[xsb] or 'black' + res = res .. "drawoptions(withcolor " .. col .. " withpen pencircle scaled 0.1pt);\n" + edge = string.format("fill (%s,%s) -- (%s,%s) -- (%s,%s+1) -- (%s,%s+1) -- cycle shifted (-(%s),-(%s));\n", + xb,v[1],xe,v[1],xe,v[1],xb,v[1],x_off,y_off) + res = res .. edge + -- + res = res .. "drawoptions(withcolor black withpen pencircle scaled 0.1pt);\n" + edge = string.format("draw (%s,%s) -- (%s,%s) -- (%s,%s+1) -- (%s,%s+1) -- cycle shifted (-(%s),-(%s));\n", + xb,v[1],xe,v[1],xe,v[1],xb,v[1],x_off,y_off) + res = res .. edge + end + -- print(v[1],xr[j][1],xr[j][2],xr[j][3]) + char['pre_res'] = char['pre_res'] .. res + end + end +end +mflua.MF.printedges = printedges + + + + +-- @ The |print_pen| subroutine illustrates these conventions by +-- reconstructing the vertices of a polygon from \MF\'s complicated +-- internal offset representation. +-- @= + +local function print_pen(p,s,nuline) + local nothing_printed -- {:boolean has there been any action yet?} + local k --1..8; {octant number} + local h -- pointer; {offset list head} + local m,n -- integer; {offset indices} + local w,ww -- :pointer; {pointers that traverse the offset list} + local res = '' + -- begin print_diagnostic("Pen polygon",s,nuline); + nothing_printed=true; -- print() + for k=1,8 do + local octant=octant_code[k]; h=p+octant; n=info(h); w=link(h); + -- print("%% octant",octant_dir[octant],n,w) + if not(odd(k)==true) then w=knil(w) end -- {in even octants, start at $w_{n+1}$} + for m=1, n+1 do + if odd(k)==true then ww=link(w) else ww=knil(w) end + -- print("%% ".. m .. "/" .. n+1 .. " w=" .. print_two_true(x_coord(w),y_coord(w),octant) .. " ww=" .. print_two_true(x_coord(ww),y_coord(ww),octant)) + if (x_coord(ww)~=x_coord(w)) or (y_coord(ww)~=y_coord(w)) then + ---@; + if nothing_printed then nothing_printed=false else -- print(" .. ") + end + -- print(print_two_true(x_coord(ww),y_coord(ww),octant)) + res = res .. print_two_true(x_coord(ww),y_coord(ww),octant) + end + w=ww; + end -- for m=1, n+1 do + end -- for k=1,8 do + if nothing_printed==true then + w=link(p+first_octant); print(print_two(x_coord(w)+y_coord(w),y_coord(w))); + res = res .. print_two(x_coord(w)+y_coord(w),y_coord(w)) + end; + res = res .. " .. cycle"; --end_diagnostic(true); + return res +end -- function +mflua.MF.print_pen = print_pen + +mflua.offset_prep = mflua.offset_prep or {} + +local function _get_pen(p) + local nothing_printed -- {:boolean has there been any action yet?} + local k --1..8; {octant number} + local h -- pointer; {offset list head} + local m,n -- integer; {offset indices} + local w,ww -- :pointer; {pointers that traverse the offset list} + local res = {} + nothing_printed=true; + for k=1,8 do + local octant=octant_code[k]; h=p+octant; n=info(h); w=link(h); + if not(odd(k)==true) then w=knil(w) end -- {in even octants, start at $w_{n+1}$} + for m=1, n+1 do + if odd(k)==true then ww=link(w) else ww=knil(w) end + if (x_coord(ww)~=x_coord(w)) or (y_coord(ww)~=y_coord(w)) then + ---@; + if nothing_printed then nothing_printed=false else -- print(" .. ") + end + -- print(print_two_true(x_coord(ww),y_coord(ww),octant)) + res[#res+1] = print_two_true(x_coord(ww),y_coord(ww),octant) + end + w=ww; + end -- for m=1, n+1 do + end -- for k=1,8 do + if nothing_printed==true then + w=link(p+first_octant); + res[#res+1] = print_two(x_coord(w)+y_coord(w),y_coord(w)) + end; + -- print(" .. cycle"); --end_diagnostic(true); + return res +end +mflua.offset_prep._get_pen = _get_pen + +local function _get_offset_coords(p,octant) + local nothing_printed -- {:boolean has there been any action yet?} + local k --1..8; {octant number} + local h -- pointer; {offset list head} + local m,n -- integer; {offset indices} + local w,ww -- :pointer; {pointers that traverse the offset list} + local res ={} + nothing_printed=true; --print() + k=octant_number[octant]; + h=p+octant; n=info(h); w=link(h); + if not(odd(k)==true) then w=knil(w) end -- {in even octants, start at $w_{n+1}$} + for m=1, n+1 do + if odd(k)==true then ww=link(w) else ww=knil(w) end + res[m] = print_two_true(x_coord(w),y_coord(w),octant) + w=ww; + end -- for m=1, n+1 do + return res +end -- function +mflua.offset_prep._get_offset_coords = _get_offset_coords + + +-- @ Given a pointer |c| to a nonempty list of cubics, +-- and a pointer~|h| to the header information of a pen polygon segment, +-- the |offset_prep| routine changes the list into cubics that are +-- associated with particular pen offsets. Namely, the cubic between |p| +-- and~|q| should be associated with the |k|th offset when |right_type(p)=k|. + +-- List |c| is actually part of a cycle spec, so it terminates at the +-- first node whose |right_type| is |endpoint|. The cubics all have +-- monotone-nondecreasing $x(t)$ and $y(t)$. + +mflua.do_add_to = mflua.do_add_to or {} +mflua.do_add_to.bezier_octant = {} +mflua.do_add_to.bezier_octant_envelope = {} +mflua.do_add_to.bezier_octant_I = {} +mflua.do_add_to.bezier_octant_contour = {} + + +local function print_specification(c,h) + local p,q,n,nh + local octant + local cur_spec + local res,res1 = "","" + local offsets = {} + local cubic,cubics ={},{} + local f + local first_point, first_point_offset + + local bezier,beziers ={},{} + local offset_list = {} + local path_list ={} + local bezier_octant + local pen_key = '' + local temp1 = mflua.print_specification.temp1 + + cur_spec=c + p=cur_spec + --n=info(h) + --lh=link(h) --{now |lh| points to $w_0$} + octant = left_octant(p) + offsets = mflua.offset_prep._get_offset_coords(MFbuiltin.cur_pen(),octant) + + -- for l=1,#offsets do print("SPEC " .. offsets[l] )end + + cubics['offsets'] = offsets + cubics['octant_number'] = octant_number[octant] + + beziers['offsets'] = offsets + beziers['octant_number'] = octant_number[octant] + beziers['pen'] = mflua.offset_prep._get_pen(MFbuiltin.cur_pen()) + + for i,v in ipairs(beziers['pen']) do + --print( "BEZ pen=",i,v) + pen_key = pen_key..v + end + --if not(mflua.pen[pen_key] == nil) then + --table.foreach(mflua.pen[pen_key],print) + --end + -- + --res = res .. "%% cur_pen " .. tostring(MFbuiltin.cur_pen()) .."\n" + --res = res .. string.format("%%%% current octant %s, octant number %s, offset %s\n",octant_dir[MFbuiltin.octant()],octant_number[octant],print_int(n)) + --res = res .. "pair offset[];\n" + --for i,v in ipairs(offsets) do + -- res = res .. string.format("offset%s:=%s;\n",i-1,v) + --end + --res = res .. "pair OffSet; OffSet:=offset"..print_int(n) ..";\n" + --res = res .. "path p; p:= " .. print_two_true(x_coord(p),y_coord(p),octant) .. "\n" + --cubic['p'] = print_two_true(x_coord(p),y_coord(p),octant) + first_point = print_two_true(x_coord(p),y_coord(p),octant) + first_point_offset = print_int(right_type(p)) + -- + --print(res); + local end_loop_1 = false + while end_loop_1 == false do + local end_loop_2 = false + while end_loop_2 == false do + q=link(p); + if right_type(p)==endpoint then + end_loop_2=true + else + cubic['p'] = print_two_true(x_coord(p),y_coord(p),octant); + cubic['control1'] = print_two_true(right_x(p),right_y(p),octant) + cubic['control2'] = print_two_true(left_x(q),left_y(q),octant) + cubic['q'] = print_two_true(x_coord(q),y_coord(q),octant) + cubic['offset'] = print_int(right_type(p)) + cubic['segment'] = print_int(left_type(q)-1) + cubics[#cubics+1] = cubic + cubic = {} + bezier['p'] = print_two_true(x_coord(p),y_coord(p),octant); + bezier['control1'] = print_two_true(right_x(p),right_y(p),octant) + bezier['control2'] = print_two_true(left_x(q),left_y(q),octant) + bezier['q'] = print_two_true(x_coord(q),y_coord(q),octant) + bezier['offset'] = print_int(right_type(p)) + bezier['segment'] = print_int(left_type(q)-1) + beziers[#beziers+1] = bezier + bezier = {} + p=q + end + end + -- not_found label + if q==cur_spec then + end_loop_1=true + else + p=q; octant=left_octant(p); -- print("% entering octant `"); + end + -- We don't want all the octans of the cubic + -- only the pieces of the current octant + end_loop_1 = not(MFbuiltin.octant() == octant) + end + if #cubics == 0 then + cubics['single_point'] = first_point + cubics['single_point_offset'] = first_point_offset + end + -- done label: + -- We can now use the results + -- + -- No curves stored + if #beziers == 0 then + beziers['single_point'] = first_point + beziers['single_point_offset'] = first_point_offset + end + if #beziers['offsets'] == 1 then + offset_list[#offset_list+1] = {0,beziers['offsets'][1]} + offset_list[#offset_list+1] = {1,beziers['offsets'][1]} + else + for i,v in ipairs(beziers['offsets']) do + if odd(beziers['octant_number']) == true then + offset_list[#offset_list+1] = {(i-1),v} + else + offset_list[#offset_list+1] = {#beziers['offsets']-i+1,v} + end + end + end + beziers['offset_list']=offset_list + beziers['path_list'] = {} + if #beziers == 0 then + path_list['p'] = beziers['single_point'] + if odd(beziers['octant_number']) == true then + path_list['offset'] = beziers['single_point_offset'] + else + path_list['offset'] = #beziers['offsets']-beziers['single_point_offset'] + end + beziers['path_list'][#beziers['path_list']+1] = path_list + path_list={} + else + for i,v in ipairs(beziers) do + bezier = v + path_list['p'] = bezier['p'] + path_list['control1'] = bezier['control1'] + path_list['control2'] = bezier['control2'] + path_list['q'] = bezier['q'] + path_list['offset'] = bezier['offset'] + beziers['path_list'][#beziers['path_list']+1] = path_list + path_list={} + end + end + bezier_octant =mflua.do_add_to.bezier_octant + bezier_octant[#bezier_octant+1] = beziers + res = "" + res = res .. "%% cur_pen " .. tostring(MFbuiltin.cur_pen()) .."\n" + --res = res .. string.format("%%%% current octant %s, offset %s\n",octant_dir[MFbuiltin.octant()],print_int(n)) + res = res .. string.format("%%%% current octant %s\n",octant_dir[MFbuiltin.octant()]) + res = res .. "pair offset[];\n" + if #cubics['offsets'] == 1 then + res = res .."%% Only one offset\n" + res = res ..string.format("offset%s:=%s;\n",0,cubics['offsets'][1]) + res = res ..string.format("offset%s:=%s;\n",1,cubics['offsets'][1]) + else + for i,v in ipairs(cubics['offsets']) do + if odd(cubics['octant_number']) == true then + res = res .. string.format("offset%s:=%s;\n",(i-1),v) + else + res = res .. string.format("offset%s:=%s;\n",#cubics['offsets']-i+1,v) + end + end + end + res = res .. "%% cubics['octant_number'])=" .. cubics['octant_number'] .. "\n" + res = res .. "%% #cubics=" .. #cubics .. "\n" + if #cubics == 0 then + res = res .. "path p; p:=" .. cubics['single_point'] .. ";\n" + res = res .. "drawoptions(withcolor red withpen pencircle scaled 0.1pt);\n" + temp1 = temp1 +1 + if odd(cubics['octant_number']) == true then + res = res .. "draw p shifted offset" .. cubics['single_point_offset'] .. ";\n" + res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(-0.5,-0.5)) shifted offset%s;\n", + cubics['single_point'],cubics['single_point_offset'],temp1,cubics['single_point'],cubics['single_point_offset']) + else + res = res .. "draw p shifted offset" .. #cubics['offsets']-cubics['single_point_offset'] .. ";\n" + res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(-0.5,-0.5)) shifted offset%s;\n", + cubics['single_point'],#cubics['offsets']-cubics['single_point_offset'],temp1,cubics['single_point'],#cubics['offsets']-cubics['single_point_offset']) + end + end + -- if #cubics == 0 then this for loop is never executed + for i,v in ipairs(cubics) do + cubic = v + res = res .. "path p; p:= " .. cubic['p'] .."\n" + res = res .. " .. controls " .. cubic['control1'] .." and " .. cubic['control2'] + res = res .. " .. " .. cubic['q'] .."\n ;\n" + res = res .. 'label("'.. octant_dir[MFbuiltin.octant()] ..'"' .. ",0.5[" .. cubic['p'] .. "," .. cubic['q'] .."]) shifted offset" .. cubic['offset'] .. ";\n" + res = res .. "drawoptions(withcolor black withpen pencircle scaled 0.2pt);\n" + res = res .. "draw p shifted offset" .. cubic['offset'] .. ";\n" + temp1 = temp1 +1 + res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(-0.5,-0.5)) shifted offset%s;\n", + cubic['p'],cubic['offset'],temp1,cubic['p'],cubic['offset']) + temp1 = temp1 +1 + res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(0.5,0.5)) shifted offset%s;\n", + cubic['q'],cubic['offset'],temp1,cubic['q'],cubic['offset']) + + end + mflua.print_specification.temp1 = temp1 + res = res .. string.format("%%%%mflua.print_specification.temp1 = %s\n" ,mflua.print_specification.temp1) + --print("\n%%POST START\n".. res .. "%%POST END\n") + -- f = io.open("envelope.tex",'a') + -- f = mflua.print_specification.outfile1 + -- f:write("\n%%POST START\n".. res .. "\n%%POST END\n") + --f:close() +end +mflua.MF.print_specification = print_specification + + + +local function PRE_offset_prep(c,h) + PRINTDBG("PRE_offset_prep") + -- local p = c + -- print("\nBEZ TEST".. print_int(right_type(p))) + -- print ("BEZ TEST".. print_two(x_coord(p),y_coord(p))) + -- print ("BEZ TEST".. print_two(right_x(p),right_y(p))) + -- p = link(p) + -- print ("BEZ TEST".. print_two(left_x(p),left_y(p))) +end + +local function POST_offset_prep(c,h) + PRINTDBG("POST_offset_prep") + -- print("\nPOST print pen"); mflua.MF.print_pen(MFbuiltin.cur_pen(),"" , "") + -- print("\nPOST print specification") + --res = print_pen(MFbuiltin.cur_pen(),"" , "") + --print(" PRINT PEN " .. res ) + mflua.MF.print_specification(c,h) +end + + +mflua.do_add_to = mflua.do_add_to or {} + +local function _get_cycle(h) + local p,q + local res = '' + local done + local done1 + local f + local cycle = {} + done = false + done1 = false + p = h + while not done do + q = link(p) + if (p==0) or (q==0) then + return '???' + end + cycle[#cycle+1] = {tonumber(print_scaled(x_coord(p))), tonumber(print_scaled(y_coord(p)))} -- p + --res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res) + if right_type(p) == endpoint then + if left_type(p)== open then return "{open?}" end -- {can't happen} + if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error} + done1 = true -- goto done1; + elseif right_type(p) == explicit then + -- begin "@" + --res = res .. "..controls " .. print_two(right_x(p),right_y(p)) .. " and "; + cycle[#cycle+1] = {tonumber(print_scaled(right_x(p))), tonumber(print_scaled(right_y(p)))} -- c1 + if left_type(q) ~= explicit then return "??" -- {can't happen} + else + --res = res .. print_two(left_x(q),left_y(q)); + cycle[#cycle+1] = {tonumber(print_scaled(left_x(q))), tonumber(print_scaled(left_y(q)))} -- c2 + done1 = true -- goto done1; + end + -- end "@" + elseif right_type(p) == open then + -- begin "@" + if (left_type(p) ~= explicit) and (left_type(p)~=open) then + return "{open?}" -- {can't happen} + end + -- end "@" + elseif (right_type(p) == curl) or (right_type(p) == given) then + -- @ A curl of 1 is shown explicitly, so that the user sees clearly that + -- \MF's default curl is present. + -- begin @= + if left_type(p)==open then res = res .. "??" end -- {can't happen} + if right_type(p)==curl then + res = res .. "{curl ".. print_scaled(right_curl(p)) + else n_sin_cos(right_given(p)); res = res .."{" + res = res .. print_scaled(n_cos) .. "," .. print_scaled(n_sin) + end + res = res .."}" + -- end @= + else return "???" -- {can't happen} + end + if not done1 then -- mimic label done 1 + if left_type(q)~=explicit then return "..control?" -- {can't happen} + else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then + -- begin "@;" + res = res .. "..tension " + if right_tension(p)<0 then res = res .. "atleast" end + res = res .. print_scaled(math.abs(right_tension(p))) + if right_tension(p) ~= left_tension(q) then + res = res .. " and " + if left_tension(q)<0 then res = res .. "atleast" end + res = res .. print_scaled(math.abs(left_tension(q))) + end + end -- "@;" + end + end --- LABEL: done1 + -- begin @= + p = q + --res = res .. " .." + if left_type(p)==given then + n_sin_cos(left_given(p)); res = res .. "{" + res = res .. print_scaled(n_cos); res = res .. ","; + res = res .. print_scaled(n_sin); res = res .. "}"; + else if left_type(p)==curl then + res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}"; + end; + end + -- end @= + -- end "@" + if p == h then done =true end + end + if left_type(h) ~= endpoint then + res = res .. "cycle" + end + -- do something with res -- + return res ,cycle +end +mflua.do_add_to._get_cycle = _get_cycle + + +-- @p procedure print_spec(@!s:str_number); +-- label not_found,done; +-- var @!p,@!q:pointer; {for list traversal} +-- @!octant:small_number; {the current octant code} +-- begin print_diagnostic("Cycle spec",s,true); +-- @.Cycle spec at line...@> +-- p:=cur_spec; octant:=left_octant(p); print_ln; +-- print_two_true(x_coord(cur_spec),y_coord(cur_spec)); +-- print(" % beginning in octant `"); +-- loop@+ begin print(octant_dir[octant]); print_char("'"); +-- loop@+ begin q:=link(p); +-- if right_type(p)=endpoint then goto not_found; +-- @; +-- p:=q; +-- end; +-- not_found: if q=cur_spec then goto done; +-- p:=q; octant:=left_octant(p); print_nl("% entering octant `"); +-- end; +-- @.entering the nth octant@> +-- done: print_nl(" & cycle"); end_diagnostic(true); +-- end; +local function _print_spec(cur_spec) + --print("\n.....Hello world from _print_spec!.....") + local p,q + local octant + --local res = '' + local knot = {} + local knots = {} + -- local res = {} + local endloop1 = false + local endloop2 = false + + p=cur_spec; octant=left_octant(p); --print() + -- res = res .. print_two_true(x_coord(cur_spec),y_coord(cur_spec),octant) + knot[#knot+1] = print_two_true(x_coord(cur_spec),y_coord(cur_spec),octant) + while (endloop1 == false) do + -- print('%%' .. octant_dir[octant]) + endloop2 = false + while (endloop2 == false) do + q = link(p) + if right_type(p)==endpoint then + endloop2 = true -- goto not_found; + else + -- print(' @;') + -- c1 + knot[#knot+1] = print_two_true(right_x(p),right_y(p),octant) + -- c2 + knot[#knot+1] = print_two_true(left_x(q),left_y(q),octant) + -- q + knot[#knot+1] = print_two_true(x_coord(q),y_coord(q),octant) + -- segment + knot[#knot+1] = print_int(left_type(q)-1) + knots[#knots+1] = knot + knot = {} + -- res = res .." ..controls " + -- res = res .. print_two_true(right_x(p),right_y(p),octant) + -- res = res .." and " + -- res = res ..print_two_true(left_x(q),left_y(q),octant) + -- res = res .. "\n .." + -- res = res .. print_two_true(x_coord(q),y_coord(q),octant) + -- res = res .." % segment " ..print_int(left_type(q)-1) .. "\n"; + p=q; + knot[#knot+1] = print_two_true(x_coord(p),y_coord(p),octant) + end + end -- endloop2 + -- not_found + if q == cur_spec then + endloop1 = true + else + p=q; octant=left_octant(p) -- print("% entering octant `"); + end + end -- endloop1 + --done: + -- print(" & cycle") ; end_diagnostic(true); + -- print("%BEZ TEST\ndraw "..res .. ";\n") + -- table.foreach(knots,function (k) table.foreach(knots[k],print) end) + return knots +end +mflua.do_add_to._print_spec = _print_spec + + +local function _store_current_envelope() + local bezier_octant_envelope = mflua.do_add_to.bezier_octant_envelope + local bezier_octant = mflua.do_add_to.bezier_octant + if (#bezier_octant_envelope == 0) then + local _t = {} + for i,v in ipairs(bezier_octant) do _t[i] = v end + bezier_octant_envelope[1] = _t + else + local _cnt=0 + for i,v in ipairs(bezier_octant_envelope) do _cnt=_cnt+#v end + local _t = {} + for i,v in ipairs(bezier_octant) do if i>_cnt then _t[#_t+1] = v end end + bezier_octant_envelope[#bezier_octant_envelope+1] = _t + end + mflua.do_add_to.bezier_octant_envelope = bezier_octant_envelope + return 0 +end +mflua.do_add_to._store_current_envelope = _store_current_envelope + + +local function _postprocessing() + local bezier_octant + local beziers,offsets + + local path_list + local prev_point + local path_cnt + local res = "%% postprocessing envelope\n" + local f + local chartable = mflua.chartable + local index + local char + + index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + --print("CHAR " .. index) + --print("%% postprocessing envelope "..index.. ' ' .. #chartable) + + res = res .. "path p[];\n" + + -- The last part of envelope added + bezier_octant = mflua.do_add_to.bezier_octant_envelope[#mflua.do_add_to.bezier_octant_envelope] + + path_cnt = 1 + for i,v in ipairs(bezier_octant) do + beziers = v + offsets = beziers['offsets'] + path_list = beziers['path_list'] + local offset_list = beziers['offset_list'] + for i,path in ipairs(path_list) do + local shifted + local p,c1,c2,q,offset = + path['p'],path['control1'],path['control2'],path['q'],path['offset'] + for i,v in ipairs(offset_list) do + if v[1] == (0+offset) then + shifted = v[2] + break + end + end + if (q == nil) then + res = res .. string.format("p%d:=(%s) shifted %s;%% shifted 1\n", + path_cnt,p,shifted) + else + res = res .. string.format("p%d:=(%s .. controls %s and %s .. %s) shifted %s;%% shifted 2\n", + path_cnt,p,c1,c2,q,shifted) + end + path_cnt = path_cnt +1 + end + end + res = res .. "%% path_cnt=" .. path_cnt .. " char_code=" .. print_int(MFbuiltin.char_code()) .. " char_ext=" .. print_int(MFbuiltin.char_ext()) + res = res .. " char_wd=" .. print_scaled(MFbuiltin.char_wd()) + res = res .. " char_ht=" .. print_scaled(MFbuiltin.char_ht()) + res = res .. " char_dp=" .. print_scaled(MFbuiltin.char_dp()) + res = res .. " char_ic=" .. print_scaled(MFbuiltin.char_ic()) + res = res .. " \n" + + res = res .. "drawoptions(withcolor (" .. math.random().."," .. math.random()..",".. math.random().. ") withpen pencircle scaled 0.4pt);\n" + res = res .. "draw p1" + for i=2,path_cnt-1 do + res = res .. string.format(" -- p%d",i) + end + res = res .. " --cycle;\n" + + index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + char = chartable[index] or {} + char['char_wd'] = print_scaled(MFbuiltin.char_wd()) + char['char_ht'] = print_scaled(MFbuiltin.char_ht()) + char['char_dp'] = print_scaled(MFbuiltin.char_dp()) + char['char_ic'] = print_scaled(MFbuiltin.char_ic()) + char['envelope'] = char['envelope'] or {} + char['envelope'][#char['envelope']+1] = bezier_octant + char['res'] = char['res'] or "" + char['res'] = char['res'] .. res + char['index'] = index + chartable[index] = char +end +mflua.do_add_to._postprocessing = _postprocessing + + +local function _store_current_contour() + local bezier_octant_contour = mflua.do_add_to.bezier_octant_contour + local bezier_octant_I = mflua.do_add_to.bezier_octant_I + if (#bezier_octant_contour == 0) then + local _t = {} + for i,v in ipairs(bezier_octant_I) do _t[i] = v end + bezier_octant_contour[1] = _t + else + local _cnt=0 + for i,v in ipairs(bezier_octant_contour) do _cnt=_cnt+#v end + local _t = {} + for i,v in ipairs(bezier_octant_I) do if i>_cnt then _t[#_t+1] = v end end + bezier_octant_contour[#bezier_octant_contour+1] = _t + end + mflua.do_add_to.bezier_octant_contour = bezier_octant_contour + return 0 +end +mflua.do_add_to._store_current_contour = _store_current_contour + + +local function _postprocessing_contour() + local bezier_octant_contour,contour,path_list + local chartable = mflua.chartable + local index + local char + local res = "" + index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + res = res .. "%% postprocessing contour for " .. index ..";\n" + res = res .. "path p[];\n" + print("CHAR " .. index) + bezier_octant_contour = mflua.do_add_to.bezier_octant_contour[#mflua.do_add_to.bezier_octant_contour] + + path_cnt = 1 + for i,v in ipairs(bezier_octant_contour) do + contour = v + path_list = contour['path_list'] + for i,path in ipairs(path_list) do + local p,c1,c2,q = path['p'],path['control1'],path['control2'],path['q'] + if (q == nil) then + res = res .. string.format("p%d:=(%s);\n", path_cnt,p) + else + res = res .. string.format("p%d:=(%s .. controls %s and %s .. %s);\n",path_cnt,p,c1,c2,q) + end + path_cnt = path_cnt +1 + end + end + if path_cnt > 1 then + res = res .. "drawoptions(withcolor black withpen pencircle scaled 0.3pt);\n" + res = res .. "draw p1" + for i=2,path_cnt-1 do + res = res .. string.format(" -- p%d",i) + end + res = res .. " --cycle ;\n" + end + + + index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + --print("BEZ index="..index) + char = chartable[index] or {} + char['char_wd'] = print_scaled(MFbuiltin.char_wd()) + char['char_ht'] = print_scaled(MFbuiltin.char_ht()) + char['char_dp'] = print_scaled(MFbuiltin.char_dp()) + char['char_ic'] = print_scaled(MFbuiltin.char_ic()) + char['contour'] = char['contour'] or {} + char['contour'][#char['contour']+1] = bezier_octant_contour + char['res'] = char['res'] or "" + char['res'] = char['res'] .. res + char['index'] = index + chartable[index] = char + return 0 +end +mflua.do_add_to._postprocessing_contour = _postprocessing_contour + +-- local function _circular_list_geti(l,i) +-- local size = #l +-- if size==0 then +-- return nil +-- end +-- return l[1+(i-1)%size] +-- end + + +local function _store_current_cycle(hs) + local res, current_cycle + res, current_cycle = mflua.do_add_to._get_cycle(hs) + --print( mflua_print_path(hs) ) + if res=='cycle' then + -- for i=0,(#current_cycle/3)-1 do + -- local l = current_cycle + -- local base = i*3 + -- local p,c1,c2,q = _circular_list_geti(l,base+1) , _circular_list_geti(l,base+2),_circular_list_geti(l,base+3),_circular_list_geti(l,base+4) + -- print (string.format("%d/%d (%f,%f) .. controls (%f,%f) and (%f,%f) .. (%f,%f) ",(i-1)%3,#current_cycle, + -- p[1],p[2],c1[1],c1[2],c2[1],c2[2],q[1],q[2])) + + -- end + local index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + local char = mflua.chartable[index] or {} + char['cycle'] = char['cycle'] or {} + char['cycle'][#char['cycle']+1] = current_cycle + + mflua.chartable[index] = char + else + print("Error:"..res) + end +end +mflua.do_add_to._store_current_cycle = _store_current_cycle + + +local function PRE_make_spec_rhs(rhs) + PRINTDBG("PRE_make_spec_rhs") + mflua.do_add_to._store_current_cycle(rhs) +end + +local function POST_make_spec_rhs(rhs) + PRINTDBG("POST_make_spec_rhs") + --print("post rhs MFbuiltin.turning_number=",MFbuiltin.turning_number() ) ; +end + + +local function PRE_make_spec_lhs(lhs) + PRINTDBG("PRE_make_spec_lhs") + mflua.do_add_to._store_current_cycle(lhs) +end + +local function POST_make_spec_lhs(lhs) + PRINTDBG("PRE_make_spec_lhs") + print("post lhs MFbuiltin.turning_number=",MFbuiltin.turning_number() ) ; +end + +local function PRE_fill_envelope_rhs(rhs) + PRINTDBG("PRE_fill_envelope_rhs") + local knots ,knots_list + local index,char + local chartable = mflua.chartable + knots = mflua.do_add_to._print_spec(rhs) + index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + char = chartable[index] or {} + knots_list = char['knots'] or {} + knots_list[#knots_list+1] = knots + char['knots'] = knots_list + chartable[index] = char +end + +local function POST_fill_envelope_rhs(rhs) + PRINTDBG("POST_fill_envelope_rhs") + mflua.do_add_to._store_current_envelope() + mflua.do_add_to._postprocessing() +end + +local function PRE_fill_envelope_lhs(lhs) + PRINTDBG("PRE_fill_envelope_lhs") +end + +local function POST_fill_envelope_lhs(lhs) + PRINTDBG("POST_fill_envelope_lhs") + mflua.do_add_to._store_current_envelope() + mflua.do_add_to._postprocessing() +end + +local function PRE_fill_spec_rhs(rhs) + PRINTDBG("PRE_fill_spec_rhs") + --print_specification_contour(rhs) +end + +local function POST_fill_spec_rhs(rhs) + PRINTDBG("POST_fill_spec_rhs") + mflua.do_add_to._store_current_contour() + mflua.do_add_to._postprocessing_contour() +end + +local function PRE_fill_spec_lhs(lhs) + PRINTDBG("PRE_fill_spec_lhs") + --print_specification_contour(lhs) +end + +local function POST_fill_spec_lhs(lhs) + PRINTDBG("POST_fill_spec_lhs") + mflua.do_add_to._store_current_contour() + mflua.do_add_to._postprocessing_contour() +end + + +-------------------------------------------------------------------------------- +-- +-- fill_spec +-- +-------------------------------------------------------------------------------- + +mflua.fill_spec = mflua.fill_spec or {} + +-- @ Here's a routine that prints a cycle spec in symbolic form, so that it +-- is possible to see what subdivision has been made. The point coordinates +-- are converted back from \MF's internal ``rotated'' form to the external +-- ``true'' form. The global variable~|cur_spec| should point to a knot just +-- after the beginning of an octant boundary, i.e., such that +-- |left_type(cur_spec)=endpoint|. +local function print_specification_contour(h) + local p,q,n,nh + local octant + local cur_spec + local res = "" + local f + local first_point, first_point_offset + local path_cnt + local bezier_contour,beziers_contour ={},{} + local offset_list = {} + local path_list ={} + local bezier_octant_I + cur_spec=h + p=cur_spec + octant = left_octant(p) + beziers_contour['octant_number'] = octant_number[octant] + first_point = print_two_true(x_coord(p),y_coord(p),octant) + first_point_offset = print_int(right_type(p)) + local end_loop_1 = false + while end_loop_1 == false do + local end_loop_2 = false + while end_loop_2 == false do + q=link(p); + if right_type(p)==endpoint then + end_loop_2=true + else + bezier_contour['p'] = print_two_true(x_coord(p),y_coord(p),octant); + bezier_contour['control1'] = print_two_true(right_x(p),right_y(p),octant) + bezier_contour['control2'] = print_two_true(left_x(q),left_y(q),octant) + bezier_contour['q'] = print_two_true(x_coord(q),y_coord(q),octant) + beziers_contour[#beziers_contour+1] = bezier_contour + bezier_contour = {} + p=q + end + end + -- not_found label + if q==cur_spec then + end_loop_1=true + else + p=q; octant=left_octant(p); -- print("% entering octant `"); + end + -- We don't want all the octans of the cycle + -- only the pieces of the current octant + end_loop_1 = not(MFbuiltin.octant() == octant) + end + -- done label: + -- We can now use the results + -- No curves stored + if #beziers_contour == 0 then + beziers_contour['single_point'] = first_point + end + beziers_contour['path_list'] = {} + if #beziers_contour == 0 then + path_list['p'] = beziers_contour['single_point'] + beziers_contour['path_list'][#beziers_contour['path_list']+1] = path_list + path_list={} + else + for i,v in ipairs(beziers_contour) do + bezier_contour = v + path_list['p'] = bezier_contour['p'] + path_list['control1'] = bezier_contour['control1'] + path_list['control2'] = bezier_contour['control2'] + path_list['q'] = bezier_contour['q'] + beziers_contour['path_list'][#beziers_contour['path_list']+1] = path_list + path_list={} + end + end + bezier_octant_I =mflua.do_add_to.bezier_octant_I + bezier_octant_I[#bezier_octant_I+1] = beziers_contour + return 0 +end +mflua.MF.print_specification_contour = print_specification_contour + + +local function PRE_move_to_edges(p) + PRINTDBG("PRE_move_to_edges") + mflua.MF.print_specification_contour(p) +end + + +local function POST_move_to_edges(p) + PRINTDBG("POST_move_to_edges") +end + + +-- +-- scan_direction +-- + +mflua.scan_direction = mflua.scan_direction or {} + +local function _print_path(h,s,nuline) + local p,q + local res + local done + local done1 + local f + done = false + done1 = false + p = h + res = '' + while not done do + q = link(p) + if (p==0) or (q==0) then + res = "???" + -- do something with res -- + return 0 + end + res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res) + if right_type(p) == endpoint then + if left_type(p)== open then print("{open?}") end -- {can't happen} + if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error} + done1 = true -- goto done1; + elseif right_type(p) == explicit then + -- begin "@" + res = res .. "..controls " .. print_two(right_x(p),right_y(p)) .. " and "; + if left_type(q) ~= explicit then print("??") -- {can't happen} + else res = res .. print_two(left_x(q),left_y(q)); + done1 = true -- goto done1; + end + -- end "@" + elseif right_type(p) == open then + -- begin "@" + if (left_type(p) ~= explicit) and (left_type(p)~=open) then + res = res .. "{open?}" -- {can't happen} + end + -- end "@" + elseif (right_type(p) == curl) or (right_type(p) == given) then + -- @ A curl of 1 is shown explicitly, so that the user sees clearly that + -- \MF's default curl is present. + -- begin @= + if left_type(p)==open then res = res .. "??" end -- {can't happen} + if right_type(p)==curl then + res = res .. "{curl ".. print_scaled(right_curl(p)) + else n_sin_cos(right_given(p)); res = res .."{" + res = res .. print_scaled(n_cos) .. "," .. print_scaled(n_sin) + end + res = res .."}" + -- end @= + else res = res .. "???" -- {can't happen} + end + if not done1 then -- mimic label done 1 + if left_type(q)~=explicit then res = res .. "..control?" -- {can't happen} + else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then + -- begin "@;" + res = res .. "..tension " + if right_tension(p)<0 then res = res .. "atleast" end + res = res .. print_scaled(math.abs(right_tension(p))) + if right_tension(p) ~= left_tension(q) then + res = res .. " and " + if left_tension(q)<0 then res = res .. "atleast" end + res = res .. print_scaled(math.abs(left_tension(q))) + end + end -- "@;" + end + end --- LABEL: done1 + -- begin @= + p = q + res = res .. " .." + if left_type(p)==given then + n_sin_cos(left_given(p)); res = res .. "{" + res = res .. print_scaled(n_cos); res = res .. ","; + res = res .. print_scaled(n_sin); res = res .. "}"; + else if left_type(p)==curl then + res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}"; + end; + end + -- end @= + -- end "@" + if p == h then done =true end + end + if left_type(h) ~= endpoint then + res = res .. "cycle" + else + res = res + end + -- do something with res -- + return res + --res = "drawoptions(withcolor black withpen pencircle scaled 1pt);\n" .. "draw " .. res .. " ;\n" + --print(res) + -- local index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + -- local char = mflua.chartable[index] or {} + -- char['char_wd'] = print_scaled(MFbuiltin.char_wd()) + -- char['char_ht'] = print_scaled(MFbuiltin.char_ht()) + -- char['char_dp'] = print_scaled(MFbuiltin.char_dp()) + -- char['char_ic'] = print_scaled(MFbuiltin.char_ic()) + -- char['res'] = char['res'] or "" + -- char['res'] = char['res'] .. res + -- mflua.chartable[index] = char + -- return 0 +end +mflua.scan_direction.print_path = _print_path + +local function PRE_make_choices(p) + PRINTDBG("PRE_make_choices") + -- _print_path(p,"PRE make choice",false) +end + +local function POST_make_choices(p) + PRINTDBG("POST_make_choices") + --local res = '' + --res = _print_path(p,"POST make choice",false) + --print(res) +end + +local function print_retrograde_line(x0,y0,cur_x,cur_y) + PRINTDBG("print_retrograde_line") + local chartable = mflua.chartable + local index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + local char = chartable[index] or {} + local tab = char['retrograde_line'] or {} + tab[#tab+1] = {print_two(x0,y0),print_two(cur_x,cur_y)} + char['retrograde_line'] = tab + --print("%%Retrograde line") + --print("drawoptions(withcolor (0,0.6,0) withpen pencircle scaled 0.09pt);") + --print("draw ".. print_two(x0,y0) .. " -- " .. print_two(cur_x,cur_y) ..";") +end + + +local function PRE_make_ellipse(major_axis,minor_axis,theta,tx,ty,q) + PRINTDBG("PRE_make_ellipse") + --print("major_axis,minor_axis,theta,tx,ty,q=",major_axis,minor_axis,theta,tx,ty,q) +end + +local function POST_make_ellipse(major_axis,minor_axis,theta,tx,ty,q) + PRINTDBG("POST_make_ellipse") + --print("major_axis,minor_axis,theta,tx,ty,q=",print_two(major_axis,minor_axis),theta*(2^-20),print_two(tx,ty),print_two(x_coord(q),y_coord(q))) + local flag=true + local p=q + local res = '' + local xy + local i = 0 + while flag do + i=i+1 + res = res ..print_two(x_coord(p),y_coord(p)) + p=link(p) + if p==q then flag=false end + end + mflua.pen[res] = {print_two(major_axis,minor_axis), + theta*(2^-20),print_two(tx,ty)} + +end + + + +local function print_transition_line_from(x,y) + PRINTDBG("print_transition_line_from") + local octant = MFbuiltin.octant() + --local res = "" + local index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + local chartable = mflua.chartable + local char = chartable[index] or {} + local p = print_two_true(x,y,octant) + local c1 = p + char['transition_lines'] = char['transition_lines'] or {} + char['transition_lines'][#char['transition_lines']+1]={p,p} + return 0 +end + + +local function print_transition_line_to(x,y) + PRINTDBG("print_transition_line_to") + local octant = MFbuiltin.octant() + local index = (0+print_int(MFbuiltin.char_code())) + (0+print_int(MFbuiltin.char_ext()))*256 + local chartable = mflua.chartable + local char = chartable[index] or {} + local q = print_two_true(x,y,octant) + local c2 = q + char['transition_lines_set'] = char['transition_lines_set'] or {} + char['transition_lines'] = char['transition_lines'] or {} + local _t = char['transition_lines'][#char['transition_lines']] + local p = _t[1] + -- + -- avoid multiple lines + -- + --print("BEZ char['transition_lines_set'][p..q]=",char['transition_lines_set'][p..q]) + if char['transition_lines_set'][p..q]==true or char['transition_lines_set'][q..p]==true then + char['transition_lines'][#char['transition_lines']]=nil + return 0 + end + char['transition_lines_set'][p..q]=true + char['transition_lines_set'][q..p]=true + -- + -- remove curves that degenerate into points + -- + if p~=q then + _t[#_t+1] = c2 + _t[#_t+1] = q + _t[#_t+1] = '(0,0)' + _t[#_t+1] = 'transition_line' + else + char['transition_lines'][#char['transition_lines']]=nil + end + return 0 +end + + +local function end_program() + PRINTDBG("end_program") + local f = kpse.find_file('end_program.lua', 'lua') + if f==nil then + print("Warning: end_program.lua not found") + return + end + local func,errmsg = loadfile(f) + if not(func) then + print(errmsg) + os.exit(1) + end + status, msg = pcall(func) + if not(status) then + print(msg) + os.exit(status) + end +end + + +-- +-- Add local function to mflua +-- + +mflua.begin_program = begin_program +mflua.PRE_start_of_MF = PRE_start_of_MF +mflua.PRE_main_control = PRE_main_control +mflua.POST_main_control = POST_main_control +mflua.mflua_initialize = mflua_initialize +mflua.POST_final_cleanup = POST_final_cleanup +mflua.printpath = printpath +mflua.printedges = printedges +mflua.PRE_offset_prep = PRE_offset_prep +mflua.POST_offset_prep = POST_offset_prep + +mflua.PRE_make_spec_rhs = PRE_make_spec_rhs +mflua.POST_make_spec_rhs = POST_make_spec_rhs +mflua.PRE_make_spec_lhs = PRE_make_spec_lhs +mflua.POST_make_spec_lhs = POST_make_spec_lhs +mflua.PRE_fill_envelope_rhs = PRE_fill_envelope_rhs +mflua.POST_fill_envelope_rhs = POST_fill_envelope_rhs +mflua.PRE_fill_envelope_lhs = PRE_fill_envelope_lhs +mflua.POST_fill_envelope_lhs = POST_fill_envelope_lhs +mflua.PRE_fill_spec_rhs = PRE_fill_spec_rhs +mflua.POST_fill_spec_rhs = POST_fill_spec_rhs +mflua.PRE_fill_spec_lhs = PRE_fill_spec_lhs +mflua.POST_fill_spec_lhs = POST_fill_spec_lhs + +mflua.PRE_move_to_edges = PRE_move_to_edges +mflua.POST_move_to_edges = POST_move_to_edges + +mflua.PRE_make_choices = PRE_make_choices +mflua.POST_make_choices = POST_make_choices + +mflua.print_retrograde_line = print_retrograde_line + +mflua.PRE_make_ellipse = PRE_make_ellipse +mflua.POST_make_ellipse = POST_make_ellipse + +mflua.print_transition_line_from = print_transition_line_from +mflua.print_transition_line_to = print_transition_line_to + +mflua.end_program = end_program + + +-------------------------------------------------------------------------------- +-- +-- Other setups, mostly depend on old routines +-- +-------------------------------------------------------------------------------- + +mflua.max_recursion_level = 32 + + + +mflua.bit = 7 -- should be 4 +mflua.pen = {} -- collect bezier curves of the pens + +mflua.pi = 2*math.atan2(1,0) +mflua.print_specification = mflua.print_specification or {} +mflua.print_specification.temp1 = 0 +mflua.print_specification.p = "" +mflua.print_specification.q = "" +mflua.threshold_path_removed = 4 -- how many path we can safely remove +mflua.threshold_extra_step = 2 -- add values/mflua.threshold_extra_step time values +mflua.threshold_small_path_check_point = 3 -- check 3 pixels for horiz/vert. paths +mflua.threshold_small_pen_path = 0.001 -- _fix_wrong_pending_path +mflua.threshold_fix = 1 -- _fix_wrong_pending_path +mflua.threshold = 1 -- _remove_small_path +mflua.threshold_degree = 2 -- _remove_small_path +mflua.threshold_degree_1 = 90 -- _remove_small_path +mflua.threshold_degree_2 = 270 -- _remove_small_path +mflua.threshold_small_curve = 2 -- _remove_reduntant_curves +mflua.threshold_normal_curve = 4 -- _remove_reduntant_curves +mflua.threshold_min_dist = 0.5 -- _remove_reduntant_curves +mflua.threshold_pending_path = 0.002 -- _remove_reduntant_curves +mflua.threshold_pen = 5 -- _remove_redundant_segments +mflua.threshold_bug = 4 -- _fix_intersection_bug +mflua.threshold_min_bug = 0.03 -- _fix_intersection_bug +mflua.threshold_equal_path=0.03 -- _remove_duplicate_pen_path +mflua.threshold_straight_line = 0.125 -- _is_a_straight_line +mflua.threshold_fix_knots = 0.125 -- _fix_knots +mflua.threshold_fix_knots_1 = 0.0005 -- _fix_knots +mflua.threshold_fix_knots_2 = 0.4 -- _fix_knots +mflua.threshold_remove_redundant_pen = 0.02 -- remove_redundant_pen +mflua.threshold_remove_redundant_curves = 3 -- _remove_redundant_curves +mflua.threshold_merge_segments = 5e-5 -- _merge_segments +mflua.threshold_join_curves = 0.049 -- _build_cycles try and error +mflua.set_poly_done={} +mflua.mflua_exe = 'mflua' +mflua.turningnumber_file='mflua_tn' +mflua.fill_envelope = {} +mflua.fill_envelope.temp_transition = "" +mflua.pen = {} + + + +-- + +mflua.chartable ={} +mflua.max_curves =1e4 + + +function mflua.lock(params) + if params ==nil then + return io.open('LOCK1','w') + else + return io.open(tostring(params),'w') + end +end + +function mflua.unlock(params) + if params == nil then + return os.remove('LOCK1') + else + return os.remove(tostring(params)) + end +end + +function mflua.checklock(params) + if params == nil then + if io.open("LOCK1") ~= nil then return true else return false end + else + if io.open(tostring(params)) ~= nil then return true else return false end + end +end + + +function mflua.dot(P1,P2) + return P1[1]*P2[1]+P1[2]*P2[2] +end + +function mflua.angle(p,q) + local dot = mflua.dot + if math.abs(1 - dot(p,q)/(math.sqrt(dot(p,p))*math.sqrt(dot(q,q)))) <0.0001 then + return 0 + else + return math.acos(dot(p,q)/(math.sqrt(dot(p,p))*math.sqrt(dot(q,q)))) + end +end +-- function mflua.vec(a,w,b1) if b1 == nil then b=w else b = b1 end ; return {b[1]-a[1],b[2]-a[2]} end +-- mflua.vec(a,b) == mflua.vec(a,'->',b) +function mflua.round(p) + local w=string.gmatch(p,"[-0-9.]+"); + local p p={w(),w()}; + return string.format("(%6.5f,%6.5f)",tostring(p[1]),tostring(p[2]) ) +end + +function mflua.round5(p) + local w=string.gmatch(p,"[-0-9.]+"); + local p; p={w(),w()}; + return string.format("(%6.5f,%6.5f)",tostring(p[1]),tostring(p[2]) ) +end + +function mflua.round2(p) + local w=string.gmatch(p,"[-0-9.]+"); + local p; p={w(),w()}; + return string.format("(%6.2f,%6.2f)",tostring(p[1]),tostring(p[2]) ) +end + +function mflua.round1(p) + local w=string.gmatch(p,"[-0-9.]+"); + local p; p={w(),w()}; + return string.format("(%6.1f,%6.1f)",tostring(p[1]),tostring(p[2]) ) +end + +function mflua.round0(p) + local w=string.gmatch(p,"[-0-9.]+"); + local p; p={w(),w()}; + return string.format("(%6.0f,%6.0f)",tostring(p[1]),tostring(p[2]) ) +end + +function mflua.floor(p) + local w=string.gmatch(p,"[-0-9.]+"); + local p; p={w(),w()}; + return string.format("(%d,%d)",math.floor(p[1]),math.floor(p[2]) ) +end + +function mflua.round5_table(p) + return {tonumber(string.format("%6.5f",tostring(p[1]))),tonumber(string.format("%6.5f",tostring(p[2])))} +end + +function mflua.number_to_string_round5(p) + return string.format("(%6.5f,%6.5f)",p[1],p[2]) +end + + +function mflua.vec(a,b) + return {b[1]-a[1],b[2]-a[2]} +end + +function mflua.modul_vec(a,b) + local dot = mflua.dot + local P ={b[1]-a[1],b[2]-a[2]} + return math.sqrt(dot(P,P)) +end + +function mflua.approx_curve_lenght(p,c1,c2,q) + return mflua.modul_vec(p,c1) + mflua.modul_vec(c1,c2) + mflua.modul_vec(c2,q) + mflua.modul_vec(p,q) +end + + +-- to permit multiple instances of mflua +if io.open('LOCK1')==nil and io.open('LOCK_ELLIPSE')==nil then + mflua.print_specification.filename = "envelope.tex" + mflua.print_specification.outfile1 = io.open(mflua.print_specification.filename,'w') +end + + + + + +-------------------------------------------------------------------------------- +-- +-- tfm module +-- +-------------------------------------------------------------------------------- +local tfm = {} +tfm.bits = + function(a,l) + local bita = {} + local a = a + for k=1,l do + local r=math.fmod(a,2) + a=math.floor(a/2) + bita[k]=r + end + return bita + end +tfm.bitand = + function(a,b,l) + local bita,bitb,bitc = tfm.bits(a,l), tfm.bits(b,l),{} + local c= 0 + for k=1,l do + bit1,bit2 = bita[k],bitb[k] + if (bit1==1) and (bit2==1) then + bitc[k]=1 + else + bitc[k]=0 + end + c = c+2^(k-1)*bitc[k] + end + return c,bitc + end +tfm.bitor = + function(a,b,l) + local bita,bitb,bitc = tfm.bits(a,l), tfm.bits(b,l),{} + local c= 0 + for k=1,l do + bit1,bit2 = bita[k],bitb[k] + if (bit1==1) or (bit2==1) then + bitc[k]=1 + else + bitc[k]=0 + end + c = c+ 2^(k-1)*bitc[k] + end + return c,bitc + end +tfm.bitnot = + function(a,l) + local bita,bitb = tfm.bits(a,l),{} + local b= 0 + for k=1,l do + bit1 = bita[k] + if (bit1==1) then + bitb[k]=0 + else + bitb[k]=1 + end + b = b+ 2^(k-1)*bitb[k] + end + return b,bitb + end +tfm.printbits= + function(t,l) + local r = '' + local l = l or #t + if l==0 then return '' end + for k=l,1,-1 do + local v = t[k] or '0' + r=r..v + end + return r + end + +tfm.stop_flag = 128 +tfm.kern_flag = 128 + +tfm.parameters = {} +tfm.parameters.init = + function() + -- 8. The first 24 bytes (6 words) of a TFM file contain twelve 16-bit integers that give the lengths of the + -- various subsequent portions of the file. These twelve integers are, in order: + -- lf = length of the entire file, in words; + -- lh = length of the header data, in words; + -- bc = smallest character code in the font; + -- ec = largest character code in the font; + -- nw = number of words in the width table; + -- nh = number of words in the height table; + -- nd = number of words in the depth table; + -- ni = number of words in the italic correction table; + -- nl = number of words in the lig/kern table; + -- nk = number of words in the kern table; + -- ne = number of words in the extensible character table; + -- np = number of font parameter words. + -- They are all nonnegative and less than 2^15 . We must have bc - 1<= ec <= 255, ne<= 256, and + -- lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np . + -- When two or more 8-bit bytes are combined to form an integer of 16 or more bits, the most + -- significant bytes appear first in the file. This is called BigEndian order. + + if tfm.content ==nil or type(tfm.content)~= 'string' then + return false, 'Error on file content' + end + tfm.parameters.w = string.gmatch(tfm.content,"[%z%Z]") + local w = tfm.parameters.w + local W1,W2 + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (lf)' end + tfm.parameters.lf = 256*string.byte(W1)+string.byte(W2) -- length of the entire file, in words; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (lh)' end + tfm.parameters.lh = 256*string.byte(W1)+string.byte(W2) -- length of the header data, in words; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (bc)' end + tfm.parameters.bc = 256*string.byte(W1)+string.byte(W2) -- smallest character code in the font; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (ec)' end + tfm.parameters.ec = 256*string.byte(W1)+string.byte(W2) -- largest character code in the font; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nw)' end + tfm.parameters.nw = 256*string.byte(W1)+string.byte(W2) -- number of words in the width table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nh)' end + tfm.parameters.nh = 256*string.byte(W1)+string.byte(W2) -- number of words in the height table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nd)' end + tfm.parameters.nd = 256*string.byte(W1)+string.byte(W2) -- number of words in the depth table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (ni)' end + tfm.parameters.ni = 256*string.byte(W1)+string.byte(W2) -- number of words in the italic correction table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nl)' end + tfm.parameters.nl = 256*string.byte(W1)+string.byte(W2) -- number of words in the lig/kern table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nk)' end + tfm.parameters.nk = 256*string.byte(W1)+string.byte(W2) -- number of words in the kern table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (ne)' end + tfm.parameters.ne = 256*string.byte(W1)+string.byte(W2) -- number of words in the extensible character table; + + W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (np)' end + tfm.parameters.np = 256*string.byte(W1)+string.byte(W2) -- number of font parameter words. + return + end + +tfm.parameters.check = + function() + local w = tfm.parameters.w + local lf = tfm.parameters.lf + local lh = tfm.parameters.lh + local bc = tfm.parameters.bc + local ec = tfm.parameters.ec + local nw = tfm.parameters.nw + local nh = tfm.parameters.nh + local nd = tfm.parameters.nd + local ni = tfm.parameters.ni + local nl = tfm.parameters.nl + local nk = tfm.parameters.nk + local ne = tfm.parameters.ne + local np = tfm.parameters.np + local status = true + local status_cnt = 0 + local status_msg = 'OK' + local function _assert(cond,msg) + if cond==false then + --print(msg) + status_msg = msg + status_cnt = status_cnt +1 + end + end + if status_cnt == 0 then _assert(lf == 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ,"Error on lf") end + if status_cnt == 0 then _assert(0<=lf and lf <2^15,"lf out of range") end + if status_cnt == 0 then _assert(0<=lh and lh <2^15,"lh out of range") end + if status_cnt == 0 then _assert(0<=bc and bc <2^15,"bc out of range") end + if status_cnt == 0 then _assert(0<=ec and ec <2^15,"ec out of range") end + if status_cnt == 0 then _assert(0<=nw and nw <2^15,"nw out of range") end + if status_cnt == 0 then _assert(0<=nh and nh <2^15,"nh out of range") end + if status_cnt == 0 then _assert(0<=nd and nd <2^15,"nd out of range") end + if status_cnt == 0 then _assert(0<=ni and ni <2^15,"ni out of range") end + if status_cnt == 0 then _assert(0<=nl and nl <2^15,"nl out of range") end + if status_cnt == 0 then _assert(0<=nk and nk <2^15,"nk out of range") end + if status_cnt == 0 then _assert(0<=ne and ne <2^15,"ne out of range") end + if status_cnt == 0 then _assert(0<=np and np <2^15,"np out of range") end + if status_cnt == 0 then _assert( (bc-1)<=ec and ec<= 255, "Error on bc and ec") end + if status_cnt == 0 then _assert(ne<= 256, "ne >256") end + if status_cnt > 0 then status=false end + return status,status_msg + end + + +tfm.int_to_frac = + function(d) + if not (0<=d and d<2^32) then + return nil, string.format("Error: %s out of range (-%s,%s-2^-20)",d,2^31,2^31) + else + if d<=2147483647 then + return d/2^20,'ok' + else + return (d-2^32)/2^20,'ok' + end + end + + end +tfm.tag_meaning = + function(d) + local t = {'vanilla character','character has a ligature/kerning program', + 'character has a successor in a charlist','character is extensible'} + local d = tonumber(d) or -1 + if d<0 or d>3 then return '' end + return t[tonumber(d+1)] + end + +tfm.getface = + function(d) + --If the value is less than 18, it has the following + --interpretation as a "weight, slope, and expansion": Add 0 or 2 or 4 (for medium or bold or light) to + --0 or 1 (for roman or italic) to 0 or 6 or 12 (for regular or condensed or extended). For example, 13 is + --0+1+12, so it represents medium italic extended. A three-letter code (e.g., MIE) can be used for such + --face data. + -- d = 3⋅rce_bit⋅2^{2,1} + ri_bit + mbl_bit⋅2^{2,1} , rce_bit,ri_bit,mbl_bit ∈ {0,1} + -- d%2 = ri_bit := ri + -- d%3 - d%2 = mbl⋅2^{2,1} := mbl + -- d - d%3 = 3⋅rce⋅2^{2,1} := rce + if d>17 then return '' end + local mbl,ri, rce = '*','*','*' + local _ri = d % 2 + if _ri==0 then ri ='R' else ri ='I' end + local _mbl = (d%3) -(d%2) + if _mbl == 0 then mbl='M' end + if _mbl == 2 then mbl='B' end + if _mbl == 4 then mbl='E' end + local _rce = d - (d%3) + if _rce == 0 then rce = 'M' end + if _rce == 1 then rce = 'I' end + if _rce == 12 then rce = 'E' end + return mbl..ri..rce, {_mbl,_ri,_rce} + end + +tfm.printfloat = + function(d,p) + local d,p = tostring(d), tonumber(p) or 6 + local f = string.format("%%.%df",p) + return string.format(f,d) + end + +tfm.array = {} +tfm.array.check = + function() + local width = tfm.array.width + local height = tfm.array.height + local depth = tfm.array.depth + local italic = tfm.array.italic + local status = true + local status_cnt = 0 + local status_msg = 'OK' + local function _assert(cond,msg) + if cond==false then + --print(msg) + status_msg = msg + status_cnt = status_cnt +1 + end + end + _assert(width[0]==0,'Error in width[0]') + _assert(height[0]==0,'Error in height[0]') + _assert(depth[0]==0,'Error in depth[0]') + _assert(italic[0]==0,'Error in italic[0]') + if status_cnt > 0 then status=false end + return status,status_msg + + end + +tfm.dump={} +tfm.dump.kernprogram = + function(d,c) + local char_info = tfm.array.char_info + local lig_kern = tfm.array.lig_kern + local kern = tfm.array.kern + local current_step = d + local current_char = c + local skip_byte=lig_kern[current_step][1] + local next_char=lig_kern[current_step][2] + local op_byte=lig_kern[current_step][3] + local remainder=lig_kern[current_step][4] + local _print = tfm.printdebug() + _print("-------") + _print("skip_byte=",skip_byte) + _print("next_char=",next_char,'C '..string.char(next_char),'O '..string.format("%o",next_char)) + _print("op_byte=",op_byte) + _print("remainder=",remainder,string.format("O %o",remainder)) + if op_byte + + + cubic Bézier commands in path data + B char + + + + %s + + + ]=], + ['emsize']= 1000, + ['filename']= 'SourceCode', + ['font'] = [=[ + + + + +Created by FontForge 20110222 at Sun Sep 18 10:37:34 2011 + By root +Copyleft 2002, 2003, 2005 Free Software Foundation. + + + + + + + %s + + +]=], +['glyph'] = + [==[%s + +]==], +['hkern'] = [==[]==], +['vkern'] = [==[]==], +['hkerns']='', +['vkerns']='', +['char']={ + ['0']={glyph_name='uni0393',unicode='Γ'}, -- U+0393 GREEK CAPITAL LETTER GAMMA + ['1']={glyph_name='uni0394',unicode='Δ'}, --U+0394 GREEK CAPITAL LETTER DELTA + ['2']={glyph_name='uni0398',unicode='Θ'}, -- U+0398 GREEK CAPITAL LETTER THETA + ['3']={glyph_name='uni039b',unicode='Λ'}, -- U+039B GREEK CAPITAL LETTER LAMBDA + ['4']={glyph_name='uni039e',unicode='Ξ'}, --U+039E GREEK CAPITAL LETTER XI + ['5']={glyph_name='uni03a0',unicode='Π'}, --U+03A0 GREEK CAPITAL LETTER PI + ['6']={glyph_name='uni03a3',unicode='Σ'}, -- U+03A3 GREEK CAPITAL LETTER SIGMA + ['7']={glyph_name='uni03a5',unicode='Υ'}, --U+03A5 GREEK CAPITAL LETTER UPSILON + ['8']={glyph_name='uni03a6',unicode='Φ'}, -- U+03A6 GREEK CAPITAL LETTER PHI + ['9']={glyph_name='uni03a8',unicode='Ψ'}, -- U+03A8 GREEK CAPITAL LETTER PSI + ['10']={glyph_name='uni03a9',unicode='Ω'}, -- U+03A9 GREEK CAPITAL LETTER OMEGA + ['11']={glyph_name='unifb00',unicode='ff'}, -- U+FB00 LATIN SMALL LIGATURE FF + ['12']={glyph_name='unifb01',unicode='fi'}, --U+FB01 LATIN SMALL LIGATURE FI + ['13']={glyph_name='unifb02',unicode='fl'}, -- U+FB02 LATIN SMALL LIGATURE FL + ['14']={glyph_name='unifb03',unicode='ffi'}, --U+FB03 LATIN SMALL LIGATURE FFI + ['15']={glyph_name='unifb04',unicode='ffl'}, -- U+FB04 LATIN SMALL LIGATURE FFL + ['16']={glyph_name='uni0131',unicode='ı'}, -- U+0131 LATIN SMALL LETTER DOTLESS I + ['17']={glyph_name='uni0237',unicode='ȷ'}, -- U+0237 LATIN SMALL LETTER DOTLESS J + ['18']={glyph_name='uni0060',unicode='`'}, -- U+0060 GRAVE ACCENT + ['19']={glyph_name='uni00b4',unicode='´'}, -- U+00B4 ACUTE ACCENT + ['20']={glyph_name='uni02c7',unicode='ˇ'}, -- U+02C7 CARON + ['21']={glyph_name='uni02d8',unicode='˘'}, -- U+02D8 BREVE + ['22']={glyph_name='uni00af',unicode='¯'}, -- U+00AF MACRON + ['23']={glyph_name='uni02da',unicode='˚'}, -- U+02DA RING ABOVE + ['24']={glyph_name='uni00b8',unicode='¸'}, -- U+00B8 CEDILLA + ['25']={glyph_name='uni00df',unicode='ß'}, -- U+00DF LATIN SMALL LETTER SHARP S + ['26']={glyph_name='uni00e6',unicode='æ'}, -- U+00E6 LATIN SMALL LETTER AE + ['27']={glyph_name='uni0153',unicode='œ'}, -- U+0153 LATIN SMALL LIGATURE OE + ['28']={glyph_name='uni00f8',unicode='ø'}, -- U+00F8 LATIN SMALL LETTER O WITH STROKE + ['29']={glyph_name='uni00c6',unicode='Æ'}, --U+00C6 LATIN CAPITAL LETTER AE + ['30']={glyph_name='uni0152',unicode='Œ'}, --U+0152 LATIN CAPITAL LIGATURE OE + ['31']={glyph_name='uni00D8',unicode='Ø'}, --U+00D8 LATIN CAPITAL LETTER O WITH STROKE + ['32']={glyph_name='uni0337',unicode='̷'}, --U+0337 COMBINING SHORT SOLIDUS OVERLAY + ['33']={glyph_name='uni0021',unicode='!'}, + ['34']={glyph_name='uni201d',unicode='”'}, -- U+201D RIGHT DOUBLE QUOTATION MARK + ['35']={glyph_name='uni0023',unicode='#'}, + ['36']={glyph_name='uni0024',unicode='$'}, + ['37']={glyph_name='uni0025',unicode='%'}, + ['38']={glyph_name='uni0026',unicode='&'}, + ['39']={glyph_name='uni0027',unicode='''}, + ['40']={glyph_name='uni0028',unicode='('}, + ['41']={glyph_name='uni0029',unicode=')'}, + ['42']={glyph_name='uni002a',unicode='*'}, + ['43']={glyph_name='uni002b',unicode='+'}, + ['44']={glyph_name='uni002c',unicode=','}, + ['45']={glyph_name='uni002d',unicode='-'}, -- U+002D HYPHEN-MINUS + ['46']={glyph_name='uni002e',unicode='.'}, + ['47']={glyph_name='uni002f',unicode='/'}, + ['48']={glyph_name='uni0030',unicode='0'}, + ['49']={glyph_name='uni0031',unicode='1'}, + ['50']={glyph_name='uni0032',unicode='2'}, + ['51']={glyph_name='uni0033',unicode='3'}, + ['52']={glyph_name='uni0034',unicode='4'}, + ['53']={glyph_name='uni0035',unicode='5'}, + ['54']={glyph_name='uni0036',unicode='6'}, + ['55']={glyph_name='uni0037',unicode='7'}, + ['56']={glyph_name='uni0038',unicode='8'}, + ['57']={glyph_name='uni0039',unicode='9'}, + ['58']={glyph_name='uni003a',unicode=':'}, + ['59']={glyph_name='uni003b',unicode=';'}, + ['60']={glyph_name='uni00a1',unicode='¡'}, -- U+00A1 INVERTED EXCLAMATION MARK, but only if ligs>1 + ['61']={glyph_name='uni003d',unicode='='}, + ['62']={glyph_name='uni00bf',unicode='¿'}, --U+00BF INVERTED QUESTION MARK + ['63']={glyph_name='uni003f',unicode='?'}, + ['64']={glyph_name='uni0040',unicode='@'}, + ['65']={glyph_name='uni0041',unicode='A'}, + ['66']={glyph_name='uni0042',unicode='B'}, + ['67']={glyph_name='uni0043',unicode='C'}, + ['68']={glyph_name='uni0044',unicode='D'}, + ['69']={glyph_name='uni0045',unicode='E'}, + ['70']={glyph_name='uni0046',unicode='F'}, + ['71']={glyph_name='uni0047',unicode='G'}, + ['72']={glyph_name='uni0048',unicode='H'}, + ['73']={glyph_name='uni0049',unicode='I'}, + ['74']={glyph_name='uni004a',unicode='J'}, + ['75']={glyph_name='uni004b',unicode='K'}, + ['76']={glyph_name='uni004c',unicode='L'}, + ['77']={glyph_name='uni004d',unicode='M'}, + ['78']={glyph_name='uni004e',unicode='N'}, + ['79']={glyph_name='uni004f',unicode='O'}, + ['80']={glyph_name='uni0050',unicode='P'}, + ['81']={glyph_name='uni0051',unicode='Q'}, + ['82']={glyph_name='uni0052',unicode='R'}, + ['83']={glyph_name='uni0053',unicode='S'}, + ['84']={glyph_name='uni0054',unicode='T'}, + ['85']={glyph_name='uni0055',unicode='U'}, + ['86']={glyph_name='uni0056',unicode='V'}, + ['87']={glyph_name='uni0057',unicode='W'}, + ['88']={glyph_name='uni0058',unicode='X'}, + ['89']={glyph_name='uni0059',unicode='Y'}, + ['90']={glyph_name='uni005a',unicode='Z'}, + ['91']={glyph_name='uni005b',unicode='['}, + ['92']={glyph_name='uni201c',unicode='“'}, -- U+201C LEFT DOUBLE QUOTATION MARK + ['93']={glyph_name='uni005d',unicode=']'}, + ['94']={glyph_name='uni0302',unicode='̂'}, --U+0302 COMBINING CIRCUMFLEX ACCENT + ['95']={glyph_name='uni0307',unicode='̇'}, --U+0307 COMBINING DOT ABOVE + ['96']={glyph_name='uni2018',unicode='‘'}, --U+2018 LEFT SINGLE QUOTATION MARK + ['97']={glyph_name='uni0061',unicode='a'}, + ['98']={glyph_name='uni0062',unicode='b'}, + ['99']={glyph_name='uni0063',unicode='c'}, + ['100']={glyph_name='uni0064',unicode='d'}, + ['101']={glyph_name='uni0065',unicode='e'}, + ['102']={glyph_name='uni0066',unicode='f'}, + ['103']={glyph_name='uni0067',unicode='g'}, + ['104']={glyph_name='uni0068',unicode='h'}, + ['105']={glyph_name='uni0069',unicode='i'}, + ['106']={glyph_name='uni006a',unicode='j'}, + ['107']={glyph_name='uni006b',unicode='k'}, + ['108']={glyph_name='uni006c',unicode='l'}, + ['109']={glyph_name='uni006d',unicode='m'}, + ['110']={glyph_name='uni006e',unicode='n'}, + ['111']={glyph_name='uni006f',unicode='o'}, + ['112']={glyph_name='uni0070',unicode='p'}, + ['113']={glyph_name='uni0071',unicode='q'}, + ['114']={glyph_name='uni0072',unicode='r'}, + ['115']={glyph_name='uni0073',unicode='s'}, + ['116']={glyph_name='uni0074',unicode='t'}, + ['117']={glyph_name='uni0075',unicode='u'}, + ['118']={glyph_name='uni0076',unicode='v'}, + ['119']={glyph_name='uni0077',unicode='w'}, + ['120']={glyph_name='uni0078',unicode='x'}, + ['121']={glyph_name='uni0079',unicode='y'}, + ['122']={glyph_name='uni007a',unicode='z'}, + ['123']={glyph_name='uni2013',unicode='–'}, -- U+2013 EN DASH + ['124']={glyph_name='uni2014',unicode='—'}, -- U+2014 EM DASH + ['125']={glyph_name='uni030b',unicode='̋'}, --U+030B COMBINING DOUBLE ACUTE ACCENT + ['126']={glyph_name='uni0303',unicode='̃'}, --U+0303 COMBINING TILDE + ['127']={glyph_name='uni0308',unicode='̈'}, --U+0308 COMBINING DIAERESIS + ['128']={glyph_name='uni0080',unicode='€'}, + ['129']={glyph_name='uni0081',unicode=''}, + ['130']={glyph_name='uni0082',unicode='‚'}, + ['131']={glyph_name='uni0083',unicode='ƒ'}, + ['132']={glyph_name='uni0084',unicode='„'}, + ['133']={glyph_name='uni0085',unicode='…'}, + ['134']={glyph_name='uni0086',unicode='†'}, + ['135']={glyph_name='uni0087',unicode='‡'}, + ['136']={glyph_name='uni0088',unicode='ˆ'}, + ['137']={glyph_name='uni0089',unicode='‰'}, + ['138']={glyph_name='uni008a',unicode='Š'}, + ['139']={glyph_name='uni008b',unicode='‹'}, + ['140']={glyph_name='uni008c',unicode='Œ'}, + ['141']={glyph_name='uni008d',unicode=''}, + ['142']={glyph_name='uni008e',unicode='Ž'}, + ['143']={glyph_name='uni008f',unicode=''}, + ['144']={glyph_name='uni0090',unicode=''}, + ['145']={glyph_name='uni0091',unicode='‘'}, + ['146']={glyph_name='uni0092',unicode='’'}, + ['147']={glyph_name='uni0093',unicode='“'}, + ['148']={glyph_name='uni0094',unicode='”'}, + ['149']={glyph_name='uni0095',unicode='•'}, + ['150']={glyph_name='uni0096',unicode='–'}, + ['151']={glyph_name='uni0097',unicode='—'}, + ['152']={glyph_name='uni0098',unicode='˜'}, + ['153']={glyph_name='uni0099',unicode='™'}, + ['154']={glyph_name='uni009a',unicode='š'}, + ['155']={glyph_name='uni009b',unicode='›'}, + ['156']={glyph_name='uni009c',unicode='œ'}, + ['157']={glyph_name='uni009d',unicode=''}, + ['158']={glyph_name='uni009e',unicode='ž'}, + ['159']={glyph_name='uni009f',unicode='Ÿ'}, + ['160']={glyph_name='uni00a0',unicode=' '}, + ['161']={glyph_name='uni00a1',unicode='¡'}, + ['162']={glyph_name='uni00a2',unicode='¢'}, + ['163']={glyph_name='uni00a3',unicode='£'}, + ['164']={glyph_name='uni00a4',unicode='¤'}, + ['165']={glyph_name='uni00a5',unicode='¥'}, + ['166']={glyph_name='uni00a6',unicode='¦'}, + ['167']={glyph_name='uni00a7',unicode='§'}, + ['168']={glyph_name='uni00a8',unicode='¨'}, + ['169']={glyph_name='uni00a9',unicode='©'}, + ['170']={glyph_name='uni00aa',unicode='ª'}, + ['171']={glyph_name='uni00ab',unicode='«'}, + ['172']={glyph_name='uni00ac',unicode='¬'}, + ['173']={glyph_name='uni00ad',unicode='­'}, + ['174']={glyph_name='uni00ae',unicode='®'}, + ['175']={glyph_name='uni00af',unicode='¯'}, + ['176']={glyph_name='uni00b0',unicode='°'}, + ['177']={glyph_name='uni00b1',unicode='±'}, + ['178']={glyph_name='uni00b2',unicode='²'}, + ['179']={glyph_name='uni00b3',unicode='³'}, + ['180']={glyph_name='uni00b4',unicode='´'}, + ['181']={glyph_name='uni00b5',unicode='µ'}, + ['182']={glyph_name='uni00b6',unicode='¶'}, + ['183']={glyph_name='uni00b7',unicode='·'}, + ['184']={glyph_name='uni00b8',unicode='¸'}, + ['185']={glyph_name='uni00b9',unicode='¹'}, + ['186']={glyph_name='uni00ba',unicode='º'}, + ['187']={glyph_name='uni00bb',unicode='»'}, + ['188']={glyph_name='uni00bc',unicode='¼'}, + ['189']={glyph_name='uni00bd',unicode='½'}, + ['190']={glyph_name='uni00be',unicode='¾'}, + ['191']={glyph_name='uni00bf',unicode='¿'}, + ['192']={glyph_name='uni00c0',unicode='À'}, +-- ['193']={glyph_name='uni00c1',unicode='Á'}, + ['193']={glyph_name='uni0060',unicode='`'}, +-- ['194']={glyph_name='uni00c2',unicode='Â'}, + ['194']={glyph_name='uni00b4',unicode='´'}, +-- ['195']={glyph_name='uni00c3',unicode='Ã'}, + ['195']={glyph_name='uni005e',unicode='^'}, + ['196']={glyph_name='uni00c4',unicode='Ä'}, + ['197']={glyph_name='uni00c5',unicode='Å'}, + ['198']={glyph_name='uni00c6',unicode='Æ'}, + ['199']={glyph_name='uni00c7',unicode='Ç'}, + ['200']={glyph_name='uni00c8',unicode='È'}, + ['201']={glyph_name='uni00c9',unicode='É'}, + ['202']={glyph_name='uni00ca',unicode='Ê'}, + ['203']={glyph_name='uni00cb',unicode='Ë'}, + ['204']={glyph_name='uni00cc',unicode='Ì'}, + ['205']={glyph_name='uni00cd',unicode='Í'}, + ['206']={glyph_name='uni00ce',unicode='Î'}, + ['207']={glyph_name='uni00cf',unicode='Ï'}, + ['208']={glyph_name='uni00d0',unicode='Ð'}, + ['209']={glyph_name='uni00d1',unicode='Ñ'}, + ['210']={glyph_name='uni00d2',unicode='Ò'}, + ['211']={glyph_name='uni00d3',unicode='Ó'}, + ['212']={glyph_name='uni00d4',unicode='Ô'}, + ['213']={glyph_name='uni00d5',unicode='Õ'}, + ['214']={glyph_name='uni00d6',unicode='Ö'}, + ['215']={glyph_name='uni00d7',unicode='×'}, + ['216']={glyph_name='uni00d8',unicode='Ø'}, + ['217']={glyph_name='uni00d9',unicode='Ù'}, + ['218']={glyph_name='uni00da',unicode='Ú'}, + ['219']={glyph_name='uni00db',unicode='Û'}, + ['220']={glyph_name='uni00dc',unicode='Ü'}, + ['221']={glyph_name='uni00dd',unicode='Ý'}, + ['222']={glyph_name='uni00de',unicode='Þ'}, + ['223']={glyph_name='uni00df',unicode='ß'}, + ['224']={glyph_name='uni00e0',unicode='à'}, + ['225']={glyph_name='uni00e1',unicode='á'}, + ['226']={glyph_name='uni00e2',unicode='â'}, + ['227']={glyph_name='uni00e3',unicode='ã'}, + ['228']={glyph_name='uni00e4',unicode='ä'}, + ['229']={glyph_name='uni00e5',unicode='å'}, + ['230']={glyph_name='uni00e6',unicode='æ'}, + ['231']={glyph_name='uni00e7',unicode='ç'}, + ['232']={glyph_name='uni00e8',unicode='è'}, + ['233']={glyph_name='uni00e9',unicode='é'}, + ['234']={glyph_name='uni00ea',unicode='ê'}, + ['235']={glyph_name='uni00eb',unicode='ë'}, + ['236']={glyph_name='uni00ec',unicode='ì'}, + ['237']={glyph_name='uni00ed',unicode='í'}, + ['238']={glyph_name='uni00ee',unicode='î'}, + ['239']={glyph_name='uni00ef',unicode='ï'}, + ['240']={glyph_name='uni00f0',unicode='ð'}, + ['241']={glyph_name='uni00f1',unicode='ñ'}, + ['242']={glyph_name='uni00f2',unicode='ò'}, + ['243']={glyph_name='uni00f3',unicode='ó'}, + ['244']={glyph_name='uni00f4',unicode='ô'}, + ['245']={glyph_name='uni00f5',unicode='õ'}, + ['246']={glyph_name='uni00f6',unicode='ö'}, + ['247']={glyph_name='uni00f7',unicode='÷'}, + ['248']={glyph_name='uni00f8',unicode='ø'}, + ['249']={glyph_name='uni00f9',unicode='ù'}, + ['250']={glyph_name='uni00fa',unicode='ú'}, + ['251']={glyph_name='uni00fb',unicode='û'}, + ['252']={glyph_name='uni00fc',unicode='ü'}, + ['253']={glyph_name='uni00fd',unicode='ý'}, + ['254']={glyph_name='uni00fe',unicode='þ'}, + ['255']={glyph_name='uni00ff',unicode='ÿ'}, + ['256']={glyph_name='uni0100',unicode='Ā'}, + }, + +} + +local function _eval_tonumber(q,offset) + local qx,qy,xo,yo + local w + local _offset = offset + if _offset == nil then _offset = '(0,0)' end + w=string.gmatch(q,"[-0-9.]+"); qx,qy=w(),w() + w=string.gmatch(_offset,"[-0-9.]+"); xo,yo=w(),w() + return {tonumber(qx+xo),tonumber(qy+yo)} +end + + +local function get_svg_glyph(valid_curves,char,cycles,tfm) + -- Write the svg + -- + -- print('BEZ MFbuiltin.hppp='..print_scaled(MFbuiltin.hppp())) + -- print('BEZ MFbuiltin.vppp='..print_scaled(MFbuiltin.vppp())) + -- print('BEZ MFbuiltin.designsize='..print_scaled(MFbuiltin.designsize())) + local tfm = tfm + local index = tostring( char['index'] ) -- better a string or a number + local design_size=tonumber ( print_scaled(MFbuiltin.designsize()) ) --pt + local char_wd=tonumber( char['char_wd'] ) -- pt + local char_ht=tonumber( char['char_ht'] ) -- pt + local char_dp=tonumber( char['char_dp'] ) -- pt + + --local xheight = 0.458333 * design_size -- must be read from tfm !! + + local x_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.hppp()) )* 72.27) + local y_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.vppp()) )* 72.27) + assert(x_resolution==y_resolution, string.format('Error on _get_svg_glyph x_res=%d and y_res=%d differ',x_resolution,y_resolution)) + + local resolution = x_resolution + local emsize = mflua.svg.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em + local em_unit = emsize + + local em_unit_for_pixel = (72.27/design_size) * (emsize / resolution) + local bp_for_pt = 72/72.27 + local char_wd_emunit = (char_wd/design_size) *em_unit + local char_ht_emunit = (char_ht/design_size) *em_unit + local char_dp_emunit = (char_dp/design_size) *em_unit + + local outdir = mflua.svg.output_dir or '.' + local fname = tostring(char['charname']) + if fname and fname ~= '' then + mflua.svg.char[index] ={glyph_name='', unicode = ''}; + mflua.svg.char[index].glyph_name = fname + local w = string.gmatch(fname,'uni(.+)') + local unicode_hex = w() + mflua.svg.char[index].unicode = [[&#x]] .. unicode_hex ..';' + end + + fname = mflua.svg.char[index].glyph_name + assert(fname~=nil, string.format("Error on svg file name for char index %s: it's nil",index)) + --local f = io.open(outdir..'/'.. fname..'.svg','w') + local w = string.gmatch(fname,'uni(.+)') + local unicode_hex = w() + local unicode = mflua.svg.char[index].unicode + local unicode_range = 'U+'..unicode_hex + local glyph_name = fname + local bezier = '' + local maxx,maxy=-1e9,-1e9 + local minx,miny=1e9,1e9 + for i,cycle in pairs(cycles) do + local path='' + local _i=1 + for _,j in ipairs(cycle) do + --local curve = valid_curves[j] + local curve = j + local p,c1,c2,q,offset=curve[1],curve[2],curve[3],curve[4],curve[5] + p=_eval_tonumber(p,offset) + c1=_eval_tonumber(c1,offset) + c2=_eval_tonumber(c2,offset) + q=_eval_tonumber(q,offset) + -- em_unit_for_pixel + p[1],p[2] = p[1]*em_unit_for_pixel,p[2]*em_unit_for_pixel + q[1],q[2] = q[1]*em_unit_for_pixel,q[2]*em_unit_for_pixel + c1[1],c1[2] = c1[1]*em_unit_for_pixel,c1[2]*em_unit_for_pixel + c2[1],c2[2] = c2[1]*em_unit_for_pixel,c2[2]*em_unit_for_pixel + if _i==1 then bezier = bezier..string.format("M%s %s ",p[1],p[2]) end + _i=_i+1 + bezier = bezier .. string.format("C%s %s %s %s %s %s\n",c1[1],c1[2],c2[1],c2[2],q[1],q[2]) + --print("BEZ bez="..bezier) + if p[1]>maxx then maxx=p[1] end + if c1[1]>maxx then maxx=c1[1] end + if c2[1]>maxx then maxx=c2[1] end + if q[1]>maxx then maxx=q[1] end + if p[2]>maxy then maxy=p[2] end + if c1[2]>maxy then maxy=c1[2] end + if c2[2]>maxy then maxy=c2[2] end + if q[2]>maxy then maxy=q[2] end + -- + if p[1]', bezier) + local raw=string.format(svg_preamble,minx,miny,maxx,maxy,-maxy,paths) + return trunk,raw +end -- _get_svg_glyph + + +local function svg_kern_and_lig(chartable,t,tfm) + -- + -- Store kerns and ligs + -- + local current_chars={} + local index + local kern, next_char,additional_space + local bp_for_pt = 72/72.27 + local x_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.hppp()) )* bp_for_pt) + local y_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.vppp()) )* bp_for_pt) + local design_size=tfm.font.designsize -- pt + assert(x_resolution==y_resolution, string.format('Error on _get_svg_glyph x_res=%d and y_res=%d differ',x_resolution,y_resolution)) + local resolution = x_resolution + local emsize = mflua.svg.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em + local em_unit = emsize + local em_unit_for_pixel = (bp_for_pt/design_size) * (emsize / resolution) + + local hkern,vkern = '' ,'' + for i,_ in ipairs(t) do + index = t[i] + current_chars[index]=true + end + for i,_ in ipairs(t) do + index = t[i] + if tfm.chars[index] and tfm.chars[index].kern then + kerntable = tfm.chars[index].kern + for _,k in ipairs(kerntable) do + next_char,additional_space = tostring(k.next_char),tonumber(k.additional_space) + -- + if additional_space~=0 then + local a_name,a_unicode = mflua.svg.char[tostring(index)].glyph_name,mflua.svg.char[tostring(index)].unicode + local b_name,b_unicode = mflua.svg.char[next_char].glyph_name,mflua.svg.char[next_char].unicode + hkern = hkern .. "\n".. string.format(mflua.svg.hkern, + a_name,a_unicode, + b_name,b_unicode, + additional_space*design_size*em_unit_for_pixel) + end + end + end + end + return hkern,vkern +end + +local function store_svg_font(tfm) + -- local outdir = mflua.svg.output_dir or '.' + -- local fname = mflua.svg.filename + -- assert(fname~=nil, string.format("Error on svg file name for %s: it's nil",fname)) + -- local f = io.open(outdir..'/'.. fname..'.svg','w') + local svg_font = mflua.svg.font + local design_size=tonumber ( print_scaled(MFbuiltin.designsize()) ) --pt + local emsize = mflua.svg.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em + local bp_for_pt = 72/72.27 + local xheight = tfm.font.x_height * design_size --0.458333 * design_size -- must be read from tfm !! + local trunk ='' + local char = mflua.svg.char + for index=0,2^16-1 do + if not(char[tostring(index)]==nil) then + --print("BEZ char[tostring(index)].data=",index,char[tostring(index)].data) + trunk= trunk.. (char[tostring(index)].data or '') + end + end + trunk = trunk.."\n"..mflua.svg.hkerns.."\n"..mflua.svg.vkerns + trunk = string.format(svg_font, + string.format("%2.2f",design_size*bp_for_pt), + emsize, + string.format("%2.2f",xheight*bp_for_pt), + trunk) + return trunk + + +end + +svg.get_svg_glyph = get_svg_glyph +svg.svg_kern_and_lig = svg_kern_and_lig +svg.store_svg_font = store_svg_font + +return svg diff --git a/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua b/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua new file mode 100644 index 00000000000..851ff284ef3 --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua @@ -0,0 +1,743 @@ +-- +-- +-- Experimental ttx back end +-- +-- + + +local format = string.format +local table_insert = table.insert +local table_concat = table.concat +local print_int = mflua.MF.print_int +local abs = math.abs + +local ttx = {} +local xmlstream = {} + +local scrt = {} -- general table for local use + +local function DUMP(t) + if type(t) == 'table' then + print("table",#table) + for k,v in pairs(t) do print(k,v) end + end +end + + +local xml_comment = 'c' +local xml_processing_instruction = 'p' +local xml_element = 'e' +local xml_header = 'h' + + +-------------------------------------------------------------------------------- +-- +-- Errors and warning +-------------------------------------------------------------------------------- +local function warning(t,msg) + print("Warning:"..msg..".") + print("Element:") + if type(t)=='table' then + for k,v in pairs(t) do print(k,v) end + print(#t.." values") + else + print(tostring(s)) + end +end + + +-------------------------------------------------------------------------------- +-- +-- Element management +-------------------------------------------------------------------------------- + + +-- Todo: valid XML totext & toattr & tocomment +local function totext(s) + if not(type(s)=='string') then + warning(s,"text:the data in not a string") + end + return tostring(s) +end + +local function toattr(s) + if not(type(s)=='string') then + warning(s,"attr.:the data in not a string") + end + return tostring(s) +end + +local function tocomment(s) + if not(type(s)=='string') then + warning(s,"comment:the data in not a string") + end + return tostring(s) +end + +local function new_comment(text) + local t ={} + t[0]=xml_comment + t[1]=false + t[2]=tocomment(text) + return t +end + +local function new_element(name,attr) + local t ={} + t[0]=xml_element + t[1]=tostring(name) + if attr and type(attr)=='table' then + for k,v in pairs(attr) do + if type(k)~='number' then + t[k]=v + end + end + end + return t +end + +local function get_elementname(t) + if t and type(t)=='table' then + return t[1] + else + return nil + end +end + +local function insert_child(f,c) + table_insert(f,c) +end + +local function insert_child_at_beginning(f,c) + -- f[1] is always the name + table_insert(f,2,c) +end + +local function insert_children(f,cc) + for j=1,#cc do + table_insert(f,cc[j]) + end +end + + +-- +-- get all the children (not descendants!) +-- of source that match target name and attr. +-- The existence of an attribute can be checked +-- with @attrname=true (not @attrname="true") in +-- target +local function get_children(source,target) + local res={} + local t_attr={} + -- only key/val from target + for k,v in pairs(target) do + if type(k)=='number' then + t_attr[k]=v + end + end + for i=2,#source do + local e = source[i] + if e[1]==target[1] then + local found=true + for k,v in pairs(t_attr) do + if not(e[k] and ((e[k]==v) or (v==true))) then + found=false + break + end + end + if found then + res[#res+1]=e + end + end + end + return res +end + +-------------------------------------------------------------------------------- +-- +-- Serialization +--------------------------------------------------------------------------------- + +local function serialize_comment(t) + if not(t[0]== xml_comment) then + warning(t,'the node to serialize is not a comment') + return + end + local name=t[1] -- false, discarded + local elem={} + elem[#elem+1]='<--' + elem[#elem+1]=tocomment(t2) + elem[#elem+1]='-->' + elem[#elem+1]='\n' + xmlstream[#xmlstream+1] = table_concat(elem) +end + + +local function serialize_processing_instruction(t) + if not(t[0]== xml_processing_instruction) then + warning(t,'the node to serialize is not a processing_instruction') + return + end + local name=t[1] + local elem={} + elem[#elem+1]='' + elem[#elem+1]="\n" + xmlstream[#xmlstream+1] = table_concat(elem) +end + +local function serialize_xml_header(t) + local _t={} + local elem={} + elem[#elem+1]='' + elem[#elem+1]='\n' + xmlstream[#xmlstream+1] = table_concat(elem) +end + +local function serialize_empty_elem(t) + local name=t[1] + local elem={} + elem[#elem+1]='<' + elem[#elem+1]=name + local _t={} + for k,v in pairs(t) do + if not(type(k)=='number') then + _t[#_t+1]=k + end + end + table.sort(_t) + for j=1,#_t do + elem[#elem+1]=format([[ %s="%s"]],_t[j],toattr(t[_t[j]])) + end + elem[#elem+1]='/>' + elem[#elem+1]="\n" + xmlstream[#xmlstream+1] = table_concat(elem) +end + +local function serialize_elem(t) + if #t==1 then + serialize_empty_elem(t) + else + local name=t[1] + local elem={} + elem[#elem+1]='<' + elem[#elem+1]=name + -- attributes + local _t={} + for k,v in pairs(t) do + if not(type(k)=='number') then + _t[#_t+1]=k + end + end + table.sort(_t) + for j=1,#_t do + elem[#elem+1]=format([[ %s="%s"]],_t[j],toattr(t[_t[j]])) -- + end + elem[#elem+1]='>' + elem[#elem+1]="\n" + xmlstream[#xmlstream+1] = table_concat(elem) + elem = {} + for j=2,#t do + if type(t[j])=='table' then + serialize_elem(t[j]) + elseif type(t[j])=='string' then + xmlstream[#xmlstream+1] = totext(t[j]) + end + end + elem[#elem+1]='' + elem[#elem+1]="\n" + xmlstream[#xmlstream+1] = table_concat(elem) + end +end + + +-------------------------------------------------------------------------------- +-- +-- First children of XML ttx, plus utilities +-------------------------------------------------------------------------------- + +local ttFont +local GlyphOrder +local GlyphID +local head +local hhea +local maxp +local OS_2,panose -- handy to have +local name +local cmap +local post +local CFF, CFFFont, Private -- handy to have +local FFTM +local GDEF +local hmtx + +-- Important, child of CFFFont +local CharStrings + +local function get_GlyphID(id,name) + return new_element('GlyphID',{['id']=tostring(id),['name']=tostring(name)}) +end + +local function put_head(name,value) + table_insert(head, new_element(name, {['value']=tostring(value)})) +end + +local function put_hhea(name,value) + table_insert(hhea, new_element(name, {['value']=tostring(value)})) +end + +local function put_maxp(name,value) + table_insert(maxp,new_element(name, {['value']=tostring(value)})) +end + +local function put_OS_2(name,value) + table_insert(OS_2,new_element(name, {['value']=tostring(value)})) +end +-- handy +local function put_panose(name,value) + table_insert(panose,new_element(name, {['value']=tostring(value)})) +end + +local function get_map(code,name) + return new_element('map', {['code']=tostring(code),['name']=tostring(name)}) +end + +local function put_post(name,value) + table_insert(post,new_element(name, {['value']=tostring(value)})) +end + +local function put_CFF(name,value) + table_insert(CFF,new_element(name, {['value']=tostring(value)})) +end + +local function put_CFFFont(name,value) + table_insert(CFFFont,new_element(name, {['value']=tostring(value)})) +end + +local function put_Private(name,value) + table_insert(Private,new_element(name, {['value']=tostring(value)})) +end + +local function put_FFTM(name,value) + table_insert(FFTM,new_element(name, {['value']=tostring(value)})) +end + +local function get_ClassDef(glyph,class) + return new_element('ClassDef', {['glyph']=tostring(glyph),['class']=tostring(class)}) +end + +local function get_mtx(name,width,lsb) + return new_element('mtx', {['name']=tostring(name),['width']=tostring(width),['lsb']=tostring(lsb)}) +end + +-- +-- convenient method for a cmap0 +-- +-- local function get_cmap0_maps(maps) +-- local t = {} +-- if not(#maps==256) then +-- warning(maps,"maps has not 256 values") +-- end +-- local s=(#maps>=256 and 256) or #maps +-- for j=1,s do +-- t[#t+1]=get_map(format("0x%x",j-1),maps[j]) +-- end +-- return t +-- end + +local function get_raw_cmap0() + local t = {} + for j=0,255 do + t[format("0x%02x",j)] = ".notdef" + end + return t +end + + + + +--for i=1,255 do table_insert(GlyphOrder,new_element('GlyphID', {['id']=i, ['name']="uni"..tostring(i)})) end +--local ttFont = dofile('ttx_sample.lua') +--savettfont(ttFont) + + +-------------------------------------------------------------------------------- +-- +-- Create & save xml font +-------------------------------------------------------------------------------- + +local function checkall(tfm) + -- several checks here + -- fix cmap0 + -- local t = {} + -- for k,_ in pairs(scrt.cmap.rawcmap0) do t[#t+1]=k end + -- table.sort(t) + -- for k=1,256 do + -- insert_child(scrt.cmap.cmap0, get_map(t[k],scrt.cmap.rawcmap0[t[k]])) + -- end + +end + +local function savettxfont(t) + serialize_xml_header([[version="1.0" encoding="UTF-8"]]) + serialize_elem(t) + return table_concat(xmlstream) + +end + +local function makefont(tfm) + -- + checkall(tfm) + serialize_xml_header([[version="1.0" encoding="UTF-8"]]) + serialize_elem(ttFont) + return table_concat(xmlstream) +end + + + + +-------------------------------------------------------------------------------- +-- +-- mflua layer +-------------------------------------------------------------------------------- + +local function _eval_tonumber(q,offset) + local qx,qy,xo,yo + local w + local _offset = offset + if _offset == nil then _offset = '(0,0)' end + w=string.gmatch(q,"[-0-9.]+"); qx,qy=w(),w() + w=string.gmatch(_offset,"[-0-9.]+"); xo,yo=w(),w() + return {tonumber(qx+xo),tonumber(qy+yo)} +end + +local function setup(tfm,index,chartable) + -- Default emsize is 1000 of CFF + ttx.emsize = ttx.emsize or 1000 + + scrt.font_space = tfm.printfloat(ttx.emsize*(tfm.font.space),3) + + ttFont = new_element('ttFont', {['sfntVersion']="OTTO", ['ttLibVersion']="3.1"}) + GlyphOrder = new_element('GlyphOrder') + GlyphID = new_element('GlyphID', {['id']="0", ['name']=".notdef"}) + head = new_element('head') + hhea = new_element('hhea') + maxp = new_element('maxp') + OS_2 = new_element('OS_2') + name = new_element('name') + cmap = new_element('cmap') + post = new_element('post') + CFF = new_element('CFF') + -- FFTM = new_element('FFTM') --FontForge TimeStamp table + GDEF = new_element('GDEF') + hmtx = new_element('hmtx') + + -- handy + panose = new_element('panose') + CFFFont = new_element('CFFFont',{['name']="SourceCode"}) + Private = new_element('Private') + + CharStrings= new_element('CharStrings') + + table_insert(ttFont,GlyphOrder) + table_insert(ttFont,head) + table_insert(ttFont,hhea) + table_insert(ttFont,maxp) + table_insert(ttFont,OS_2) + table_insert(ttFont,name) + table_insert(ttFont,cmap) + table_insert(ttFont,post) + table_insert(ttFont,CFF) +-- table_insert(ttFont,FFTM) + table_insert(ttFont,GDEF) + table_insert(ttFont,hmtx) + + table_insert(GlyphOrder,GlyphID) + + if ttx.userdata.head then + for k,v in pairs(ttx.userdata.head) do + put_head(k,v) + end + end + + if ttx.userdata.hhea then + for k,v in pairs(ttx.userdata.hhea) do + put_hhea(k,v) + end + end + + if ttx.userdata.maxp then + for k,v in pairs(ttx.userdata.maxp) do + put_maxp(k,v) + end + end + + if ttx.userdata.OS_2 then + for k,v in pairs(ttx.userdata.OS_2) do + put_OS_2(k,v) + end + end + + if ttx.userdata.panose then + for k,v in pairs(ttx.userdata.panose) do + put_panose(k,v) + end + end + insert_child(OS_2,panose) + + if ttx.userdata.namerecord then + local _e + local t + for i=1,#ttx.userdata.namerecord do + t = ttx.userdata.namerecord[i] + _e = new_element('namerecord',{['nameID']=t.nameID,['platformID']=t.platformID, + ['platEncID']=t.platEncID, ['langID']=t.langID, ['unicode']=t.unicode}) + insert_child(_e,t.value); insert_child(name,_e) + end + end + + + local cmap0,cmap4_0,cmap4_3 + cmap4_0 = new_element('cmap_format_4', {['platformID']="0",['platEncID']="3",['language']="0",}) + --cmap0 = new_element('cmap_format_0', {['platformID']="1",['platEncID']="0",['language']="0",}) + cmap4_3 = new_element('cmap_format_4', {['platformID']="3",['platEncID']="1",['language']="0",}) + + + insert_child(cmap4_0,get_map("0x0",".notdef")) + insert_child(cmap4_3,get_map("0x0",".notdef")) + + scrt.cmap = scrt.cmap or {} + scrt.cmap.cmap4_0 = cmap4_0 + scrt.cmap.cmap4_3 = cmap4_3 + --scrt.cmap.cmap0 = cmap0 + --scrt.cmap.rawcmap0 = get_raw_cmap0() + + + insert_child(cmap,{'tableVersion', ['version']="0"}) + insert_child(cmap,cmap4_0) + --insert_child(cmap,cmap0) + insert_child(cmap,cmap4_3) + + + if ttx.userdata.post then + for k,v in pairs(ttx.userdata.post) do + put_post(k,v) + end + end + + put_CFF('major',"1") + put_CFF('minor',"0") + insert_child(CFF,CFFFont) + + if ttx.userdata.CFFFont then + for k,v in pairs(mflua.ttx.userdata.CFFFont) do + put_CFFFont(k,v) + end + end + + insert_child(CFFFont,{'Encoding', ['name']=mflua.ttx.userdata.CFFFont.Encoding}) + + insert_child(CFFFont,Private) + if ttx.userdata.CFFFont.Private then + for k,v in pairs(ttx.userdata.CFFFont.Private) do + put_Private(k,v) + end + end + + local subrs = new_element('Subrs') + scrt.subrs = subrs + if ttx.userdata.CFFFont.Private.Subrs then + for k,v in pairs(ttx.userdata.CFFFont.Private.Subrs) do + insert_child(subrs,{'CharString', ['index']=k, v}) + end + end + insert_child(Private,subrs) + + -- .notdef char + local notdef = new_element('CharString', {['name']=".notdef"}) + insert_child(notdef,"107 endchar\n") + insert_child_at_beginning(CharStrings, notdef) + + insert_child(CFFFont,CharStrings) + + -- + -- TODO: check GlobalSubrs!! + -- + local globsubrs = new_element('GlobalSubrs') + insert_child(CFF,globsubrs) + if ttx.userdata.CFF.GlobalSubrs then + for k,v in pairs(ttx.userdata.CFF.GlobalSubrs) do + insert_child(globsubrs,{'CharString', ['index']=k, v}) + end + end + + -- + -- fontforge timestamp table. + -- + -- put_FFTM('version', "1") + -- put_FFTM('FFTimeStamp', "Fri Oct 7 21:32:10 2016") + -- put_FFTM('sourceCreated', "Tue Apr 4 13:38:00 2017") + -- put_FFTM('sourceModified', "Wed Apr 5 16:26:11 2017") + + + local glyphclassdef = new_element('GlyphClassDef',{['Format']="2"}) + insert_child(GDEF,{'Version',['value']="0x00010000"}) + insert_child(GDEF,glyphclassdef) + scrt.gdef = scrt.gdef or {} + scrt.gdef.glyphclassdef = glyphclassdef + + local LigCaretList = new_element('LigCaretList') + insert_child(LigCaretList,new_element('Coverage',{['Format']="2"})) + insert_child(GDEF,LigCaretList) + + insert_child(hmtx, get_mtx('.notdef',scrt.font_space,"0")) +end + + +local function reverse(cycle) + local t={} + local curve + local p,c1,c2,q + for i=#cycle,1,-1 do + curve=cycle[i] + p,c1,c2,q=curve[1],curve[2],curve[3],curve[4] + curve[1],curve[2],curve[3],curve[4]=q,c2,c1,p + t[#t+1]=curve + end + return t +end + +local function _reverse(cycle) + local cv1, cv2 + local p,c1,c2,q + local l=#cycle + for i=1,l/2 do + cv1=cycle[i] + cv2=cycle[l+1-i] + p,c1,c2,q = cv1[1],cv1[2],cv1[3],cv1[4] + cv1[1],cv1[2],cv1[3],cv1[4] = q,c2,c1,p + p,c1,c2,q = cv2[1],cv2[2],cv2[3],cv2[4] + cv2[1],cv2[2],cv2[3],cv2[4] = q,c2,c1,p + cycle[l+1-i]=cv1 + cycle[i]=cv2 + end +end + + + +local function make_glyph(valid_curves,char,cycles,tfm) + -- Write the ttx + -- + -- print('BEZ MFbuiltin.hppp='..print_scaled(MFbuiltin.hppp())) + -- print('BEZ MFbuiltin.vppp='..print_scaled(MFbuiltin.vppp())) + -- print('BEZ MFbuiltin.designsize='..print_scaled(MFbuiltin.designsize())) + local tfm = tfm + local mflua_index = tonumber( char['index'] ) -- better a string or a number + local index = mflua_index + if mflua.ttx.userdata.charindex and mflua.ttx.userdata.charindex[index] then + index = mflua.ttx.userdata.charindex[index] + end + + local design_size=tonumber ( print_scaled(MFbuiltin.designsize()) ) --pt + local char_wd=tonumber( char['char_wd'] ) -- pt + local char_ht=tonumber( char['char_ht'] ) -- pt + local char_dp=tonumber( char['char_dp'] ) -- pt + + local cmap4_0 = scrt.cmap.cmap4_0 + local cmap4_3 = scrt.cmap.cmap4_3 + --local rawcmap0 = scrt.cmap.rawcmap0 + + local glyphclassdef = scrt.gdef.glyphclassdef + + --local xheight = 0.458333 * design_size -- must be read from tfm !! + + local x_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.hppp()) )* 72.27) + local y_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.vppp()) )* 72.27) + assert(x_resolution==y_resolution, format('Error on _make_glyph x_res=%d and y_res=%d differ',x_resolution,y_resolution)) + + local resolution = x_resolution + local emsize = ttx.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em + local em_unit = emsize + + local em_unit_for_pixel = (72.27/design_size) * (emsize / resolution) + local bp_for_pt = 72/72.27 + local char_wd_emunit = (char_wd/design_size) *em_unit + local char_ht_emunit = (char_ht/design_size) *em_unit + local char_dp_emunit = (char_dp/design_size) *em_unit + + local glyph_name = tostring(char['charname']) + if glyph_name and glyph_name ~= '' and not(index==0) then + table_insert(GlyphOrder,get_GlyphID(index,glyph_name)) + end + local content = {} + if (abs(char_wd_emunit-scrt.font_space)>1e-4) then + table_insert(content,format("%0.3f w",char_wd_emunit-scrt.font_space,print_int(1000*(tfm.font.space)))) + end + --table_insert(content,"stem ?") -- TODO + --table_insert(content,"mask ?") -- TODO + local origin = {0,0} + for i,cycle in pairs(cycles) do + local p,c1,c2,q,offset + cycle = reverse(cycle) + for i1,curve in ipairs(cycle) do + p,c1,c2,q,offset=curve[1],curve[2],curve[3],curve[4],curve[5] + p =_eval_tonumber(p ,offset) + c1=_eval_tonumber(c1,offset) + c2=_eval_tonumber(c2,offset) + q =_eval_tonumber(q ,offset) + -- em_unit_for_pixel + p[1],p[2] = p[1] *em_unit_for_pixel, p[2]*em_unit_for_pixel + q[1],q[2] = q[1] *em_unit_for_pixel, q[2]*em_unit_for_pixel + c1[1],c1[2] = c1[1]*em_unit_for_pixel, c1[2]*em_unit_for_pixel + c2[1],c2[2] = c2[1]*em_unit_for_pixel, c2[2]*em_unit_for_pixel + if i1==1 then + table_insert(content,format("%0.2f %0.2f rmoveto",p[1]-origin[1],p[2]-origin[2])) + origin = {p[1],p[2]} + end + --table_insert(content,format("%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f rrcurveto", + table_insert(content,format("%0.0f %0.0f %0.0f %0.0f %0.0f %0.0f rrcurveto", + c1[1] -p[1], c1[2]-p[2], + c2[1]-c1[1], c2[2]-c1[2], + q[1] -c2[1], q[2]-c2[2],p[1],p[2],c1[1],c1[2],c2[1],c2[2],q[1],q[2])) + end + end + table_insert(content,"endchar\n") + local CharString = new_element('CharString', {['name']=glyph_name}) + insert_child(CharString,table_concat(content,"\n")) + + insert_child(CharStrings,CharString) + insert_child(cmap4_0,get_map(format("0x%x",index),glyph_name)) + --rawcmap0[format("0x%x",1+index%256)] = glyph_name + insert_child(cmap4_3,get_map(format("0x%x",index),glyph_name)) + + insert_child(glyphclassdef, get_ClassDef(glyph_name,"1")) + insert_child(hmtx, get_mtx(glyph_name,char_wd_emunit,"80")) + + +end -- make_glyph + + + + + +ttx.make_glyph = make_glyph +ttx.makefont = makefont +ttx.setup = setup +ttx.userdata = {} + +return ttx -- cgit v1.2.3