summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/mflua
diff options
context:
space:
mode:
authorLuigi Scarso <luigi.scarso@gmail.com>2017-04-19 06:59:52 +0000
committerLuigi Scarso <luigi.scarso@gmail.com>2017-04-19 06:59:52 +0000
commitd2d419a890173446ae0254d73e056ffd199f6668 (patch)
tree2c389776c0cf9fa228d4c83bdbab24a1b4450eed /Master/texmf-dist/scripts/mflua
parent8f7e5c15460e954747291156b5c37d5d2ea4a180 (diff)
MFLua aux. files
git-svn-id: svn://tug.org/texlive/trunk@43918 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/mflua')
-rw-r--r--Master/texmf-dist/scripts/mflua/begin_program.lua1
-rw-r--r--Master/texmf-dist/scripts/mflua/do_add_to.lua9
-rw-r--r--Master/texmf-dist/scripts/mflua/fill_envelope.lua2
-rw-r--r--Master/texmf-dist/scripts/mflua/fill_spec.lua2
-rw-r--r--Master/texmf-dist/scripts/mflua/final_cleanup.lua1
-rw-r--r--Master/texmf-dist/scripts/mflua/main_control.lua2
-rw-r--r--Master/texmf-dist/scripts/mflua/make_ellipse.lua2
-rw-r--r--Master/texmf-dist/scripts/mflua/mflua.lua2857
-rw-r--r--Master/texmf-dist/scripts/mflua/mflua_svg_backend.lua538
-rw-r--r--Master/texmf-dist/scripts/mflua/mflua_ttx_backend.lua743
-rw-r--r--Master/texmf-dist/scripts/mflua/mfluaini.lua1
-rw-r--r--Master/texmf-dist/scripts/mflua/offset_prep.lua2
-rw-r--r--Master/texmf-dist/scripts/mflua/print_edges.lua1
-rw-r--r--Master/texmf-dist/scripts/mflua/print_path.lua1
-rw-r--r--Master/texmf-dist/scripts/mflua/scan_direction.lua2
-rw-r--r--Master/texmf-dist/scripts/mflua/skew_line_edges.lua1
-rw-r--r--Master/texmf-dist/scripts/mflua/start_of_mf.lua1
17 files changed, 4138 insertions, 28 deletions
diff --git a/Master/texmf-dist/scripts/mflua/begin_program.lua b/Master/texmf-dist/scripts/mflua/begin_program.lua
deleted file mode 100644
index 0711ed9dddb..00000000000
--- a/Master/texmf-dist/scripts/mflua/begin_program.lua
+++ /dev/null
@@ -1 +0,0 @@
--- empty
diff --git a/Master/texmf-dist/scripts/mflua/do_add_to.lua b/Master/texmf-dist/scripts/mflua/do_add_to.lua
deleted file mode 100644
index 98dd9750722..00000000000
--- a/Master/texmf-dist/scripts/mflua/do_add_to.lua
+++ /dev/null
@@ -1,9 +0,0 @@
-function PRE_fill_envelope_rhs(rhs) return 0 end
-function POST_fill_envelope_rhs(rhs) return 0 end
-function PRE_fill_envelope_lhs(rhs) return 0 end
-function POST_fill_envelope_lhs(rhs) return 0 end
-
-function PRE_fill_spec_rhs(rhs) return 0 end
-function POST_fill_spec_rhs(rhs) return 0 end
-function PRE_fill_spec_lhs(rhs) return 0 end
-function POST_fill_spec_lhs(rhs) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/fill_envelope.lua b/Master/texmf-dist/scripts/mflua/fill_envelope.lua
deleted file mode 100644
index cbd9b2841be..00000000000
--- a/Master/texmf-dist/scripts/mflua/fill_envelope.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function print_transition_line_from(x,y) return 0 end
-function print_transition_line_to(x,y) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/fill_spec.lua b/Master/texmf-dist/scripts/mflua/fill_spec.lua
deleted file mode 100644
index 54367f46110..00000000000
--- a/Master/texmf-dist/scripts/mflua/fill_spec.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function PRE_move_to_edges(lhs) return 0 end
-function POST_move_to_edges(lhs) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/final_cleanup.lua b/Master/texmf-dist/scripts/mflua/final_cleanup.lua
deleted file mode 100644
index 627d09c0fec..00000000000
--- a/Master/texmf-dist/scripts/mflua/final_cleanup.lua
+++ /dev/null
@@ -1 +0,0 @@
-function POST_final_cleanup() return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/main_control.lua b/Master/texmf-dist/scripts/mflua/main_control.lua
deleted file mode 100644
index bf6c5784959..00000000000
--- a/Master/texmf-dist/scripts/mflua/main_control.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function PRE_main_control() return 0 end
-function POST_main_control() return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/make_ellipse.lua b/Master/texmf-dist/scripts/mflua/make_ellipse.lua
deleted file mode 100644
index 7c094499b88..00000000000
--- a/Master/texmf-dist/scripts/mflua/make_ellipse.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function PRE_make_ellipse(major_axis,minor_axis,theta,tx,ty) return 0 end
-function POST_make_ellipse(major_axis,minor_axis,theta,tx,ty) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/mflua.lua b/Master/texmf-dist/scripts/mflua/mflua.lua
new file mode 100644
index 00000000000..2596469d1d8
--- /dev/null
+++ b/Master/texmf-dist/scripts/mflua/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.
+-- @<Glob...@>=
+-- @!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|.
+-- @<Basic print...@>=
+-- 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
+
+
+-- @<Basic print...@>=
+-- 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
+
+
+
+-- @<Basic printing...@>=
+-- 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
+
+
+
+-- @<Basic printing...@>=
+-- 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+-- 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+-- elseif right_type(p) == open then
+-- -- begin "@<Print information for a curve that begins |open|@>"
+-- if (left_type(p) ~= explicit) and (left_type(p)~=open) then
+-- res = res .. "{open?}" -- {can't happen}
+-- end
+-- -- end "@<Print information for a curve that begins |open|@>"
+-- 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 @<Print information for a curve that begins |curl|...@>=
+-- 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 @<Print information for a curve that begins |curl|...@>=
+-- 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 "@<Print tension between |p| and |q|@>;"
+-- 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 -- "@<Print tension between |p| and |q|@>;"
+-- end
+-- end --- LABEL: done1
+-- -- begin @<Print two dots...@>=
+-- 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 @<Print two dots...@>=
+-- -- end "@<Print information for adjacent knots |p| and |q|@>"
+-- 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
+
+
+
+-- @ @<Declare the procedure called |print_weight|@>=
+-- 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 w<zero_w do
+-- begin print_char("-"); incr(w);
+-- end;
+-- end;
+local function print_weight(q,x_off)
+ local w,m -- {unpacked weight and coordinate}
+ local d --{temporary data register}
+ local cur_edges = MFbuiltin.cur_edges()
+ local res = ''
+ local temp
+ d=ho(info(q)); w=math.fmod(d,8); m=math.floor(d/8)-m_offset(cur_edges);
+ res = tostring(print_int(m+x_off))
+ while w>zero_w do
+ --print(tostring(print_int(m+x_off)) .. " w=" .. w.. " " .. zero_w .. " " .. (w-zero_w))
+ res = res .. "+" ; w=decr(w);
+ end
+ while w<zero_w do
+ --print(tostring(print_int(m+x_off)) .. " w=" .. w.. " " .. zero_w .. " " .. (w-zero_w))
+ res = res .. "-" ; w=incr(w)
+ end
+ --print("res=" .. res .. "w=" .. math.fmod(d,8)-zero_w)
+ return res, math.fmod(d,8)-zero_w,tostring(print_int(m+x_off))
+end
+chMF(mflua.MF,print_weight);mflua.MF.print_weight = print_weight
+
+-- Others utilities functions
+local function odd(n)
+ return math.fmod(n,2) == 1
+end
+chMF(mflua.MF,odd);mflua.MF.odd = odd
+
+--------------------------------------------------------------------------------
+--
+-- Read-only callbacs aka Sensors
+--
+--------------------------------------------------------------------------------
+
+local function begin_program()
+ PRINTDBG("begin_program")
+end
+
+local function PRE_start_of_MF()
+ PRINTDBG("PRE_start_of_MF")
+end
+
+local function PRE_main_control()
+ PRINTDBG("PRE_main_control")
+end
+
+local function POST_main_control()
+ PRINTDBG("POST_main_control")
+end
+
+local function mflua_initialize()
+ PRINTDBG("mflua_initialize")
+end
+
+local function POST_final_cleanup()
+ PRINTDBG("POST_final_cleanup")
+end
+
+local function printpath(h,s,nuline)
+ PRINTDBG("printpath")
+ 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
+ -- We can choose to follow the pascal-web way
+ -- or to follow the C-web2c way
+ -- begin "@<Print information for adjacent knots |p| and |q|@>"
+ 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+ 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+ elseif right_type(p) == open then
+ -- begin "@<Print information for a curve that begins |open|@>"
+ if (left_type(p) ~= explicit) and (left_type(p)~=open) then
+ res = res .. "{open?}" -- {can't happen}
+ end
+ -- end "@<Print information for a curve that begins |open|@>"
+ 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 @<Print information for a curve that begins |curl|...@>=
+ 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 @<Print information for a curve that begins |curl|...@>=
+ 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 "@<Print tension between |p| and |q|@>;"
+ 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 -- "@<Print tension between |p| and |q|@>;"
+ end
+ end --- LABEL: done1
+ -- begin @<Print two dots...@>=
+ 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 @<Print two dots...@>=
+ -- end "@<Print information for adjacent knots |p| and |q|@>"
+ 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.
+
+-- @<Declare subroutines for printing expressions@>=
+-- @t\4@>@<Declare the procedure called |print_weight|@>@;@/
+-- 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.
+-- @<Declare subroutines for printing expressions@>=
+
+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
+ ---@<Print the unskewed and unrotated coordinates of node |ww|@>;
+ 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
+ ---@<Print the unskewed and unrotated coordinates of node |ww|@>;
+ 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+ --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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+ elseif right_type(p) == open then
+ -- begin "@<Print information for a curve that begins |open|@>"
+ if (left_type(p) ~= explicit) and (left_type(p)~=open) then
+ return "{open?}" -- {can't happen}
+ end
+ -- end "@<Print information for a curve that begins |open|@>"
+ 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 @<Print information for a curve that begins |curl|...@>=
+ 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 @<Print information for a curve that begins |curl|...@>=
+ 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 "@<Print tension between |p| and |q|@>;"
+ 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 -- "@<Print tension between |p| and |q|@>;"
+ end
+ end --- LABEL: done1
+ -- begin @<Print two dots...@>=
+ 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 @<Print two dots...@>=
+ -- end "@<Print information for adjacent knots |p| and |q|@>"
+ 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;
+-- @<Print the cubic between |p| and |q|@>;
+-- 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(' @<Print the cubic between |p| and |q|@>;')
+ -- 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+ 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 "@<Print control points between |p| and |q|, then |goto done1|@>"
+ elseif right_type(p) == open then
+ -- begin "@<Print information for a curve that begins |open|@>"
+ if (left_type(p) ~= explicit) and (left_type(p)~=open) then
+ res = res .. "{open?}" -- {can't happen}
+ end
+ -- end "@<Print information for a curve that begins |open|@>"
+ 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 @<Print information for a curve that begins |curl|...@>=
+ 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 @<Print information for a curve that begins |curl|...@>=
+ 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 "@<Print tension between |p| and |q|@>;"
+ 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 -- "@<Print tension between |p| and |q|@>;"
+ end
+ end --- LABEL: done1
+ -- begin @<Print two dots...@>=
+ 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 @<Print two dots...@>=
+ -- end "@<Print information for adjacent knots |p| and |q|@>"
+ 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 <tfm.kern_flag then -- a ligature step
+ -- op_byte= 4a+2b+c where 0<=a<=b+c and 0<=b,c<=1.
+ local a,b,c
+ c= op_byte%2
+ b = ((op_byte-c)%4)/2
+ a = (op_byte-2*b-c)/4
+ _print("ligature step: a,b,c=",a,b,c)
+ if b==0 then
+ _print("current char: deleted")
+ else
+ _print("current char: not deleted" )
+ end
+ if c==0 then
+ _print("next char: deleted")
+ else
+ _print("next char: not deleted ")
+ end
+ if a==0 then
+ _print("no next char")
+ else
+ -- we must pass over the next a characters
+ -- local _,_remainder,_,_,_tag,_ = char_info[current_char+a]
+ -- if _tag==1 then
+ -- local kern_program = tfm.dump.kernprogram(_remainder,current_char+a)
+ -- end
+ end
+ tfm.chars[current_char] = tfm.chars[current_char] or {}
+ tfm.chars[current_char].ligature = tfm.chars[current_char].ligature or {}
+ tfm.chars[current_char].ligature[#tfm.chars[current_char].ligature+1]=
+ {['next_char']=next_char,['a']=a,['b']=b,['c']=c}
+
+ else -- a kern step
+ local additional_space = kern[256*(op_byte-128)+remainder]
+ _print("kern step:additional_space=",tfm.printfloat(additional_space))
+ tfm.chars[current_char] = tfm.chars[current_char] or {}
+ tfm.chars[current_char].kern = tfm.chars[current_char].kern or {}
+ tfm.chars[current_char].kern[#tfm.chars[current_char].kern+1] =
+ {['next_char']=next_char,['additional_space']=additional_space}
+ end
+
+ if skip_byte>=tfm.stop_flag then
+ -- end
+ return
+ else
+ -- take next instruction
+ tfm.dump.kernprogram(current_step+1+skip_byte,current_char)
+ end
+ end
+
+
+tfm.build = {}
+tfm.build.header =
+ function(i,j,w)
+ local _i,_j,_a = i,j,{}
+ for i=_i,_j do
+ if i<=1 or i>17 then
+ _a[i] =2^24*string.byte(w())+2^16*string.byte(w())+2^8*string.byte(w())+string.byte(w())
+ elseif 2<=i and i<=16 then
+ _a[i] =w()..w()..w()..w()
+ elseif i==17 then
+ _a[i] ={string.byte(w()),string.byte(w()),string.byte(w()),string.byte(w())}
+ end
+ end
+ return _a
+ end
+
+tfm.build._bytearray =
+ function(i,j,w)
+ local _i,_j,_a = i,j,{}
+ for i=_i,_j do
+ _a[i] ={string.byte(w()),string.byte(w()),string.byte(w()),string.byte(w())}
+ end
+ return _a
+ end
+tfm.build.char_info = tfm.build._bytearray
+tfm.build.lig_kern = tfm.build._bytearray
+tfm.build.exten = tfm.build._bytearray
+
+tfm.build._dimension =
+ function(i,j,w)
+ local _i,_j,_a = i,j,{}
+ for i=_i,_j do
+ _a[i] = tfm.int_to_frac(2^24*string.byte(w())+2^16*string.byte(w())+2^8*string.byte(w())+string.byte(w()))
+ end
+ return _a
+ end
+tfm.build.width = tfm.build._dimension
+tfm.build.height = tfm.build._dimension
+tfm.build.depth = tfm.build._dimension
+tfm.build.italic = tfm.build._dimension
+tfm.build.kern = tfm.build._dimension
+tfm.build.param = tfm.build._dimension
+
+tfm.build.all =
+ 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
+ tfm.array.header = tfm.build.header(0,lh-1,w)
+ tfm.array.char_info = tfm.build.char_info(bc,ec,w)
+ tfm.array.width = tfm.build.width( 0,nw-1,w)
+ tfm.array.height = tfm.build.height(0,nh-1,w)
+ tfm.array.depth = tfm.build.depth( 0,nd-1,w)
+ tfm.array.italic = tfm.build.italic(0,ni-1,w)
+ tfm.array.lig_kern = tfm.build.lig_kern(0,nl-1,w)
+ tfm.array.kern = tfm.build.kern(0,nk-1,w)
+ tfm.array.exten = tfm.build.exten(0,ne-1,w)
+ tfm.array.param = tfm.build.param(1,np,w)
+ end
+
+tfm.debug = 1
+tfm.printdebug =
+ function()
+ if tfm.debug==1 then
+ return print
+ else
+ return function(...) end
+ end
+ end
+
+tfm.getdata={}
+tfm.getdata.char_info =
+ function(i)
+ local char_info = tfm.array.char_info
+ local width_index = char_info[i][1]
+ local height_index_plus_depth_index = char_info[i][2]
+ local italic_index_plus_tag = char_info[i][3]
+ local remainder = char_info[i][4]
+ local depth_index = height_index_plus_depth_index % 16
+ local height_index= (height_index_plus_depth_index -depth_index)/16
+ local tag = italic_index_plus_tag % 4
+ local italic_index = (italic_index_plus_tag -tag)/4
+ return width_index,remainder,depth_index,height_index,tag,italic_index
+ end
+tfm.chars = {}
+tfm.font = {}
+
+tfm.run=
+ function(name)
+ local name = name
+ local _print = tfm.printdebug
+ local header ={}
+ local char_info ={}
+ local width ={}
+ local height ={}
+ local depth ={}
+ local italic ={}
+ local lig_kern ={}
+ local kern ={}
+ local exten ={}
+ local param ={}
+ local w
+ local lf
+ local lh
+ local bc
+ local ec
+ local nw
+ local nh
+ local nd
+ local ni
+ local nl
+ local nk
+ local ne
+ local np
+
+ if kpse.find_file(name)==nil then
+ name = name .. ".tfm"
+ end
+ if kpse.find_file(name)==nil then
+ return false, "Error: file "..tostring(name).." not found"
+ end
+ tfm.name = name
+ tfm.file = io.open(tfm.name,'rb')
+ if tfm.file == nil then
+ return false, "Error on opening file "..tostring(tfm.name)
+ end
+ tfm.content = tfm.file:read("*a")
+ status,status_msg = tfm.parameters.init()
+ if status== false then
+ _print("ERROR="..tostring(status_msg))
+ return false, tostring(status_msg)
+ end
+
+ status,status_msg = tfm.parameters.check()
+ if status == false then
+ _print("ERROR="..tostring(status_msg))
+ return false, tostring(status_msg)
+ end
+ -- Build all arrays
+ tfm.build.all()
+ header = tfm.array.header
+ char_info = tfm.array.char_info
+ width = tfm.array.width
+ height = tfm.array.height
+ depth = tfm.array.depth
+ italic = tfm.array.italic
+ lig_kern = tfm.array.lig_kern
+ kern = tfm.array.kern
+ exten = tfm.array.exten
+ param = tfm.array.param
+
+ w = tfm.parameters.w
+ lf = tfm.parameters.lf
+ lh = tfm.parameters.lh
+ bc = tfm.parameters.bc
+ ec = tfm.parameters.ec
+ nw = tfm.parameters.nw
+ nh = tfm.parameters.nh
+ nd = tfm.parameters.nd
+ ni = tfm.parameters.ni
+ nl = tfm.parameters.nl
+ nk = tfm.parameters.nk
+ ne = tfm.parameters.ne
+ np = tfm.parameters.np
+
+ status,status_msg = tfm.array.check()
+ if status == false then
+ _print("ERROR="..tostring(status_msg))
+ return false, tostring(status_msg)
+ end
+ tfm.font.checksum =header[0]
+ tfm.font.designsize = tfm.int_to_frac(header[1])
+ local coding_scheme
+ if header[2]~= nil then
+ coding_scheme = ''
+ for j=2,11 do coding_scheme=coding_scheme..tostring(header[j]) end
+ tfm.font.coding_scheme=coding_scheme
+ _print(string.format("CODING SCHEME:%s",tfm.font.coding_scheme))
+ end
+ local font_identifier
+ if header[12]~= nil then
+ font_identifier = ''
+ for j=12,16 do font_identifier=font_identifier..tostring(header[j]) end
+ tfm.font.font_identifier=font_identifier
+ _print(string.format("FONT IDENTIFIER:%s",tfm.font.font_identifier))
+ end
+ local seven_bit_safe_flag ,face
+ if header[17]~= nil then
+ seven_bit_safe_flag ,face = header[17][1],header[17][4]
+ tfm.font.seven_bit_safe_flag = seven_bit_safe_flag
+ tfm.font.face = face
+ _print(string.format("SEVEN_BIT_SAFE_FLAG=%x",seven_bit_safe_flag))
+ local f,t = tfm.getface(face)
+ face = f
+ _print(string.format("FACE=%s (mbl=%d,ri=%d,rce=%d)",face,t[1],t[2],t[3]))
+ end
+ local _pf = tfm.printfloat
+ for current_char=bc,ec do
+ --for current_char=102,102 do
+ local width_index,remainder,depth_index,height_index,tag,italic_index = tfm.getdata.char_info(current_char)
+ tfm.chars[current_char] = tfm.chars[current_char] or {}
+ tfm.chars[current_char].width = width[width_index]
+ tfm.chars[current_char].height = height[height_index]
+ tfm.chars[current_char].depth = depth[depth_index]
+ tfm.chars[current_char].italic = italic[italic_index]
+ tfm.chars[current_char].tag = tag
+ _print(i,string.format("O %o",current_char),string.char(current_char),
+ 'WIDTH='.._pf(width[width_index]),
+ 'HEIGHT='.._pf(height[height_index]),
+ 'DEPTH='.._pf(depth[depth_index]),
+ 'ITALIC='.._pf(italic[italic_index]),
+ 'TAG='..tfm.tag_meaning(tag)
+ )
+ if tag==1 then -- character has a ligature/kerning program
+ local kern_program = tfm.dump.kernprogram(remainder,current_char)
+ end
+ end
+ tfm.font.slant = param[1]
+ _print("SLANT=".._pf(tfm.font.slant))
+
+ tfm.font.space = param[2]
+ _print("SPACE=".._pf(tfm.font.space))
+
+ tfm.font.space_stretch = param[3]
+ _print("SPACE_STRETCH=".._pf(tfm.font.space_stretch))
+
+ tfm.font.space_shrink = param[4]
+ _print("SPACE_SHRINK=".._pf(tfm.font.space_shrink))
+
+ tfm.font.x_height = param[5]
+ _print("X_HEIGHT=".._pf(tfm.font.x_height))
+
+ tfm.font.quad = param[6]
+ _print("QUAD=".._pf(tfm.font.quad))
+
+ tfm.font.extra_space = param[7]
+ _print("EXTRA_SPACE=".._pf(tfm.font.extra_space))
+
+ return true,'ok'
+
+ end
+--------------------------------------------------------------------------------
+
+-- Add tfm to the mflua table
+mflua.tfm = tfm
+
+
+
diff --git a/Master/texmf-dist/scripts/mflua/mflua_svg_backend.lua b/Master/texmf-dist/scripts/mflua/mflua_svg_backend.lua
new file mode 100644
index 00000000000..67bdeb97058
--- /dev/null
+++ b/Master/texmf-dist/scripts/mflua/mflua_svg_backend.lua
@@ -0,0 +1,538 @@
+--
+--
+-- Experimental svg back end
+--
+--
+
+--print ("mflua_svg_backend")
+local MFbuiltin = mflua.MFbuiltin
+local MF = mflua.MF
+print_scaled = mflua.MF.print_scaled
+
+local svg = svg or {}
+svg = {
+ ['enabled']=true,
+ ['enabled_raw']=false,
+ ['output_dir']='svg',
+ ['svg_preamble'] = [=[<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="15cm" height="15cm" viewBox="%s %s %s %s"
+ xmlns="http://www.w3.org/2000/svg" version="1.1">
+ <title>cubic Bézier commands in path data</title>
+ <desc>B char</desc>
+ <style type="text/css"><![CDATA[
+ .Border { fill:none; stroke:blue; stroke-width:1 }
+ .Connect { fill:none; stroke:#888888; stroke-width:2 }
+ .SamplePath { fill:none; stroke:black; stroke-width:1 }
+ .EndPoint { fill:none; stroke:#888888; stroke-width:2 }
+ .CtlPoint { fill:#888888; stroke:none }
+ .AutoCtlPoint { fill:none; stroke:blue; stroke-width:4 }
+ .Label { font-size:22; font-family:Verdana }
+ ]]></style>
+ <g transform="matrix(1 0 0 -1 0 0)">
+ <g transform="translate(0 %s)">
+ %s
+ </g>
+ </g>
+ </svg>]=],
+ ['emsize']= 1000,
+ ['filename']= 'SourceCode',
+ ['font'] = [=[
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg>
+<metadata>
+Created by FontForge 20110222 at Sun Sep 18 10:37:34 2011
+ By root
+Copyleft 2002, 2003, 2005 Free Software Foundation.
+ </metadata>
+<defs>
+<font id="SourceCode" >
+ <font-face
+ font-size='%s'
+ units-per-em="%s"
+ ascent='800' descent='200'
+ x-height='%s'
+ font-family="SourceCode"
+ font-weight="400"
+ font-stretch="normal"
+ panose-1="2 2 6 3 5 4 5 2 3 4"
+ alphabetic='0'
+ />
+ <missing-glyph horiz-adv-x="280" />
+
+ %s
+ </font>
+</defs></svg>
+]=],
+['glyph'] =
+ [==[<glyph glyph-name="%s" unicode="%s" orientation="h"
+ horiz-adv-x="%s" vert-adv-y="%s"
+ d="%s" >%s
+ </glyph>
+]==],
+['hkern'] = [==[<hkern g1="%s" u1="%s" g2="%s" u2="%s" k="%s" />]==],
+['vkern'] = [==[<vkern g1="%s" u1="%s" g2="%s" u2="%s" k="%s" />]==],
+['hkerns']='',
+['vkerns']='',
+['char']={
+ ['0']={glyph_name='uni0393',unicode='&#x0393;'}, -- U+0393 GREEK CAPITAL LETTER GAMMA
+ ['1']={glyph_name='uni0394',unicode='&#x0394;'}, --U+0394 GREEK CAPITAL LETTER DELTA
+ ['2']={glyph_name='uni0398',unicode='&#x0398;'}, -- U+0398 GREEK CAPITAL LETTER THETA
+ ['3']={glyph_name='uni039b',unicode='&#x039b;'}, -- U+039B GREEK CAPITAL LETTER LAMBDA
+ ['4']={glyph_name='uni039e',unicode='&#x039e;'}, --U+039E GREEK CAPITAL LETTER XI
+ ['5']={glyph_name='uni03a0',unicode='&#x03a0;'}, --U+03A0 GREEK CAPITAL LETTER PI
+ ['6']={glyph_name='uni03a3',unicode='&#x03a3;'}, -- U+03A3 GREEK CAPITAL LETTER SIGMA
+ ['7']={glyph_name='uni03a5',unicode='&#x03a5;'}, --U+03A5 GREEK CAPITAL LETTER UPSILON
+ ['8']={glyph_name='uni03a6',unicode='&#x03a6;'}, -- U+03A6 GREEK CAPITAL LETTER PHI
+ ['9']={glyph_name='uni03a8',unicode='&#x03a8;'}, -- U+03A8 GREEK CAPITAL LETTER PSI
+ ['10']={glyph_name='uni03a9',unicode='&#x03a9;'}, -- 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='&#x0131;'}, -- U+0131 LATIN SMALL LETTER DOTLESS I
+ ['17']={glyph_name='uni0237',unicode='&#x0237;'}, -- U+0237 LATIN SMALL LETTER DOTLESS J
+ ['18']={glyph_name='uni0060',unicode='&#x0060;'}, -- U+0060 GRAVE ACCENT
+ ['19']={glyph_name='uni00b4',unicode='&#x00b4;'}, -- U+00B4 ACUTE ACCENT
+ ['20']={glyph_name='uni02c7',unicode='&#x02c7;'}, -- U+02C7 CARON
+ ['21']={glyph_name='uni02d8',unicode='&#x02d8;'}, -- U+02D8 BREVE
+ ['22']={glyph_name='uni00af',unicode='&#x00af;'}, -- U+00AF MACRON
+ ['23']={glyph_name='uni02da',unicode='&#x02da;'}, -- U+02DA RING ABOVE
+ ['24']={glyph_name='uni00b8',unicode='&#x00b8;'}, -- U+00B8 CEDILLA
+ ['25']={glyph_name='uni00df',unicode='&#x00df;'}, -- U+00DF LATIN SMALL LETTER SHARP S
+ ['26']={glyph_name='uni00e6',unicode='&#x00e6;'}, -- U+00E6 LATIN SMALL LETTER AE
+ ['27']={glyph_name='uni0153',unicode='&#x0153;'}, -- U+0153 LATIN SMALL LIGATURE OE
+ ['28']={glyph_name='uni00f8',unicode='&#x00f8;'}, -- U+00F8 LATIN SMALL LETTER O WITH STROKE
+ ['29']={glyph_name='uni00c6',unicode='&#x00c6;'}, --U+00C6 LATIN CAPITAL LETTER AE
+ ['30']={glyph_name='uni0152',unicode='&#x0152;'}, --U+0152 LATIN CAPITAL LIGATURE OE
+ ['31']={glyph_name='uni00D8',unicode='&#x00D8;'}, --U+00D8 LATIN CAPITAL LETTER O WITH STROKE
+ ['32']={glyph_name='uni0337',unicode='&#x0337;'}, --U+0337 COMBINING SHORT SOLIDUS OVERLAY
+ ['33']={glyph_name='uni0021',unicode='&#x0021;'},
+ ['34']={glyph_name='uni201d',unicode='&#x201d;'}, -- U+201D RIGHT DOUBLE QUOTATION MARK
+ ['35']={glyph_name='uni0023',unicode='&#x0023;'},
+ ['36']={glyph_name='uni0024',unicode='&#x0024;'},
+ ['37']={glyph_name='uni0025',unicode='&#x0025;'},
+ ['38']={glyph_name='uni0026',unicode='&#x0026;'},
+ ['39']={glyph_name='uni0027',unicode='&#x0027;'},
+ ['40']={glyph_name='uni0028',unicode='&#x0028;'},
+ ['41']={glyph_name='uni0029',unicode='&#x0029;'},
+ ['42']={glyph_name='uni002a',unicode='&#x002a;'},
+ ['43']={glyph_name='uni002b',unicode='&#x002b;'},
+ ['44']={glyph_name='uni002c',unicode='&#x002c;'},
+ ['45']={glyph_name='uni002d',unicode='&#x002d;'}, -- U+002D HYPHEN-MINUS
+ ['46']={glyph_name='uni002e',unicode='&#x002e;'},
+ ['47']={glyph_name='uni002f',unicode='&#x002f;'},
+ ['48']={glyph_name='uni0030',unicode='&#x0030;'},
+ ['49']={glyph_name='uni0031',unicode='&#x0031;'},
+ ['50']={glyph_name='uni0032',unicode='&#x0032;'},
+ ['51']={glyph_name='uni0033',unicode='&#x0033;'},
+ ['52']={glyph_name='uni0034',unicode='&#x0034;'},
+ ['53']={glyph_name='uni0035',unicode='&#x0035;'},
+ ['54']={glyph_name='uni0036',unicode='&#x0036;'},
+ ['55']={glyph_name='uni0037',unicode='&#x0037;'},
+ ['56']={glyph_name='uni0038',unicode='&#x0038;'},
+ ['57']={glyph_name='uni0039',unicode='&#x0039;'},
+ ['58']={glyph_name='uni003a',unicode='&#x003a;'},
+ ['59']={glyph_name='uni003b',unicode='&#x003b;'},
+ ['60']={glyph_name='uni00a1',unicode='&#x00a1;'}, -- U+00A1 INVERTED EXCLAMATION MARK, but only if ligs>1
+ ['61']={glyph_name='uni003d',unicode='&#x003d;'},
+ ['62']={glyph_name='uni00bf',unicode='&#x00bf;'}, --U+00BF INVERTED QUESTION MARK
+ ['63']={glyph_name='uni003f',unicode='&#x003f;'},
+ ['64']={glyph_name='uni0040',unicode='&#x0040;'},
+ ['65']={glyph_name='uni0041',unicode='&#x0041;'},
+ ['66']={glyph_name='uni0042',unicode='&#x0042;'},
+ ['67']={glyph_name='uni0043',unicode='&#x0043;'},
+ ['68']={glyph_name='uni0044',unicode='&#x0044;'},
+ ['69']={glyph_name='uni0045',unicode='&#x0045;'},
+ ['70']={glyph_name='uni0046',unicode='&#x0046;'},
+ ['71']={glyph_name='uni0047',unicode='&#x0047;'},
+ ['72']={glyph_name='uni0048',unicode='&#x0048;'},
+ ['73']={glyph_name='uni0049',unicode='&#x0049;'},
+ ['74']={glyph_name='uni004a',unicode='&#x004a;'},
+ ['75']={glyph_name='uni004b',unicode='&#x004b;'},
+ ['76']={glyph_name='uni004c',unicode='&#x004c;'},
+ ['77']={glyph_name='uni004d',unicode='&#x004d;'},
+ ['78']={glyph_name='uni004e',unicode='&#x004e;'},
+ ['79']={glyph_name='uni004f',unicode='&#x004f;'},
+ ['80']={glyph_name='uni0050',unicode='&#x0050;'},
+ ['81']={glyph_name='uni0051',unicode='&#x0051;'},
+ ['82']={glyph_name='uni0052',unicode='&#x0052;'},
+ ['83']={glyph_name='uni0053',unicode='&#x0053;'},
+ ['84']={glyph_name='uni0054',unicode='&#x0054;'},
+ ['85']={glyph_name='uni0055',unicode='&#x0055;'},
+ ['86']={glyph_name='uni0056',unicode='&#x0056;'},
+ ['87']={glyph_name='uni0057',unicode='&#x0057;'},
+ ['88']={glyph_name='uni0058',unicode='&#x0058;'},
+ ['89']={glyph_name='uni0059',unicode='&#x0059;'},
+ ['90']={glyph_name='uni005a',unicode='&#x005a;'},
+ ['91']={glyph_name='uni005b',unicode='&#x005b;'},
+ ['92']={glyph_name='uni201c',unicode='&#x201c;'}, -- U+201C LEFT DOUBLE QUOTATION MARK
+ ['93']={glyph_name='uni005d',unicode='&#x005d;'},
+ ['94']={glyph_name='uni0302',unicode='&#x0302;'}, --U+0302 COMBINING CIRCUMFLEX ACCENT
+ ['95']={glyph_name='uni0307',unicode='&#x0307;'}, --U+0307 COMBINING DOT ABOVE
+ ['96']={glyph_name='uni2018',unicode='&#x2018;'}, --U+2018 LEFT SINGLE QUOTATION MARK
+ ['97']={glyph_name='uni0061',unicode='&#x0061;'},
+ ['98']={glyph_name='uni0062',unicode='&#x0062;'},
+ ['99']={glyph_name='uni0063',unicode='&#x0063;'},
+ ['100']={glyph_name='uni0064',unicode='&#x0064;'},
+ ['101']={glyph_name='uni0065',unicode='&#x0065;'},
+ ['102']={glyph_name='uni0066',unicode='&#x0066;'},
+ ['103']={glyph_name='uni0067',unicode='&#x0067;'},
+ ['104']={glyph_name='uni0068',unicode='&#x0068;'},
+ ['105']={glyph_name='uni0069',unicode='&#x0069;'},
+ ['106']={glyph_name='uni006a',unicode='&#x006a;'},
+ ['107']={glyph_name='uni006b',unicode='&#x006b;'},
+ ['108']={glyph_name='uni006c',unicode='&#x006c;'},
+ ['109']={glyph_name='uni006d',unicode='&#x006d;'},
+ ['110']={glyph_name='uni006e',unicode='&#x006e;'},
+ ['111']={glyph_name='uni006f',unicode='&#x006f;'},
+ ['112']={glyph_name='uni0070',unicode='&#x0070;'},
+ ['113']={glyph_name='uni0071',unicode='&#x0071;'},
+ ['114']={glyph_name='uni0072',unicode='&#x0072;'},
+ ['115']={glyph_name='uni0073',unicode='&#x0073;'},
+ ['116']={glyph_name='uni0074',unicode='&#x0074;'},
+ ['117']={glyph_name='uni0075',unicode='&#x0075;'},
+ ['118']={glyph_name='uni0076',unicode='&#x0076;'},
+ ['119']={glyph_name='uni0077',unicode='&#x0077;'},
+ ['120']={glyph_name='uni0078',unicode='&#x0078;'},
+ ['121']={glyph_name='uni0079',unicode='&#x0079;'},
+ ['122']={glyph_name='uni007a',unicode='&#x007a;'},
+ ['123']={glyph_name='uni2013',unicode='&#x2013;'}, -- U+2013 EN DASH
+ ['124']={glyph_name='uni2014',unicode='&#x2014;'}, -- U+2014 EM DASH
+ ['125']={glyph_name='uni030b',unicode='&#x030b;'}, --U+030B COMBINING DOUBLE ACUTE ACCENT
+ ['126']={glyph_name='uni0303',unicode='&#x0303;'}, --U+0303 COMBINING TILDE
+ ['127']={glyph_name='uni0308',unicode='&#x0308;'}, --U+0308 COMBINING DIAERESIS
+ ['128']={glyph_name='uni0080',unicode='&#x0080;'},
+ ['129']={glyph_name='uni0081',unicode='&#x0081;'},
+ ['130']={glyph_name='uni0082',unicode='&#x0082;'},
+ ['131']={glyph_name='uni0083',unicode='&#x0083;'},
+ ['132']={glyph_name='uni0084',unicode='&#x0084;'},
+ ['133']={glyph_name='uni0085',unicode='&#x0085;'},
+ ['134']={glyph_name='uni0086',unicode='&#x0086;'},
+ ['135']={glyph_name='uni0087',unicode='&#x0087;'},
+ ['136']={glyph_name='uni0088',unicode='&#x0088;'},
+ ['137']={glyph_name='uni0089',unicode='&#x0089;'},
+ ['138']={glyph_name='uni008a',unicode='&#x008a;'},
+ ['139']={glyph_name='uni008b',unicode='&#x008b;'},
+ ['140']={glyph_name='uni008c',unicode='&#x008c;'},
+ ['141']={glyph_name='uni008d',unicode='&#x008d;'},
+ ['142']={glyph_name='uni008e',unicode='&#x008e;'},
+ ['143']={glyph_name='uni008f',unicode='&#x008f;'},
+ ['144']={glyph_name='uni0090',unicode='&#x0090;'},
+ ['145']={glyph_name='uni0091',unicode='&#x0091;'},
+ ['146']={glyph_name='uni0092',unicode='&#x0092;'},
+ ['147']={glyph_name='uni0093',unicode='&#x0093;'},
+ ['148']={glyph_name='uni0094',unicode='&#x0094;'},
+ ['149']={glyph_name='uni0095',unicode='&#x0095;'},
+ ['150']={glyph_name='uni0096',unicode='&#x0096;'},
+ ['151']={glyph_name='uni0097',unicode='&#x0097;'},
+ ['152']={glyph_name='uni0098',unicode='&#x0098;'},
+ ['153']={glyph_name='uni0099',unicode='&#x0099;'},
+ ['154']={glyph_name='uni009a',unicode='&#x009a;'},
+ ['155']={glyph_name='uni009b',unicode='&#x009b;'},
+ ['156']={glyph_name='uni009c',unicode='&#x009c;'},
+ ['157']={glyph_name='uni009d',unicode='&#x009d;'},
+ ['158']={glyph_name='uni009e',unicode='&#x009e;'},
+ ['159']={glyph_name='uni009f',unicode='&#x009f;'},
+ ['160']={glyph_name='uni00a0',unicode='&#x00a0;'},
+ ['161']={glyph_name='uni00a1',unicode='&#x00a1;'},
+ ['162']={glyph_name='uni00a2',unicode='&#x00a2;'},
+ ['163']={glyph_name='uni00a3',unicode='&#x00a3;'},
+ ['164']={glyph_name='uni00a4',unicode='&#x00a4;'},
+ ['165']={glyph_name='uni00a5',unicode='&#x00a5;'},
+ ['166']={glyph_name='uni00a6',unicode='&#x00a6;'},
+ ['167']={glyph_name='uni00a7',unicode='&#x00a7;'},
+ ['168']={glyph_name='uni00a8',unicode='&#x00a8;'},
+ ['169']={glyph_name='uni00a9',unicode='&#x00a9;'},
+ ['170']={glyph_name='uni00aa',unicode='&#x00aa;'},
+ ['171']={glyph_name='uni00ab',unicode='&#x00ab;'},
+ ['172']={glyph_name='uni00ac',unicode='&#x00ac;'},
+ ['173']={glyph_name='uni00ad',unicode='&#x00ad;'},
+ ['174']={glyph_name='uni00ae',unicode='&#x00ae;'},
+ ['175']={glyph_name='uni00af',unicode='&#x00af;'},
+ ['176']={glyph_name='uni00b0',unicode='&#x00b0;'},
+ ['177']={glyph_name='uni00b1',unicode='&#x00b1;'},
+ ['178']={glyph_name='uni00b2',unicode='&#x00b2;'},
+ ['179']={glyph_name='uni00b3',unicode='&#x00b3;'},
+ ['180']={glyph_name='uni00b4',unicode='&#x00b4;'},
+ ['181']={glyph_name='uni00b5',unicode='&#x00b5;'},
+ ['182']={glyph_name='uni00b6',unicode='&#x00b6;'},
+ ['183']={glyph_name='uni00b7',unicode='&#x00b7;'},
+ ['184']={glyph_name='uni00b8',unicode='&#x00b8;'},
+ ['185']={glyph_name='uni00b9',unicode='&#x00b9;'},
+ ['186']={glyph_name='uni00ba',unicode='&#x00ba;'},
+ ['187']={glyph_name='uni00bb',unicode='&#x00bb;'},
+ ['188']={glyph_name='uni00bc',unicode='&#x00bc;'},
+ ['189']={glyph_name='uni00bd',unicode='&#x00bd;'},
+ ['190']={glyph_name='uni00be',unicode='&#x00be;'},
+ ['191']={glyph_name='uni00bf',unicode='&#x00bf;'},
+ ['192']={glyph_name='uni00c0',unicode='&#x00c0;'},
+-- ['193']={glyph_name='uni00c1',unicode='&#x00c1;'},
+ ['193']={glyph_name='uni0060',unicode='&#x0060;'},
+-- ['194']={glyph_name='uni00c2',unicode='&#x00c2;'},
+ ['194']={glyph_name='uni00b4',unicode='&#x00b4;'},
+-- ['195']={glyph_name='uni00c3',unicode='&#x00c3;'},
+ ['195']={glyph_name='uni005e',unicode='&#x005e;'},
+ ['196']={glyph_name='uni00c4',unicode='&#x00c4;'},
+ ['197']={glyph_name='uni00c5',unicode='&#x00c5;'},
+ ['198']={glyph_name='uni00c6',unicode='&#x00c6;'},
+ ['199']={glyph_name='uni00c7',unicode='&#x00c7;'},
+ ['200']={glyph_name='uni00c8',unicode='&#x00c8;'},
+ ['201']={glyph_name='uni00c9',unicode='&#x00c9;'},
+ ['202']={glyph_name='uni00ca',unicode='&#x00ca;'},
+ ['203']={glyph_name='uni00cb',unicode='&#x00cb;'},
+ ['204']={glyph_name='uni00cc',unicode='&#x00cc;'},
+ ['205']={glyph_name='uni00cd',unicode='&#x00cd;'},
+ ['206']={glyph_name='uni00ce',unicode='&#x00ce;'},
+ ['207']={glyph_name='uni00cf',unicode='&#x00cf;'},
+ ['208']={glyph_name='uni00d0',unicode='&#x00d0;'},
+ ['209']={glyph_name='uni00d1',unicode='&#x00d1;'},
+ ['210']={glyph_name='uni00d2',unicode='&#x00d2;'},
+ ['211']={glyph_name='uni00d3',unicode='&#x00d3;'},
+ ['212']={glyph_name='uni00d4',unicode='&#x00d4;'},
+ ['213']={glyph_name='uni00d5',unicode='&#x00d5;'},
+ ['214']={glyph_name='uni00d6',unicode='&#x00d6;'},
+ ['215']={glyph_name='uni00d7',unicode='&#x00d7;'},
+ ['216']={glyph_name='uni00d8',unicode='&#x00d8;'},
+ ['217']={glyph_name='uni00d9',unicode='&#x00d9;'},
+ ['218']={glyph_name='uni00da',unicode='&#x00da;'},
+ ['219']={glyph_name='uni00db',unicode='&#x00db;'},
+ ['220']={glyph_name='uni00dc',unicode='&#x00dc;'},
+ ['221']={glyph_name='uni00dd',unicode='&#x00dd;'},
+ ['222']={glyph_name='uni00de',unicode='&#x00de;'},
+ ['223']={glyph_name='uni00df',unicode='&#x00df;'},
+ ['224']={glyph_name='uni00e0',unicode='&#x00e0;'},
+ ['225']={glyph_name='uni00e1',unicode='&#x00e1;'},
+ ['226']={glyph_name='uni00e2',unicode='&#x00e2;'},
+ ['227']={glyph_name='uni00e3',unicode='&#x00e3;'},
+ ['228']={glyph_name='uni00e4',unicode='&#x00e4;'},
+ ['229']={glyph_name='uni00e5',unicode='&#x00e5;'},
+ ['230']={glyph_name='uni00e6',unicode='&#x00e6;'},
+ ['231']={glyph_name='uni00e7',unicode='&#x00e7;'},
+ ['232']={glyph_name='uni00e8',unicode='&#x00e8;'},
+ ['233']={glyph_name='uni00e9',unicode='&#x00e9;'},
+ ['234']={glyph_name='uni00ea',unicode='&#x00ea;'},
+ ['235']={glyph_name='uni00eb',unicode='&#x00eb;'},
+ ['236']={glyph_name='uni00ec',unicode='&#x00ec;'},
+ ['237']={glyph_name='uni00ed',unicode='&#x00ed;'},
+ ['238']={glyph_name='uni00ee',unicode='&#x00ee;'},
+ ['239']={glyph_name='uni00ef',unicode='&#x00ef;'},
+ ['240']={glyph_name='uni00f0',unicode='&#x00f0;'},
+ ['241']={glyph_name='uni00f1',unicode='&#x00f1;'},
+ ['242']={glyph_name='uni00f2',unicode='&#x00f2;'},
+ ['243']={glyph_name='uni00f3',unicode='&#x00f3;'},
+ ['244']={glyph_name='uni00f4',unicode='&#x00f4;'},
+ ['245']={glyph_name='uni00f5',unicode='&#x00f5;'},
+ ['246']={glyph_name='uni00f6',unicode='&#x00f6;'},
+ ['247']={glyph_name='uni00f7',unicode='&#x00f7;'},
+ ['248']={glyph_name='uni00f8',unicode='&#x00f8;'},
+ ['249']={glyph_name='uni00f9',unicode='&#x00f9;'},
+ ['250']={glyph_name='uni00fa',unicode='&#x00fa;'},
+ ['251']={glyph_name='uni00fb',unicode='&#x00fb;'},
+ ['252']={glyph_name='uni00fc',unicode='&#x00fc;'},
+ ['253']={glyph_name='uni00fd',unicode='&#x00fd;'},
+ ['254']={glyph_name='uni00fe',unicode='&#x00fe;'},
+ ['255']={glyph_name='uni00ff',unicode='&#x00ff;'},
+ ['256']={glyph_name='uni0100',unicode='&#x0100;'},
+ },
+
+}
+
+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]<minx then minx=p[1] end
+ if c1[1]<minx then minx=c1[1] end
+ if c2[1]<minx then minx=c2[1] end
+ if q[1]<minx then minx=q[1] end
+ if p[2]<miny then miny=p[2] end
+ if c1[2]<miny then miny=c1[2] end
+ if c2[2]<miny then miny=c2[2] end
+ if q[2]<miny then miny=q[2] end
+ end
+ bezier = bezier .. 'Z\n'
+ end
+ --print('BEZ (x,y) (X,Y)=',minx,miny,maxx,maxy)
+ --print('BEZ', svg_glyph,glyph_name,unicode,char_wd_emunit,char_ht_emunit,bezier)
+ local trunk = ''
+ local svg_glyph = mflua.svg.glyph
+ local svg_font = mflua.svg.font
+ trunk = string.format(svg_glyph,
+ glyph_name,unicode,
+ char_wd_emunit,
+ char_ht_emunit,
+ bezier,'')
+ local svg_preamble = mflua.svg.svg_preamble
+ local paths = string.format('<path style="fill:#000000;stroke=none;fill-rule:nonzero" d="%s" />', 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/Master/texmf-dist/scripts/mflua/mflua_ttx_backend.lua b/Master/texmf-dist/scripts/mflua/mflua_ttx_backend.lua
new file mode 100644
index 00000000000..851ff284ef3
--- /dev/null
+++ b/Master/texmf-dist/scripts/mflua/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]=name
+ local _t={}
+ for k,v in pairs(t) do
+ if not(type(k)=='number') then
+ _t[#_t+1]=k
+ end
+ end
+ 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_xml_header(t)
+ local _t={}
+ local elem={}
+ elem[#elem+1]='<?'
+ elem[#elem+1]='xml '
+ elem[#elem+1]=t
+ 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]=name
+ 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
diff --git a/Master/texmf-dist/scripts/mflua/mfluaini.lua b/Master/texmf-dist/scripts/mflua/mfluaini.lua
deleted file mode 100644
index 0711ed9dddb..00000000000
--- a/Master/texmf-dist/scripts/mflua/mfluaini.lua
+++ /dev/null
@@ -1 +0,0 @@
--- empty
diff --git a/Master/texmf-dist/scripts/mflua/offset_prep.lua b/Master/texmf-dist/scripts/mflua/offset_prep.lua
deleted file mode 100644
index 1452e0325cd..00000000000
--- a/Master/texmf-dist/scripts/mflua/offset_prep.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function PRE_offset_prep(c,h) return 0 end
-function POST_offset_prep(c,h) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/print_edges.lua b/Master/texmf-dist/scripts/mflua/print_edges.lua
deleted file mode 100644
index ae35ce6585e..00000000000
--- a/Master/texmf-dist/scripts/mflua/print_edges.lua
+++ /dev/null
@@ -1 +0,0 @@
-function print_edges(s,nuline,xoff,yoff) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/print_path.lua b/Master/texmf-dist/scripts/mflua/print_path.lua
deleted file mode 100644
index 1733bc9d2cd..00000000000
--- a/Master/texmf-dist/scripts/mflua/print_path.lua
+++ /dev/null
@@ -1 +0,0 @@
-function print_path(h,s,nuline) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/scan_direction.lua b/Master/texmf-dist/scripts/mflua/scan_direction.lua
deleted file mode 100644
index 6c896677f6c..00000000000
--- a/Master/texmf-dist/scripts/mflua/scan_direction.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function PRE_make_choices(p) return 0 end
-function POST_make_choices(p) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/skew_line_edges.lua b/Master/texmf-dist/scripts/mflua/skew_line_edges.lua
deleted file mode 100644
index 2ae9dc20a6a..00000000000
--- a/Master/texmf-dist/scripts/mflua/skew_line_edges.lua
+++ /dev/null
@@ -1 +0,0 @@
-function print_retrograde_line(x0,y0,cur_x,cur_y) return 0 end \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/mflua/start_of_mf.lua b/Master/texmf-dist/scripts/mflua/start_of_mf.lua
deleted file mode 100644
index 7c24087ca5d..00000000000
--- a/Master/texmf-dist/scripts/mflua/start_of_mf.lua
+++ /dev/null
@@ -1 +0,0 @@
-function PRE_start_of_MF() return 0 end \ No newline at end of file