luatex-fonts-merged.lua /size: 965 Kb    last modification: 2024-01-16 09:03
1-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
2-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
3-- merge date  : 2024-01-08 11:23
4
5do -- begin closure to overcome local limits and interference
6
7if not modules then modules={} end modules ['l-lua']={
8 version=1.001,
9 comment="companion to luat-lib.mkiv",
10 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
11 copyright="PRAGMA ADE / ConTeXt Development Team",
12 license="see context related readme files"
13}
14local next,type,tonumber=next,type,tonumber
15LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
16LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5
17LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1
18LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10
19if LUAVERSION<5.2 and jit then
20 MINORVERSION=2
21 LUAVERSION=5.2
22end
23if not lpeg then
24 lpeg=require("lpeg")
25end
26if loadstring then
27 local loadnormal=load
28 function load(first,...)
29  if type(first)=="string" then
30   return loadstring(first,...)
31  else
32   return loadnormal(first,...)
33  end
34 end
35else
36 loadstring=load
37end
38if not ipairs then
39 local function iterate(a,i)
40  i=i+1
41  local v=a[i]
42  if v~=nil then
43   return i,v 
44  end
45 end
46 function ipairs(a)
47  return iterate,a,0
48 end
49end
50if not pairs then
51 function pairs(t)
52  return next,t 
53 end
54end
55if not table.unpack then
56 table.unpack=_G.unpack
57elseif not unpack then
58 _G.unpack=table.unpack
59end
60if not package.loaders then 
61 package.loaders=package.searchers
62end
63local print,select,tostring=print,select,tostring
64local inspectors={}
65function setinspector(kind,inspector) 
66 inspectors[kind]=inspector
67end
68function inspect(...) 
69 for s=1,select("#",...) do
70  local value=select(s,...)
71  if value==nil then
72   print("nil")
73  else
74   local done=false
75   local kind=type(value)
76   local inspector=inspectors[kind]
77   if inspector then
78    done=inspector(value)
79    if done then
80     break
81    end
82   end
83   for kind,inspector in next,inspectors do
84    done=inspector(value)
85    if done then
86     break
87    end
88   end
89   if not done then
90    print(tostring(value))
91   end
92  end
93 end
94end
95local dummy=function() end
96function optionalrequire(...)
97 local ok,result=xpcall(require,dummy,...)
98 if ok then
99  return result
100 end
101end
102local flush=io.flush
103if flush then
104 local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end
105 local exec=os.exec if exec then function os.exec   (...) flush() return exec   (...) end end
106 local spawn=os.spawn   if spawn   then function os.spawn  (...) flush() return spawn  (...) end end
107 local popen=io.popen   if popen   then function io.popen  (...) flush() return popen  (...) end end
108end
109FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
110if not FFISUPPORTED then
111 local okay;okay,ffi=pcall(require,"ffi")
112 FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
113end
114if not FFISUPPORTED then
115 ffi=nil
116elseif not ffi.number then
117 ffi.number=tonumber
118end
119if LUAVERSION>5.3 then
120end
121if status and os.setenv then
122 os.setenv("engine",string.lower(status.luatex_engine or "unknown"))
123end
124
125end -- closure
126
127do -- begin closure to overcome local limits and interference
128
129if not modules then modules={} end modules ['l-lpeg']={
130 version=1.001,
131 comment="companion to luat-lib.mkiv",
132 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
133 copyright="PRAGMA ADE / ConTeXt Development Team",
134 license="see context related readme files"
135}
136lpeg=require("lpeg") 
137local lpeg=lpeg
138if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
139local type,next,tostring=type,next,tostring
140local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
141local floor=math.floor
142local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt
143local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print
144if setinspector then
145 setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end)
146end
147lpeg.patterns=lpeg.patterns or {} 
148local patterns=lpeg.patterns
149local anything=P(1)
150local endofstring=P(-1)
151local alwaysmatched=P(true)
152patterns.anything=anything
153patterns.endofstring=endofstring
154patterns.beginofstring=alwaysmatched
155patterns.alwaysmatched=alwaysmatched
156local sign=S('+-')
157local zero=P('0')
158local digit=R('09')
159local digits=digit^1
160local octdigit=R("07")
161local octdigits=octdigit^1
162local lowercase=R("az")
163local uppercase=R("AZ")
164local underscore=P("_")
165local hexdigit=digit+lowercase+uppercase
166local hexdigits=hexdigit^1
167local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
168local newline=P("\r")*(P("\n")+P(true))+P("\n")  
169local escaped=P("\\")*anything
170local squote=P("'")
171local dquote=P('"')
172local space=P(" ")
173local period=P(".")
174local comma=P(",")
175local utfbom_32_be=P('\000\000\254\255') 
176local utfbom_32_le=P('\255\254\000\000') 
177local utfbom_16_be=P('\254\255')   
178local utfbom_16_le=P('\255\254')   
179local utfbom_8=P('\239\187\191')  
180local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
181local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") 
182local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")
183local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0)
184local utf8next=R("\128\191")
185patterns.utfbom_32_be=utfbom_32_be
186patterns.utfbom_32_le=utfbom_32_le
187patterns.utfbom_16_be=utfbom_16_be
188patterns.utfbom_16_le=utfbom_16_le
189patterns.utfbom_8=utfbom_8
190patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") 
191patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") 
192patterns.utf_32_be_nl=P("\000\000\000\r\000\000\000\n")+P("\000\000\000\r")+P("\000\000\000\n")
193patterns.utf_32_le_nl=P("\r\000\000\000\n\000\000\000")+P("\r\000\000\000")+P("\n\000\000\000")
194patterns.utf8one=R("\000\127")
195patterns.utf8two=R("\194\223")*utf8next
196patterns.utf8three=R("\224\239")*utf8next*utf8next
197patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
198patterns.utfbom=utfbom
199patterns.utftype=utftype
200patterns.utfstricttype=utfstricttype
201patterns.utfoffset=utfoffset
202local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
203local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false)
204local utf8character=P(1)*R("\128\191")^0 
205patterns.utf8=utf8char
206patterns.utf8char=utf8char
207patterns.utf8character=utf8character 
208patterns.validutf8=validutf8char
209patterns.validutf8char=validutf8char
210local eol=S("\n\r")
211local spacer=S(" \t\f\v")  
212local whitespace=eol+spacer
213local nonspacer=1-spacer
214local nonwhitespace=1-whitespace
215patterns.eol=eol
216patterns.spacer=spacer
217patterns.whitespace=whitespace
218patterns.nonspacer=nonspacer
219patterns.nonwhitespace=nonwhitespace
220local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)  
221local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
222local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
223local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
224local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
225local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
226local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
227local x_collapser=Cs((nonwhitespace^1+whitespace^1/"" )^0)
228local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
229local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
230local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
231local x_stripper=Cs((nonspacer^1+spacer^1/"" )^0)
232patterns.stripper=stripper
233patterns.fullstripper=fullstripper
234patterns.collapser=collapser
235patterns.nospacer=nospacer
236patterns.b_collapser=b_collapser
237patterns.m_collapser=m_collapser
238patterns.e_collapser=e_collapser
239patterns.x_collapser=x_collapser
240patterns.b_stripper=b_stripper
241patterns.m_stripper=m_stripper
242patterns.e_stripper=e_stripper
243patterns.x_stripper=x_stripper
244patterns.lowercase=lowercase
245patterns.uppercase=uppercase
246patterns.letter=patterns.lowercase+patterns.uppercase
247patterns.space=space
248patterns.tab=P("\t")
249patterns.spaceortab=patterns.space+patterns.tab
250patterns.newline=newline
251patterns.emptyline=newline^1
252patterns.equal=P("=")
253patterns.comma=comma
254patterns.commaspacer=comma*spacer^0
255patterns.period=period
256patterns.colon=P(":")
257patterns.semicolon=P(";")
258patterns.underscore=underscore
259patterns.escaped=escaped
260patterns.squote=squote
261patterns.dquote=dquote
262patterns.nosquote=(escaped+(1-squote))^0
263patterns.nodquote=(escaped+(1-dquote))^0
264patterns.unsingle=(squote/"")*patterns.nosquote*(squote/"") 
265patterns.undouble=(dquote/"")*patterns.nodquote*(dquote/"") 
266patterns.unquoted=patterns.undouble+patterns.unsingle 
267patterns.unspacer=((patterns.spacer^1)/"")^0
268patterns.singlequoted=squote*patterns.nosquote*squote
269patterns.doublequoted=dquote*patterns.nodquote*dquote
270patterns.quoted=patterns.doublequoted+patterns.singlequoted
271patterns.digit=digit
272patterns.digits=digits
273patterns.octdigit=octdigit
274patterns.octdigits=octdigits
275patterns.hexdigit=hexdigit
276patterns.hexdigits=hexdigits
277patterns.sign=sign
278patterns.cardinal=digits
279patterns.integer=sign^-1*digits
280patterns.unsigned=digit^0*period*digits
281patterns.float=sign^-1*patterns.unsigned
282patterns.cunsigned=digit^0*comma*digits
283patterns.cpunsigned=digit^0*(period+comma)*digits
284patterns.cfloat=sign^-1*patterns.cunsigned
285patterns.cpfloat=sign^-1*patterns.cpunsigned
286patterns.number=patterns.float+patterns.integer
287patterns.cnumber=patterns.cfloat+patterns.integer
288patterns.cpnumber=patterns.cpfloat+patterns.integer
289patterns.oct=zero*octdigits 
290patterns.octal=patterns.oct
291patterns.HEX=zero*P("X")*(digit+uppercase)^1
292patterns.hex=zero*P("x")*(digit+lowercase)^1
293patterns.hexadecimal=zero*S("xX")*hexdigits
294patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigits+hexdigits*period*hexdigit^0+hexdigits)*(S("pP")*sign^-1*hexdigits)^-1
295patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)*S("eE")*sign^-1*digits
296patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
297patterns.somecontent=(anything-newline-space)^1 
298patterns.beginline=#(1-newline)
299patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0))
300local function anywhere(pattern) 
301 return (1-P(pattern))^0*P(pattern)
302end
303lpeg.anywhere=anywhere
304function lpeg.instringchecker(p)
305 p=anywhere(p)
306 return function(str)
307  return lpegmatch(p,str) and true or false
308 end
309end
310function lpeg.splitter(pattern,action)
311 if action then
312  return (((1-P(pattern))^1)/action+1)^0
313 else
314  return (Cs((1-P(pattern))^1)+1)^0
315 end
316end
317function lpeg.tsplitter(pattern,action)
318 if action then
319  return Ct((((1-P(pattern))^1)/action+1)^0)
320 else
321  return Ct((Cs((1-P(pattern))^1)+1)^0)
322 end
323end
324local splitters_s,splitters_m,splitters_t={},{},{}
325local function splitat(separator,single)
326 local splitter=(single and splitters_s[separator]) or splitters_m[separator]
327 if not splitter then
328  separator=P(separator)
329  local other=C((1-separator)^0)
330  if single then
331   local any=anything
332   splitter=other*(separator*C(any^0)+"") 
333   splitters_s[separator]=splitter
334  else
335   splitter=other*(separator*other)^0
336   splitters_m[separator]=splitter
337  end
338 end
339 return splitter
340end
341local function tsplitat(separator)
342 local splitter=splitters_t[separator]
343 if not splitter then
344  splitter=Ct(splitat(separator))
345  splitters_t[separator]=splitter
346 end
347 return splitter
348end
349lpeg.splitat=splitat
350lpeg.tsplitat=tsplitat
351function string.splitup(str,separator)
352 if not separator then
353  separator=","
354 end
355 return lpegmatch(splitters_m[separator] or splitat(separator),str)
356end
357local cache={}
358function lpeg.split(separator,str)
359 local c=cache[separator]
360 if not c then
361  c=tsplitat(separator)
362  cache[separator]=c
363 end
364 return lpegmatch(c,str)
365end
366function string.split(str,separator)
367 if separator then
368  local c=cache[separator]
369  if not c then
370   c=tsplitat(separator)
371   cache[separator]=c
372  end
373  return lpegmatch(c,str)
374 else
375  return { str }
376 end
377end
378local spacing=patterns.spacer^0*newline 
379local empty=spacing*Cc("")
380local nonempty=Cs((1-spacing)^1)*spacing^-1
381local content=(empty+nonempty)^1
382patterns.textline=content
383local linesplitter=tsplitat(newline)
384patterns.linesplitter=linesplitter
385function string.splitlines(str)
386 return lpegmatch(linesplitter,str)
387end
388local cache={}
389function lpeg.checkedsplit(separator,str)
390 local c=cache[separator]
391 if not c then
392  separator=P(separator)
393  local other=C((1-separator)^1)
394  c=Ct(separator^0*other*(separator^1*other)^0)
395  cache[separator]=c
396 end
397 return lpegmatch(c,str)
398end
399function string.checkedsplit(str,separator)
400 local c=cache[separator]
401 if not c then
402  separator=P(separator)
403  local other=C((1-separator)^1)
404  c=Ct(separator^0*other*(separator^1*other)^0)
405  cache[separator]=c
406 end
407 return lpegmatch(c,str)
408end
409local function f2(s) local c1,c2=byte(s,1,2) return   c1*64+c2-12416 end
410local function f3(s) local c1,c2,c3=byte(s,1,3) return  (c1*64+c2)*64+c3-925824 end
411local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end
412local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4
413patterns.utf8byte=utf8byte
414local cache={}
415function lpeg.stripper(str)
416 if type(str)=="string" then
417  local s=cache[str]
418  if not s then
419   s=Cs(((S(str)^1)/""+1)^0)
420   cache[str]=s
421  end
422  return s
423 else
424  return Cs(((str^1)/""+1)^0)
425 end
426end
427local cache={}
428function lpeg.keeper(str)
429 if type(str)=="string" then
430  local s=cache[str]
431  if not s then
432   s=Cs((((1-S(str))^1)/""+1)^0)
433   cache[str]=s
434  end
435  return s
436 else
437  return Cs((((1-str)^1)/""+1)^0)
438 end
439end
440function lpeg.frontstripper(str) 
441 return (P(str)+P(true))*Cs(anything^0)
442end
443function lpeg.endstripper(str) 
444 return Cs((1-P(str)*endofstring)^0)
445end
446function lpeg.replacer(one,two,makefunction,isutf) 
447 local pattern
448 local u=isutf and utf8char or 1
449 if type(one)=="table" then
450  local no=#one
451  local p=P(false)
452  if no==0 then
453   for k,v in next,one do
454    p=p+P(k)/v
455   end
456   pattern=Cs((p+u)^0)
457  elseif no==1 then
458   local o=one[1]
459   one,two=P(o[1]),o[2]
460   pattern=Cs((one/two+u)^0)
461  else
462   for i=1,no do
463    local o=one[i]
464    p=p+P(o[1])/o[2]
465   end
466   pattern=Cs((p+u)^0)
467  end
468 else
469  pattern=Cs((P(one)/(two or "")+u)^0)
470 end
471 if makefunction then
472  return function(str)
473   return lpegmatch(pattern,str)
474  end
475 else
476  return pattern
477 end
478end
479function lpeg.finder(lst,makefunction,isutf) 
480 local pattern
481 if type(lst)=="table" then
482  pattern=P(false)
483  if #lst==0 then
484   for k,v in next,lst do
485    pattern=pattern+P(k) 
486   end
487  else
488   for i=1,#lst do
489    pattern=pattern+P(lst[i])
490   end
491  end
492 else
493  pattern=P(lst)
494 end
495 if isutf then
496  pattern=((utf8char or 1)-pattern)^0*pattern
497 else
498  pattern=(1-pattern)^0*pattern
499 end
500 if makefunction then
501  return function(str)
502   return lpegmatch(pattern,str)
503  end
504 else
505  return pattern
506 end
507end
508local splitters_f,splitters_s={},{}
509function lpeg.firstofsplit(separator) 
510 local splitter=splitters_f[separator]
511 if not splitter then
512  local pattern=P(separator)
513  splitter=C((1-pattern)^0)
514  splitters_f[separator]=splitter
515 end
516 return splitter
517end
518function lpeg.secondofsplit(separator) 
519 local splitter=splitters_s[separator]
520 if not splitter then
521  local pattern=P(separator)
522  splitter=(1-pattern)^0*pattern*C(anything^0)
523  splitters_s[separator]=splitter
524 end
525 return splitter
526end
527local splitters_s,splitters_p={},{}
528function lpeg.beforesuffix(separator) 
529 local splitter=splitters_s[separator]
530 if not splitter then
531  local pattern=P(separator)
532  splitter=C((1-pattern)^0)*pattern*endofstring
533  splitters_s[separator]=splitter
534 end
535 return splitter
536end
537function lpeg.afterprefix(separator) 
538 local splitter=splitters_p[separator]
539 if not splitter then
540  local pattern=P(separator)
541  splitter=pattern*C(anything^0)
542  splitters_p[separator]=splitter
543 end
544 return splitter
545end
546function lpeg.balancer(left,right)
547 left,right=P(left),P(right)
548 return P { left*((1-left-right)+V(1))^0*right }
549end
550function lpeg.counter(pattern,action)
551 local n=0
552 local pattern=(P(pattern)/function() n=n+1 end+anything)^0
553 if action then
554  return function(str) n=0;lpegmatch(pattern,str);action(n) end
555 else
556  return function(str) n=0;lpegmatch(pattern,str);return n end
557 end
558end
559function lpeg.is_lpeg(p)
560 return p and lpegtype(p)=="pattern"
561end
562function lpeg.oneof(list,...) 
563 if type(list)~="table" then
564  list={ list,... }
565 end
566 local p=P(list[1])
567 for l=2,#list do
568  p=p+P(list[l])
569 end
570 return p
571end
572local sort=table.sort
573local function copyindexed(old)
574 local new={}
575 for i=1,#old do
576  new[i]=old
577 end
578 return new
579end
580local function sortedkeys(tab)
581 local keys,s={},0
582 for key,_ in next,tab do
583  s=s+1
584  keys[s]=key
585 end
586 sort(keys)
587 return keys
588end
589function lpeg.append(list,pp,delayed,checked)
590 local p=pp
591 if #list>0 then
592  local keys=copyindexed(list)
593  sort(keys)
594  for i=#keys,1,-1 do
595   local k=keys[i]
596   if p then
597    p=P(k)+p
598   else
599    p=P(k)
600   end
601  end
602 elseif delayed then 
603  local keys=sortedkeys(list)
604  if p then
605   for i=1,#keys,1 do
606    local k=keys[i]
607    local v=list[k]
608    p=P(k)/list+p
609   end
610  else
611   for i=1,#keys do
612    local k=keys[i]
613    local v=list[k]
614    if p then
615     p=P(k)+p
616    else
617     p=P(k)
618    end
619   end
620   if p then
621    p=p/list
622   end
623  end
624 elseif checked then
625  local keys=sortedkeys(list)
626  for i=1,#keys do
627   local k=keys[i]
628   local v=list[k]
629   if p then
630    if k==v then
631     p=P(k)+p
632    else
633     p=P(k)/v+p
634    end
635   else
636    if k==v then
637     p=P(k)
638    else
639     p=P(k)/v
640    end
641   end
642  end
643 else
644  local keys=sortedkeys(list)
645  for i=1,#keys do
646   local k=keys[i]
647   local v=list[k]
648   if p then
649    p=P(k)/v+p
650   else
651    p=P(k)/v
652   end
653  end
654 end
655 return p
656end
657local p_false=P(false)
658local p_true=P(true)
659local lower=utf and utf.lower or string.lower
660local upper=utf and utf.upper or string.upper
661function lpeg.setutfcasers(l,u)
662 lower=l or lower
663 upper=u or upper
664end
665local function make1(t,rest)
666 local p=p_false
667 local keys=sortedkeys(t)
668 for i=1,#keys do
669  local k=keys[i]
670  if k~="" then
671   local v=t[k]
672   if v==true then
673    p=p+P(k)*p_true
674   elseif v==false then
675   else
676    p=p+P(k)*make1(v,v[""])
677   end
678  end
679 end
680 if rest then
681  p=p+p_true
682 end
683 return p
684end
685local function make2(t,rest) 
686 local p=p_false
687 local keys=sortedkeys(t)
688 for i=1,#keys do
689  local k=keys[i]
690  if k~="" then
691   local v=t[k]
692   if v==true then
693    p=p+(P(lower(k))+P(upper(k)))*p_true
694   elseif v==false then
695   else
696    p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""])
697   end
698  end
699 end
700 if rest then
701  p=p+p_true
702 end
703 return p
704end
705local function utfchartabletopattern(list,insensitive) 
706 local tree={}
707 local n=#list
708 if n==0 then
709  for s in next,list do
710   local t=tree
711   local p,pk
712   for c in gmatch(s,".") do
713    if t==true then
714     t={ [c]=true,[""]=true }
715     p[pk]=t
716     p=t
717     t=false
718    elseif t==false then
719     t={ [c]=false }
720     p[pk]=t
721     p=t
722     t=false
723    else
724     local tc=t[c]
725     if not tc then
726      tc=false
727      t[c]=false
728     end
729     p=t
730     t=tc
731    end
732    pk=c
733   end
734   if t==false then
735    p[pk]=true
736   elseif t==true then
737   else
738    t[""]=true
739   end
740  end
741 else
742  for i=1,n do
743   local s=list[i]
744   local t=tree
745   local p,pk
746   for c in gmatch(s,".") do
747    if t==true then
748     t={ [c]=true,[""]=true }
749     p[pk]=t
750     p=t
751     t=false
752    elseif t==false then
753     t={ [c]=false }
754     p[pk]=t
755     p=t
756     t=false
757    else
758     local tc=t[c]
759     if not tc then
760      tc=false
761      t[c]=false
762     end
763     p=t
764     t=tc
765    end
766    pk=c
767   end
768   if t==false then
769    p[pk]=true
770   elseif t==true then
771   else
772    t[""]=true
773   end
774  end
775 end
776 return (insensitive and make2 or make1)(tree)
777end
778lpeg.utfchartabletopattern=utfchartabletopattern
779function lpeg.utfreplacer(list,insensitive)
780 local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0)
781 return function(str)
782  return lpegmatch(pattern,str) or str
783 end
784end
785patterns.containseol=lpeg.finder(eol)
786local function nextstep(n,step,result)
787 local m=n%step   
788 local d=floor(n/step) 
789 if d>0 then
790  local v=V(tostring(step))
791  local s=result.start
792  for i=1,d do
793   if s then
794    s=v*s
795   else
796    s=v
797   end
798  end
799  result.start=s
800 end
801 if step>1 and result.start then
802  local v=V(tostring(step/2))
803  result[tostring(step)]=v*v
804 end
805 if step>0 then
806  return nextstep(m,step/2,result)
807 else
808  return result
809 end
810end
811function lpeg.times(pattern,n)
812 return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
813end
814do
815 local trailingzeros=zero^0*-digit 
816 local stripper=Cs((
817  digits*(
818   period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"")
819  )+1
820 )^0)
821 lpeg.patterns.stripzeros=stripper 
822 local nonzero=digit-zero
823 local trailingzeros=zero^1*endofstring
824 local stripper=Cs((1-period)^0*(
825  period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring
826 ))
827 lpeg.patterns.stripzero=stripper
828end
829local byte_to_HEX={}
830local byte_to_hex={}
831local byte_to_dec={} 
832local hex_to_byte={}
833for i=0,255 do
834 local H=format("%02X",i)
835 local h=format("%02x",i)
836 local d=format("%03i",i)
837 local c=char(i)
838 byte_to_HEX[c]=H
839 byte_to_hex[c]=h
840 byte_to_dec[c]=d
841 hex_to_byte[h]=c
842 hex_to_byte[H]=c
843end
844local hextobyte=P(2)/hex_to_byte
845local bytetoHEX=P(1)/byte_to_HEX
846local bytetohex=P(1)/byte_to_hex
847local bytetodec=P(1)/byte_to_dec
848local hextobytes=Cs(hextobyte^0)
849local bytestoHEX=Cs(bytetoHEX^0)
850local bytestohex=Cs(bytetohex^0)
851local bytestodec=Cs(bytetodec^0)
852patterns.hextobyte=hextobyte
853patterns.bytetoHEX=bytetoHEX
854patterns.bytetohex=bytetohex
855patterns.bytetodec=bytetodec
856patterns.hextobytes=hextobytes
857patterns.bytestoHEX=bytestoHEX
858patterns.bytestohex=bytestohex
859patterns.bytestodec=bytestodec
860function string.toHEX(s)
861 if not s or s=="" then
862  return s
863 else
864  return lpegmatch(bytestoHEX,s)
865 end
866end
867function string.tohex(s)
868 if not s or s=="" then
869  return s
870 else
871  return lpegmatch(bytestohex,s)
872 end
873end
874function string.todec(s)
875 if not s or s=="" then
876  return s
877 else
878  return lpegmatch(bytestodec,s)
879 end
880end
881function string.tobytes(s)
882 if not s or s=="" then
883  return s
884 else
885  return lpegmatch(hextobytes,s)
886 end
887end
888local patterns={} 
889local function containsws(what)
890 local p=patterns[what]
891 if not p then
892  local p1=P(what)*(whitespace+endofstring)*Cc(true)
893  local p2=whitespace*P(p1)
894  p=P(p1)+P(1-p2)^0*p2+Cc(false)
895  patterns[what]=p
896 end
897 return p
898end
899lpeg.containsws=containsws
900function string.containsws(str,what)
901 return lpegmatch(patterns[what] or containsws(what),str)
902end
903
904end -- closure
905
906do -- begin closure to overcome local limits and interference
907
908if not modules then modules={} end modules ['l-functions']={
909 version=1.001,
910 comment="companion to luat-lib.mkiv",
911 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
912 copyright="PRAGMA ADE / ConTeXt Development Team",
913 license="see context related readme files"
914}
915functions=functions or {}
916function functions.dummy() end
917
918end -- closure
919
920do -- begin closure to overcome local limits and interference
921
922if not modules then modules={} end modules ['l-string']={
923 version=1.001,
924 comment="companion to luat-lib.mkiv",
925 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
926 copyright="PRAGMA ADE / ConTeXt Development Team",
927 license="see context related readme files"
928}
929local string=string
930local sub,gmatch,format,char,byte,rep,lower,find=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower,string.find
931local lpegmatch,patterns=lpeg.match,lpeg.patterns
932local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs
933local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote
934function string.unquoted(str)
935 return lpegmatch(unquoted,str) or str
936end
937function string.quoted(str)
938 return format("%q",str) 
939end
940function string.count(str,pattern)
941 local n=0
942 local i=1
943 local l=#pattern
944 while true do
945  i=find(str,pattern,i)
946  if i then
947   n=n+1
948   i=i+l
949  else
950   break
951  end
952 end
953 return n
954end
955function string.limit(str,n,sentinel) 
956 if #str>n then
957  sentinel=sentinel or "..."
958  return sub(str,1,(n-#sentinel))..sentinel
959 else
960  return str
961 end
962end
963local stripper=patterns.stripper
964local fullstripper=patterns.fullstripper
965local collapser=patterns.collapser
966local nospacer=patterns.nospacer
967local longtostring=patterns.longtostring
968function string.strip(str)
969 return str and lpegmatch(stripper,str) or ""
970end
971function string.fullstrip(str)
972 return str and lpegmatch(fullstripper,str) or ""
973end
974function string.collapsespaces(str)
975 return str and lpegmatch(collapser,str) or ""
976end
977function string.nospaces(str)
978 return str and lpegmatch(nospacer,str) or ""
979end
980function string.longtostring(str)
981 return str and lpegmatch(longtostring,str) or ""
982end
983local pattern=P(" ")^0*P(-1)
984function string.is_empty(str)
985 if not str or str=="" then
986  return true
987 else
988  return lpegmatch(pattern,str) and true or false
989 end
990end
991local anything=patterns.anything
992local moreescapes=Cc("%")*S(".-+%?()[]*$^{}")
993local allescapes=Cc("%")*S(".-+%?()[]*")   
994local someescapes=Cc("%")*S(".-+%()[]")  
995local matchescapes=Cc(".")*S("*?")     
996local pattern_m=Cs ((moreescapes+anything )^0 )
997local pattern_a=Cs ((allescapes+anything )^0 )
998local pattern_b=Cs ((someescapes+matchescapes+anything )^0 )
999local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") )
1000function string.escapedpattern(str,simple)
1001 return lpegmatch(simple and pattern_b or pattern_a,str)
1002end
1003function string.topattern(str,lowercase,strict)
1004 if str=="" or type(str)~="string" then
1005  return ".*"
1006 elseif strict=="all" then
1007  str=lpegmatch(pattern_m,str)
1008 elseif strict then
1009  str=lpegmatch(pattern_c,str)
1010 else
1011  str=lpegmatch(pattern_b,str)
1012 end
1013 if lowercase then
1014  return lower(str)
1015 else
1016  return str
1017 end
1018end
1019function string.valid(str,default)
1020 return (type(str)=="string" and str~="" and str) or default or nil
1021end
1022string.itself=function(s) return s end
1023local pattern_c=Ct(C(1)^0) 
1024local pattern_b=Ct((C(1)/byte)^0)
1025function string.totable(str,bytes)
1026 return lpegmatch(bytes and pattern_b or pattern_c,str)
1027end
1028local replacer=lpeg.replacer("@","%%") 
1029function string.tformat(fmt,...)
1030 return format(lpegmatch(replacer,fmt),...)
1031end
1032string.quote=string.quoted
1033string.unquote=string.unquoted
1034if not string.bytetable then 
1035 local limit=5000 
1036 function string.bytetable(str) 
1037  local n=#str
1038  if n>limit then
1039   local t={ byte(str,1,limit) }
1040   for i=limit+1,n do
1041    t[i]=byte(str,i)
1042   end
1043   return t
1044  else
1045   return { byte(str,1,n) }
1046  end
1047 end
1048end
1049
1050end -- closure
1051
1052do -- begin closure to overcome local limits and interference
1053
1054if not modules then modules={} end modules ['l-table']={
1055 version=1.001,
1056 comment="companion to luat-lib.mkiv",
1057 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
1058 copyright="PRAGMA ADE / ConTeXt Development Team",
1059 license="see context related readme files"
1060}
1061local type,next,tostring,tonumber,select,rawget=type,next,tostring,tonumber,select,rawget
1062local table,string=table,string
1063local concat,sort=table.concat,table.sort
1064local format,lower,dump=string.format,string.lower,string.dump
1065local getmetatable,setmetatable=getmetatable,setmetatable
1066local lpegmatch,patterns=lpeg.match,lpeg.patterns
1067local floor=math.floor
1068local stripper=patterns.stripper
1069function table.getn(t)
1070 return t and #t 
1071end
1072function table.strip(tab)
1073 local lst={}
1074 local l=0
1075 for i=1,#tab do
1076  local s=lpegmatch(stripper,tab[i]) or ""
1077  if s=="" then
1078  else
1079   l=l+1
1080   lst[l]=s
1081  end
1082 end
1083 return lst
1084end
1085function table.keys(t)
1086 if t then
1087  local keys={}
1088  local k=0
1089  for key in next,t do
1090   k=k+1
1091   keys[k]=key
1092  end
1093  return keys
1094 else
1095  return {}
1096 end
1097end
1098local function compare(a,b)
1099 local ta=type(a) 
1100 if ta=="number" then
1101  local tb=type(b) 
1102  if ta==tb then
1103   return a<b
1104  elseif tb=="string" then
1105   return tostring(a)<b
1106  end
1107 elseif ta=="string" then
1108  local tb=type(b) 
1109  if ta==tb then
1110   return a<b
1111  else
1112   return a<tostring(b)
1113  end
1114 end
1115 return tostring(a)<tostring(b) 
1116end
1117local function sortedkeys(tab)
1118 if tab then
1119  local srt={}
1120  local category=0 
1121  local s=0
1122  for key in next,tab do
1123   s=s+1
1124   srt[s]=key
1125   if category~=3 then
1126    local tkey=type(key)
1127    if category==1 then
1128     if tkey~="string" then
1129      category=3
1130     end
1131    elseif category==2 then
1132     if tkey~="number" then
1133      category=3
1134     end
1135    else
1136     if tkey=="string" then
1137      category=1
1138     elseif tkey=="number" then
1139      category=2
1140     else
1141      category=3
1142     end
1143    end
1144   end
1145  end
1146  if s<2 then
1147  elseif category==3 then
1148   sort(srt,compare)
1149  else
1150   sort(srt)
1151  end
1152  return srt
1153 else
1154  return {}
1155 end
1156end
1157local function sortedhashonly(tab)
1158 if tab then
1159  local srt={}
1160  local s=0
1161  for key in next,tab do
1162   if type(key)=="string" then
1163    s=s+1
1164    srt[s]=key
1165   end
1166  end
1167  if s>1 then
1168   sort(srt)
1169  end
1170  return srt
1171 else
1172  return {}
1173 end
1174end
1175local function sortedindexonly(tab)
1176 if tab then
1177  local srt={}
1178  local s=0
1179  for key in next,tab do
1180   if type(key)=="number" then
1181    s=s+1
1182    srt[s]=key
1183   end
1184  end
1185  if s>1 then
1186   sort(srt)
1187  end
1188  return srt
1189 else
1190  return {}
1191 end
1192end
1193local function sortedhashkeys(tab,cmp) 
1194 if tab then
1195  local srt={}
1196  local s=0
1197  for key in next,tab do
1198   if key then
1199    s=s+1
1200    srt[s]=key
1201   end
1202  end
1203  if s>1 then
1204   sort(srt,cmp)
1205  end
1206  return srt
1207 else
1208  return {}
1209 end
1210end
1211function table.allkeys(t)
1212 local keys={}
1213 for k,v in next,t do
1214  for k in next,v do
1215   keys[k]=true
1216  end
1217 end
1218 return sortedkeys(keys)
1219end
1220table.sortedkeys=sortedkeys
1221table.sortedhashonly=sortedhashonly
1222table.sortedindexonly=sortedindexonly
1223table.sortedhashkeys=sortedhashkeys
1224local function nothing() end
1225local function sortedhash(t,cmp)
1226 if t then
1227  local s
1228  if cmp then
1229   s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
1230  else
1231   s=sortedkeys(t) 
1232  end
1233  local m=#s
1234  if m==1 then
1235   return next,t
1236  elseif m>0 then
1237   local n=0
1238   return function()
1239    if n<m then
1240     n=n+1
1241     local k=s[n]
1242     return k,t[k]
1243    end
1244   end
1245  end
1246 end
1247 return nothing
1248end
1249table.sortedhash=sortedhash
1250table.sortedpairs=sortedhash 
1251function table.append(t,list)
1252 local n=#t
1253 for i=1,#list do
1254  n=n+1
1255  t[n]=list[i]
1256 end
1257 return t
1258end
1259function table.prepend(t,list)
1260 local nl=#list
1261 local nt=nl+#t
1262 for i=#t,1,-1 do
1263  t[nt]=t[i]
1264  nt=nt-1
1265 end
1266 for i=1,#list do
1267  t[i]=list[i]
1268 end
1269 return t
1270end
1271function table.merge(t,...) 
1272 if not t then
1273  t={}
1274 end
1275 for i=1,select("#",...) do
1276  for k,v in next,(select(i,...)) do
1277   t[k]=v
1278  end
1279 end
1280 return t
1281end
1282function table.merged(...)
1283 local t={}
1284 for i=1,select("#",...) do
1285  for k,v in next,(select(i,...)) do
1286   t[k]=v
1287  end
1288 end
1289 return t
1290end
1291function table.imerge(t,...)
1292 local nt=#t
1293 for i=1,select("#",...) do
1294  local nst=select(i,...)
1295  for j=1,#nst do
1296   nt=nt+1
1297   t[nt]=nst[j]
1298  end
1299 end
1300 return t
1301end
1302function table.imerged(...)
1303 local tmp={}
1304 local ntmp=0
1305 for i=1,select("#",...) do
1306  local nst=select(i,...)
1307  for j=1,#nst do
1308   ntmp=ntmp+1
1309   tmp[ntmp]=nst[j]
1310  end
1311 end
1312 return tmp
1313end
1314local function fastcopy(old,metatabletoo) 
1315 if old then
1316  local new={}
1317  for k,v in next,old do
1318   if type(v)=="table" then
1319    new[k]=fastcopy(v,metatabletoo) 
1320   else
1321    new[k]=v
1322   end
1323  end
1324  if metatabletoo then
1325   local mt=getmetatable(old)
1326   if mt then
1327    setmetatable(new,mt)
1328   end
1329  end
1330  return new
1331 else
1332  return {}
1333 end
1334end
1335local function copy(t,tables) 
1336 if not tables then
1337  tables={}
1338 end
1339 local tcopy={}
1340 if not tables[t] then
1341  tables[t]=tcopy
1342 end
1343 for i,v in next,t do 
1344  if type(i)=="table" then
1345   if tables[i] then
1346    i=tables[i]
1347   else
1348    i=copy(i,tables)
1349   end
1350  end
1351  if type(v)~="table" then
1352   tcopy[i]=v
1353  elseif tables[v] then
1354   tcopy[i]=tables[v]
1355  else
1356   tcopy[i]=copy(v,tables)
1357  end
1358 end
1359 local mt=getmetatable(t)
1360 if mt then
1361  setmetatable(tcopy,mt)
1362 end
1363 return tcopy
1364end
1365table.fastcopy=fastcopy
1366table.copy=copy
1367function table.derive(parent) 
1368 local child={}
1369 if parent then
1370  setmetatable(child,{ __index=parent })
1371 end
1372 return child
1373end
1374function table.tohash(t,value)
1375 local h={}
1376 if t then
1377  if value==nil then value=true end
1378  for _,v in next,t do
1379   h[v]=value
1380  end
1381 end
1382 return h
1383end
1384function table.fromhash(t)
1385 local hsh={}
1386 local h=0
1387 for k,v in next,t do
1388  if v then
1389   h=h+1
1390   hsh[h]=k
1391  end
1392 end
1393 return hsh
1394end
1395local noquotes,hexify,handle,compact,inline,functions,metacheck,accurate
1396local reserved=table.tohash { 
1397 'and','break','do','else','elseif','end','false','for','function','if',
1398 'in','local','nil','not','or','repeat','return','then','true','until','while',
1399 'NaN','goto','const',
1400}
1401local function is_simple_table(t,hexify,accurate) 
1402 local nt=#t
1403 if nt>0 then
1404  local n=0
1405  for _,v in next,t do
1406   n=n+1
1407   if type(v)=="table" then
1408    return nil
1409   end
1410  end
1411  local haszero=rawget(t,0) 
1412  if n==nt then
1413   local tt={}
1414   for i=1,nt do
1415    local v=t[i]
1416    local tv=type(v)
1417    if tv=="number" then
1418     if hexify then
1419      tt[i]=format("0x%X",v)
1420     elseif accurate then
1421      tt[i]=format("%q",v)
1422     else
1423      tt[i]=v 
1424     end
1425    elseif tv=="string" then
1426     tt[i]=format("%q",v) 
1427    elseif tv=="boolean" then
1428     tt[i]=v and "true" or "false"
1429    else
1430     return nil
1431    end
1432   end
1433   return tt
1434  elseif haszero and (n==nt+1) then
1435   local tt={}
1436   for i=0,nt do
1437    local v=t[i]
1438    local tv=type(v)
1439    if tv=="number" then
1440     if hexify then
1441      tt[i+1]=format("0x%X",v)
1442     elseif accurate then
1443      tt[i+1]=format("%q",v)
1444     else
1445      tt[i+1]=v 
1446     end
1447    elseif tv=="string" then
1448     tt[i+1]=format("%q",v) 
1449    elseif tv=="boolean" then
1450     tt[i+1]=v and "true" or "false"
1451    else
1452     return nil
1453    end
1454   end
1455   tt[1]="[0] = "..tt[1]
1456   return tt
1457  end
1458 end
1459 return nil
1460end
1461table.is_simple_table=is_simple_table
1462local propername=patterns.propername 
1463local function dummy() end
1464local function do_serialize(root,name,depth,level,indexed)
1465 if level>0 then
1466  depth=depth.." "
1467  if indexed then
1468   handle(format("%s{",depth))
1469  else
1470   local tn=type(name)
1471   if tn=="number" then
1472    if hexify then
1473     handle(format("%s[0x%X]={",depth,name))
1474    else
1475     handle(format("%s[%s]={",depth,name))
1476    end
1477   elseif tn=="string" then
1478    if noquotes and not reserved[name] and lpegmatch(propername,name) then
1479     handle(format("%s%s={",depth,name))
1480    else
1481     handle(format("%s[%q]={",depth,name))
1482    end
1483   elseif tn=="boolean" then
1484    handle(format("%s[%s]={",depth,name and "true" or "false"))
1485   else
1486    handle(format("%s{",depth))
1487   end
1488  end
1489 end
1490 if root and next(root)~=nil then
1491  local first=nil
1492  local last=0
1493  if compact then
1494   last=#root
1495   for k=1,last do
1496    if rawget(root,k)==nil then
1497     last=k-1
1498     break
1499    end
1500   end
1501   if last>0 then
1502    first=1
1503   end
1504  end
1505  local sk=sortedkeys(root)
1506  for i=1,#sk do
1507   local k=sk[i]
1508   local v=root[k]
1509   local tv=type(v)
1510   local tk=type(k)
1511   if compact and first and tk=="number" and k>=first and k<=last then
1512    if tv=="number" then
1513     if hexify then
1514      handle(format("%s 0x%X,",depth,v))
1515     elseif accurate then
1516      handle(format("%s %q,",depth,v))
1517     else
1518      handle(format("%s %s,",depth,v)) 
1519     end
1520    elseif tv=="string" then
1521     handle(format("%s %q,",depth,v))
1522    elseif tv=="table" then
1523     if next(v)==nil then
1524      handle(format("%s {},",depth))
1525     elseif inline then 
1526      local st=is_simple_table(v,hexify,accurate)
1527      if st then
1528       handle(format("%s { %s },",depth,concat(st,", ")))
1529      else
1530       do_serialize(v,k,depth,level+1,true)
1531      end
1532     else
1533      do_serialize(v,k,depth,level+1,true)
1534     end
1535    elseif tv=="boolean" then
1536     handle(format("%s %s,",depth,v and "true" or "false"))
1537    elseif tv=="function" then
1538     if functions then
1539      handle(format('%s load(%q),',depth,dump(v))) 
1540     else
1541      handle(format('%s "function",',depth))
1542     end
1543    else
1544     handle(format("%s %q,",depth,tostring(v)))
1545    end
1546   elseif k=="__p__" then 
1547    if false then
1548     handle(format("%s __p__=nil,",depth))
1549    end
1550   elseif tv=="number" then
1551    if tk=="number" then
1552     if hexify then
1553      if accurate then
1554       handle(format("%s [0x%X]=%q,",depth,k,v))
1555      else
1556       handle(format("%s [0x%X]=%s,",depth,k,v))
1557      end
1558     elseif accurate then
1559      handle(format("%s [%s]=%q,",depth,k,v))
1560     else
1561      handle(format("%s [%s]=%s,",depth,k,v)) 
1562     end
1563    elseif tk=="boolean" then
1564     if hexify then
1565      if accurate then
1566       handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
1567      else
1568       handle(format("%s [%s]=%s,",depth,k and "true" or "false",v))
1569      end
1570     elseif accurate then
1571      handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
1572     else
1573      handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
1574     end
1575    elseif tk~="string" then
1576    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1577     if hexify then
1578      if accurate then
1579       handle(format("%s %s=%q,",depth,k,v))
1580      else
1581       handle(format("%s %s=0x%X,",depth,k,v))
1582      end
1583     elseif accurate then
1584      handle(format("%s %s=%q,",depth,k,v))
1585     else
1586      handle(format("%s %s=%s,",depth,k,v)) 
1587     end
1588    else
1589     if hexify then
1590      if accurate then
1591       handle(format("%s [%q]=%q,",depth,k,v))
1592      else
1593       handle(format("%s [%q]=0x%X,",depth,k,v))
1594      end
1595     elseif accurate then
1596      handle(format("%s [%q]=%q,",depth,k,v))
1597     else
1598      handle(format("%s [%q]=%s,",depth,k,v)) 
1599     end
1600    end
1601   elseif tv=="string" then
1602    if tk=="number" then
1603     if hexify then
1604      handle(format("%s [0x%X]=%q,",depth,k,v))
1605     elseif accurate then
1606      handle(format("%s [%q]=%q,",depth,k,v))
1607     else
1608      handle(format("%s [%s]=%q,",depth,k,v))
1609     end
1610    elseif tk=="boolean" then
1611     handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
1612    elseif tk~="string" then
1613    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1614     handle(format("%s %s=%q,",depth,k,v))
1615    else
1616     handle(format("%s [%q]=%q,",depth,k,v))
1617    end
1618   elseif tv=="table" then
1619    if next(v)==nil then
1620     if tk=="number" then
1621      if hexify then
1622       handle(format("%s [0x%X]={},",depth,k))
1623      elseif accurate then
1624       handle(format("%s [%q]={},",depth,k))
1625      else
1626       handle(format("%s [%s]={},",depth,k))
1627      end
1628     elseif tk=="boolean" then
1629      handle(format("%s [%s]={},",depth,k and "true" or "false"))
1630     elseif tk~="string" then
1631     elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1632      handle(format("%s %s={},",depth,k))
1633     else
1634      handle(format("%s [%q]={},",depth,k))
1635     end
1636    elseif inline then
1637     local st=is_simple_table(v,hexify,accurate)
1638     if st then
1639      if tk=="number" then
1640       if hexify then
1641        handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
1642       elseif accurate then
1643        handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
1644       else
1645        handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
1646       end
1647      elseif tk=="boolean" then
1648       handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
1649      elseif tk~="string" then
1650      elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1651       handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
1652      else
1653       handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
1654      end
1655     else
1656      do_serialize(v,k,depth,level+1)
1657     end
1658    else
1659     do_serialize(v,k,depth,level+1)
1660    end
1661   elseif tv=="boolean" then
1662    if tk=="number" then
1663     if hexify then
1664      handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
1665     elseif accurate then
1666      handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
1667     else
1668      handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
1669     end
1670    elseif tk=="boolean" then
1671     handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
1672    elseif tk~="string" then
1673    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1674     handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
1675    else
1676     handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
1677    end
1678   elseif tv=="function" then
1679    if functions then
1680     local getinfo=debug and debug.getinfo
1681     if getinfo then
1682      local f=getinfo(v).what=="C" and dump(dummy) or dump(v)
1683      if tk=="number" then
1684       if hexify then
1685        handle(format("%s [0x%X]=load(%q),",depth,k,f))
1686       elseif accurate then
1687        handle(format("%s [%q]=load(%q),",depth,k,f))
1688       else
1689        handle(format("%s [%s]=load(%q),",depth,k,f))
1690       end
1691      elseif tk=="boolean" then
1692       handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
1693      elseif tk~="string" then
1694      elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1695       handle(format("%s %s=load(%q),",depth,k,f))
1696      else
1697       handle(format("%s [%q]=load(%q),",depth,k,f))
1698      end
1699     end
1700    end
1701   else
1702    if tk=="number" then
1703     if hexify then
1704      handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
1705     elseif accurate then
1706      handle(format("%s [%q]=%q,",depth,k,tostring(v)))
1707     else
1708      handle(format("%s [%s]=%q,",depth,k,tostring(v)))
1709     end
1710    elseif tk=="boolean" then
1711     handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
1712    elseif tk~="string" then
1713    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
1714     handle(format("%s %s=%q,",depth,k,tostring(v)))
1715    else
1716     handle(format("%s [%q]=%q,",depth,k,tostring(v)))
1717    end
1718   end
1719  end
1720 end
1721 if level>0 then
1722  handle(format("%s},",depth))
1723 end
1724end
1725local function serialize(_handle,root,name,specification) 
1726 local tname=type(name)
1727 if type(specification)=="table" then
1728  noquotes=specification.noquotes
1729  hexify=specification.hexify
1730  accurate=specification.accurate
1731  handle=_handle or specification.handle or print
1732  functions=specification.functions
1733  compact=specification.compact
1734  inline=specification.inline and compact
1735  metacheck=specification.metacheck
1736  if functions==nil then
1737   functions=true
1738  end
1739  if compact==nil then
1740   compact=true
1741  end
1742  if inline==nil then
1743   inline=compact
1744  end
1745  if metacheck==nil then
1746   metacheck=true
1747  end
1748 else
1749  noquotes=false
1750  hexify=false
1751  handle=_handle or print
1752  compact=true
1753  inline=true
1754  functions=true
1755  metacheck=true
1756 end
1757 if tname=="string" then
1758  if name=="return" then
1759   handle("return {")
1760  else
1761   handle(name.."={")
1762  end
1763 elseif tname=="number" then
1764  if hexify then
1765   handle(format("[0x%X]={",name))
1766  else
1767   handle("["..name.."]={")
1768  end
1769 elseif tname=="boolean" then
1770  if name then
1771   handle("return {")
1772  else
1773   handle("{")
1774  end
1775 else
1776  handle("t={")
1777 end
1778 if root then
1779  if metacheck and getmetatable(root) then
1780   local dummy=root._w_h_a_t_e_v_e_r_
1781   root._w_h_a_t_e_v_e_r_=nil
1782  end
1783  if next(root)~=nil then
1784   do_serialize(root,name,"",0)
1785  end
1786 end
1787 handle("}")
1788end
1789function table.serialize(root,name,specification)
1790 local t={}
1791 local n=0
1792 local function flush(s)
1793  n=n+1
1794  t[n]=s
1795 end
1796 serialize(flush,root,name,specification)
1797 return concat(t,"\n")
1798end
1799table.tohandle=serialize
1800local maxtab=2*1024
1801function table.tofile(filename,root,name,specification)
1802 local f=io.open(filename,'w')
1803 if f then
1804  if maxtab>1 then
1805   local t={}
1806   local n=0
1807   local function flush(s)
1808    n=n+1
1809    t[n]=s
1810    if n>maxtab then
1811     f:write(concat(t,"\n"),"\n") 
1812     t={} 
1813     n=0
1814    end
1815   end
1816   serialize(flush,root,name,specification)
1817   f:write(concat(t,"\n"),"\n")
1818  else
1819   local function flush(s)
1820    f:write(s,"\n")
1821   end
1822   serialize(flush,root,name,specification)
1823  end
1824  f:close()
1825  io.flush()
1826 end
1827end
1828local function flattened(t,f,depth) 
1829 if f==nil then
1830  f={}
1831  depth=0xFFFF
1832 elseif tonumber(f) then
1833  depth=f
1834  f={}
1835 elseif not depth then
1836  depth=0xFFFF
1837 end
1838 for k,v in next,t do
1839  if type(k)~="number" then
1840   if depth>0 and type(v)=="table" then
1841    flattened(v,f,depth-1)
1842   else
1843    f[#f+1]=v
1844   end
1845  end
1846 end
1847 for k=1,#t do
1848  local v=t[k]
1849  if depth>0 and type(v)=="table" then
1850   flattened(v,f,depth-1)
1851  else
1852   f[#f+1]=v
1853  end
1854 end
1855 return f
1856end
1857table.flattened=flattened
1858local function collapsed(t,f,h)
1859 if f==nil then
1860  f={}
1861  h={}
1862 end
1863 for k=1,#t do
1864  local v=t[k]
1865  if type(v)=="table" then
1866   collapsed(v,f,h)
1867  elseif not h[v] then
1868   f[#f+1]=v
1869   h[v]=true
1870  end
1871 end
1872 return f
1873end
1874local function collapsedhash(t,h)
1875 if h==nil then
1876  h={}
1877 end
1878 for k=1,#t do
1879  local v=t[k]
1880  if type(v)=="table" then
1881   collapsedhash(v,h)
1882  else
1883   h[v]=true
1884  end
1885 end
1886 return h
1887end
1888table.collapsed=collapsed  
1889table.collapsedhash=collapsedhash
1890local function unnest(t,f) 
1891 if not f then    
1892  f={}   
1893 end
1894 for i=1,#t do
1895  local v=t[i]
1896  if type(v)=="table" then
1897   if type(v[1])=="table" then
1898    unnest(v,f)
1899   else
1900    f[#f+1]=v
1901   end
1902  else
1903   f[#f+1]=v
1904  end
1905 end
1906 return f
1907end
1908function table.unnest(t) 
1909 return unnest(t)
1910end
1911local function are_equal(a,b,n,m) 
1912 if a==b then
1913  return true
1914 elseif a and b and #a==#b then
1915  if not n then
1916   n=1
1917  end
1918  if not m then
1919   m=#a
1920  end
1921  for i=n,m do
1922   local ai,bi=a[i],b[i]
1923   if ai==bi then
1924   elseif type(ai)=="table" and type(bi)=="table" then
1925    if not are_equal(ai,bi) then
1926     return false
1927    end
1928   else
1929    return false
1930   end
1931  end
1932  return true
1933 else
1934  return false
1935 end
1936end
1937local function identical(a,b) 
1938 if a~=b then
1939  for ka,va in next,a do
1940   local vb=b[ka]
1941   if va==vb then
1942   elseif type(va)=="table" and  type(vb)=="table" then
1943    if not identical(va,vb) then
1944     return false
1945    end
1946   else
1947    return false
1948   end
1949  end
1950 end
1951 return true
1952end
1953table.identical=identical
1954table.are_equal=are_equal
1955local function sparse(old,nest,keeptables)
1956 local new={}
1957 for k,v in next,old do
1958  if not (v=="" or v==false) then
1959   if nest and type(v)=="table" then
1960    v=sparse(v,nest)
1961    if keeptables or next(v)~=nil then
1962     new[k]=v
1963    end
1964   else
1965    new[k]=v
1966   end
1967  end
1968 end
1969 return new
1970end
1971table.sparse=sparse
1972function table.compact(t)
1973 return sparse(t,true,true)
1974end
1975function table.contains(t,v)
1976 if t then
1977  for i=1,#t do
1978   if t[i]==v then
1979    return i
1980   end
1981  end
1982 end
1983 return false
1984end
1985function table.count(t)
1986 local n=0
1987 for k,v in next,t do
1988  n=n+1
1989 end
1990 return n
1991end
1992function table.swapped(t,s) 
1993 local n={}
1994 if s then
1995  for k,v in next,s do
1996   n[k]=v
1997  end
1998 end
1999 for k,v in next,t do
2000  n[v]=k
2001 end
2002 return n
2003end
2004function table.hashed(t) 
2005 for i=1,#t do
2006  t[t[i]]=i
2007 end
2008 return t
2009end
2010function table.mirrored(t) 
2011 local n={}
2012 for k,v in next,t do
2013  n[v]=k
2014  n[k]=v
2015 end
2016 return n
2017end
2018function table.reversed(t)
2019 if t then
2020  local tt={}
2021  local tn=#t
2022  if tn>0 then
2023   local ttn=0
2024   for i=tn,1,-1 do
2025    ttn=ttn+1
2026    tt[ttn]=t[i]
2027   end
2028  end
2029  return tt
2030 end
2031end
2032function table.reverse(t) 
2033 if t then
2034  local n=#t
2035  local m=n+1
2036  for i=1,floor(n/2) do 
2037   local j=m-i
2038   t[i],t[j]=t[j],t[i]
2039  end
2040  return t
2041 end
2042end
2043local function sequenced(t,sep,simple)
2044 if not t then
2045  return ""
2046 elseif type(t)~="table" then
2047  return t 
2048 end
2049 local n=#t
2050 local s={}
2051 if n>0 then
2052  for i=1,n do
2053   local v=t[i]
2054   if type(v)=="table" then
2055    s[i]="{"..sequenced(v,sep,simple).."}"
2056   else
2057    s[i]=tostring(t[i])
2058   end
2059  end
2060 else
2061  n=0
2062  for k,v in sortedhash(t) do
2063   if simple then
2064    if v==true then
2065     n=n+1
2066     s[n]=k
2067    elseif v and v~="" then
2068     n=n+1
2069     if type(v)=="table" then
2070      s[n]=k.."={"..sequenced(v,sep,simple).."}"
2071     else
2072      s[n]=k.."="..tostring(v)
2073     end
2074    end
2075   else
2076    n=n+1
2077    if type(v)=="table" then
2078     s[n]=k.."={"..sequenced(v,sep,simple).."}"
2079    else
2080     s[n]=k.."="..tostring(v)
2081    end
2082   end
2083  end
2084 end
2085 if sep==true then
2086  return "{ "..concat(s,", ").." }"
2087 else
2088  return concat(s,sep or " | ")
2089 end
2090end
2091table.sequenced=sequenced
2092function table.print(t,...)
2093 if type(t)~="table" then
2094  print(tostring(t))
2095 else
2096  serialize(print,t,...)
2097 end
2098end
2099if setinspector then
2100 setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end)
2101end
2102function table.sub(t,i,j)
2103 return { unpack(t,i,j) }
2104end
2105function table.is_empty(t)
2106 return not t or next(t)==nil
2107end
2108function table.has_one_entry(t)
2109 return t and next(t,next(t))==nil
2110end
2111function table.loweredkeys(t) 
2112 local l={}
2113 for k,v in next,t do
2114  l[lower(k)]=v
2115 end
2116 return l
2117end
2118function table.unique(old)
2119 local hash={}
2120 local new={}
2121 local n=0
2122 for i=1,#old do
2123  local oi=old[i]
2124  if not hash[oi] then
2125   n=n+1
2126   new[n]=oi
2127   hash[oi]=true
2128  end
2129 end
2130 return new
2131end
2132function table.sorted(t,...)
2133 sort(t,...)
2134 return t 
2135end
2136function table.values(t,s) 
2137 if t then
2138  local values={}
2139  local keys={}
2140  local v=0
2141  for key,value in next,t do
2142   if not keys[value] then
2143    v=v+1
2144    values[v]=value
2145    keys[k]=key
2146   end
2147  end
2148  if s then
2149   sort(values)
2150  end
2151  return values
2152 else
2153  return {}
2154 end
2155end
2156function table.filtered(t,pattern,sort,cmp)
2157 if t and type(pattern)=="string" then
2158  if sort then
2159   local s
2160   if cmp then
2161    s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
2162   else
2163    s=sortedkeys(t) 
2164   end
2165   local n=0
2166   local m=#s
2167   local function kv(s)
2168    while n<m do
2169     n=n+1
2170     local k=s[n]
2171     if find(k,pattern) then
2172      return k,t[k]
2173     end
2174    end
2175   end
2176   return kv,s
2177  else
2178   local n=next(t)
2179   local function iterator()
2180    while n~=nil do
2181     local k=n
2182     n=next(t,k)
2183     if find(k,pattern) then
2184      return k,t[k]
2185     end
2186    end
2187   end
2188   return iterator,t
2189  end
2190 else
2191  return nothing
2192 end
2193end
2194if not table.move then
2195 function table.move(a1,f,e,t,a2)
2196  if a2 and a1~=a2 then
2197   for i=f,e do
2198    a2[t]=a1[i]
2199    t=t+1
2200   end
2201   return a2
2202  else
2203   t=t+e-f
2204   for i=e,f,-1 do
2205    a1[t]=a1[i]
2206    t=t-1
2207   end
2208   return a1
2209  end
2210 end
2211end
2212
2213end -- closure
2214
2215do -- begin closure to overcome local limits and interference
2216
2217if not modules then modules={} end modules ['l-io']={
2218 version=1.001,
2219 comment="companion to luat-lib.mkiv",
2220 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
2221 copyright="PRAGMA ADE / ConTeXt Development Team",
2222 license="see context related readme files"
2223}
2224local io=io
2225local open,flush,write,read=io.open,io.flush,io.write,io.read
2226local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format
2227local concat=table.concat
2228local type=type
2229if string.find(os.getenv("PATH") or "",";",1,true) then
2230 io.fileseparator,io.pathseparator="\\",";"
2231else
2232 io.fileseparator,io.pathseparator="/",":"
2233end
2234local large=0x01000000 
2235local medium=0x00100000 
2236local small=0x00020000
2237local function readall(f)
2238 local size=f:seek("end")
2239 if size>0 then
2240  f:seek("set",0)
2241  return f:read(size)
2242 else
2243  return ""
2244 end
2245end
2246io.readall=readall
2247function io.loaddata(filename,textmode) 
2248 local f=open(filename,(textmode and 'r') or 'rb')
2249 if f then
2250  local size=f:seek("end")
2251  local data=nil
2252  if size>0 then
2253   f:seek("set",0)
2254   data=f:read(size)
2255  end
2256  f:close()
2257  return data
2258 end
2259end
2260function io.copydata(source,target,action)
2261 local f=open(source,"rb")
2262 if f then
2263  local g=open(target,"wb")
2264  if g then
2265   local size=f:seek("end")
2266   if size>0 then
2267    f:seek("set",0)
2268    local data=f:read(size)
2269    if action then
2270     data=action(data)
2271    end
2272    if data then
2273     g:write(data)
2274    end
2275   end
2276   g:close()
2277  end
2278  f:close()
2279  flush()
2280 end
2281end
2282function io.savedata(filename,data,joiner,append)
2283 local f=open(filename,append and "ab" or "wb")
2284 if f then
2285  if append and joiner and f:seek("end")>0 then
2286   f:write(joiner)
2287  end
2288  if type(data)=="table" then
2289   f:write(concat(data,joiner or ""))
2290  elseif type(data)=="function" then
2291   data(f)
2292  else
2293   f:write(data or "")
2294  end
2295  f:close()
2296  flush()
2297  return true
2298 else
2299  return false
2300 end
2301end
2302if fio and fio.readline then
2303 local readline=fio.readline
2304 function io.loadlines(filename,n) 
2305  local f=open(filename,'r')
2306  if not f then
2307  elseif n then
2308   local lines={}
2309   for i=1,n do
2310    local line=readline(f)
2311    if line then
2312     lines[i]=line
2313    else
2314     break
2315    end
2316   end
2317   f:close()
2318   lines=concat(lines,"\n")
2319   if #lines>0 then
2320    return lines
2321   end
2322  else
2323   local line=readline(f)
2324   f:close()
2325   if line and #line>0 then
2326    return line
2327   end
2328  end
2329 end
2330else
2331 function io.loadlines(filename,n) 
2332  local f=open(filename,'r')
2333  if not f then
2334  elseif n then
2335   local lines={}
2336   for i=1,n do
2337    local line=f:read("*lines")
2338    if line then
2339     lines[i]=line
2340    else
2341     break
2342    end
2343   end
2344   f:close()
2345   lines=concat(lines,"\n")
2346   if #lines>0 then
2347    return lines
2348   end
2349  else
2350   local line=f:read("*line") or ""
2351   f:close()
2352   if #line>0 then
2353    return line
2354   end
2355  end
2356 end
2357end
2358function io.loadchunk(filename,n)
2359 local f=open(filename,'rb')
2360 if f then
2361  local data=f:read(n or 1024)
2362  f:close()
2363  if #data>0 then
2364   return data
2365  end
2366 end
2367end
2368function io.exists(filename)
2369 local f=open(filename)
2370 if f==nil then
2371  return false
2372 else
2373  f:close()
2374  return true
2375 end
2376end
2377function io.size(filename)
2378 local f=open(filename)
2379 if f==nil then
2380  return 0
2381 else
2382  local s=f:seek("end")
2383  f:close()
2384  return s
2385 end
2386end
2387local function noflines(f)
2388 if type(f)=="string" then
2389  local f=open(filename)
2390  if f then
2391   local n=f and noflines(f) or 0
2392   f:close()
2393   return n
2394  else
2395   return 0
2396  end
2397 else
2398  local n=0
2399  for _ in f:lines() do
2400   n=n+1
2401  end
2402  f:seek('set',0)
2403  return n
2404 end
2405end
2406io.noflines=noflines
2407local nextchar={
2408 [ 4]=function(f)
2409  return f:read(1,1,1,1)
2410 end,
2411 [ 2]=function(f)
2412  return f:read(1,1)
2413 end,
2414 [ 1]=function(f)
2415  return f:read(1)
2416 end,
2417 [-2]=function(f)
2418  local a,b=f:read(1,1)
2419  return b,a
2420 end,
2421 [-4]=function(f)
2422  local a,b,c,d=f:read(1,1,1,1)
2423  return d,c,b,a
2424 end
2425}
2426function io.characters(f,n)
2427 if f then
2428  return nextchar[n or 1],f
2429 end
2430end
2431local nextbyte={
2432 [4]=function(f)
2433  local a,b,c,d=f:read(1,1,1,1)
2434  if d then
2435   return byte(a),byte(b),byte(c),byte(d)
2436  end
2437 end,
2438 [3]=function(f)
2439  local a,b,c=f:read(1,1,1)
2440  if b then
2441   return byte(a),byte(b),byte(c)
2442  end
2443 end,
2444 [2]=function(f)
2445  local a,b=f:read(1,1)
2446  if b then
2447   return byte(a),byte(b)
2448  end
2449 end,
2450 [1]=function (f)
2451  local a=f:read(1)
2452  if a then
2453   return byte(a)
2454  end
2455 end,
2456 [-2]=function (f)
2457  local a,b=f:read(1,1)
2458  if b then
2459   return byte(b),byte(a)
2460  end
2461 end,
2462 [-3]=function(f)
2463  local a,b,c=f:read(1,1,1)
2464  if b then
2465   return byte(c),byte(b),byte(a)
2466  end
2467 end,
2468 [-4]=function(f)
2469  local a,b,c,d=f:read(1,1,1,1)
2470  if d then
2471   return byte(d),byte(c),byte(b),byte(a)
2472  end
2473 end
2474}
2475function io.bytes(f,n)
2476 if f then
2477  return nextbyte[n or 1],f
2478 else
2479  return nil,nil
2480 end
2481end
2482function io.ask(question,default,options)
2483 while true do
2484  write(question)
2485  if options then
2486   write(format(" [%s]",concat(options,"|")))
2487  end
2488  if default then
2489   write(format(" [%s]",default))
2490  end
2491  write(format(" "))
2492  flush()
2493  local answer=read()
2494  answer=gsub(answer,"^%s*(.*)%s*$","%1")
2495  if answer=="" and default then
2496   return default
2497  elseif not options then
2498   return answer
2499  else
2500   for k=1,#options do
2501    if options[k]==answer then
2502     return answer
2503    end
2504   end
2505   local pattern="^"..answer
2506   for k=1,#options do
2507    local v=options[k]
2508    if find(v,pattern) then
2509     return v
2510    end
2511   end
2512  end
2513 end
2514end
2515local function readnumber(f,n,m) 
2516 if m then
2517  f:seek("set",n)
2518  n=m
2519 end
2520 if n==1 then
2521  return byte(f:read(1))
2522 elseif n==2 then
2523  local a,b=byte(f:read(2),1,2)
2524  return 0x100*a+b
2525 elseif n==3 then
2526  local a,b,c=byte(f:read(3),1,3)
2527  return 0x10000*a+0x100*b+c
2528 elseif n==4 then
2529  local a,b,c,d=byte(f:read(4),1,4)
2530  return 0x1000000*a+0x10000*b+0x100*c+d
2531 elseif n==8 then
2532  local a,b=readnumber(f,4),readnumber(f,4)
2533  return 0x100*a+b
2534 elseif n==12 then
2535  local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
2536  return 0x10000*a+0x100*b+c
2537 elseif n==-2 then
2538  local b,a=byte(f:read(2),1,2)
2539  return 0x100*a+b
2540 elseif n==-3 then
2541  local c,b,a=byte(f:read(3),1,3)
2542  return 0x10000*a+0x100*b+c
2543 elseif n==-4 then
2544  local d,c,b,a=byte(f:read(4),1,4)
2545  return 0x1000000*a+0x10000*b+0x100*c+d
2546 elseif n==-8 then
2547  local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
2548  return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
2549 else
2550  return 0
2551 end
2552end
2553io.readnumber=readnumber
2554function io.readstring(f,n,m)
2555 if m then
2556  f:seek("set",n)
2557  n=m
2558 end
2559 local str=gsub(f:read(n),"\000","")
2560 return str
2561end
2562
2563end -- closure
2564
2565do -- begin closure to overcome local limits and interference
2566
2567if not modules then modules={} end modules ['l-file']={
2568 version=1.001,
2569 comment="companion to luat-lib.mkiv",
2570 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
2571 copyright="PRAGMA ADE / ConTeXt Development Team",
2572 license="see context related readme files"
2573}
2574file=file or {}
2575local file=file
2576if not lfs then
2577 lfs=optionalrequire("lfs")
2578end
2579local insert,concat=table.insert,table.concat
2580local match,find,gmatch=string.match,string.find,string.gmatch
2581local lpegmatch=lpeg.match
2582local getcurrentdir,attributes=lfs.currentdir,lfs.attributes
2583local checkedsplit=string.checkedsplit
2584local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct
2585local attributes=lfs.attributes
2586function lfs.isdir(name)
2587 if name then
2588  return attributes(name,"mode")=="directory"
2589 end
2590end
2591function lfs.isfile(name)
2592 if name then
2593  local a=attributes(name,"mode")
2594  return a=="file" or a=="link" or nil
2595 end
2596end
2597function lfs.isfound(name)
2598 if name then
2599  local a=attributes(name,"mode")
2600  return (a=="file" or a=="link") and name or nil
2601 end
2602end
2603function lfs.modification(name)
2604 return name and attributes(name,"modification") or nil
2605end
2606if sandbox then
2607 sandbox.redefine(lfs.isfile,"lfs.isfile")
2608 sandbox.redefine(lfs.isdir,"lfs.isdir")
2609 sandbox.redefine(lfs.isfound,"lfs.isfound")
2610end
2611local colon=P(":")
2612local period=P(".")
2613local periods=P("..")
2614local fwslash=P("/")
2615local bwslash=P("\\")
2616local slashes=S("\\/")
2617local noperiod=1-period
2618local noslashes=1-slashes
2619local name=noperiod^1
2620local suffix=period/""*(1-period-slashes)^1*-1
2621local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) 
2622local function pathpart(name,default)
2623 return name and lpegmatch(pattern,name) or default or ""
2624end
2625local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1
2626local function basename(name)
2627 return name and lpegmatch(pattern,name) or name
2628end
2629local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0
2630local function nameonly(name)
2631 return name and lpegmatch(pattern,name) or name
2632end
2633local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1
2634local function suffixonly(name)
2635 return name and lpegmatch(pattern,name) or ""
2636end
2637local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("")
2638local function suffixesonly(name)
2639 if name then
2640  return lpegmatch(pattern,name)
2641 else
2642  return ""
2643 end
2644end
2645file.pathpart=pathpart
2646file.basename=basename
2647file.nameonly=nameonly
2648file.suffixonly=suffixonly
2649file.suffix=suffixonly
2650file.suffixesonly=suffixesonly
2651file.suffixes=suffixesonly
2652file.dirname=pathpart   
2653file.extname=suffixonly
2654local drive=C(R("az","AZ"))*colon
2655local path=C((noslashes^0*slashes)^0)
2656local suffix=period*C(P(1-period)^0*P(-1))
2657local base=C((1-suffix)^0)
2658local rest=C(P(1)^0)
2659drive=drive+Cc("")
2660path=path+Cc("")
2661base=base+Cc("")
2662suffix=suffix+Cc("")
2663local pattern_a=drive*path*base*suffix
2664local pattern_b=path*base*suffix
2665local pattern_c=C(drive*path)*C(base*suffix) 
2666local pattern_d=path*rest
2667function file.splitname(str,splitdrive)
2668 if not str then
2669 elseif splitdrive then
2670  return lpegmatch(pattern_a,str) 
2671 else
2672  return lpegmatch(pattern_b,str) 
2673 end
2674end
2675function file.splitbase(str)
2676 if str then
2677  return lpegmatch(pattern_d,str) 
2678 else
2679  return "",str 
2680 end
2681end
2682function file.nametotable(str,splitdrive)
2683 if str then
2684  local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str)
2685  if splitdrive then
2686   return {
2687    path=path,
2688    drive=drive,
2689    subpath=subpath,
2690    name=name,
2691    base=base,
2692    suffix=suffix,
2693   }
2694  else
2695   return {
2696    path=path,
2697    name=name,
2698    base=base,
2699    suffix=suffix,
2700   }
2701  end
2702 end
2703end
2704local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1)
2705function file.removesuffix(name)
2706 return name and lpegmatch(pattern,name)
2707end
2708local suffix=period/""*(1-period-slashes)^1*-1
2709local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix)
2710function file.addsuffix(filename,suffix,criterium)
2711 if not filename or not suffix or suffix=="" then
2712  return filename
2713 elseif criterium==true then
2714  return filename.."."..suffix
2715 elseif not criterium then
2716  local n,s=lpegmatch(pattern,filename)
2717  if not s or s=="" then
2718   return filename.."."..suffix
2719  else
2720   return filename
2721  end
2722 else
2723  local n,s=lpegmatch(pattern,filename)
2724  if s and s~="" then
2725   local t=type(criterium)
2726   if t=="table" then
2727    for i=1,#criterium do
2728     if s==criterium[i] then
2729      return filename
2730     end
2731    end
2732   elseif t=="string" then
2733    if s==criterium then
2734     return filename
2735    end
2736   end
2737  end
2738  return (n or filename).."."..suffix
2739 end
2740end
2741local suffix=period*(1-period-slashes)^1*-1
2742local pattern=Cs((1-suffix)^0)
2743function file.replacesuffix(name,suffix)
2744 if name and suffix and suffix~="" then
2745  return lpegmatch(pattern,name).."."..suffix
2746 else
2747  return name
2748 end
2749end
2750local reslasher=lpeg.replacer(P("\\"),"/")
2751function file.reslash(str)
2752 return str and lpegmatch(reslasher,str)
2753end
2754if lfs.isreadablefile and lfs.iswritablefile then
2755 file.is_readable=lfs.isreadablefile
2756 file.is_writable=lfs.iswritablefile
2757else
2758 function file.is_writable(name)
2759  if not name then
2760  elseif lfs.isdir(name) then
2761   name=name.."/m_t_x_t_e_s_t.tmp"
2762   local f=io.open(name,"wb")
2763   if f then
2764    f:close()
2765    os.remove(name)
2766    return true
2767   end
2768  elseif lfs.isfile(name) then
2769   local f=io.open(name,"ab")
2770   if f then
2771    f:close()
2772    return true
2773   end
2774  else
2775   local f=io.open(name,"ab")
2776   if f then
2777    f:close()
2778    os.remove(name)
2779    return true
2780   end
2781  end
2782  return false
2783 end
2784 local readable=P("r")*Cc(true)
2785 function file.is_readable(name)
2786  if name then
2787   local a=attributes(name)
2788   return a and lpegmatch(readable,a.permissions) or false
2789  else
2790   return false
2791  end
2792 end
2793end
2794file.isreadable=file.is_readable 
2795file.iswritable=file.is_writable 
2796function file.size(name)
2797 if name then
2798  local a=attributes(name)
2799  return a and a.size or 0
2800 else
2801  return 0
2802 end
2803end
2804function file.splitpath(str,separator) 
2805 return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator)
2806end
2807function file.joinpath(tab,separator) 
2808 return tab and concat(tab,separator or io.pathseparator) 
2809end
2810local someslash=S("\\/")
2811local stripper=Cs(P(fwslash)^0/""*reslasher)
2812local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon
2813local isroot=fwslash^1*-1
2814local hasroot=fwslash^1
2815local reslasher=lpeg.replacer(S("\\/"),"/")
2816local deslasher=lpeg.replacer(S("\\/")^1,"/")
2817function file.join(one,two,three,...)
2818 if not two then
2819  return one=="" and one or lpegmatch(reslasher,one)
2820 end
2821 if not one or one=="" then
2822  return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
2823 end
2824 if lpegmatch(isnetwork,one) then
2825  local one=lpegmatch(reslasher,one)
2826  local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
2827  if lpegmatch(hasroot,two) then
2828   return one..two
2829  else
2830   return one.."/"..two
2831  end
2832 elseif lpegmatch(isroot,one) then
2833  local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
2834  if lpegmatch(hasroot,two) then
2835   return two
2836  else
2837   return "/"..two
2838  end
2839 else
2840  return lpegmatch(deslasher,concat({  one,two,three,... },"/"))
2841 end
2842end
2843local drivespec=R("az","AZ")^1*colon
2844local anchors=fwslash+drivespec
2845local untouched=periods+(1-period)^1*P(-1)
2846local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0)
2847local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//")
2848local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
2849local absolute=fwslash
2850function file.collapsepath(str,anchor) 
2851 if not str then
2852  return
2853 end
2854 if anchor==true and not lpegmatch(anchors,str) then
2855  str=getcurrentdir().."/"..str
2856 end
2857 if str=="" or str=="." then
2858  return "."
2859 elseif lpegmatch(untouched,str) then
2860  return lpegmatch(reslasher,str)
2861 end
2862 local starter,oldelements=lpegmatch(splitstarter,str)
2863 local newelements={}
2864 local i=#oldelements
2865 while i>0 do
2866  local element=oldelements[i]
2867  if element=='.' then
2868  elseif element=='..' then
2869   local n=i-1
2870   while n>0 do
2871    local element=oldelements[n]
2872    if element~='..' and element~='.' then
2873     oldelements[n]='.'
2874     break
2875    else
2876     n=n-1
2877    end
2878    end
2879   if n<1 then
2880      insert(newelements,1,'..')
2881   end
2882  elseif element~="" then
2883   insert(newelements,1,element)
2884  end
2885  i=i-1
2886 end
2887 if #newelements==0 then
2888  return starter or "."
2889 elseif starter then
2890  return starter..concat(newelements,'/')
2891 elseif lpegmatch(absolute,str) then
2892  return "/"..concat(newelements,'/')
2893 else
2894  newelements=concat(newelements,'/')
2895  if anchor=="." and find(str,"^%./") then
2896   return "./"..newelements
2897  else
2898   return newelements
2899  end
2900 end
2901end
2902local validchars=R("az","09","AZ","--","..")
2903local pattern_a=lpeg.replacer(1-validchars)
2904local pattern_a=Cs((validchars+P(1)/"-")^1)
2905local whatever=P("-")^0/""
2906local pattern_b=Cs(whatever*(1-whatever*-1)^1)
2907function file.robustname(str,strict)
2908 if str then
2909  str=lpegmatch(pattern_a,str) or str
2910  if strict then
2911   return lpegmatch(pattern_b,str) or str 
2912  else
2913   return str
2914  end
2915 end
2916end
2917local loaddata=io.loaddata
2918local savedata=io.savedata
2919file.readdata=loaddata
2920file.savedata=savedata
2921function file.copy(oldname,newname)
2922 if oldname and newname then
2923  local data=loaddata(oldname)
2924  if data and data~="" then
2925   savedata(newname,data)
2926  end
2927 end
2928end
2929local letter=R("az","AZ")+S("_-+")
2930local separator=P("://")
2931local qualified=period^0*fwslash+letter*colon+letter^1*separator+letter^1*fwslash
2932local rootbased=fwslash+letter*colon
2933lpeg.patterns.qualified=qualified
2934lpeg.patterns.rootbased=rootbased
2935function file.is_qualified_path(filename)
2936 return filename and lpegmatch(qualified,filename)~=nil
2937end
2938function file.is_rootbased_path(filename)
2939 return filename and lpegmatch(rootbased,filename)~=nil
2940end
2941function file.strip(name,dir)
2942 if name then
2943  local b,a=match(name,"^(.-)"..dir.."(.*)$")
2944  return a~="" and a or name
2945 end
2946end
2947function lfs.mkdirs(path)
2948 local full=""
2949 for sub in gmatch(path,"(/*[^\\/]+)") do 
2950  full=full..sub
2951  lfs.mkdir(full)
2952 end
2953end
2954function file.withinbase(path) 
2955 local l=0
2956 if not find(path,"^/") then
2957  path="/"..path
2958 end
2959 for dir in gmatch(path,"/([^/]+)") do
2960  if dir==".." then
2961   l=l-1
2962  elseif dir~="." then
2963   l=l+1
2964  end
2965  if l<0 then
2966   return false
2967  end
2968 end
2969 return true
2970end
2971do
2972 local symlinktarget=lfs.symlinktarget  
2973 local symlinkattributes=lfs.symlinkattributes 
2974 if symlinktarget then
2975  function lfs.readlink(name)
2976   local target=symlinktarget(name)
2977   return name~=target and name or nil
2978  end
2979 elseif symlinkattributes then
2980  function lfs.readlink(name)
2981   return symlinkattributes(name,"target") or nil
2982  end
2983 else
2984  function lfs.readlink(name)
2985   return nil
2986  end
2987 end
2988end
2989
2990end -- closure
2991
2992do -- begin closure to overcome local limits and interference
2993
2994if not modules then modules={} end modules ['l-boolean']={
2995 version=1.001,
2996 comment="companion to luat-lib.mkiv",
2997 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
2998 copyright="PRAGMA ADE / ConTeXt Development Team",
2999 license="see context related readme files"
3000}
3001local type,tonumber=type,tonumber
3002boolean=boolean or {}
3003local boolean=boolean
3004function boolean.tonumber(b)
3005 if b then return 1 else return 0 end 
3006end
3007function toboolean(str,tolerant) 
3008 if  str==nil then
3009  return false
3010 elseif str==false then
3011  return false
3012 elseif str==true then
3013  return true
3014 elseif str=="true" then
3015  return true
3016 elseif str=="false" then
3017  return false
3018 elseif not tolerant then
3019  return false
3020 elseif str==0 then
3021  return false
3022 elseif (tonumber(str) or 0)>0 then
3023  return true
3024 else
3025  return str=="yes" or str=="on" or str=="t"
3026 end
3027end
3028string.toboolean=toboolean
3029function string.booleanstring(str)
3030 if str=="0" then
3031  return false
3032 elseif str=="1" then
3033  return true
3034 elseif str=="" then
3035  return false
3036 elseif str=="false" then
3037  return false
3038 elseif str=="true" then
3039  return true
3040 elseif (tonumber(str) or 0)>0 then
3041  return true
3042 else
3043  return str=="yes" or str=="on" or str=="t"
3044 end
3045end
3046function string.is_boolean(str,default,strict)
3047 if type(str)=="string" then
3048  if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then
3049   return true
3050  elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then
3051   return false
3052  end
3053 end
3054 return default
3055end
3056
3057end -- closure
3058
3059do -- begin closure to overcome local limits and interference
3060
3061if not modules then modules={} end modules ['l-math']={
3062 version=1.001,
3063 comment="companion to luat-lib.mkiv",
3064 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
3065 copyright="PRAGMA ADE / ConTeXt Development Team",
3066 license="see context related readme files"
3067}
3068if not math.ceiling then
3069 math.ceiling=math.ceil
3070end
3071if not math.round then
3072 if xmath then
3073  math.round=xmath.round
3074 else
3075  local floor=math.floor
3076  function math.round(x)
3077   return x<0 and -floor(-x+0.5) or floor(x+0.5)
3078  end
3079 end
3080end
3081if not math.div then
3082 local floor=math.floor
3083 function math.div(n,m) return floor(n/m) end
3084end
3085if not math.mod then
3086 function math.mod(n,m) return n%m end
3087end
3088if not math.sind then
3089 local sin,cos,tan=math.sin,math.cos,math.tan
3090 local pipi=2*math.pi/360
3091 function math.sind(d) return sin(d*pipi) end
3092 function math.cosd(d) return cos(d*pipi) end
3093 function math.tand(d) return tan(d*pipi) end
3094end
3095if not math.odd then
3096 function math.odd (n) return n%2~=0 end
3097 function math.even(n) return n%2==0 end
3098end
3099if not math.cosh then
3100 local exp=math.exp
3101 function math.cosh(x)
3102  local xx=exp(x)
3103  return (xx+1/xx)/2
3104 end
3105 function math.sinh(x)
3106  local xx=exp(x)
3107  return (xx-1/xx)/2
3108 end
3109 function math.tanh(x)
3110  local xx=exp(x)
3111  return (xx-1/xx)/(xx+1/xx)
3112 end
3113end
3114if not math.pow then
3115 function math.pow(x,y)
3116  return x^y
3117 end
3118end
3119if not math.atan2 then
3120 math.atan2=math.atan
3121end
3122if not math.ldexp then
3123 function math.ldexp(x,e)
3124  return x*2.0^e
3125 end
3126end
3127if not math.log10 then
3128 local log=math.log
3129 function math.log10(x)
3130  return log(x,10)
3131 end
3132end
3133if not math.type then
3134 function math.type()
3135  return "float"
3136 end
3137end
3138if not math.tointeger then
3139 math.mininteger=-0x4FFFFFFFFFFF
3140 math.maxinteger=0x4FFFFFFFFFFF
3141 local floor=math.floor
3142 function math.tointeger(n)
3143  local f=floor(n)
3144  return f==n and f or nil
3145 end
3146end
3147if not math.ult then
3148 local floor=math.floor
3149 function math.ult(m,n)
3150  return floor(m)<floor(n) 
3151 end
3152end
3153
3154end -- closure
3155
3156do -- begin closure to overcome local limits and interference
3157
3158if not modules then modules={} end modules ['util-str']={
3159 version=1.001,
3160 comment="companion to luat-lib.mkiv",
3161 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
3162 copyright="PRAGMA ADE / ConTeXt Development Team",
3163 license="see context related readme files"
3164}
3165utilities=utilities or {}
3166utilities.strings=utilities.strings or {}
3167local strings=utilities.strings
3168local format,gsub,rep,sub,find,char=string.format,string.gsub,string.rep,string.sub,string.find,string.char
3169local load,dump=load,string.dump
3170local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
3171local unpack,concat=table.unpack,table.concat
3172local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc
3173local patterns,lpegmatch=lpeg.patterns,lpeg.match
3174local tsplitat=lpeg.tsplitat
3175local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
3176local loadstripped=function(str,shortcuts)
3177 if shortcuts then
3178  return load(dump(load(str),true),nil,nil,shortcuts)
3179 else
3180  return load(dump(load(str),true))
3181 end
3182end
3183if not number then number={} end 
3184local stripzero=patterns.stripzero
3185local stripzeros=patterns.stripzeros
3186local newline=patterns.newline
3187local endofstring=patterns.endofstring
3188local anything=patterns.anything
3189local whitespace=patterns.whitespace
3190local space=patterns.space
3191local spacer=patterns.spacer
3192local spaceortab=patterns.spaceortab
3193local digit=patterns.digit
3194local sign=patterns.sign
3195local period=patterns.period
3196local ptf=1/65536
3197local bpf=(7200/7227)/65536
3198local function points(n)
3199 if n==0 then
3200  return "0pt"
3201 end
3202 n=tonumber(n)
3203 if not n or n==0 then
3204  return "0pt"
3205 end
3206 n=n*ptf
3207 if n%1==0 then
3208  return format("%ipt",n)
3209 else
3210  return lpegmatch(stripzeros,format("%.5fpt",n)) 
3211 end
3212end
3213local function nupoints(n)
3214 if n==0 then
3215  return "0"
3216 end
3217 n=tonumber(n)
3218 if not n or n==0 then
3219  return "0"
3220 end
3221 n=n*ptf
3222 if n%1==0 then
3223  return format("%i",n)
3224 else
3225  return format("%.5f",n) 
3226 end
3227end
3228local function basepoints(n)
3229 if n==0 then
3230  return "0bp"
3231 end
3232 n=tonumber(n)
3233 if not n or n==0 then
3234  return "0bp"
3235 end
3236 n=n*bpf
3237 if n%1==0 then
3238  return format("%ibp",n)
3239 else
3240  return lpegmatch(stripzeros,format("%.5fbp",n)) 
3241 end
3242end
3243local function nubasepoints(n)
3244 if n==0 then
3245  return "0"
3246 end
3247 n=tonumber(n)
3248 if not n or n==0 then
3249  return "0"
3250 end
3251 n=n*bpf
3252 if n%1==0 then
3253  return format("%i",n)
3254 else
3255  return format("%.5f",n) 
3256 end
3257end
3258number.points=points
3259number.nupoints=nupoints
3260number.basepoints=basepoints
3261number.nubasepoints=nubasepoints
3262local rubish=spaceortab^0*newline
3263local anyrubish=spaceortab+newline
3264local stripped=(spaceortab^1/"")*newline
3265local leading=rubish^0/""
3266local trailing=(anyrubish^1*endofstring)/""
3267local redundant=rubish^3/"\n"
3268local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0)
3269function strings.collapsecrlf(str)
3270 return lpegmatch(pattern,str)
3271end
3272local repeaters={} 
3273function strings.newrepeater(str,offset)
3274 offset=offset or 0
3275 local s=repeaters[str]
3276 if not s then
3277  s={}
3278  repeaters[str]=s
3279 end
3280 local t=s[offset]
3281 if t then
3282  return t
3283 end
3284 t={}
3285 setmetatable(t,{ __index=function(t,k)
3286  if not k then
3287   return ""
3288  end
3289  local n=k+offset
3290  local s=n>0 and rep(str,n) or ""
3291  t[k]=s
3292  return s
3293 end })
3294 s[offset]=t
3295 return t
3296end
3297local extra,tab,start=0,0,4,0
3298local nspaces=strings.newrepeater(" ")
3299string.nspaces=nspaces
3300local pattern=Carg(1)/function(t)
3301  extra,tab,start=0,t or 7,1
3302 end*Cs((
3303   Cp()*patterns.tab/function(position)
3304    local current=(position-start+1)+extra
3305    local spaces=tab-(current-1)%tab
3306    if spaces>0 then
3307     extra=extra+spaces-1
3308     return nspaces[spaces] 
3309    else
3310     return ""
3311    end
3312   end+newline*Cp()/function(position)
3313    extra,start=0,position
3314   end+anything
3315  )^1)
3316function strings.tabtospace(str,tab)
3317 return lpegmatch(pattern,str,1,tab or 7)
3318end
3319function string.utfpadding(s,n)
3320 if not n or n==0 then
3321  return ""
3322 end
3323 local l=utflen(s)
3324 if n>0 then
3325  return nspaces[n-l]
3326 else
3327  return nspaces[-n-l]
3328 end
3329end
3330local optionalspace=spacer^0
3331local nospace=optionalspace/""
3332local endofline=nospace*newline
3333local stripend=(whitespace^1*endofstring)/""
3334local normalline=(nospace*((1-optionalspace*(newline+endofstring))^1)*nospace)
3335local stripempty=endofline^1/""
3336local normalempty=endofline^1
3337local singleempty=endofline*(endofline^0/"")
3338local doubleempty=endofline*endofline^-1*(endofline^0/"")
3339local stripstart=stripempty^0
3340local intospace=whitespace^1/" "
3341local noleading=whitespace^1/""
3342local notrailing=noleading*endofstring
3343local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 )
3344local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 )
3345local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 )
3346local p_prune_intospace=Cs (noleading*(notrailing+intospace+1     )^0 )
3347local p_retain_normal=Cs ((normalline+normalempty )^0 )
3348local p_retain_collapse=Cs ((normalline+doubleempty )^0 )
3349local p_retain_noempty=Cs ((normalline+singleempty )^0 )
3350local p_collapse_all=Cs (stripstart*(stripend+((whitespace+newline)^1/" ")+1)^0 )
3351local striplinepatterns={
3352 ["prune"]=p_prune_normal,
3353 ["prune and collapse"]=p_prune_collapse,
3354 ["prune and no empty"]=p_prune_noempty,
3355 ["prune and to space"]=p_prune_intospace,
3356 ["retain"]=p_retain_normal,
3357 ["retain and collapse"]=p_retain_collapse,
3358 ["retain and no empty"]=p_retain_noempty,
3359 ["collapse all"]=p_collapse_all,
3360 ["collapse"]=patterns.collapser,
3361}
3362setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end })
3363strings.striplinepatterns=striplinepatterns
3364function strings.striplines(str,how)
3365 return str and lpegmatch(striplinepatterns[how],str) or str
3366end
3367function strings.collapse(str) 
3368 return str and lpegmatch(p_prune_intospace,str) or str
3369end
3370strings.striplong=strings.striplines
3371function strings.nice(str)
3372 str=gsub(str,"[:%-+_]+"," ") 
3373 return str
3374end
3375local n=0
3376local sequenced=table.sequenced
3377function string.autodouble(s,sep)
3378 if s==nil then
3379  return '""'
3380 end
3381 local t=type(s)
3382 if t=="number" then
3383  return tostring(s) 
3384 end
3385 if t=="table" then
3386  return ('"'..sequenced(s,sep or ",")..'"')
3387 end
3388 return ('"'..tostring(s)..'"')
3389end
3390function string.autosingle(s,sep)
3391 if s==nil then
3392  return "''"
3393 end
3394 local t=type(s)
3395 if t=="number" then
3396  return tostring(s) 
3397 end
3398 if t=="table" then
3399  return ("'"..sequenced(s,sep or ",").."'")
3400 end
3401 return ("'"..tostring(s).."'")
3402end
3403local tracedchars={ [0]=
3404 "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]",
3405 "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]",
3406 "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]",
3407 "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]",
3408 "[space]",
3409}
3410string.tracedchars=tracedchars
3411strings.tracers=tracedchars
3412function string.tracedchar(b)
3413 if type(b)=="number" then
3414  return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")")
3415 else
3416  local c=utfbyte(b)
3417  return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")")
3418 end
3419end
3420function number.signed(i)
3421 if i>0 then
3422  return "+",i
3423 else
3424  return "-",-i
3425 end
3426end
3427local two=digit*digit
3428local three=two*digit
3429local prefix=(Carg(1)*three)^1
3430local splitter=Cs (
3431 (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2)
3432)
3433local splitter3=Cs (
3434 three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit
3435)
3436patterns.formattednumber=splitter
3437function number.formatted(n,sep1,sep2)
3438 if sep1==false then
3439  if type(n)=="number" then
3440   n=tostring(n)
3441  end
3442  return lpegmatch(splitter3,n,1,sep2 or ".")
3443 else
3444  if type(n)=="number" then
3445   n=format("%0.2f",n)
3446  end
3447  if sep1==true then
3448   return lpegmatch(splitter,n,1,".",",")
3449  elseif sep1=="." then
3450   return lpegmatch(splitter,n,1,sep1,sep2 or ",")
3451  elseif sep1=="," then
3452   return lpegmatch(splitter,n,1,sep1,sep2 or ".")
3453  else
3454   return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".")
3455  end
3456 end
3457end
3458local p=Cs(
3459  P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0
3460 )
3461function number.compactfloat(n,fmt)
3462 if n==0 then
3463  return "0"
3464 elseif n==1 then
3465  return "1"
3466 end
3467 n=lpegmatch(p,format(fmt or "%0.3f",n))
3468 if n=="." or n=="" or n=="-" then
3469  return "0"
3470 end
3471 return n
3472end
3473local zero=P("0")^1/""
3474local plus=P("+")/""
3475local minus=P("-")
3476local separator=period
3477local trailing=zero^1*#S("eE")
3478local exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1))
3479local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
3480local pattern_b=Cs((exponent+anything)^0)
3481function number.sparseexponent(f,n)
3482 if not n then
3483  n=f
3484  f="%e"
3485 end
3486 local tn=type(n)
3487 if tn=="string" then 
3488  local m=tonumber(n)
3489  if m then
3490   return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,m))
3491  end
3492 elseif tn=="number" then
3493  return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,n))
3494 end
3495 return tostring(n)
3496end
3497local hf={}
3498local hs={}
3499setmetatable(hf,{ __index=function(t,k)
3500 local v="%."..k.."f"
3501 t[k]=v
3502 return v
3503end } )
3504setmetatable(hs,{ __index=function(t,k)
3505 local v="%"..k.."s"
3506 t[k]=v
3507 return v
3508end } )
3509function number.formattedfloat(n,b,a)
3510 local s=format(hf[a],n)
3511 local l=(b or 0)+(a or 0)+1
3512 if #s<l then
3513  return format(hs[l],s)
3514 else
3515  return s
3516 end
3517end
3518local template=[[
3519%s
3520%s
3521return function(%s) return %s end
3522]]
3523local pattern=Cs(Cc('"')*(
3524 (1-S('"\\\n\r'))^1+P('"')/'\\"'+P('\\')/'\\\\'+P('\n')/'\\n'+P('\r')/'\\r'
3525)^0*Cc('"'))
3526patterns.escapedquotes=pattern
3527function string.escapedquotes(s)
3528 return lpegmatch(pattern,s)
3529end
3530local pattern=(1-P("\\"))^1;pattern=Cs (
3531 pattern*((P("\\")/""*(digit^-3/function(s) return char(tonumber(s)) end))+pattern )^1
3532)
3533patterns.unescapedquotes=pattern
3534function string.unescapedquotes(s)
3535 return lpegmatch(pattern,s) or s
3536end
3537string.texnewlines=lpeg.replacer(patterns.newline,"\r",true)
3538local preamble=""
3539local environment={
3540 global=global or _G,
3541 lpeg=lpeg,
3542 type=type,
3543 tostring=tostring,
3544 tonumber=tonumber,
3545 format=string.format,
3546 concat=table.concat,
3547 signed=number.signed,
3548 points=number.points,
3549 nupoints=number.nupoints,
3550 basepoints=number.basepoints,
3551 nubasepoints=number.nubasepoints,
3552 utfchar=utf.char,
3553 utfbyte=utf.byte,
3554 lpegmatch=lpeg.match,
3555 nspaces=string.nspaces,
3556 utfpadding=string.utfpadding,
3557 tracedchar=string.tracedchar,
3558 autosingle=string.autosingle,
3559 autodouble=string.autodouble,
3560 sequenced=table.sequenced,
3561 formattednumber=number.formatted,
3562 sparseexponent=number.sparseexponent,
3563 formattedfloat=number.formattedfloat,
3564 stripzero=patterns.stripzero,
3565 stripzeros=patterns.stripzeros,
3566 escapedquotes=string.escapedquotes,
3567 FORMAT=string.f6,
3568}
3569local arguments={ "a1" } 
3570setmetatable(arguments,{ __index=function(t,k)
3571  local v=t[k-1]..",a"..k
3572  t[k]=v
3573  return v
3574 end
3575})
3576local prefix_any=C((sign+space+period+digit)^0)
3577local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(0))
3578local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0)
3579local format_s=function(f)
3580 n=n+1
3581 if f and f~="" then
3582  return format("format('%%%ss',a%s)",f,n)
3583 else 
3584  return format("(a%s or '')",n) 
3585 end
3586end
3587local format_S=function(f) 
3588 n=n+1
3589 if f and f~="" then
3590  return format("format('%%%ss',tostring(a%s))",f,n)
3591 else
3592  return format("tostring(a%s)",n)
3593 end
3594end
3595local format_right=function(f)
3596 n=n+1
3597 f=tonumber(f)
3598 if not f or f==0 then
3599  return format("(a%s or '')",n)
3600 elseif f>0 then
3601  return format("utfpadding(a%s,%i)..a%s",n,f,n)
3602 else
3603  return format("a%s..utfpadding(a%s,%i)",n,n,f)
3604 end
3605end
3606local format_left=function(f)
3607 n=n+1
3608 f=tonumber(f)
3609 if not f or f==0 then
3610  return format("(a%s or '')",n)
3611 end
3612 if f<0 then
3613  return format("utfpadding(a%s,%i)..a%s",n,-f,n)
3614 else
3615  return format("a%s..utfpadding(a%s,%i)",n,n,-f)
3616 end
3617end
3618local format_q=JITSUPPORTED and function()
3619 n=n+1
3620 return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
3621end or function()
3622 n=n+1
3623 return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
3624end
3625local format_Q=function() 
3626 n=n+1
3627 return format("escapedquotes(tostring(a%s))",n)
3628end
3629local format_i=function(f)
3630 n=n+1
3631 if f and f~="" then
3632  return format("format('%%%si',a%s)",f,n)
3633 else
3634  return format("format('%%i',a%s)",n) 
3635 end
3636end
3637local format_d=format_i
3638local format_I=function(f)
3639 n=n+1
3640 return format("format('%%s%%%si',signed(a%s))",f,n)
3641end
3642local format_f=function(f)
3643 n=n+1
3644 return format("format('%%%sf',a%s)",f,n)
3645end
3646local format_F=function(f) 
3647 n=n+1
3648 if not f or f=="" then
3649  return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n)
3650 else
3651  return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n)
3652 end
3653end
3654local format_k=function(b,a) 
3655 n=n+1
3656 return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0)
3657end
3658local format_g=function(f)
3659 n=n+1
3660 return format("format('%%%sg',a%s)",f,n)
3661end
3662local format_G=function(f)
3663 n=n+1
3664 return format("format('%%%sG',a%s)",f,n)
3665end
3666local format_e=function(f)
3667 n=n+1
3668 return format("format('%%%se',a%s)",f,n)
3669end
3670local format_E=function(f)
3671 n=n+1
3672 return format("format('%%%sE',a%s)",f,n)
3673end
3674local format_j=function(f)
3675 n=n+1
3676 return format("sparseexponent('%%%se',a%s)",f,n)
3677end
3678local format_J=function(f)
3679 n=n+1
3680 return format("sparseexponent('%%%sE',a%s)",f,n)
3681end
3682local format_x=function(f)
3683 n=n+1
3684 return format("format('%%%sx',a%s)",f,n)
3685end
3686local format_X=function(f)
3687 n=n+1
3688 return format("format('%%%sX',a%s)",f,n)
3689end
3690local format_o=function(f)
3691 n=n+1
3692 return format("format('%%%so',a%s)",f,n)
3693end
3694local format_c=function()
3695 n=n+1
3696 return format("utfchar(a%s)",n)
3697end
3698local format_C=function()
3699 n=n+1
3700 return format("tracedchar(a%s)",n)
3701end
3702local format_r=function(f)
3703 n=n+1
3704 return format("format('%%%s.0f',a%s)",f,n)
3705end
3706local format_h=function(f)
3707 n=n+1
3708 if f=="-" then
3709  f=sub(f,2)
3710  return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3711 else
3712  return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3713 end
3714end
3715local format_H=function(f)
3716 n=n+1
3717 if f=="-" then
3718  f=sub(f,2)
3719  return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3720 else
3721  return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3722 end
3723end
3724local format_u=function(f)
3725 n=n+1
3726 if f=="-" then
3727  f=sub(f,2)
3728  return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3729 else
3730  return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3731 end
3732end
3733local format_U=function(f)
3734 n=n+1
3735 if f=="-" then
3736  f=sub(f,2)
3737  return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3738 else
3739  return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n)
3740 end
3741end
3742local format_p=function()
3743 n=n+1
3744 return format("points(a%s)",n)
3745end
3746local format_P=function()
3747 n=n+1
3748 return format("nupoints(a%s)",n)
3749end
3750local format_b=function()
3751 n=n+1
3752 return format("basepoints(a%s)",n)
3753end
3754local format_B=function()
3755 n=n+1
3756 return format("nubasepoints(a%s)",n)
3757end
3758local format_t=function(f)
3759 n=n+1
3760 if f and f~="" then
3761  return format("concat(a%s,%q)",n,f)
3762 else
3763  return format("concat(a%s)",n)
3764 end
3765end
3766local format_T=function(f)
3767 n=n+1
3768 if f and f~="" then
3769  return format("sequenced(a%s,%q)",n,f)
3770 else
3771  return format("sequenced(a%s)",n)
3772 end
3773end
3774local format_l=function()
3775 n=n+1
3776 return format("(a%s and 'true' or 'false')",n)
3777end
3778local format_L=function()
3779 n=n+1
3780 return format("(a%s and 'TRUE' or 'FALSE')",n)
3781end
3782local format_n=function() 
3783 n=n+1
3784 return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n)
3785end
3786local format_N  if environment.FORMAT then
3787 format_N=function(f)
3788  n=n+1
3789  if not f or f=="" then
3790   return format("FORMAT(a%s,'%%.9f')",n)
3791  elseif f==".6" or f=="0.6" then
3792   return format("FORMAT(a%s)",n)
3793  else
3794   return format("FORMAT(a%s,'%%%sf')",n,f)
3795  end
3796 end
3797else
3798 format_N=function(f) 
3799  n=n+1
3800  if not f or f=="" then
3801   f=".9"
3802  end 
3803  return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
3804 end
3805end
3806local format_a=function(f)
3807 n=n+1
3808 if f and f~="" then
3809  return format("autosingle(a%s,%q)",n,f)
3810 else
3811  return format("autosingle(a%s)",n)
3812 end
3813end
3814local format_A=function(f)
3815 n=n+1
3816 if f and f~="" then
3817  return format("autodouble(a%s,%q)",n,f)
3818 else
3819  return format("autodouble(a%s)",n)
3820 end
3821end
3822local format_w=function(f) 
3823 n=n+1
3824 f=tonumber(f)
3825 if f then 
3826  return format("nspaces[%s+a%s]",f,n) 
3827 else
3828  return format("nspaces[a%s]",n) 
3829 end
3830end
3831local format_W=function(f) 
3832 return format("nspaces[%s]",tonumber(f) or 0)
3833end
3834local format_m=function(f)
3835 n=n+1
3836 if not f or f=="" then
3837  f=","
3838 end
3839 if f=="0" then
3840  return format([[formattednumber(a%s,false)]],n)
3841 else
3842  return format([[formattednumber(a%s,%q,".")]],n,f)
3843 end
3844end
3845local format_M=function(f)
3846 n=n+1
3847 if not f or f=="" then
3848  f="."
3849 end
3850 if f=="0" then
3851  return format([[formattednumber(a%s,false)]],n)
3852 else
3853  return format([[formattednumber(a%s,%q,",")]],n,f)
3854 end
3855end
3856local format_z=function(f)
3857 n=n+(tonumber(f) or 1)
3858 return "''" 
3859end
3860local format_rest=function(s)
3861 return format("%q",s) 
3862end
3863local format_extension=function(extensions,f,name)
3864 local extension=extensions[name] or "tostring(%s)"
3865 local f=tonumber(f) or 1
3866 local w=find(extension,"%.%.%.")
3867 if f==0 then
3868  if w then
3869   extension=gsub(extension,"%.%.%.","")
3870  end
3871  return extension
3872 elseif f==1 then
3873  if w then
3874   extension=gsub(extension,"%.%.%.","%%s")
3875  end
3876  n=n+1
3877  local a="a"..n
3878  return format(extension,a,a) 
3879 elseif f<0 then
3880  if w then
3881   extension=gsub(extension,"%.%.%.","")
3882   return extension
3883  else
3884   local a="a"..(n+f+1)
3885   return format(extension,a,a)
3886  end
3887 else
3888  if w then
3889   extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
3890  end
3891  local t={}
3892  for i=1,f do
3893   n=n+1
3894   t[i]="a"..n
3895  end
3896  return format(extension,unpack(t))
3897 end
3898end
3899local builder=Cs { "start",
3900 start=(
3901  (
3902   P("%")/""*(
3903    V("!") 
3904+V("s")+V("q")+V("i")+V("d")+V("f")+V("F")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o")
3905+V("c")+V("C")+V("S") 
3906+V("Q") 
3907+V("n") 
3908+V("N") 
3909+V("k")
3910+V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("P")+V("b")+V("B")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w") 
3911+V("W") 
3912+V("a") 
3913+V("A") 
3914+V("j")+V("J") 
3915+V("m")+V("M") 
3916+V("z")
3917+V(">") 
3918+V("<")
3919   )+V("*")
3920  )*(endofstring+Carg(1))
3921 )^0,
3922 ["s"]=(prefix_any*P("s"))/format_s,
3923 ["q"]=(prefix_any*P("q"))/format_q,
3924 ["i"]=(prefix_any*P("i"))/format_i,
3925 ["d"]=(prefix_any*P("d"))/format_d,
3926 ["f"]=(prefix_any*P("f"))/format_f,
3927 ["F"]=(prefix_any*P("F"))/format_F,
3928 ["g"]=(prefix_any*P("g"))/format_g,
3929 ["G"]=(prefix_any*P("G"))/format_G,
3930 ["e"]=(prefix_any*P("e"))/format_e,
3931 ["E"]=(prefix_any*P("E"))/format_E,
3932 ["x"]=(prefix_any*P("x"))/format_x,
3933 ["X"]=(prefix_any*P("X"))/format_X,
3934 ["o"]=(prefix_any*P("o"))/format_o,
3935 ["S"]=(prefix_any*P("S"))/format_S,
3936 ["Q"]=(prefix_any*P("Q"))/format_Q,
3937 ["n"]=(prefix_any*P("n"))/format_n,
3938 ["N"]=(prefix_any*P("N"))/format_N,
3939 ["k"]=(prefix_sub*P("k"))/format_k,
3940 ["c"]=(prefix_any*P("c"))/format_c,
3941 ["C"]=(prefix_any*P("C"))/format_C,
3942 ["r"]=(prefix_any*P("r"))/format_r,
3943 ["h"]=(prefix_any*P("h"))/format_h,
3944 ["H"]=(prefix_any*P("H"))/format_H,
3945 ["u"]=(prefix_any*P("u"))/format_u,
3946 ["U"]=(prefix_any*P("U"))/format_U,
3947 ["p"]=(prefix_any*P("p"))/format_p,
3948 ["P"]=(prefix_any*P("P"))/format_P,
3949 ["b"]=(prefix_any*P("b"))/format_b,
3950 ["B"]=(prefix_any*P("B"))/format_B,
3951 ["t"]=(prefix_tab*P("t"))/format_t,
3952 ["T"]=(prefix_tab*P("T"))/format_T,
3953 ["l"]=(prefix_any*P("l"))/format_l,
3954 ["L"]=(prefix_any*P("L"))/format_L,
3955 ["I"]=(prefix_any*P("I"))/format_I,
3956 ["w"]=(prefix_any*P("w"))/format_w,
3957 ["W"]=(prefix_any*P("W"))/format_W,
3958 ["j"]=(prefix_any*P("j"))/format_j,
3959 ["J"]=(prefix_any*P("J"))/format_J,
3960 ["m"]=(prefix_any*P("m"))/format_m,
3961 ["M"]=(prefix_any*P("M"))/format_M,
3962 ["z"]=(prefix_any*P("z"))/format_z,
3963 ["a"]=(prefix_any*P("a"))/format_a,
3964 ["A"]=(prefix_any*P("A"))/format_A,
3965 ["<"]=(prefix_any*P("<"))/format_left,
3966 [">"]=(prefix_any*P(">"))/format_right,
3967 ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest,
3968 ["?"]=Cs(((1-P("%"))^1      )^1)/format_rest,
3969 ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension,
3970}
3971local xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end })
3972local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end })
3973local preset={
3974 ["%02x"]=function(n) return xx[n] end,
3975 ["%02X"]=function(n) return XX[n] end,
3976}
3977local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]]
3978local function make(t,str)
3979 local f=preset[str]
3980 if f then
3981  return f
3982 end
3983 local p=lpegmatch(direct,str)
3984 if p then
3985  f=loadstripped(p)()
3986 else
3987  n=0
3988  p=lpegmatch(builder,str,1,t._connector_,t._extensions_) 
3989  if n>0 then
3990   p=format(template,preamble,t._preamble_,arguments[n],p)
3991   f=loadstripped(p,t._environment_)() 
3992  else
3993   f=function() return str end
3994  end
3995 end
3996 t[str]=f
3997 return f
3998end
3999local function use(t,fmt,...)
4000 return t[fmt](...)
4001end
4002strings.formatters={}
4003function strings.formatters.new(noconcat)
4004 local e={} 
4005 for k,v in next,environment do
4006  e[k]=v
4007 end
4008 local t={
4009  _type_="formatter",
4010  _connector_=noconcat and "," or "..",
4011  _extensions_={},
4012  _preamble_="",
4013  _environment_=e,
4014 }
4015 setmetatable(t,{ __index=make,__call=use })
4016 return t
4017end
4018local formatters=strings.formatters.new() 
4019string.formatters=formatters 
4020string.formatter=function(str,...) return formatters[str](...) end 
4021local function add(t,name,template,preamble)
4022 if type(t)=="table" and t._type_=="formatter" then
4023  t._extensions_[name]=template or "%s"
4024  if type(preamble)=="string" then
4025   t._preamble_=preamble.."\n"..t._preamble_ 
4026  elseif type(preamble)=="table" then
4027   for k,v in next,preamble do
4028    t._environment_[k]=v
4029   end
4030  end
4031 end
4032end
4033strings.formatters.add=add
4034patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+anything)^0)
4035patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^0)
4036patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) 
4037patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"'))
4038add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=patterns.xmlescape })
4039add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=patterns.texescape })
4040add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=patterns.luaescape })
4041local dquote=patterns.dquote 
4042local equote=patterns.escaped+dquote/'\\"'+1
4043local cquote=Cc('"')
4044local pattern=Cs(dquote*(equote-P(-2))^0*dquote)     
4045+Cs(cquote*(equote-space)^0*space*equote^0*cquote) 
4046function string.optionalquoted(str)
4047 return lpegmatch(pattern,str) or str
4048end
4049local pattern=Cs((newline/(os.newline or "\r")+1)^0)
4050function string.replacenewlines(str)
4051 return lpegmatch(pattern,str)
4052end
4053function strings.newcollector()
4054 local result,r={},0
4055 return
4056  function(fmt,str,...) 
4057   r=r+1
4058   result[r]=str==nil and fmt or formatters[fmt](str,...)
4059  end,
4060  function(connector) 
4061   if result then
4062    local str=concat(result,connector)
4063    result,r={},0
4064    return str
4065   end
4066  end
4067end
4068local f_16_16=formatters["%0.5N"]
4069function number.to16dot16(n)
4070 return f_16_16(n/65536.0)
4071end
4072if not string.explode then
4073 local p_utf=patterns.utf8character
4074 local p_check=C(p_utf)*(P("+")*Cc(true))^0
4075 local p_split=Ct(C(p_utf)^0)
4076 local p_space=Ct((C(1-P(" ")^1)+P(" ")^1)^0)
4077 function string.explode(str,symbol)
4078  if symbol=="" then
4079   return lpegmatch(p_split,str)
4080  elseif symbol then
4081   local a,b=lpegmatch(p_check,symbol)
4082   if b then
4083    return lpegmatch(tsplitat(P(a)^1),str)
4084   else
4085    return lpegmatch(tsplitat(a),str)
4086   end
4087  else
4088   return lpegmatch(p_space,str)
4089  end
4090 end
4091end
4092do
4093 local p_whitespace=patterns.whitespace^1
4094 local cache=setmetatable({},{ __index=function(t,k)
4095  local p=tsplitat(p_whitespace*P(k)*p_whitespace)
4096  local v=function(s)
4097   return lpegmatch(p,s)
4098  end
4099  t[k]=v
4100  return v
4101 end })
4102 function string.wordsplitter(s)
4103  return cache[s]
4104 end
4105end
4106if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
4107 local t={
4108  ["#"]="#H",
4109  ["\n"]="#L",
4110  ['"']="#Q",
4111  ["\r"]="#R",
4112  [" "]="#S",
4113  ["\t"]="#T",
4114  ["\\"]="#X",
4115 }
4116 function string.texhashed(s)
4117  return (gsub(s,".",t))
4118 end
4119end
4120
4121end -- closure
4122
4123do -- begin closure to overcome local limits and interference
4124
4125if not modules then modules={} end modules ['util-fil']={
4126 version=1.001,
4127 optimize=true,
4128 comment="companion to luat-lib.mkiv",
4129 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
4130 copyright="PRAGMA ADE / ConTeXt Development Team",
4131 license="see context related readme files"
4132}
4133local tonumber=tonumber
4134local byte=string.byte
4135local char=string.char
4136utilities=utilities or {}
4137local files={}
4138utilities.files=files
4139local zerobased={}
4140function files.open(filename,zb)
4141 local f=io.open(filename,"rb")
4142 if f then
4143  zerobased[f]=zb or false
4144 end
4145 return f
4146end
4147function files.close(f)
4148 zerobased[f]=nil
4149 f:close()
4150end
4151function files.size(f)
4152 local current=f:seek()
4153 local size=f:seek("end")
4154 f:seek("set",current)
4155 return size
4156end
4157files.getsize=files.size
4158function files.setposition(f,n)
4159 if zerobased[f] then
4160  f:seek("set",n)
4161 else
4162  f:seek("set",n-1)
4163 end
4164end
4165function files.getposition(f)
4166 if zerobased[f] then
4167  return f:seek()
4168 else
4169  return f:seek()+1
4170 end
4171end
4172function files.look(f,n,chars)
4173 local p=f:seek()
4174 local s=f:read(n)
4175 f:seek("set",p)
4176 if chars then
4177  return s
4178 else
4179  return byte(s,1,#s)
4180 end
4181end
4182function files.skip(f,n)
4183 if n==1 then
4184  f:read(n)
4185 else
4186  f:seek("set",f:seek()+n)
4187 end
4188end
4189function files.readbyte(f)
4190 return byte(f:read(1))
4191end
4192function files.readbytes(f,n)
4193 return byte(f:read(n),1,n)
4194end
4195function files.readbytetable(f,n)
4196 local s=f:read(n or 1)
4197 return { byte(s,1,#s) } 
4198end
4199function files.readchar(f)
4200 return f:read(1)
4201end
4202function files.readstring(f,n)
4203 return f:read(n or 1)
4204end
4205function files.readinteger1(f)  
4206 local n=byte(f:read(1))
4207 if n>=0x80 then
4208  return n-0x100
4209 else
4210  return n
4211 end
4212end
4213files.readcardinal1=files.readbyte  
4214files.readcardinal=files.readcardinal1
4215files.readinteger=files.readinteger1
4216files.readsignedbyte=files.readinteger1
4217function files.readcardinal2(f)
4218 local a,b=byte(f:read(2),1,2)
4219 return 0x100*a+b
4220end
4221function files.readcardinal2le(f)
4222 local b,a=byte(f:read(2),1,2)
4223 return 0x100*a+b
4224end
4225function files.readinteger2(f)
4226 local a,b=byte(f:read(2),1,2)
4227 if a>=0x80 then
4228  return 0x100*a+b-0x10000
4229 else
4230  return 0x100*a+b
4231 end
4232end
4233function files.readinteger2le(f)
4234 local b,a=byte(f:read(2),1,2)
4235 if a>=0x80 then
4236  return 0x100*a+b-0x10000
4237 else
4238  return 0x100*a+b
4239 end
4240end
4241function files.readcardinal3(f)
4242 local a,b,c=byte(f:read(3),1,3)
4243 return 0x10000*a+0x100*b+c
4244end
4245function files.readcardinal3le(f)
4246 local c,b,a=byte(f:read(3),1,3)
4247 return 0x10000*a+0x100*b+c
4248end
4249function files.readinteger3(f)
4250 local a,b,c=byte(f:read(3),1,3)
4251 if a>=0x80 then
4252  return 0x10000*a+0x100*b+c-0x1000000
4253 else
4254  return 0x10000*a+0x100*b+c
4255 end
4256end
4257function files.readinteger3le(f)
4258 local c,b,a=byte(f:read(3),1,3)
4259 if a>=0x80 then
4260  return 0x10000*a+0x100*b+c-0x1000000
4261 else
4262  return 0x10000*a+0x100*b+c
4263 end
4264end
4265function files.readcardinal4(f)
4266 local a,b,c,d=byte(f:read(4),1,4)
4267 return 0x1000000*a+0x10000*b+0x100*c+d
4268end
4269function files.readcardinal4le(f)
4270 local d,c,b,a=byte(f:read(4),1,4)
4271 return 0x1000000*a+0x10000*b+0x100*c+d
4272end
4273function files.readinteger4(f)
4274 local a,b,c,d=byte(f:read(4),1,4)
4275 if a>=0x80 then
4276  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
4277 else
4278  return 0x1000000*a+0x10000*b+0x100*c+d
4279 end
4280end
4281function files.readinteger4le(f)
4282 local d,c,b,a=byte(f:read(4),1,4)
4283 if a>=0x80 then
4284  return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
4285 else
4286  return 0x1000000*a+0x10000*b+0x100*c+d
4287 end
4288end
4289function files.readfixed2(f)
4290 local n1,n2=byte(f:read(2),1,2)
4291 if n1>=0x80 then
4292  n1=n1-0x100
4293 end
4294 return n1+n2/0xFF
4295end
4296function files.readfixed4(f)
4297 local a,b,c,d=byte(f:read(4),1,4)
4298 local n1=0x100*a+b
4299 local n2=0x100*c+d
4300 if n1>=0x8000 then
4301  n1=n1-0x10000
4302 end
4303 return n1+n2/0xFFFF
4304end
4305if bit32 then
4306 local extract=bit32.extract
4307 local band=bit32.band
4308 function files.read2dot14(f)
4309  local a,b=byte(f:read(2),1,2)
4310  if a>=0x80 then
4311   local n=-(0x100*a+b)
4312   return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
4313  else
4314   local n=0x100*a+b
4315   return   (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
4316  end
4317 end
4318end
4319function files.skipshort(f,n)
4320 f:read(2*(n or 1))
4321end
4322function files.skiplong(f,n)
4323 f:read(4*(n or 1))
4324end
4325if bit32 then
4326 local rshift=bit32.rshift
4327 function files.writecardinal2(f,n)
4328  local a=char(n%256)
4329  n=rshift(n,8)
4330  local b=char(n%256)
4331  f:write(b,a)
4332 end
4333 function files.writecardinal4(f,n)
4334  local a=char(n%256)
4335  n=rshift(n,8)
4336  local b=char(n%256)
4337  n=rshift(n,8)
4338  local c=char(n%256)
4339  n=rshift(n,8)
4340  local d=char(n%256)
4341  f:write(d,c,b,a)
4342 end
4343 function files.writecardinal2le(f,n)
4344  local a=char(n%256)
4345  n=rshift(n,8)
4346  local b=char(n%256)
4347  f:write(a,b)
4348 end
4349 function files.writecardinal4le(f,n)
4350  local a=char(n%256)
4351  n=rshift(n,8)
4352  local b=char(n%256)
4353  n=rshift(n,8)
4354  local c=char(n%256)
4355  n=rshift(n,8)
4356  local d=char(n%256)
4357  f:write(a,b,c,d)
4358 end
4359else
4360 local floor=math.floor
4361 function files.writecardinal2(f,n)
4362  local a=char(n%256)
4363  n=floor(n/256)
4364  local b=char(n%256)
4365  f:write(b,a)
4366 end
4367 function files.writecardinal4(f,n)
4368  local a=char(n%256)
4369  n=floor(n/256)
4370  local b=char(n%256)
4371  n=floor(n/256)
4372  local c=char(n%256)
4373  n=floor(n/256)
4374  local d=char(n%256)
4375  f:write(d,c,b,a)
4376 end
4377 function files.writecardinal2le(f,n)
4378  local a=char(n%256)
4379  n=floor(n/256)
4380  local b=char(n%256)
4381  f:write(a,b)
4382 end
4383 function files.writecardinal4le(f,n)
4384  local a=char(n%256)
4385  n=floor(n/256)
4386  local b=char(n%256)
4387  n=floor(n/256)
4388  local c=char(n%256)
4389  n=floor(n/256)
4390  local d=char(n%256)
4391  f:write(a,b,c,d)
4392 end
4393end
4394function files.writestring(f,s)
4395 f:write(char(byte(s,1,#s)))
4396end
4397function files.writebyte(f,b)
4398 f:write(char(b))
4399end
4400if fio and fio.readcardinal1 then
4401 files.readcardinal1=fio.readcardinal1
4402 files.readcardinal2=fio.readcardinal2
4403 files.readcardinal3=fio.readcardinal3
4404 files.readcardinal4=fio.readcardinal4
4405 files.readcardinal1le=fio.readcardinal1le or files.readcardinal1le
4406 files.readcardinal2le=fio.readcardinal2le or files.readcardinal2le
4407 files.readcardinal3le=fio.readcardinal3le or files.readcardinal3le
4408 files.readcardinal4le=fio.readcardinal4le or files.readcardinal4le
4409 files.readinteger1=fio.readinteger1
4410 files.readinteger2=fio.readinteger2
4411 files.readinteger3=fio.readinteger3
4412 files.readinteger4=fio.readinteger4
4413 files.readinteger1le=fio.readinteger1le or files.readinteger1le
4414 files.readinteger2le=fio.readinteger2le or files.readinteger2le
4415 files.readinteger3le=fio.readinteger3le or files.readinteger3le
4416 files.readinteger4le=fio.readinteger4le or files.readinteger4le
4417 files.readfixed2=fio.readfixed2
4418 files.readfixed4=fio.readfixed4
4419 files.read2dot14=fio.read2dot14
4420 files.setposition=fio.setposition
4421 files.getposition=fio.getposition
4422 files.readbyte=files.readcardinal1
4423 files.readsignedbyte=files.readinteger1
4424 files.readcardinal=files.readcardinal1
4425 files.readinteger=files.readinteger1
4426 local skipposition=fio.skipposition
4427 files.skipposition=skipposition
4428 files.readbytes=fio.readbytes
4429 files.readbytetable=fio.readbytetable
4430 function files.skipshort(f,n)
4431  skipposition(f,2*(n or 1))
4432 end
4433 function files.skiplong(f,n)
4434  skipposition(f,4*(n or 1))
4435 end
4436end
4437if fio and fio.writecardinal1 then
4438 files.writecardinal1=fio.writecardinal1
4439 files.writecardinal2=fio.writecardinal2
4440 files.writecardinal3=fio.writecardinal3
4441 files.writecardinal4=fio.writecardinal4
4442 files.writecardinal1le=fio.writecardinal1le
4443 files.writecardinal2le=fio.writecardinal2le
4444 files.writecardinal3le=fio.writecardinal3le
4445 files.writecardinal4le=fio.writecardinal4le
4446 files.writeinteger1=fio.writeinteger1 or fio.writecardinal1
4447 files.writeinteger2=fio.writeinteger2 or fio.writecardinal2
4448 files.writeinteger3=fio.writeinteger3 or fio.writecardinal3
4449 files.writeinteger4=fio.writeinteger4 or fio.writecardinal4
4450 files.writeinteger1le=files.writeinteger1le or fio.writecardinal1le
4451 files.writeinteger2le=files.writeinteger2le or fio.writecardinal2le
4452 files.writeinteger3le=files.writeinteger3le or fio.writecardinal3le
4453 files.writeinteger4le=files.writeinteger4le or fio.writecardinal4le
4454end
4455if fio and fio.readcardinaltable then
4456 files.readcardinaltable=fio.readcardinaltable
4457 files.readintegertable=fio.readintegertable
4458else
4459 local readcardinal1=files.readcardinal1
4460 local readcardinal2=files.readcardinal2
4461 local readcardinal3=files.readcardinal3
4462 local readcardinal4=files.readcardinal4
4463 function files.readcardinaltable(f,n,b)
4464  local t={}
4465   if b==1 then for i=1,n do t[i]=readcardinal1(f) end
4466  elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end
4467  elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end
4468  elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end
4469  return t
4470 end
4471 local readinteger1=files.readinteger1
4472 local readinteger2=files.readinteger2
4473 local readinteger3=files.readinteger3
4474 local readinteger4=files.readinteger4
4475 function files.readintegertable(f,n,b)
4476  local t={}
4477   if b==1 then for i=1,n do t[i]=readinteger1(f) end
4478  elseif b==2 then for i=1,n do t[i]=readinteger2(f) end
4479  elseif b==3 then for i=1,n do t[i]=readinteger3(f) end
4480  elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end
4481  return t
4482 end
4483end
4484
4485end -- closure
4486
4487do -- begin closure to overcome local limits and interference
4488
4489if not modules then modules={} end modules ['luat-basics-gen']={
4490 version=1.100,
4491 comment="companion to luatex-*.tex",
4492 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
4493 copyright="PRAGMA ADE / ConTeXt Development Team",
4494 license="see context related readme files"
4495}
4496if context then
4497--removed
4498
4499end
4500local match,gmatch,gsub,lower=string.match,string.gmatch,string.gsub,string.lower
4501local formatters,split,format,dump=string.formatters,string.split,string.format,string.dump
4502local loadfile,type=loadfile,type
4503local setmetatable,getmetatable,collectgarbage=setmetatable,getmetatable,collectgarbage
4504local floor=math.floor
4505local dummyfunction=function()
4506end
4507local dummyreporter=function(c)
4508 return function(f,...)
4509  local r=texio.reporter or texio.write_nl
4510  if f then
4511   r(c.." : "..(formatters or format)(f,...))
4512  else
4513   r("")
4514  end
4515 end
4516end
4517local dummyreport=function(c,f,...)
4518 local r=texio.reporter or texio.write_nl
4519 if f then
4520  r(c.." : "..(formatters or format)(f,...))
4521 else
4522  r("")
4523 end
4524end
4525statistics={
4526 register=dummyfunction,
4527 starttiming=dummyfunction,
4528 stoptiming=dummyfunction,
4529 elapsedtime=nil,
4530}
4531directives={
4532 register=dummyfunction,
4533 enable=dummyfunction,
4534 disable=dummyfunction,
4535}
4536trackers={
4537 register=dummyfunction,
4538 enable=dummyfunction,
4539 disable=dummyfunction,
4540}
4541experiments={
4542 register=dummyfunction,
4543 enable=dummyfunction,
4544 disable=dummyfunction,
4545}
4546storage={ 
4547 register=dummyfunction,
4548 shared={},
4549}
4550logs={
4551 new=dummyreporter,
4552 reporter=dummyreporter,
4553 messenger=dummyreporter,
4554 report=dummyreport,
4555}
4556callbacks={
4557 register=function(n,f)
4558  return callback.register(n,f)
4559 end,
4560}
4561utilities=utilities or {}
4562utilities.storage=utilities.storage or {
4563 allocate=function(t)
4564  return t or {}
4565 end,
4566 mark=function(t)
4567  return t or {}
4568 end,
4569}
4570utilities.parsers=utilities.parsers or {
4571 settings_to_array=function(s)
4572  return split(s,",")
4573 end,
4574 settings_to_hash=function(s)
4575  local t={}
4576  for k,v in gmatch((gsub(s,"^{(.*)}$","%1")),"([^%s,=]+)=([^%s,]+)") do
4577   t[k]=v
4578  end
4579  return t
4580 end,
4581 settings_to_hash_colon_too=function(s)
4582  local t={}
4583  for k,v in gmatch((gsub(s,"^{(.*)}$","%1")),"([^%s,=:]+)[=:]([^%s,]+)") do
4584   t[k]=v
4585  end
4586  return t
4587 end,
4588}
4589characters=characters or {
4590 data={}
4591}
4592texconfig.kpse_init=true
4593resolvers=resolvers or {} 
4594local remapper={
4595 otf="opentype fonts",
4596 ttf="truetype fonts",
4597 ttc="truetype fonts",
4598 cid="cid maps",
4599 cidmap="cid maps",
4600 pfb="type1 fonts",
4601 afm="afm",
4602 enc="enc files",
4603 lua="tex",
4604}
4605function resolvers.findfile(name,fileformat)
4606 name=gsub(name,"\\","/")
4607 if not fileformat or fileformat=="" then
4608  fileformat=file.suffix(name)
4609  if fileformat=="" then
4610   fileformat="tex"
4611  end
4612 end
4613 fileformat=lower(fileformat)
4614 fileformat=remapper[fileformat] or fileformat
4615 local found=kpse.find_file(name,fileformat)
4616 if not found or found=="" then
4617  found=kpse.find_file(name,"other text files")
4618 end
4619 return found
4620end
4621resolvers.findbinfile=resolvers.findfile
4622function resolvers.loadbinfile(filename,filetype)
4623 local data=io.loaddata(filename)
4624 return true,data,#data
4625end
4626function resolvers.resolve(s)
4627 return s
4628end
4629function resolvers.unresolve(s)
4630 return s
4631end
4632caches={}
4633local writable=nil
4634local readables={}
4635local usingjit=jit
4636if not caches.namespace or caches.namespace=="" or caches.namespace=="context" then
4637 caches.namespace='generic'
4638end
4639do
4640 local cachepaths=kpse.expand_var('$TEXMFCACHE') or ""
4641 if cachepaths=="" or cachepaths=="$TEXMFCACHE" then
4642  cachepaths=kpse.expand_var('$TEXMFVAR') or ""
4643 end
4644 if cachepaths=="" or cachepaths=="$TEXMFVAR" then
4645  cachepaths=kpse.expand_var('$VARTEXMF') or ""
4646 end
4647 if cachepaths=="" then
4648  local fallbacks={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }
4649  for i=1,#fallbacks do
4650   cachepaths=os.getenv(fallbacks[i]) or ""
4651   if cachepath~="" and lfs.isdir(cachepath) then
4652    break
4653   end
4654  end
4655 end
4656 if cachepaths=="" then
4657  cachepaths="."
4658 end
4659 cachepaths=split(cachepaths,os.type=="windows" and ";" or ":")
4660 for i=1,#cachepaths do
4661  local cachepath=cachepaths[i]
4662  if not lfs.isdir(cachepath) then
4663   lfs.mkdirs(cachepath) 
4664   if lfs.isdir(cachepath) then
4665    logs.report("system","creating cache path '%s'",cachepath)
4666   end
4667  end
4668  if file.is_writable(cachepath) then
4669   writable=file.join(cachepath,"luatex-cache")
4670   lfs.mkdir(writable)
4671   writable=file.join(writable,caches.namespace)
4672   lfs.mkdir(writable)
4673   break
4674  end
4675 end
4676 for i=1,#cachepaths do
4677  if file.is_readable(cachepaths[i]) then
4678   readables[#readables+1]=file.join(cachepaths[i],"luatex-cache",caches.namespace)
4679  end
4680 end
4681 if not writable then
4682  logs.report("system","no writeable cache path, quiting")
4683  os.exit()
4684 elseif #readables==0 then
4685  logs.report("system","no readable cache path, quiting")
4686  os.exit()
4687 elseif #readables==1 and readables[1]==writable then
4688  logs.report("system","using cache '%s'",writable)
4689 else
4690  logs.report("system","using write cache '%s'",writable)
4691  logs.report("system","using read cache '%s'",table.concat(readables," "))
4692 end
4693end
4694function caches.getwritablepath(category,subcategory)
4695 local path=file.join(writable,category)
4696 lfs.mkdir(path)
4697 path=file.join(path,subcategory)
4698 lfs.mkdir(path)
4699 return path
4700end
4701function caches.getreadablepaths(category,subcategory)
4702 local t={}
4703 for i=1,#readables do
4704  t[i]=file.join(readables[i],category,subcategory)
4705 end
4706 return t
4707end
4708local function makefullname(path,name)
4709 if path and path~="" then
4710  return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),usingjit and "lub" or "luc")
4711 end
4712end
4713function caches.is_writable(path,name)
4714 local fullname=makefullname(path,name)
4715 return fullname and file.is_writable(fullname)
4716end
4717function caches.loaddata(readables,name,writable)
4718 for i=1,#readables do
4719  local path=readables[i]
4720  local loader=false
4721  local luaname,lucname=makefullname(path,name)
4722  if lfs.isfile(lucname) then
4723   logs.report("system","loading luc file '%s'",lucname)
4724   loader=loadfile(lucname)
4725  end
4726  if not loader and lfs.isfile(luaname) then
4727   local luacrap,lucname=makefullname(writable,name)
4728   logs.report("system","compiling luc file '%s'",lucname)
4729   if lfs.isfile(lucname) then
4730    loader=loadfile(lucname)
4731   end
4732   caches.compile(data,luaname,lucname)
4733   if lfs.isfile(lucname) then
4734    logs.report("system","loading luc file '%s'",lucname)
4735    loader=loadfile(lucname)
4736   else
4737    logs.report("system","error in loading luc file '%s'",lucname)
4738   end
4739   if not loader then
4740    logs.report("system","loading lua file '%s'",luaname)
4741    loader=loadfile(luaname)
4742   else
4743    logs.report("system","error in loading lua file '%s'",luaname)
4744   end
4745  end
4746  if loader then
4747   loader=loader()
4748   collectgarbage("step")
4749   return loader
4750  end
4751 end
4752 return false
4753end
4754function caches.savedata(path,name,data)
4755 local luaname,lucname=makefullname(path,name)
4756 if luaname then
4757  logs.report("system","saving lua file '%s'",luaname)
4758  table.tofile(luaname,data,true)
4759  if lucname and type(caches.compile)=="function" then
4760   os.remove(lucname) 
4761   logs.report("system","saving luc file '%s'",lucname)
4762   caches.compile(data,luaname,lucname)
4763  end
4764 end
4765end
4766function caches.compile(data,luaname,lucname)
4767 local d=io.loaddata(luaname)
4768 if not d or d=="" then
4769  d=table.serialize(data,true) 
4770 end
4771 if d and d~="" then
4772  local f=io.open(lucname,'wb')
4773  if f then
4774   local s=loadstring(d)
4775   if s then
4776    f:write(dump(s,true))
4777   end
4778   f:close()
4779  end
4780 end
4781end
4782function table.setmetatableindex(t,f)
4783 if type(t)~="table" then
4784  f,t=t,{}
4785 end
4786 local m=getmetatable(t)
4787 if f=="table" then
4788  f=function(t,k) local v={} t[k]=v return v end
4789 end
4790 if m then
4791  m.__index=f
4792 else
4793  setmetatable(t,{ __index=f })
4794 end
4795 return t
4796end
4797function table.makeweak(t)
4798 local m=getmetatable(t)
4799 if m then
4800  m.__mode="v"
4801 else
4802  setmetatable(t,{ __mode="v" })
4803 end
4804 return t
4805end
4806arguments={}
4807if arg then
4808 for i=1,#arg do
4809  local k,v=match(arg[i],"^%-%-([^=]+)=?(.-)$")
4810  if k and v then
4811   arguments[k]=v
4812  end
4813 end
4814end
4815if not number.idiv then
4816 function number.idiv(i,d)
4817  return floor(i/d) 
4818 end
4819end
4820local u=unicode and unicode.utf8
4821if u then
4822 utf.lower=u.lower
4823 utf.upper=u.upper
4824 utf.char=u.char
4825 utf.byte=u.byte
4826 utf.len=u.len
4827 if lpeg.setutfcasers then
4828  lpeg.setutfcasers(u.lower,u.upper)
4829 end
4830 local bytepairs=string.bytepairs
4831 local utfchar=utf.char
4832 local concat=table.concat
4833 function utf.utf16_to_utf8_be(s)
4834  if not s then
4835   return nil
4836  elseif s=="" then
4837   return ""
4838  end
4839  local result,r,more={},0,0
4840  for left,right in bytepairs(s) do
4841   if right then
4842    local now=256*left+right
4843    if more>0 then
4844     now=(more-0xD800)*0x400+(now-0xDC00)+0x10000
4845     more=0
4846     r=r+1
4847     result[r]=utfchar(now)
4848    elseif now>=0xD800 and now<=0xDBFF then
4849     more=now
4850    else
4851     r=r+1
4852     result[r]=utfchar(now)
4853    end
4854   end
4855  end
4856  return concat(result)
4857 end
4858 local characters=string.utfcharacters
4859 function utf.split(str)
4860  local t,n={},0
4861  for s in characters(str) do
4862   n=n+1
4863   t[n]=s
4864  end
4865  return t
4866 end
4867end
4868
4869end -- closure
4870
4871do -- begin closure to overcome local limits and interference
4872
4873if not modules then modules={} end modules ['data-con']={
4874 version=1.100,
4875 comment="companion to luat-lib.mkiv",
4876 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
4877 copyright="PRAGMA ADE / ConTeXt Development Team",
4878 license="see context related readme files"
4879}
4880local setmetatable=setmetatable
4881local format,lower,gsub=string.format,string.lower,string.gsub
4882local trace_cache=false  trackers.register("resolvers.cache",function(v) trace_cache=v end)
4883local trace_containers=false  trackers.register("resolvers.containers",function(v) trace_containers=v end)
4884local trace_storage=false  trackers.register("resolvers.storage",function(v) trace_storage=v end)
4885containers=containers or {}
4886local containers=containers
4887containers.usecache=true
4888local getwritablepath=caches.getwritablepath
4889local getreadablepaths=caches.getreadablepaths
4890local cacheiswritable=caches.is_writable
4891local loaddatafromcache=caches.loaddata
4892local savedataincache=caches.savedata
4893local report_containers=logs.reporter("resolvers","containers")
4894local allocated={}
4895local mt={
4896 __index=function(t,k)
4897  if k=="writable" then
4898   local writable=getwritablepath(t.category,t.subcategory) or { "." }
4899   t.writable=writable
4900   return writable
4901  elseif k=="readables" then
4902   local readables=getreadablepaths(t.category,t.subcategory) or { "." }
4903   t.readables=readables
4904   return readables
4905  end
4906 end,
4907 __storage__=true
4908}
4909function containers.define(category,subcategory,version,enabled,reload)
4910 if category and subcategory then
4911  local c=allocated[category]
4912  if not c then
4913   c={}
4914   allocated[category]=c
4915  end
4916  local s=c[subcategory]
4917  if not s then
4918   s={
4919    category=category,
4920    subcategory=subcategory,
4921    storage={},
4922    enabled=enabled,
4923    reload=reload,
4924    version=version or math.pi,
4925    trace=false,
4926   }
4927   setmetatable(s,mt)
4928   c[subcategory]=s
4929  end
4930  return s
4931 end
4932end
4933function containers.is_usable(container,name)
4934 return container.enabled and caches and cacheiswritable(container.writable,name)
4935end
4936function containers.is_valid(container,name)
4937 if name and name~="" then
4938  local storage=container.storage[name]
4939  return storage and storage.cache_version==container.version
4940 else
4941  return false
4942 end
4943end
4944function containers.read(container,name)
4945 local storage=container.storage
4946 local reload=container.reload
4947 local stored=not reload and storage[name]
4948 if not stored and container.enabled and caches and containers.usecache then
4949  stored=loaddatafromcache(container.readables,name,container.writable)
4950  if stored and stored.cache_version==container.version then
4951   if trace_cache or trace_containers then
4952    report_containers("action %a, category %a, name %a","load",container.subcategory,name)
4953   end
4954  else
4955   stored=nil
4956  end
4957  storage[name]=stored
4958 elseif stored then
4959  if trace_cache or trace_containers then
4960   report_containers("action %a, category %a, name %a","reuse",container.subcategory,name)
4961  end
4962 end
4963 return stored
4964end
4965function containers.write(container,name,data,fast)
4966 if data then
4967  data.cache_version=container.version
4968  if container.enabled and caches then
4969   local unique=data.unique
4970   local shared=data.shared
4971   data.unique=nil
4972   data.shared=nil
4973   savedataincache(container.writable,name,data,fast)
4974   if trace_cache or trace_containers then
4975    report_containers("action %a, category %a, name %a","save",container.subcategory,name)
4976   end
4977   data.unique=unique
4978   data.shared=shared
4979  end
4980  if trace_cache or trace_containers then
4981   report_containers("action %a, category %a, name %a","store",container.subcategory,name)
4982  end
4983  container.storage[name]=data
4984 end
4985 return data
4986end
4987function containers.content(container,name)
4988 return container.storage[name]
4989end
4990function containers.cleanname(name)
4991 return (gsub(lower(name),"[^%w\128-\255]+","-")) 
4992end
4993
4994end -- closure
4995
4996do -- begin closure to overcome local limits and interference
4997
4998if not modules then modules={} end modules ['luatex-fonts-nod']={
4999 version=1.001,
5000 comment="companion to luatex-fonts.lua",
5001 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
5002 copyright="PRAGMA ADE / ConTeXt Development Team",
5003 license="see context related readme files"
5004}
5005if context then
5006--removed
5007
5008end
5009if tex.attribute[0]~=0 then
5010 texio.write_nl("log","!")
5011 texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
5012 texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
5013 texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
5014 texio.write_nl("log","!")
5015 tex.attribute[0]=0 
5016end
5017attributes=attributes or {}
5018attributes.unsetvalue=-0x7FFFFFFF
5019local numbers,last={},127
5020attributes.private=attributes.private or function(name)
5021 local number=numbers[name]
5022 if not number then
5023  if last<255 then
5024   last=last+1
5025  end
5026  number=last
5027  numbers[name]=number
5028 end
5029 return number
5030end
5031nodes={}
5032nodes.handlers={}
5033local nodecodes={}
5034local glyphcodes=node.subtypes("glyph")
5035local disccodes=node.subtypes("disc")
5036for k,v in next,node.types() do
5037 v=string.gsub(v,"_","")
5038 nodecodes[k]=v
5039 nodecodes[v]=k
5040end
5041for k,v in next,glyphcodes do
5042 glyphcodes[v]=k
5043end
5044for k,v in next,disccodes do
5045 disccodes[v]=k
5046end
5047nodes.nodecodes=nodecodes
5048nodes.glyphcodes=glyphcodes
5049nodes.disccodes=disccodes
5050nodes.dirvalues={ lefttoright=0,righttoleft=1 }
5051nodes.handlers.protectglyphs=node.protectglyphs   or node.protect_glyphs   
5052nodes.handlers.unprotectglyphs=node.unprotectglyphs or node.unprotect_glyphs
5053local direct=node.direct
5054local nuts={}
5055nodes.nuts=nuts
5056local tonode=direct.tonode
5057local tonut=direct.todirect
5058nodes.tonode=tonode
5059nodes.tonut=tonut
5060nuts.tonode=tonode
5061nuts.tonut=tonut
5062nuts.getattr=direct.get_attribute
5063nuts.getboth=direct.getboth
5064nuts.getchar=direct.getchar
5065nuts.getdirection=direct.getdirection
5066nuts.getdisc=direct.getdisc
5067nuts.getreplace=direct.getreplace
5068nuts.getfield=direct.getfield
5069nuts.getfont=direct.getfont
5070nuts.getid=direct.getid
5071nuts.getkern=direct.getkern
5072nuts.getlist=direct.getlist
5073nuts.getnext=direct.getnext
5074nuts.getoffsets=direct.getoffsets
5075nuts.getoptions=direct.getoptions or function() return 0 end
5076nuts.getprev=direct.getprev
5077nuts.getsubtype=direct.getsubtype
5078nuts.getwidth=direct.getwidth
5079nuts.setattr=direct.setfield
5080nuts.setboth=direct.setboth
5081nuts.setchar=direct.setchar
5082nuts.setcomponents=direct.setcomponents
5083nuts.setdirection=direct.setdirection
5084nuts.setdisc=direct.setdisc
5085nuts.setreplace=direct.setreplace
5086nuts.setfield=direct.setfield
5087nuts.setkern=direct.setkern
5088nuts.setlink=direct.setlink
5089nuts.setlist=direct.setlist
5090nuts.setnext=direct.setnext
5091nuts.setoffsets=direct.setoffsets
5092nuts.setprev=direct.setprev
5093nuts.setsplit=direct.setsplit
5094nuts.setsubtype=direct.setsubtype
5095nuts.setwidth=direct.setwidth
5096nuts.getglyphdata=nuts.getattribute or nuts.getattr
5097nuts.setglyphdata=nuts.setattribute or nuts.setattr
5098nuts.ischar=direct.ischar  or direct.is_char
5099nuts.isglyph=direct.isglyph    or direct.is_glyph
5100nuts.copy=direct.copy
5101nuts.copynode=direct.copy
5102nuts.copylist=direct.copylist   or direct.copy_list
5103nuts.endofmath=direct.endofmath  or direct.end_of_math
5104nuts.flush=direct.flush
5105nuts.flushlist=direct.flushlist  or direct.flush_list
5106nuts.flushnode=direct.flushnode  or direct.flush_node
5107nuts.free=direct.free
5108nuts.insertafter=direct.insertafter   or direct.insert_after
5109nuts.insertbefore=direct.insertbefore  or direct.insert_before
5110nuts.isnode=direct.isnode  or direct.is_node
5111nuts.isdirect=direct.isdirect   or direct.is_direct
5112nuts.isnut=direct.isdirect   or direct.is_direct
5113nuts.kerning=direct.kerning
5114nuts.ligaturing=direct.ligaturing
5115nuts.new=direct.new
5116nuts.remove=direct.remove
5117nuts.tail=direct.tail
5118nuts.traverse=direct.traverse
5119nuts.traversechar=direct.traversechar  or direct.traverse_char
5120nuts.traverseglyph=direct.traverseglyph or direct.traverse_glyph
5121nuts.traverseid=direct.traverseid or direct.traverse_id
5122local propertydata=(direct.getpropertiestable or direct.get_properties_table)()
5123nodes.properties={ data=propertydata }
5124if direct.set_properties_mode then
5125 direct.set_properties_mode(true,true)
5126 function direct.set_properties_mode() end
5127end
5128nuts.getprop=function(n,k)
5129 local p=propertydata[n]
5130 if p then
5131  return p[k]
5132 end
5133end
5134nuts.setprop=function(n,k,v)
5135 if v then
5136  local p=propertydata[n]
5137  if p then
5138   p[k]=v
5139  else
5140   propertydata[n]={ [k]=v }
5141  end
5142 end
5143end
5144nodes.setprop=nodes.setproperty
5145nodes.getprop=nodes.getproperty
5146local setprev=nuts.setprev
5147local setnext=nuts.setnext
5148local getnext=nuts.getnext
5149local setlink=nuts.setlink
5150local getfield=nuts.getfield
5151local setfield=nuts.setfield
5152local getsubtype=nuts.getsubtype
5153local isglyph=nuts.isglyph
5154local find_tail=nuts.tail
5155local flushlist=nuts.flushlist
5156local flushnode=nuts.flushnode
5157local traverseid=nuts.traverseid
5158local copynode=nuts.copynode
5159local glyph_code=nodes.nodecodes.glyph
5160local ligature_code=nodes.glyphcodes.ligature
5161do 
5162 local p=nodecodes.localpar or nodecodes.local_par
5163 if p then
5164  nodecodes.par=p
5165  nodecodes[p]="par"
5166  nodecodes.localpar=p 
5167  nodecodes.local_par=p 
5168 end
5169end
5170do
5171 local getcomponents=node.direct.getcomponents
5172 local setcomponents=node.direct.setcomponents
5173 local function copynocomponents(g,copyinjection)
5174  local components=getcomponents(g)
5175  if components then
5176   setcomponents(g)
5177   local n=copynode(g)
5178   if copyinjection then
5179    copyinjection(n,g)
5180   end
5181   setcomponents(g,components)
5182   return n
5183  else
5184   local n=copynode(g)
5185   if copyinjection then
5186    copyinjection(n,g)
5187   end
5188   return n
5189  end
5190 end
5191 local function copyonlyglyphs(current)
5192  local head=nil
5193  local previous=nil
5194  for n in traverseid(glyph_code,current) do
5195   n=copynode(n)
5196   if head then
5197    setlink(previous,n)
5198   else
5199    head=n
5200   end
5201   previous=n
5202  end
5203  return head
5204 end
5205 local function countcomponents(start,marks)
5206  local char=isglyph(start)
5207  if char then
5208   if getsubtype(start)==ligature_code then
5209    local n=0
5210    local components=getcomponents(start)
5211    while components do
5212     n=n+countcomponents(components,marks)
5213     components=getnext(components)
5214    end
5215    return n
5216   elseif not marks[char] then
5217    return 1
5218   end
5219  end
5220  return 0
5221 end
5222 local function flushcomponents()
5223 end
5224 nuts.components={
5225  set=setcomponents,
5226  get=getcomponents,
5227  copyonlyglyphs=copyonlyglyphs,
5228  copynocomponents=copynocomponents,
5229  count=countcomponents,
5230  flush=flushcomponents,
5231 }
5232end
5233nuts.usesfont=direct.usesfont or direct.uses_font
5234do
5235 local dummy=tonut(node.new("glyph"))
5236 nuts.traversers={
5237  glyph=nuts.traverseid(nodecodes.glyph,dummy),
5238  glue=nuts.traverseid(nodecodes.glue,dummy),
5239  disc=nuts.traverseid(nodecodes.disc,dummy),
5240  boundary=nuts.traverseid(nodecodes.boundary,dummy),
5241  char=nuts.traversechar(dummy),
5242  node=nuts.traverse(dummy),
5243 }
5244end
5245if not nuts.setreplace then
5246 local getdisc=nuts.getdisc
5247 local setfield=nuts.setfield
5248 function nuts.getreplace(n)
5249  local _,_,h,_,_,t=getdisc(n,true)
5250  return h,t
5251 end
5252 function nuts.setreplace(n,h)
5253  setfield(n,"replace",h)
5254 end
5255end
5256do
5257 local getsubtype=nuts.getsubtype
5258 function nuts.startofpar(n)
5259  local s=getsubtype(n)
5260  return s==0 or s==2 
5261 end
5262end
5263
5264end -- closure
5265
5266do -- begin closure to overcome local limits and interference
5267
5268
5269characters=characters or {}
5270characters.blockrange={}
5271characters.classifiers={
5272 [768]=5,
5273 [769]=5,
5274 [770]=5,
5275 [771]=5,
5276 [772]=5,
5277 [773]=5,
5278 [774]=5,
5279 [775]=5,
5280 [776]=5,
5281 [777]=5,
5282 [778]=5,
5283 [779]=5,
5284 [780]=5,
5285 [781]=5,
5286 [782]=5,
5287 [783]=5,
5288 [784]=5,
5289 [785]=5,
5290 [786]=5,
5291 [787]=5,
5292 [788]=5,
5293 [789]=5,
5294 [790]=5,
5295 [791]=5,
5296 [792]=5,
5297 [793]=5,
5298 [794]=5,
5299 [795]=5,
5300 [796]=5,
5301 [797]=5,
5302 [798]=5,
5303 [799]=5,
5304 [800]=5,
5305 [801]=5,
5306 [802]=5,
5307 [803]=5,
5308 [804]=5,
5309 [805]=5,
5310 [806]=5,
5311 [807]=5,
5312 [808]=5,
5313 [809]=5,
5314 [810]=5,
5315 [811]=5,
5316 [812]=5,
5317 [813]=5,
5318 [814]=5,
5319 [815]=5,
5320 [816]=5,
5321 [817]=5,
5322 [818]=5,
5323 [819]=5,
5324 [820]=5,
5325 [821]=5,
5326 [822]=5,
5327 [823]=5,
5328 [824]=5,
5329 [825]=5,
5330 [826]=5,
5331 [827]=5,
5332 [828]=5,
5333 [829]=5,
5334 [830]=5,
5335 [831]=5,
5336 [832]=5,
5337 [833]=5,
5338 [834]=5,
5339 [835]=5,
5340 [836]=5,
5341 [837]=5,
5342 [838]=5,
5343 [839]=5,
5344 [840]=5,
5345 [841]=5,
5346 [842]=5,
5347 [843]=5,
5348 [844]=5,
5349 [845]=5,
5350 [846]=5,
5351 [847]=5,
5352 [848]=5,
5353 [849]=5,
5354 [850]=5,
5355 [851]=5,
5356 [852]=5,
5357 [853]=5,
5358 [854]=5,
5359 [855]=5,
5360 [856]=5,
5361 [857]=5,
5362 [858]=5,
5363 [859]=5,
5364 [860]=5,
5365 [861]=5,
5366 [862]=5,
5367 [863]=5,
5368 [864]=5,
5369 [865]=5,
5370 [866]=5,
5371 [867]=5,
5372 [868]=5,
5373 [869]=5,
5374 [870]=5,
5375 [871]=5,
5376 [872]=5,
5377 [873]=5,
5378 [874]=5,
5379 [875]=5,
5380 [876]=5,
5381 [877]=5,
5382 [878]=5,
5383 [879]=5,
5384 [1155]=5,
5385 [1156]=5,
5386 [1157]=5,
5387 [1158]=5,
5388 [1159]=5,
5389 [1425]=5,
5390 [1426]=5,
5391 [1427]=5,
5392 [1428]=5,
5393 [1429]=5,
5394 [1430]=5,
5395 [1431]=5,
5396 [1432]=5,
5397 [1433]=5,
5398 [1434]=5,
5399 [1435]=5,
5400 [1436]=5,
5401 [1437]=5,
5402 [1438]=5,
5403 [1439]=5,
5404 [1440]=5,
5405 [1441]=5,
5406 [1442]=5,
5407 [1443]=5,
5408 [1444]=5,
5409 [1445]=5,
5410 [1446]=5,
5411 [1447]=5,
5412 [1448]=5,
5413 [1449]=5,
5414 [1450]=5,
5415 [1451]=5,
5416 [1452]=5,
5417 [1453]=5,
5418 [1454]=5,
5419 [1455]=5,
5420 [1456]=5,
5421 [1457]=5,
5422 [1458]=5,
5423 [1459]=5,
5424 [1460]=5,
5425 [1461]=5,
5426 [1462]=5,
5427 [1463]=5,
5428 [1464]=5,
5429 [1465]=5,
5430 [1466]=5,
5431 [1467]=5,
5432 [1468]=5,
5433 [1469]=5,
5434 [1471]=5,
5435 [1473]=5,
5436 [1474]=5,
5437 [1476]=5,
5438 [1477]=5,
5439 [1479]=5,
5440 [1536]=4,
5441 [1537]=4,
5442 [1538]=4,
5443 [1539]=4,
5444 [1540]=4,
5445 [1541]=4,
5446 [1542]=6,
5447 [1543]=6,
5448 [1544]=4,
5449 [1545]=6,
5450 [1546]=6,
5451 [1547]=4,
5452 [1548]=6,
5453 [1549]=6,
5454 [1550]=6,
5455 [1551]=6,
5456 [1552]=5,
5457 [1553]=5,
5458 [1554]=5,
5459 [1555]=5,
5460 [1556]=5,
5461 [1557]=5,
5462 [1558]=5,
5463 [1559]=5,
5464 [1560]=5,
5465 [1561]=5,
5466 [1562]=5,
5467 [1563]=6,
5468 [1564]=6,
5469 [1565]=6,
5470 [1566]=6,
5471 [1567]=6,
5472 [1568]=2,
5473 [1569]=4,
5474 [1570]=3,
5475 [1571]=3,
5476 [1572]=3,
5477 [1573]=3,
5478 [1574]=2,
5479 [1575]=3,
5480 [1576]=2,
5481 [1577]=3,
5482 [1578]=2,
5483 [1579]=2,
5484 [1580]=2,
5485 [1581]=2,
5486 [1582]=2,
5487 [1583]=3,
5488 [1584]=3,
5489 [1585]=3,
5490 [1586]=3,
5491 [1587]=2,
5492 [1588]=2,
5493 [1589]=2,
5494 [1590]=2,
5495 [1591]=2,
5496 [1592]=2,
5497 [1593]=2,
5498 [1594]=2,
5499 [1595]=2,
5500 [1596]=2,
5501 [1597]=2,
5502 [1598]=2,
5503 [1599]=2,
5504 [1600]=2,
5505 [1601]=2,
5506 [1602]=2,
5507 [1603]=2,
5508 [1604]=2,
5509 [1605]=2,
5510 [1606]=2,
5511 [1607]=2,
5512 [1608]=3,
5513 [1609]=2,
5514 [1610]=2,
5515 [1611]=5,
5516 [1612]=5,
5517 [1613]=5,
5518 [1614]=5,
5519 [1615]=5,
5520 [1616]=5,
5521 [1617]=5,
5522 [1618]=5,
5523 [1619]=5,
5524 [1620]=5,
5525 [1621]=5,
5526 [1622]=5,
5527 [1623]=5,
5528 [1624]=5,
5529 [1625]=5,
5530 [1626]=5,
5531 [1627]=5,
5532 [1628]=5,
5533 [1629]=5,
5534 [1630]=5,
5535 [1631]=5,
5536 [1632]=6,
5537 [1633]=6,
5538 [1634]=6,
5539 [1635]=6,
5540 [1636]=6,
5541 [1637]=6,
5542 [1638]=6,
5543 [1639]=6,
5544 [1640]=6,
5545 [1641]=6,
5546 [1642]=6,
5547 [1643]=6,
5548 [1644]=6,
5549 [1645]=6,
5550 [1646]=2,
5551 [1647]=2,
5552 [1648]=5,
5553 [1649]=3,
5554 [1650]=3,
5555 [1651]=3,
5556 [1652]=4,
5557 [1653]=3,
5558 [1654]=3,
5559 [1655]=3,
5560 [1656]=2,
5561 [1657]=2,
5562 [1658]=2,
5563 [1659]=2,
5564 [1660]=2,
5565 [1661]=2,
5566 [1662]=2,
5567 [1663]=2,
5568 [1664]=2,
5569 [1665]=2,
5570 [1666]=2,
5571 [1667]=2,
5572 [1668]=2,
5573 [1669]=2,
5574 [1670]=2,
5575 [1671]=2,
5576 [1672]=3,
5577 [1673]=3,
5578 [1674]=3,
5579 [1675]=3,
5580 [1676]=3,
5581 [1677]=3,
5582 [1678]=3,
5583 [1679]=3,
5584 [1680]=3,
5585 [1681]=3,
5586 [1682]=3,
5587 [1683]=3,
5588 [1684]=3,
5589 [1685]=3,
5590 [1686]=3,
5591 [1687]=3,
5592 [1688]=3,
5593 [1689]=3,
5594 [1690]=2,
5595 [1691]=2,
5596 [1692]=2,
5597 [1693]=2,
5598 [1694]=2,
5599 [1695]=2,
5600 [1696]=2,
5601 [1697]=2,
5602 [1698]=2,
5603 [1699]=2,
5604 [1700]=2,
5605 [1701]=2,
5606 [1702]=2,
5607 [1703]=2,
5608 [1704]=2,
5609 [1705]=2,
5610 [1706]=2,
5611 [1707]=2,
5612 [1708]=2,
5613 [1709]=2,
5614 [1710]=2,
5615 [1711]=2,
5616 [1712]=2,
5617 [1713]=2,
5618 [1714]=2,
5619 [1715]=2,
5620 [1716]=2,
5621 [1717]=2,
5622 [1718]=2,
5623 [1719]=2,
5624 [1720]=2,
5625 [1721]=2,
5626 [1722]=2,
5627 [1723]=2,
5628 [1724]=2,
5629 [1725]=2,
5630 [1726]=2,
5631 [1727]=2,
5632 [1728]=3,
5633 [1729]=2,
5634 [1730]=2,
5635 [1731]=3,
5636 [1732]=3,
5637 [1733]=3,
5638 [1734]=3,
5639 [1735]=3,
5640 [1736]=3,
5641 [1737]=3,
5642 [1738]=3,
5643 [1739]=3,
5644 [1740]=2,
5645 [1741]=3,
5646 [1742]=2,
5647 [1743]=3,
5648 [1744]=2,
5649 [1745]=2,
5650 [1746]=3,
5651 [1747]=3,
5652 [1748]=6,
5653 [1749]=3,
5654 [1750]=5,
5655 [1751]=5,
5656 [1752]=5,
5657 [1753]=5,
5658 [1754]=5,
5659 [1755]=5,
5660 [1756]=5,
5661 [1757]=4,
5662 [1758]=6,
5663 [1759]=5,
5664 [1760]=5,
5665 [1761]=5,
5666 [1762]=5,
5667 [1763]=5,
5668 [1764]=5,
5669 [1765]=6,
5670 [1766]=6,
5671 [1767]=5,
5672 [1768]=5,
5673 [1769]=6,
5674 [1770]=5,
5675 [1771]=5,
5676 [1772]=5,
5677 [1773]=5,
5678 [1774]=3,
5679 [1775]=3,
5680 [1776]=6,
5681 [1777]=6,
5682 [1778]=6,
5683 [1779]=6,
5684 [1780]=6,
5685 [1781]=6,
5686 [1782]=6,
5687 [1783]=6,
5688 [1784]=6,
5689 [1785]=6,
5690 [1786]=2,
5691 [1787]=2,
5692 [1788]=2,
5693 [1789]=6,
5694 [1790]=6,
5695 [1791]=2,
5696 [1792]=6,
5697 [1793]=6,
5698 [1794]=6,
5699 [1795]=6,
5700 [1796]=6,
5701 [1797]=6,
5702 [1798]=6,
5703 [1799]=6,
5704 [1800]=6,
5705 [1801]=6,
5706 [1802]=6,
5707 [1803]=6,
5708 [1804]=6,
5709 [1805]=6,
5710 [1808]=3,
5711 [1809]=5,
5712 [1810]=2,
5713 [1811]=2,
5714 [1812]=2,
5715 [1813]=3,
5716 [1814]=3,
5717 [1815]=3,
5718 [1816]=3,
5719 [1817]=3,
5720 [1818]=2,
5721 [1819]=2,
5722 [1820]=2,
5723 [1821]=2,
5724 [1822]=3,
5725 [1823]=2,
5726 [1824]=2,
5727 [1825]=2,
5728 [1826]=2,
5729 [1827]=2,
5730 [1828]=2,
5731 [1829]=2,
5732 [1830]=2,
5733 [1831]=2,
5734 [1832]=3,
5735 [1833]=2,
5736 [1834]=3,
5737 [1835]=2,
5738 [1836]=3,
5739 [1837]=2,
5740 [1838]=2,
5741 [1839]=3,
5742 [1840]=5,
5743 [1841]=5,
5744 [1842]=5,
5745 [1843]=5,
5746 [1844]=5,
5747 [1845]=5,
5748 [1846]=5,
5749 [1847]=5,
5750 [1848]=5,
5751 [1849]=5,
5752 [1850]=5,
5753 [1851]=5,
5754 [1852]=5,
5755 [1853]=5,
5756 [1854]=5,
5757 [1855]=5,
5758 [1856]=5,
5759 [1857]=5,
5760 [1858]=5,
5761 [1859]=5,
5762 [1860]=5,
5763 [1861]=5,
5764 [1862]=5,
5765 [1863]=5,
5766 [1864]=5,
5767 [1865]=5,
5768 [1866]=5,
5769 [1869]=3,
5770 [1870]=2,
5771 [1871]=2,
5772 [1872]=2,
5773 [1873]=2,
5774 [1874]=2,
5775 [1875]=2,
5776 [1876]=2,
5777 [1877]=2,
5778 [1878]=2,
5779 [1879]=2,
5780 [1880]=2,
5781 [1881]=3,
5782 [1882]=3,
5783 [1883]=3,
5784 [1884]=2,
5785 [1885]=2,
5786 [1886]=2,
5787 [1887]=2,
5788 [1888]=2,
5789 [1889]=2,
5790 [1890]=2,
5791 [1891]=2,
5792 [1892]=2,
5793 [1893]=2,
5794 [1894]=2,
5795 [1895]=2,
5796 [1896]=2,
5797 [1897]=2,
5798 [1898]=2,
5799 [1899]=3,
5800 [1900]=3,
5801 [1901]=2,
5802 [1902]=2,
5803 [1903]=2,
5804 [1904]=2,
5805 [1905]=3,
5806 [1906]=2,
5807 [1907]=3,
5808 [1908]=3,
5809 [1909]=2,
5810 [1910]=2,
5811 [1911]=2,
5812 [1912]=3,
5813 [1913]=3,
5814 [1914]=2,
5815 [1915]=2,
5816 [1916]=2,
5817 [1917]=2,
5818 [1918]=2,
5819 [1919]=2,
5820 [1958]=5,
5821 [1959]=5,
5822 [1960]=5,
5823 [1961]=5,
5824 [1962]=5,
5825 [1963]=5,
5826 [1964]=5,
5827 [1965]=5,
5828 [1966]=5,
5829 [1967]=5,
5830 [1968]=5,
5831 [1984]=6,
5832 [1985]=6,
5833 [1986]=6,
5834 [1987]=6,
5835 [1988]=6,
5836 [1989]=6,
5837 [1990]=6,
5838 [1991]=6,
5839 [1992]=6,
5840 [1993]=6,
5841 [1994]=2,
5842 [1995]=2,
5843 [1996]=2,
5844 [1997]=2,
5845 [1998]=2,
5846 [1999]=2,
5847 [2000]=2,
5848 [2001]=2,
5849 [2002]=2,
5850 [2003]=2,
5851 [2004]=2,
5852 [2005]=2,
5853 [2006]=2,
5854 [2007]=2,
5855 [2008]=2,
5856 [2009]=2,
5857 [2010]=2,
5858 [2011]=2,
5859 [2012]=2,
5860 [2013]=2,
5861 [2014]=2,
5862 [2015]=2,
5863 [2016]=2,
5864 [2017]=2,
5865 [2018]=2,
5866 [2019]=2,
5867 [2020]=2,
5868 [2021]=2,
5869 [2022]=2,
5870 [2023]=2,
5871 [2024]=2,
5872 [2025]=2,
5873 [2026]=2,
5874 [2027]=5,
5875 [2028]=5,
5876 [2029]=5,
5877 [2030]=5,
5878 [2031]=5,
5879 [2032]=5,
5880 [2033]=5,
5881 [2034]=5,
5882 [2035]=5,
5883 [2036]=6,
5884 [2037]=6,
5885 [2038]=6,
5886 [2039]=6,
5887 [2040]=6,
5888 [2041]=6,
5889 [2042]=2,
5890 [2045]=5,
5891 [2046]=6,
5892 [2047]=6,
5893 [2070]=5,
5894 [2071]=5,
5895 [2072]=5,
5896 [2073]=5,
5897 [2075]=5,
5898 [2076]=5,
5899 [2077]=5,
5900 [2078]=5,
5901 [2079]=5,
5902 [2080]=5,
5903 [2081]=5,
5904 [2082]=5,
5905 [2083]=5,
5906 [2085]=5,
5907 [2086]=5,
5908 [2087]=5,
5909 [2089]=5,
5910 [2090]=5,
5911 [2091]=5,
5912 [2092]=5,
5913 [2093]=5,
5914 [2112]=3,
5915 [2113]=2,
5916 [2114]=2,
5917 [2115]=2,
5918 [2116]=2,
5919 [2117]=2,
5920 [2118]=3,
5921 [2119]=3,
5922 [2120]=2,
5923 [2121]=3,
5924 [2122]=2,
5925 [2123]=2,
5926 [2124]=2,
5927 [2125]=2,
5928 [2126]=2,
5929 [2127]=2,
5930 [2128]=2,
5931 [2129]=2,
5932 [2130]=2,
5933 [2131]=2,
5934 [2132]=3,
5935 [2133]=2,
5936 [2134]=3,
5937 [2135]=3,
5938 [2136]=3,
5939 [2137]=5,
5940 [2138]=5,
5941 [2139]=5,
5942 [2144]=2,
5943 [2145]=4,
5944 [2146]=2,
5945 [2147]=2,
5946 [2148]=2,
5947 [2149]=2,
5948 [2150]=4,
5949 [2151]=3,
5950 [2152]=2,
5951 [2153]=3,
5952 [2154]=3,
5953 [2160]=3,
5954 [2161]=3,
5955 [2162]=3,
5956 [2163]=3,
5957 [2164]=3,
5958 [2165]=3,
5959 [2166]=3,
5960 [2167]=3,
5961 [2168]=3,
5962 [2169]=3,
5963 [2170]=3,
5964 [2171]=3,
5965 [2172]=3,
5966 [2173]=3,
5967 [2174]=3,
5968 [2175]=3,
5969 [2176]=3,
5970 [2177]=3,
5971 [2178]=3,
5972 [2179]=2,
5973 [2180]=2,
5974 [2181]=2,
5975 [2182]=2,
5976 [2183]=4,
5977 [2184]=4,
5978 [2185]=2,
5979 [2186]=2,
5980 [2187]=2,
5981 [2188]=2,
5982 [2189]=2,
5983 [2190]=3,
5984 [2192]=4,
5985 [2193]=4,
5986 [2200]=5,
5987 [2201]=5,
5988 [2202]=5,
5989 [2203]=5,
5990 [2204]=5,
5991 [2205]=5,
5992 [2206]=5,
5993 [2207]=5,
5994 [2208]=2,
5995 [2209]=2,
5996 [2210]=2,
5997 [2211]=2,
5998 [2212]=2,
5999 [2213]=2,
6000 [2214]=2,
6001 [2215]=2,
6002 [2216]=2,
6003 [2217]=2,
6004 [2218]=3,
6005 [2219]=3,
6006 [2220]=3,
6007 [2221]=4,
6008 [2222]=3,
6009 [2223]=2,
6010 [2224]=2,
6011 [2225]=3,
6012 [2226]=3,
6013 [2227]=2,
6014 [2228]=2,
6015 [2229]=2,
6016 [2230]=2,
6017 [2231]=2,
6018 [2232]=2,
6019 [2233]=3,
6020 [2234]=2,
6021 [2235]=2,
6022 [2236]=2,
6023 [2237]=2,
6024 [2238]=2,
6025 [2239]=2,
6026 [2240]=2,
6027 [2241]=2,
6028 [2242]=2,
6029 [2243]=2,
6030 [2244]=2,
6031 [2245]=2,
6032 [2246]=2,
6033 [2247]=2,
6034 [2248]=2,
6035 [2250]=5,
6036 [2251]=5,
6037 [2252]=5,
6038 [2253]=5,
6039 [2254]=5,
6040 [2255]=5,
6041 [2256]=5,
6042 [2257]=5,
6043 [2258]=5,
6044 [2259]=5,
6045 [2260]=5,
6046 [2261]=5,
6047 [2262]=5,
6048 [2263]=5,
6049 [2264]=5,
6050 [2265]=5,
6051 [2266]=5,
6052 [2267]=5,
6053 [2268]=5,
6054 [2269]=5,
6055 [2270]=5,
6056 [2271]=5,
6057 [2272]=5,
6058 [2273]=5,
6059 [2274]=4,
6060 [2275]=5,
6061 [2276]=5,
6062 [2277]=5,
6063 [2278]=5,
6064 [2279]=5,
6065 [2280]=5,
6066 [2281]=5,
6067 [2282]=5,
6068 [2283]=5,
6069 [2284]=5,
6070 [2285]=5,
6071 [2286]=5,
6072 [2287]=5,
6073 [2288]=5,
6074 [2289]=5,
6075 [2290]=5,
6076 [2291]=5,
6077 [2292]=5,
6078 [2293]=5,
6079 [2294]=5,
6080 [2295]=5,
6081 [2296]=5,
6082 [2297]=5,
6083 [2298]=5,
6084 [2299]=5,
6085 [2300]=5,
6086 [2301]=5,
6087 [2302]=5,
6088 [2303]=5,
6089 [2304]=5,
6090 [2305]=5,
6091 [2306]=5,
6092 [2362]=5,
6093 [2364]=5,
6094 [2369]=5,
6095 [2370]=5,
6096 [2371]=5,
6097 [2372]=5,
6098 [2373]=5,
6099 [2374]=5,
6100 [2375]=5,
6101 [2376]=5,
6102 [2381]=5,
6103 [2385]=5,
6104 [2386]=5,
6105 [2387]=5,
6106 [2388]=5,
6107 [2389]=5,
6108 [2390]=5,
6109 [2391]=5,
6110 [2402]=5,
6111 [2403]=5,
6112 [2433]=5,
6113 [2492]=5,
6114 [2497]=5,
6115 [2498]=5,
6116 [2499]=5,
6117 [2500]=5,
6118 [2509]=5,
6119 [2530]=5,
6120 [2531]=5,
6121 [2558]=5,
6122 [2561]=5,
6123 [2562]=5,
6124 [2620]=5,
6125 [2625]=5,
6126 [2626]=5,
6127 [2631]=5,
6128 [2632]=5,
6129 [2635]=5,
6130 [2636]=5,
6131 [2637]=5,
6132 [2641]=5,
6133 [2672]=5,
6134 [2673]=5,
6135 [2677]=5,
6136 [2689]=5,
6137 [2690]=5,
6138 [2748]=5,
6139 [2753]=5,
6140 [2754]=5,
6141 [2755]=5,
6142 [2756]=5,
6143 [2757]=5,
6144 [2759]=5,
6145 [2760]=5,
6146 [2765]=5,
6147 [2786]=5,
6148 [2787]=5,
6149 [2810]=5,
6150 [2811]=5,
6151 [2812]=5,
6152 [2813]=5,
6153 [2814]=5,
6154 [2815]=5,
6155 [2817]=5,
6156 [2876]=5,
6157 [2879]=5,
6158 [2881]=5,
6159 [2882]=5,
6160 [2883]=5,
6161 [2884]=5,
6162 [2893]=5,
6163 [2901]=5,
6164 [2902]=5,
6165 [2914]=5,
6166 [2915]=5,
6167 [2946]=5,
6168 [3008]=5,
6169 [3021]=5,
6170 [3072]=5,
6171 [3076]=5,
6172 [3132]=5,
6173 [3134]=5,
6174 [3135]=5,
6175 [3136]=5,
6176 [3142]=5,
6177 [3143]=5,
6178 [3144]=5,
6179 [3146]=5,
6180 [3147]=5,
6181 [3148]=5,
6182 [3149]=5,
6183 [3157]=5,
6184 [3158]=5,
6185 [3170]=5,
6186 [3171]=5,
6187 [3201]=5,
6188 [3260]=5,
6189 [3263]=5,
6190 [3270]=5,
6191 [3276]=5,
6192 [3277]=5,
6193 [3298]=5,
6194 [3299]=5,
6195 [3328]=5,
6196 [3329]=5,
6197 [3387]=5,
6198 [3388]=5,
6199 [3393]=5,
6200 [3394]=5,
6201 [3395]=5,
6202 [3396]=5,
6203 [3405]=5,
6204 [3426]=5,
6205 [3427]=5,
6206 [3457]=5,
6207 [3530]=5,
6208 [3538]=5,
6209 [3539]=5,
6210 [3540]=5,
6211 [3542]=5,
6212 [3633]=5,
6213 [3636]=5,
6214 [3637]=5,
6215 [3638]=5,
6216 [3639]=5,
6217 [3640]=5,
6218 [3641]=5,
6219 [3642]=5,
6220 [3655]=5,
6221 [3656]=5,
6222 [3657]=5,
6223 [3658]=5,
6224 [3659]=5,
6225 [3660]=5,
6226 [3661]=5,
6227 [3662]=5,
6228 [3761]=5,
6229 [3764]=5,
6230 [3765]=5,
6231 [3766]=5,
6232 [3767]=5,
6233 [3768]=5,
6234 [3769]=5,
6235 [3770]=5,
6236 [3771]=5,
6237 [3772]=5,
6238 [3784]=5,
6239 [3785]=5,
6240 [3786]=5,
6241 [3787]=5,
6242 [3788]=5,
6243 [3789]=5,
6244 [3864]=5,
6245 [3865]=5,
6246 [3893]=5,
6247 [3895]=5,
6248 [3897]=5,
6249 [3953]=5,
6250 [3954]=5,
6251 [3955]=5,
6252 [3956]=5,
6253 [3957]=5,
6254 [3958]=5,
6255 [3959]=5,
6256 [3960]=5,
6257 [3961]=5,
6258 [3962]=5,
6259 [3963]=5,
6260 [3964]=5,
6261 [3965]=5,
6262 [3966]=5,
6263 [3968]=5,
6264 [3969]=5,
6265 [3970]=5,
6266 [3971]=5,
6267 [3972]=5,
6268 [3974]=5,
6269 [3975]=5,
6270 [3981]=5,
6271 [3982]=5,
6272 [3983]=5,
6273 [3984]=5,
6274 [3985]=5,
6275 [3986]=5,
6276 [3987]=5,
6277 [3988]=5,
6278 [3989]=5,
6279 [3990]=5,
6280 [3991]=5,
6281 [3993]=5,
6282 [3994]=5,
6283 [3995]=5,
6284 [3996]=5,
6285 [3997]=5,
6286 [3998]=5,
6287 [3999]=5,
6288 [4000]=5,
6289 [4001]=5,
6290 [4002]=5,
6291 [4003]=5,
6292 [4004]=5,
6293 [4005]=5,
6294 [4006]=5,
6295 [4007]=5,
6296 [4008]=5,
6297 [4009]=5,
6298 [4010]=5,
6299 [4011]=5,
6300 [4012]=5,
6301 [4013]=5,
6302 [4014]=5,
6303 [4015]=5,
6304 [4016]=5,
6305 [4017]=5,
6306 [4018]=5,
6307 [4019]=5,
6308 [4020]=5,
6309 [4021]=5,
6310 [4022]=5,
6311 [4023]=5,
6312 [4024]=5,
6313 [4025]=5,
6314 [4026]=5,
6315 [4027]=5,
6316 [4028]=5,
6317 [4038]=5,
6318 [4141]=5,
6319 [4142]=5,
6320 [4143]=5,
6321 [4144]=5,
6322 [4146]=5,
6323 [4147]=5,
6324 [4148]=5,
6325 [4149]=5,
6326 [4150]=5,
6327 [4151]=5,
6328 [4153]=5,
6329 [4154]=5,
6330 [4157]=5,
6331 [4158]=5,
6332 [4184]=5,
6333 [4185]=5,
6334 [4190]=5,
6335 [4191]=5,
6336 [4192]=5,
6337 [4209]=5,
6338 [4210]=5,
6339 [4211]=5,
6340 [4212]=5,
6341 [4226]=5,
6342 [4229]=5,
6343 [4230]=5,
6344 [4237]=5,
6345 [4253]=5,
6346 [4957]=5,
6347 [4958]=5,
6348 [4959]=5,
6349 [5906]=5,
6350 [5907]=5,
6351 [5908]=5,
6352 [5938]=5,
6353 [5939]=5,
6354 [5940]=5,
6355 [5970]=5,
6356 [5971]=5,
6357 [6002]=5,
6358 [6003]=5,
6359 [6071]=5,
6360 [6072]=5,
6361 [6073]=5,
6362 [6074]=5,
6363 [6075]=5,
6364 [6076]=5,
6365 [6077]=5,
6366 [6086]=5,
6367 [6089]=5,
6368 [6090]=5,
6369 [6091]=5,
6370 [6092]=5,
6371 [6093]=5,
6372 [6094]=5,
6373 [6095]=5,
6374 [6096]=5,
6375 [6097]=5,
6376 [6098]=5,
6377 [6099]=5,
6378 [6109]=5,
6379 [6150]=4,
6380 [6151]=2,
6381 [6154]=2,
6382 [6155]=5,
6383 [6156]=5,
6384 [6157]=5,
6385 [6158]=4,
6386 [6159]=5,
6387 [6176]=2,
6388 [6177]=2,
6389 [6178]=2,
6390 [6179]=2,
6391 [6180]=2,
6392 [6181]=2,
6393 [6182]=2,
6394 [6183]=2,
6395 [6184]=2,
6396 [6185]=2,
6397 [6186]=2,
6398 [6187]=2,
6399 [6188]=2,
6400 [6189]=2,
6401 [6190]=2,
6402 [6191]=2,
6403 [6192]=2,
6404 [6193]=2,
6405 [6194]=2,
6406 [6195]=2,
6407 [6196]=2,
6408 [6197]=2,
6409 [6198]=2,
6410 [6199]=2,
6411 [6200]=2,
6412 [6201]=2,
6413 [6202]=2,
6414 [6203]=2,
6415 [6204]=2,
6416 [6205]=2,
6417 [6206]=2,
6418 [6207]=2,
6419 [6208]=2,
6420 [6209]=2,
6421 [6210]=2,
6422 [6211]=2,
6423 [6212]=2,
6424 [6213]=2,
6425 [6214]=2,
6426 [6215]=2,
6427 [6216]=2,
6428 [6217]=2,
6429 [6218]=2,
6430 [6219]=2,
6431 [6220]=2,
6432 [6221]=2,
6433 [6222]=2,
6434 [6223]=2,
6435 [6224]=2,
6436 [6225]=2,
6437 [6226]=2,
6438 [6227]=2,
6439 [6228]=2,
6440 [6229]=2,
6441 [6230]=2,
6442 [6231]=2,
6443 [6232]=2,
6444 [6233]=2,
6445 [6234]=2,
6446 [6235]=2,
6447 [6236]=2,
6448 [6237]=2,
6449 [6238]=2,
6450 [6239]=2,
6451 [6240]=2,
6452 [6241]=2,
6453 [6242]=2,
6454 [6243]=2,
6455 [6244]=2,
6456 [6245]=2,
6457 [6246]=2,
6458 [6247]=2,
6459 [6248]=2,
6460 [6249]=2,
6461 [6250]=2,
6462 [6251]=2,
6463 [6252]=2,
6464 [6253]=2,
6465 [6254]=2,
6466 [6255]=2,
6467 [6256]=2,
6468 [6257]=2,
6469 [6258]=2,
6470 [6259]=2,
6471 [6260]=2,
6472 [6261]=2,
6473 [6262]=2,
6474 [6263]=2,
6475 [6264]=2,
6476 [6272]=4,
6477 [6273]=4,
6478 [6274]=4,
6479 [6275]=4,
6480 [6276]=4,
6481 [6279]=2,
6482 [6280]=2,
6483 [6281]=2,
6484 [6282]=2,
6485 [6283]=2,
6486 [6284]=2,
6487 [6285]=2,
6488 [6286]=2,
6489 [6287]=2,
6490 [6288]=2,
6491 [6289]=2,
6492 [6290]=2,
6493 [6291]=2,
6494 [6292]=2,
6495 [6293]=2,
6496 [6294]=2,
6497 [6295]=2,
6498 [6296]=2,
6499 [6297]=2,
6500 [6298]=2,
6501 [6299]=2,
6502 [6300]=2,
6503 [6301]=2,
6504 [6302]=2,
6505 [6303]=2,
6506 [6304]=2,
6507 [6305]=2,
6508 [6306]=2,
6509 [6307]=2,
6510 [6308]=2,
6511 [6309]=2,
6512 [6310]=2,
6513 [6311]=2,
6514 [6312]=2,
6515 [6313]=5,
6516 [6314]=2,
6517 [6432]=5,
6518 [6433]=5,
6519 [6434]=5,
6520 [6439]=5,
6521 [6440]=5,
6522 [6450]=5,
6523 [6457]=5,
6524 [6458]=5,
6525 [6459]=5,
6526 [6679]=5,
6527 [6680]=5,
6528 [6742]=5,
6529 [6744]=5,
6530 [6745]=5,
6531 [6746]=5,
6532 [6747]=5,
6533 [6748]=5,
6534 [6749]=5,
6535 [6750]=5,
6536 [6752]=5,
6537 [6754]=5,
6538 [6757]=5,
6539 [6758]=5,
6540 [6759]=5,
6541 [6760]=5,
6542 [6761]=5,
6543 [6762]=5,
6544 [6763]=5,
6545 [6764]=5,
6546 [6771]=5,
6547 [6772]=5,
6548 [6773]=5,
6549 [6774]=5,
6550 [6775]=5,
6551 [6776]=5,
6552 [6777]=5,
6553 [6778]=5,
6554 [6779]=5,
6555 [6780]=5,
6556 [6783]=5,
6557 [6832]=5,
6558 [6833]=5,
6559 [6834]=5,
6560 [6835]=5,
6561 [6836]=5,
6562 [6837]=5,
6563 [6838]=5,
6564 [6839]=5,
6565 [6840]=5,
6566 [6841]=5,
6567 [6842]=5,
6568 [6843]=5,
6569 [6844]=5,
6570 [6845]=5,
6571 [6847]=5,
6572 [6848]=5,
6573 [6849]=5,
6574 [6850]=5,
6575 [6851]=5,
6576 [6852]=5,
6577 [6853]=5,
6578 [6854]=5,
6579 [6855]=5,
6580 [6856]=5,
6581 [6857]=5,
6582 [6858]=5,
6583 [6859]=5,
6584 [6860]=5,
6585 [6861]=5,
6586 [6862]=5,
6587 [6912]=5,
6588 [6913]=5,
6589 [6914]=5,
6590 [6915]=5,
6591 [6964]=5,
6592 [6966]=5,
6593 [6967]=5,
6594 [6968]=5,
6595 [6969]=5,
6596 [6970]=5,
6597 [6972]=5,
6598 [6978]=5,
6599 [7019]=5,
6600 [7020]=5,
6601 [7021]=5,
6602 [7022]=5,
6603 [7023]=5,
6604 [7024]=5,
6605 [7025]=5,
6606 [7026]=5,
6607 [7027]=5,
6608 [7040]=5,
6609 [7041]=5,
6610 [7074]=5,
6611 [7075]=5,
6612 [7076]=5,
6613 [7077]=5,
6614 [7080]=5,
6615 [7081]=5,
6616 [7083]=5,
6617 [7142]=5,
6618 [7144]=5,
6619 [7145]=5,
6620 [7149]=5,
6621 [7151]=5,
6622 [7152]=5,
6623 [7153]=5,
6624 [7212]=5,
6625 [7213]=5,
6626 [7214]=5,
6627 [7215]=5,
6628 [7216]=5,
6629 [7217]=5,
6630 [7218]=5,
6631 [7219]=5,
6632 [7222]=5,
6633 [7223]=5,
6634 [7376]=5,
6635 [7377]=5,
6636 [7378]=5,
6637 [7380]=5,
6638 [7381]=5,
6639 [7382]=5,
6640 [7383]=5,
6641 [7384]=5,
6642 [7385]=5,
6643 [7386]=5,
6644 [7387]=5,
6645 [7388]=5,
6646 [7389]=5,
6647 [7390]=5,
6648 [7391]=5,
6649 [7392]=5,
6650 [7394]=5,
6651 [7395]=5,
6652 [7396]=5,
6653 [7397]=5,
6654 [7398]=5,
6655 [7399]=5,
6656 [7400]=5,
6657 [7405]=5,
6658 [7412]=5,
6659 [7416]=5,
6660 [7417]=5,
6661 [7616]=5,
6662 [7617]=5,
6663 [7618]=5,
6664 [7619]=5,
6665 [7620]=5,
6666 [7621]=5,
6667 [7622]=5,
6668 [7623]=5,
6669 [7624]=5,
6670 [7625]=5,
6671 [7626]=5,
6672 [7627]=5,
6673 [7628]=5,
6674 [7629]=5,
6675 [7630]=5,
6676 [7631]=5,
6677 [7632]=5,
6678 [7633]=5,
6679 [7634]=5,
6680 [7635]=5,
6681 [7636]=5,
6682 [7637]=5,
6683 [7638]=5,
6684 [7639]=5,
6685 [7640]=5,
6686 [7641]=5,
6687 [7642]=5,
6688 [7643]=5,
6689 [7644]=5,
6690 [7645]=5,
6691 [7646]=5,
6692 [7647]=5,
6693 [7648]=5,
6694 [7649]=5,
6695 [7650]=5,
6696 [7651]=5,
6697 [7652]=5,
6698 [7653]=5,
6699 [7654]=5,
6700 [7655]=5,
6701 [7656]=5,
6702 [7657]=5,
6703 [7658]=5,
6704 [7659]=5,
6705 [7660]=5,
6706 [7661]=5,
6707 [7662]=5,
6708 [7663]=5,
6709 [7664]=5,
6710 [7665]=5,
6711 [7666]=5,
6712 [7667]=5,
6713 [7668]=5,
6714 [7669]=5,
6715 [7670]=5,
6716 [7671]=5,
6717 [7672]=5,
6718 [7673]=5,
6719 [7674]=5,
6720 [7675]=5,
6721 [7676]=5,
6722 [7677]=5,
6723 [7678]=5,
6724 [7679]=5,
6725 [8204]=4,
6726 [8205]=2,
6727 [8239]=4,
6728 [8294]=4,
6729 [8295]=4,
6730 [8296]=4,
6731 [8297]=4,
6732 [8400]=5,
6733 [8401]=5,
6734 [8402]=5,
6735 [8403]=5,
6736 [8404]=5,
6737 [8405]=5,
6738 [8406]=5,
6739 [8407]=5,
6740 [8408]=5,
6741 [8409]=5,
6742 [8410]=5,
6743 [8411]=5,
6744 [8412]=5,
6745 [8417]=5,
6746 [8421]=5,
6747 [8422]=5,
6748 [8423]=5,
6749 [8424]=5,
6750 [8425]=5,
6751 [8426]=5,
6752 [8427]=5,
6753 [8428]=5,
6754 [8429]=5,
6755 [8430]=5,
6756 [8431]=5,
6757 [8432]=5,
6758 [11503]=5,
6759 [11504]=5,
6760 [11505]=5,
6761 [11647]=5,
6762 [11744]=5,
6763 [11745]=5,
6764 [11746]=5,
6765 [11747]=5,
6766 [11748]=5,
6767 [11749]=5,
6768 [11750]=5,
6769 [11751]=5,
6770 [11752]=5,
6771 [11753]=5,
6772 [11754]=5,
6773 [11755]=5,
6774 [11756]=5,
6775 [11757]=5,
6776 [11758]=5,
6777 [11759]=5,
6778 [11760]=5,
6779 [11761]=5,
6780 [11762]=5,
6781 [11763]=5,
6782 [11764]=5,
6783 [11765]=5,
6784 [11766]=5,
6785 [11767]=5,
6786 [11768]=5,
6787 [11769]=5,
6788 [11770]=5,
6789 [11771]=5,
6790 [11772]=5,
6791 [11773]=5,
6792 [11774]=5,
6793 [11775]=5,
6794 [12330]=5,
6795 [12331]=5,
6796 [12332]=5,
6797 [12333]=5,
6798 [12334]=5,
6799 [12335]=5,
6800 [12441]=5,
6801 [12442]=5,
6802 [42607]=5,
6803 [42612]=5,
6804 [42613]=5,
6805 [42614]=5,
6806 [42615]=5,
6807 [42616]=5,
6808 [42617]=5,
6809 [42618]=5,
6810 [42619]=5,
6811 [42620]=5,
6812 [42621]=5,
6813 [42654]=5,
6814 [42655]=5,
6815 [42736]=5,
6816 [42737]=5,
6817 [43014]=5,
6818 [43019]=5,
6819 [43045]=5,
6820 [43046]=5,
6821 [43052]=5,
6822 [43072]=2,
6823 [43073]=2,
6824 [43074]=2,
6825 [43075]=2,
6826 [43076]=2,
6827 [43077]=2,
6828 [43078]=2,
6829 [43079]=2,
6830 [43080]=2,
6831 [43081]=2,
6832 [43082]=2,
6833 [43083]=2,
6834 [43084]=2,
6835 [43085]=2,
6836 [43086]=2,
6837 [43087]=2,
6838 [43088]=2,
6839 [43089]=2,
6840 [43090]=2,
6841 [43091]=2,
6842 [43092]=2,
6843 [43093]=2,
6844 [43094]=2,
6845 [43095]=2,
6846 [43096]=2,
6847 [43097]=2,
6848 [43098]=2,
6849 [43099]=2,
6850 [43100]=2,
6851 [43101]=2,
6852 [43102]=2,
6853 [43103]=2,
6854 [43104]=2,
6855 [43105]=2,
6856 [43106]=2,
6857 [43107]=2,
6858 [43108]=2,
6859 [43109]=2,
6860 [43110]=2,
6861 [43111]=2,
6862 [43112]=2,
6863 [43113]=2,
6864 [43114]=2,
6865 [43115]=2,
6866 [43116]=2,
6867 [43117]=2,
6868 [43118]=2,
6869 [43119]=2,
6870 [43120]=2,
6871 [43121]=2,
6872 [43122]=1,
6873 [43123]=4,
6874 [43204]=5,
6875 [43205]=5,
6876 [43232]=5,
6877 [43233]=5,
6878 [43234]=5,
6879 [43235]=5,
6880 [43236]=5,
6881 [43237]=5,
6882 [43238]=5,
6883 [43239]=5,
6884 [43240]=5,
6885 [43241]=5,
6886 [43242]=5,
6887 [43243]=5,
6888 [43244]=5,
6889 [43245]=5,
6890 [43246]=5,
6891 [43247]=5,
6892 [43248]=5,
6893 [43249]=5,
6894 [43263]=5,
6895 [43302]=5,
6896 [43303]=5,
6897 [43304]=5,
6898 [43305]=5,
6899 [43306]=5,
6900 [43307]=5,
6901 [43308]=5,
6902 [43309]=5,
6903 [43335]=5,
6904 [43336]=5,
6905 [43337]=5,
6906 [43338]=5,
6907 [43339]=5,
6908 [43340]=5,
6909 [43341]=5,
6910 [43342]=5,
6911 [43343]=5,
6912 [43344]=5,
6913 [43345]=5,
6914 [43392]=5,
6915 [43393]=5,
6916 [43394]=5,
6917 [43443]=5,
6918 [43446]=5,
6919 [43447]=5,
6920 [43448]=5,
6921 [43449]=5,
6922 [43452]=5,
6923 [43493]=5,
6924 [43561]=5,
6925 [43562]=5,
6926 [43563]=5,
6927 [43564]=5,
6928 [43565]=5,
6929 [43566]=5,
6930 [43569]=5,
6931 [43570]=5,
6932 [43573]=5,
6933 [43574]=5,
6934 [43587]=5,
6935 [43596]=5,
6936 [43644]=5,
6937 [43696]=5,
6938 [43698]=5,
6939 [43699]=5,
6940 [43700]=5,
6941 [43703]=5,
6942 [43704]=5,
6943 [43710]=5,
6944 [43711]=5,
6945 [43713]=5,
6946 [43756]=5,
6947 [43757]=5,
6948 [43766]=5,
6949 [44005]=5,
6950 [44008]=5,
6951 [44013]=5,
6952 [64286]=5,
6953 [65056]=5,
6954 [65057]=5,
6955 [65058]=5,
6956 [65059]=5,
6957 [65060]=5,
6958 [65061]=5,
6959 [65062]=5,
6960 [65063]=5,
6961 [65064]=5,
6962 [65065]=5,
6963 [65066]=5,
6964 [65067]=5,
6965 [65068]=5,
6966 [65069]=5,
6967 [65070]=5,
6968 [65071]=5,
6969 [66045]=5,
6970 [66272]=5,
6971 [66422]=5,
6972 [66423]=5,
6973 [66424]=5,
6974 [66425]=5,
6975 [66426]=5,
6976 [68097]=5,
6977 [68098]=5,
6978 [68099]=5,
6979 [68101]=5,
6980 [68102]=5,
6981 [68108]=5,
6982 [68109]=5,
6983 [68110]=5,
6984 [68111]=5,
6985 [68152]=5,
6986 [68153]=5,
6987 [68154]=5,
6988 [68159]=5,
6989 [68288]=2,
6990 [68289]=2,
6991 [68290]=2,
6992 [68291]=2,
6993 [68292]=2,
6994 [68293]=3,
6995 [68294]=4,
6996 [68295]=3,
6997 [68296]=4,
6998 [68297]=3,
6999 [68298]=3,
7000 [68299]=4,
7001 [68300]=4,
7002 [68301]=1,
7003 [68302]=3,
7004 [68303]=3,
7005 [68304]=3,
7006 [68305]=3,
7007 [68306]=3,
7008 [68307]=2,
7009 [68308]=2,
7010 [68309]=2,
7011 [68310]=2,
7012 [68311]=1,
7013 [68312]=2,
7014 [68313]=2,
7015 [68314]=2,
7016 [68315]=2,
7017 [68316]=2,
7018 [68317]=3,
7019 [68318]=2,
7020 [68319]=2,
7021 [68320]=2,
7022 [68321]=3,
7023 [68322]=4,
7024 [68323]=4,
7025 [68324]=3,
7026 [68325]=5,
7027 [68326]=5,
7028 [68331]=2,
7029 [68332]=2,
7030 [68333]=2,
7031 [68334]=2,
7032 [68335]=3,
7033 [68480]=2,
7034 [68481]=3,
7035 [68482]=2,
7036 [68483]=3,
7037 [68484]=3,
7038 [68485]=3,
7039 [68486]=2,
7040 [68487]=2,
7041 [68488]=2,
7042 [68489]=3,
7043 [68490]=2,
7044 [68491]=2,
7045 [68492]=3,
7046 [68493]=2,
7047 [68494]=3,
7048 [68495]=3,
7049 [68496]=2,
7050 [68497]=3,
7051 [68521]=3,
7052 [68522]=3,
7053 [68523]=3,
7054 [68524]=3,
7055 [68525]=2,
7056 [68526]=2,
7057 [68527]=4,
7058 [68864]=1,
7059 [68865]=2,
7060 [68866]=2,
7061 [68867]=2,
7062 [68868]=2,
7063 [68869]=2,
7064 [68870]=2,
7065 [68871]=2,
7066 [68872]=2,
7067 [68873]=2,
7068 [68874]=2,
7069 [68875]=2,
7070 [68876]=2,
7071 [68877]=2,
7072 [68878]=2,
7073 [68879]=2,
7074 [68880]=2,
7075 [68881]=2,
7076 [68882]=2,
7077 [68883]=2,
7078 [68884]=2,
7079 [68885]=2,
7080 [68886]=2,
7081 [68887]=2,
7082 [68888]=2,
7083 [68889]=2,
7084 [68890]=2,
7085 [68891]=2,
7086 [68892]=2,
7087 [68893]=2,
7088 [68894]=2,
7089 [68895]=2,
7090 [68896]=2,
7091 [68897]=2,
7092 [68898]=3,
7093 [68899]=2,
7094 [68900]=5,
7095 [68901]=5,
7096 [68902]=5,
7097 [68903]=5,
7098 [69291]=5,
7099 [69292]=5,
7100 [69424]=2,
7101 [69425]=2,
7102 [69426]=2,
7103 [69427]=3,
7104 [69428]=2,
7105 [69429]=2,
7106 [69430]=2,
7107 [69431]=2,
7108 [69432]=2,
7109 [69433]=2,
7110 [69434]=2,
7111 [69435]=2,
7112 [69436]=2,
7113 [69437]=2,
7114 [69438]=2,
7115 [69439]=2,
7116 [69440]=2,
7117 [69441]=2,
7118 [69442]=2,
7119 [69443]=2,
7120 [69444]=2,
7121 [69445]=4,
7122 [69446]=5,
7123 [69447]=5,
7124 [69448]=5,
7125 [69449]=5,
7126 [69450]=5,
7127 [69451]=5,
7128 [69452]=5,
7129 [69453]=5,
7130 [69454]=5,
7131 [69455]=5,
7132 [69456]=5,
7133 [69457]=2,
7134 [69458]=2,
7135 [69459]=2,
7136 [69460]=3,
7137 [69488]=2,
7138 [69489]=2,
7139 [69490]=2,
7140 [69491]=2,
7141 [69492]=3,
7142 [69493]=3,
7143 [69494]=2,
7144 [69495]=2,
7145 [69496]=2,
7146 [69497]=2,
7147 [69498]=2,
7148 [69499]=2,
7149 [69500]=2,
7150 [69501]=2,
7151 [69502]=2,
7152 [69503]=2,
7153 [69504]=2,
7154 [69505]=2,
7155 [69506]=5,
7156 [69507]=5,
7157 [69508]=5,
7158 [69509]=5,
7159 [69552]=2,
7160 [69553]=4,
7161 [69554]=2,
7162 [69555]=2,
7163 [69556]=3,
7164 [69557]=3,
7165 [69558]=3,
7166 [69559]=4,
7167 [69560]=2,
7168 [69561]=3,
7169 [69562]=3,
7170 [69563]=2,
7171 [69564]=2,
7172 [69565]=3,
7173 [69566]=2,
7174 [69567]=2,
7175 [69568]=4,
7176 [69569]=2,
7177 [69570]=3,
7178 [69571]=3,
7179 [69572]=2,
7180 [69573]=4,
7181 [69574]=4,
7182 [69575]=4,
7183 [69576]=4,
7184 [69577]=3,
7185 [69578]=2,
7186 [69579]=1,
7187 [69633]=5,
7188 [69688]=5,
7189 [69689]=5,
7190 [69690]=5,
7191 [69691]=5,
7192 [69692]=5,
7193 [69693]=5,
7194 [69694]=5,
7195 [69695]=5,
7196 [69696]=5,
7197 [69697]=5,
7198 [69698]=5,
7199 [69699]=5,
7200 [69700]=5,
7201 [69701]=5,
7202 [69702]=5,
7203 [69744]=5,
7204 [69747]=5,
7205 [69748]=5,
7206 [69759]=5,
7207 [69760]=5,
7208 [69761]=5,
7209 [69811]=5,
7210 [69812]=5,
7211 [69813]=5,
7212 [69814]=5,
7213 [69817]=5,
7214 [69818]=5,
7215 [69821]=4,
7216 [69826]=5,
7217 [69837]=4,
7218 [69888]=5,
7219 [69889]=5,
7220 [69890]=5,
7221 [69927]=5,
7222 [69928]=5,
7223 [69929]=5,
7224 [69930]=5,
7225 [69931]=5,
7226 [69933]=5,
7227 [69934]=5,
7228 [69935]=5,
7229 [69936]=5,
7230 [69937]=5,
7231 [69938]=5,
7232 [69939]=5,
7233 [69940]=5,
7234 [70003]=5,
7235 [70016]=5,
7236 [70017]=5,
7237 [70070]=5,
7238 [70071]=5,
7239 [70072]=5,
7240 [70073]=5,
7241 [70074]=5,
7242 [70075]=5,
7243 [70076]=5,
7244 [70077]=5,
7245 [70078]=5,
7246 [70090]=5,
7247 [70091]=5,
7248 [70092]=5,
7249 [70095]=5,
7250 [70191]=5,
7251 [70192]=5,
7252 [70193]=5,
7253 [70196]=5,
7254 [70198]=5,
7255 [70199]=5,
7256 [70206]=5,
7257 [70367]=5,
7258 [70371]=5,
7259 [70372]=5,
7260 [70373]=5,
7261 [70374]=5,
7262 [70375]=5,
7263 [70376]=5,
7264 [70377]=5,
7265 [70378]=5,
7266 [70400]=5,
7267 [70401]=5,
7268 [70459]=5,
7269 [70460]=5,
7270 [70464]=5,
7271 [70502]=5,
7272 [70503]=5,
7273 [70504]=5,
7274 [70505]=5,
7275 [70506]=5,
7276 [70507]=5,
7277 [70508]=5,
7278 [70512]=5,
7279 [70513]=5,
7280 [70514]=5,
7281 [70515]=5,
7282 [70516]=5,
7283 [70712]=5,
7284 [70713]=5,
7285 [70714]=5,
7286 [70715]=5,
7287 [70716]=5,
7288 [70717]=5,
7289 [70718]=5,
7290 [70719]=5,
7291 [70722]=5,
7292 [70723]=5,
7293 [70724]=5,
7294 [70726]=5,
7295 [70750]=5,
7296 [70835]=5,
7297 [70836]=5,
7298 [70837]=5,
7299 [70838]=5,
7300 [70839]=5,
7301 [70840]=5,
7302 [70842]=5,
7303 [70847]=5,
7304 [70848]=5,
7305 [70850]=5,
7306 [70851]=5,
7307 [71090]=5,
7308 [71091]=5,
7309 [71092]=5,
7310 [71093]=5,
7311 [71100]=5,
7312 [71101]=5,
7313 [71103]=5,
7314 [71104]=5,
7315 [71132]=5,
7316 [71133]=5,
7317 [71219]=5,
7318 [71220]=5,
7319 [71221]=5,
7320 [71222]=5,
7321 [71223]=5,
7322 [71224]=5,
7323 [71225]=5,
7324 [71226]=5,
7325 [71229]=5,
7326 [71231]=5,
7327 [71232]=5,
7328 [71339]=5,
7329 [71341]=5,
7330 [71344]=5,
7331 [71345]=5,
7332 [71346]=5,
7333 [71347]=5,
7334 [71348]=5,
7335 [71349]=5,
7336 [71351]=5,
7337 [71453]=5,
7338 [71454]=5,
7339 [71455]=5,
7340 [71458]=5,
7341 [71459]=5,
7342 [71460]=5,
7343 [71461]=5,
7344 [71463]=5,
7345 [71464]=5,
7346 [71465]=5,
7347 [71466]=5,
7348 [71467]=5,
7349 [71727]=5,
7350 [71728]=5,
7351 [71729]=5,
7352 [71730]=5,
7353 [71731]=5,
7354 [71732]=5,
7355 [71733]=5,
7356 [71734]=5,
7357 [71735]=5,
7358 [71737]=5,
7359 [71738]=5,
7360 [71995]=5,
7361 [71996]=5,
7362 [71998]=5,
7363 [72003]=5,
7364 [72148]=5,
7365 [72149]=5,
7366 [72150]=5,
7367 [72151]=5,
7368 [72154]=5,
7369 [72155]=5,
7370 [72160]=5,
7371 [72193]=5,
7372 [72194]=5,
7373 [72195]=5,
7374 [72196]=5,
7375 [72197]=5,
7376 [72198]=5,
7377 [72201]=5,
7378 [72202]=5,
7379 [72243]=5,
7380 [72244]=5,
7381 [72245]=5,
7382 [72246]=5,
7383 [72247]=5,
7384 [72248]=5,
7385 [72251]=5,
7386 [72252]=5,
7387 [72253]=5,
7388 [72254]=5,
7389 [72263]=5,
7390 [72273]=5,
7391 [72274]=5,
7392 [72275]=5,
7393 [72276]=5,
7394 [72277]=5,
7395 [72278]=5,
7396 [72281]=5,
7397 [72282]=5,
7398 [72283]=5,
7399 [72330]=5,
7400 [72331]=5,
7401 [72332]=5,
7402 [72333]=5,
7403 [72334]=5,
7404 [72335]=5,
7405 [72336]=5,
7406 [72337]=5,
7407 [72338]=5,
7408 [72339]=5,
7409 [72340]=5,
7410 [72341]=5,
7411 [72342]=5,
7412 [72344]=5,
7413 [72345]=5,
7414 [72752]=5,
7415 [72753]=5,
7416 [72754]=5,
7417 [72755]=5,
7418 [72756]=5,
7419 [72757]=5,
7420 [72758]=5,
7421 [72760]=5,
7422 [72761]=5,
7423 [72762]=5,
7424 [72763]=5,
7425 [72764]=5,
7426 [72765]=5,
7427 [72767]=5,
7428 [72850]=5,
7429 [72851]=5,
7430 [72852]=5,
7431 [72853]=5,
7432 [72854]=5,
7433 [72855]=5,
7434 [72856]=5,
7435 [72857]=5,
7436 [72858]=5,
7437 [72859]=5,
7438 [72860]=5,
7439 [72861]=5,
7440 [72862]=5,
7441 [72863]=5,
7442 [72864]=5,
7443 [72865]=5,
7444 [72866]=5,
7445 [72867]=5,
7446 [72868]=5,
7447 [72869]=5,
7448 [72870]=5,
7449 [72871]=5,
7450 [72874]=5,
7451 [72875]=5,
7452 [72876]=5,
7453 [72877]=5,
7454 [72878]=5,
7455 [72879]=5,
7456 [72880]=5,
7457 [72882]=5,
7458 [72883]=5,
7459 [72885]=5,
7460 [72886]=5,
7461 [73009]=5,
7462 [73010]=5,
7463 [73011]=5,
7464 [73012]=5,
7465 [73013]=5,
7466 [73014]=5,
7467 [73018]=5,
7468 [73020]=5,
7469 [73021]=5,
7470 [73023]=5,
7471 [73024]=5,
7472 [73025]=5,
7473 [73026]=5,
7474 [73027]=5,
7475 [73028]=5,
7476 [73029]=5,
7477 [73031]=5,
7478 [73104]=5,
7479 [73105]=5,
7480 [73109]=5,
7481 [73111]=5,
7482 [73459]=5,
7483 [73460]=5,
7484 [92912]=5,
7485 [92913]=5,
7486 [92914]=5,
7487 [92915]=5,
7488 [92916]=5,
7489 [92976]=5,
7490 [92977]=5,
7491 [92978]=5,
7492 [92979]=5,
7493 [92980]=5,
7494 [92981]=5,
7495 [92982]=5,
7496 [94031]=5,
7497 [94095]=5,
7498 [94096]=5,
7499 [94097]=5,
7500 [94098]=5,
7501 [94180]=5,
7502 [113821]=5,
7503 [113822]=5,
7504 [118528]=5,
7505 [118529]=5,
7506 [118530]=5,
7507 [118531]=5,
7508 [118532]=5,
7509 [118533]=5,
7510 [118534]=5,
7511 [118535]=5,
7512 [118536]=5,
7513 [118537]=5,
7514 [118538]=5,
7515 [118539]=5,
7516 [118540]=5,
7517 [118541]=5,
7518 [118542]=5,
7519 [118543]=5,
7520 [118544]=5,
7521 [118545]=5,
7522 [118546]=5,
7523 [118547]=5,
7524 [118548]=5,
7525 [118549]=5,
7526 [118550]=5,
7527 [118551]=5,
7528 [118552]=5,
7529 [118553]=5,
7530 [118554]=5,
7531 [118555]=5,
7532 [118556]=5,
7533 [118557]=5,
7534 [118558]=5,
7535 [118559]=5,
7536 [118560]=5,
7537 [118561]=5,
7538 [118562]=5,
7539 [118563]=5,
7540 [118564]=5,
7541 [118565]=5,
7542 [118566]=5,
7543 [118567]=5,
7544 [118568]=5,
7545 [118569]=5,
7546 [118570]=5,
7547 [118571]=5,
7548 [118572]=5,
7549 [118573]=5,
7550 [118576]=5,
7551 [118577]=5,
7552 [118578]=5,
7553 [118579]=5,
7554 [118580]=5,
7555 [118581]=5,
7556 [118582]=5,
7557 [118583]=5,
7558 [118584]=5,
7559 [118585]=5,
7560 [118586]=5,
7561 [118587]=5,
7562 [118588]=5,
7563 [118589]=5,
7564 [118590]=5,
7565 [118591]=5,
7566 [118592]=5,
7567 [118593]=5,
7568 [118594]=5,
7569 [118595]=5,
7570 [118596]=5,
7571 [118597]=5,
7572 [118598]=5,
7573 [119143]=5,
7574 [119144]=5,
7575 [119145]=5,
7576 [119163]=5,
7577 [119164]=5,
7578 [119165]=5,
7579 [119166]=5,
7580 [119167]=5,
7581 [119168]=5,
7582 [119169]=5,
7583 [119170]=5,
7584 [119173]=5,
7585 [119174]=5,
7586 [119175]=5,
7587 [119176]=5,
7588 [119177]=5,
7589 [119178]=5,
7590 [119179]=5,
7591 [119210]=5,
7592 [119211]=5,
7593 [119212]=5,
7594 [119213]=5,
7595 [119362]=5,
7596 [119363]=5,
7597 [119364]=5,
7598 [121344]=5,
7599 [121345]=5,
7600 [121346]=5,
7601 [121347]=5,
7602 [121348]=5,
7603 [121349]=5,
7604 [121350]=5,
7605 [121351]=5,
7606 [121352]=5,
7607 [121353]=5,
7608 [121354]=5,
7609 [121355]=5,
7610 [121356]=5,
7611 [121357]=5,
7612 [121358]=5,
7613 [121359]=5,
7614 [121360]=5,
7615 [121361]=5,
7616 [121362]=5,
7617 [121363]=5,
7618 [121364]=5,
7619 [121365]=5,
7620 [121366]=5,
7621 [121367]=5,
7622 [121368]=5,
7623 [121369]=5,
7624 [121370]=5,
7625 [121371]=5,
7626 [121372]=5,
7627 [121373]=5,
7628 [121374]=5,
7629 [121375]=5,
7630 [121376]=5,
7631 [121377]=5,
7632 [121378]=5,
7633 [121379]=5,
7634 [121380]=5,
7635 [121381]=5,
7636 [121382]=5,
7637 [121383]=5,
7638 [121384]=5,
7639 [121385]=5,
7640 [121386]=5,
7641 [121387]=5,
7642 [121388]=5,
7643 [121389]=5,
7644 [121390]=5,
7645 [121391]=5,
7646 [121392]=5,
7647 [121393]=5,
7648 [121394]=5,
7649 [121395]=5,
7650 [121396]=5,
7651 [121397]=5,
7652 [121398]=5,
7653 [121403]=5,
7654 [121404]=5,
7655 [121405]=5,
7656 [121406]=5,
7657 [121407]=5,
7658 [121408]=5,
7659 [121409]=5,
7660 [121410]=5,
7661 [121411]=5,
7662 [121412]=5,
7663 [121413]=5,
7664 [121414]=5,
7665 [121415]=5,
7666 [121416]=5,
7667 [121417]=5,
7668 [121418]=5,
7669 [121419]=5,
7670 [121420]=5,
7671 [121421]=5,
7672 [121422]=5,
7673 [121423]=5,
7674 [121424]=5,
7675 [121425]=5,
7676 [121426]=5,
7677 [121427]=5,
7678 [121428]=5,
7679 [121429]=5,
7680 [121430]=5,
7681 [121431]=5,
7682 [121432]=5,
7683 [121433]=5,
7684 [121434]=5,
7685 [121435]=5,
7686 [121436]=5,
7687 [121437]=5,
7688 [121438]=5,
7689 [121439]=5,
7690 [121440]=5,
7691 [121441]=5,
7692 [121442]=5,
7693 [121443]=5,
7694 [121444]=5,
7695 [121445]=5,
7696 [121446]=5,
7697 [121447]=5,
7698 [121448]=5,
7699 [121449]=5,
7700 [121450]=5,
7701 [121451]=5,
7702 [121452]=5,
7703 [121461]=5,
7704 [121476]=5,
7705 [121499]=5,
7706 [121500]=5,
7707 [121501]=5,
7708 [121502]=5,
7709 [121503]=5,
7710 [121505]=5,
7711 [121506]=5,
7712 [121507]=5,
7713 [121508]=5,
7714 [121509]=5,
7715 [121510]=5,
7716 [121511]=5,
7717 [121512]=5,
7718 [121513]=5,
7719 [121514]=5,
7720 [121515]=5,
7721 [121516]=5,
7722 [121517]=5,
7723 [121518]=5,
7724 [121519]=5,
7725 [122880]=5,
7726 [122881]=5,
7727 [122882]=5,
7728 [122883]=5,
7729 [122884]=5,
7730 [122885]=5,
7731 [122886]=5,
7732 [122888]=5,
7733 [122889]=5,
7734 [122890]=5,
7735 [122891]=5,
7736 [122892]=5,
7737 [122893]=5,
7738 [122894]=5,
7739 [122895]=5,
7740 [122896]=5,
7741 [122897]=5,
7742 [122898]=5,
7743 [122899]=5,
7744 [122900]=5,
7745 [122901]=5,
7746 [122902]=5,
7747 [122903]=5,
7748 [122904]=5,
7749 [122907]=5,
7750 [122908]=5,
7751 [122909]=5,
7752 [122910]=5,
7753 [122911]=5,
7754 [122912]=5,
7755 [122913]=5,
7756 [122915]=5,
7757 [122916]=5,
7758 [122918]=5,
7759 [122919]=5,
7760 [122920]=5,
7761 [122921]=5,
7762 [122922]=5,
7763 [123184]=5,
7764 [123185]=5,
7765 [123186]=5,
7766 [123187]=5,
7767 [123188]=5,
7768 [123189]=5,
7769 [123190]=5,
7770 [123566]=5,
7771 [123628]=5,
7772 [123629]=5,
7773 [123630]=5,
7774 [123631]=5,
7775 [125136]=5,
7776 [125137]=5,
7777 [125138]=5,
7778 [125139]=5,
7779 [125140]=5,
7780 [125141]=5,
7781 [125142]=5,
7782 [125184]=2,
7783 [125185]=2,
7784 [125186]=2,
7785 [125187]=2,
7786 [125188]=2,
7787 [125189]=2,
7788 [125190]=2,
7789 [125191]=2,
7790 [125192]=2,
7791 [125193]=2,
7792 [125194]=2,
7793 [125195]=2,
7794 [125196]=2,
7795 [125197]=2,
7796 [125198]=2,
7797 [125199]=2,
7798 [125200]=2,
7799 [125201]=2,
7800 [125202]=2,
7801 [125203]=2,
7802 [125204]=2,
7803 [125205]=2,
7804 [125206]=2,
7805 [125207]=2,
7806 [125208]=2,
7807 [125209]=2,
7808 [125210]=2,
7809 [125211]=2,
7810 [125212]=2,
7811 [125213]=2,
7812 [125214]=2,
7813 [125215]=2,
7814 [125216]=2,
7815 [125217]=2,
7816 [125218]=2,
7817 [125219]=2,
7818 [125220]=2,
7819 [125221]=2,
7820 [125222]=2,
7821 [125223]=2,
7822 [125224]=2,
7823 [125225]=2,
7824 [125226]=2,
7825 [125227]=2,
7826 [125228]=2,
7827 [125229]=2,
7828 [125230]=2,
7829 [125231]=2,
7830 [125232]=2,
7831 [125233]=2,
7832 [125234]=2,
7833 [125235]=2,
7834 [125236]=2,
7835 [125237]=2,
7836 [125238]=2,
7837 [125239]=2,
7838 [125240]=2,
7839 [125241]=2,
7840 [125242]=2,
7841 [125243]=2,
7842 [125244]=2,
7843 [125245]=2,
7844 [125246]=2,
7845 [125247]=2,
7846 [125248]=2,
7847 [125249]=2,
7848 [125250]=2,
7849 [125251]=2,
7850 [125252]=5,
7851 [125253]=5,
7852 [125254]=5,
7853 [125255]=5,
7854 [125256]=5,
7855 [125257]=5,
7856 [125258]=5,
7857 [1042752]=5,
7858}
7859characters.indicgroups={
7860 ["above_mark"]={
7861  [2304]=true,
7862  [2305]=true,
7863  [2306]=true,
7864  [2362]=true,
7865  [2373]=true,
7866  [2374]=true,
7867  [2375]=true,
7868  [2376]=true,
7869  [2385]=true,
7870  [2387]=true,
7871  [2388]=true,
7872  [2389]=true,
7873  [2631]=true,
7874  [2632]=true,
7875  [2635]=true,
7876  [2636]=true,
7877  [2690]=true,
7878  [2757]=true,
7879  [2759]=true,
7880  [2760]=true,
7881  [2879]=true,
7882  [3008]=true,
7883  [3021]=true,
7884  [3134]=true,
7885  [3135]=true,
7886  [3136]=true,
7887  [3142]=true,
7888  [3143]=true,
7889  [3146]=true,
7890  [3147]=true,
7891  [3148]=true,
7892  [3149]=true,
7893  [3263]=true,
7894  [3270]=true,
7895  [3406]=true,
7896  [4141]=true,
7897  [4142]=true,
7898  [4146]=true,
7899  [4147]=true,
7900  [4148]=true,
7901  [4149]=true,
7902  [4150]=true,
7903  [4154]=true,
7904  [4209]=true,
7905  [4210]=true,
7906  [4211]=true,
7907  [4212]=true,
7908  [4229]=true,
7909  [4230]=true,
7910  [4253]=true,
7911  [43232]=true,
7912  [43233]=true,
7913  [43234]=true,
7914  [43235]=true,
7915  [43236]=true,
7916  [43237]=true,
7917  [43238]=true,
7918  [43239]=true,
7919  [43240]=true,
7920  [43241]=true,
7921  [43242]=true,
7922  [43243]=true,
7923  [43244]=true,
7924  [43245]=true,
7925  [43246]=true,
7926  [43247]=true,
7927  [43248]=true,
7928  [43249]=true,
7929  [43493]=true,
7930  [43644]=true,
7931 },
7932 ["after_half"]={},
7933 ["after_main"]={
7934  [2864]=true,
7935  [2879]=true,
7936  [2902]=true,
7937  [3376]=true,
7938  [5901]=true,
7939 },
7940 ["after_postscript"]={
7941  [2433]=true,
7942  [2494]=true,
7943  [2496]=true,
7944  [2519]=true,
7945  [2561]=true,
7946  [2562]=true,
7947  [2622]=true,
7948  [2624]=true,
7949  [2625]=true,
7950  [2626]=true,
7951  [2672]=true,
7952  [2673]=true,
7953  [2735]=true,
7954  [2750]=true,
7955  [2752]=true,
7956  [2753]=true,
7957  [2754]=true,
7958  [2755]=true,
7959  [2756]=true,
7960  [2761]=true,
7961  [2763]=true,
7962  [2764]=true,
7963  [2786]=true,
7964  [2787]=true,
7965  [2878]=true,
7966  [2880]=true,
7967  [2903]=true,
7968  [2992]=true,
7969  [3006]=true,
7970  [3007]=true,
7971  [3009]=true,
7972  [3010]=true,
7973  [3031]=true,
7974  [3120]=true,
7975  [3248]=true,
7976  [3390]=true,
7977  [3391]=true,
7978  [3392]=true,
7979  [3393]=true,
7980  [3394]=true,
7981  [3395]=true,
7982  [3415]=true,
7983 },
7984 ["after_subscript"]={
7985  [2366]=true,
7986  [2368]=true,
7987  [2369]=true,
7988  [2370]=true,
7989  [2371]=true,
7990  [2372]=true,
7991  [2373]=true,
7992  [2374]=true,
7993  [2375]=true,
7994  [2376]=true,
7995  [2377]=true,
7996  [2378]=true,
7997  [2379]=true,
7998  [2380]=true,
7999  [2402]=true,
8000  [2403]=true,
8001  [2480]=true,
8002  [2497]=true,
8003  [2498]=true,
8004  [2499]=true,
8005  [2500]=true,
8006  [2530]=true,
8007  [2531]=true,
8008  [2544]=true,
8009  [2631]=true,
8010  [2632]=true,
8011  [2635]=true,
8012  [2636]=true,
8013  [2757]=true,
8014  [2759]=true,
8015  [2760]=true,
8016  [2881]=true,
8017  [2882]=true,
8018  [2883]=true,
8019  [3008]=true,
8020  [3139]=true,
8021  [3140]=true,
8022  [3267]=true,
8023  [3268]=true,
8024  [3285]=true,
8025  [3286]=true,
8026 },
8027 ["anudatta"]={
8028  [2386]=true,
8029 },
8030 ["before_half"]={
8031  [2367]=true,
8032  [2382]=true,
8033  [2495]=true,
8034  [2503]=true,
8035  [2504]=true,
8036  [2623]=true,
8037  [2751]=true,
8038  [2887]=true,
8039 },
8040 ["before_main"]={
8041  [3014]=true,
8042  [3015]=true,
8043  [3016]=true,
8044  [3398]=true,
8045  [3399]=true,
8046  [3400]=true,
8047 },
8048 ["before_postscript"]={
8049  [2352]=true,
8050  [2736]=true,
8051 },
8052 ["before_subscript"]={
8053  [2608]=true,
8054  [2817]=true,
8055  [3134]=true,
8056  [3135]=true,
8057  [3136]=true,
8058  [3137]=true,
8059  [3138]=true,
8060  [3142]=true,
8061  [3143]=true,
8062  [3146]=true,
8063  [3147]=true,
8064  [3148]=true,
8065  [3157]=true,
8066  [3158]=true,
8067  [3262]=true,
8068  [3263]=true,
8069  [3265]=true,
8070  [3266]=true,
8071  [3270]=true,
8072  [3276]=true,
8073  [3298]=true,
8074  [3299]=true,
8075 },
8076 ["below_mark"]={
8077  [2364]=true,
8078  [2369]=true,
8079  [2370]=true,
8080  [2371]=true,
8081  [2372]=true,
8082  [2381]=true,
8083  [2386]=true,
8084  [2390]=true,
8085  [2391]=true,
8086  [2402]=true,
8087  [2403]=true,
8088  [2492]=true,
8089  [2497]=true,
8090  [2498]=true,
8091  [2499]=true,
8092  [2500]=true,
8093  [2509]=true,
8094  [2620]=true,
8095  [2625]=true,
8096  [2626]=true,
8097  [2637]=true,
8098  [2748]=true,
8099  [2753]=true,
8100  [2754]=true,
8101  [2755]=true,
8102  [2756]=true,
8103  [2765]=true,
8104  [2876]=true,
8105  [2881]=true,
8106  [2882]=true,
8107  [2883]=true,
8108  [2884]=true,
8109  [2893]=true,
8110  [2914]=true,
8111  [2915]=true,
8112  [3009]=true,
8113  [3010]=true,
8114  [3132]=true,
8115  [3170]=true,
8116  [3171]=true,
8117  [3260]=true,
8118  [3286]=true,
8119  [3298]=true,
8120  [3299]=true,
8121  [3426]=true,
8122  [3427]=true,
8123  [4143]=true,
8124  [4144]=true,
8125  [4151]=true,
8126  [4153]=true,
8127  [4157]=true,
8128  [4158]=true,
8129  [4184]=true,
8130  [4185]=true,
8131  [4190]=true,
8132  [4191]=true,
8133  [4192]=true,
8134  [4226]=true,
8135  [4237]=true,
8136 },
8137 ["consonant"]={
8138  [2325]=true,
8139  [2326]=true,
8140  [2327]=true,
8141  [2328]=true,
8142  [2329]=true,
8143  [2330]=true,
8144  [2331]=true,
8145  [2332]=true,
8146  [2333]=true,
8147  [2334]=true,
8148  [2335]=true,
8149  [2336]=true,
8150  [2337]=true,
8151  [2338]=true,
8152  [2339]=true,
8153  [2340]=true,
8154  [2341]=true,
8155  [2342]=true,
8156  [2343]=true,
8157  [2344]=true,
8158  [2345]=true,
8159  [2346]=true,
8160  [2347]=true,
8161  [2348]=true,
8162  [2349]=true,
8163  [2350]=true,
8164  [2351]=true,
8165  [2352]=true,
8166  [2353]=true,
8167  [2354]=true,
8168  [2355]=true,
8169  [2356]=true,
8170  [2357]=true,
8171  [2358]=true,
8172  [2359]=true,
8173  [2360]=true,
8174  [2361]=true,
8175  [2392]=true,
8176  [2393]=true,
8177  [2394]=true,
8178  [2395]=true,
8179  [2396]=true,
8180  [2397]=true,
8181  [2398]=true,
8182  [2399]=true,
8183  [2424]=true,
8184  [2425]=true,
8185  [2426]=true,
8186  [2453]=true,
8187  [2454]=true,
8188  [2455]=true,
8189  [2456]=true,
8190  [2457]=true,
8191  [2458]=true,
8192  [2459]=true,
8193  [2460]=true,
8194  [2461]=true,
8195  [2462]=true,
8196  [2463]=true,
8197  [2464]=true,
8198  [2465]=true,
8199  [2466]=true,
8200  [2467]=true,
8201  [2468]=true,
8202  [2469]=true,
8203  [2470]=true,
8204  [2471]=true,
8205  [2472]=true,
8206  [2474]=true,
8207  [2475]=true,
8208  [2476]=true,
8209  [2477]=true,
8210  [2478]=true,
8211  [2479]=true,
8212  [2480]=true,
8213  [2482]=true,
8214  [2486]=true,
8215  [2487]=true,
8216  [2488]=true,
8217  [2489]=true,
8218  [2510]=true,
8219  [2524]=true,
8220  [2525]=true,
8221  [2527]=true,
8222  [2581]=true,
8223  [2582]=true,
8224  [2583]=true,
8225  [2584]=true,
8226  [2585]=true,
8227  [2586]=true,
8228  [2587]=true,
8229  [2588]=true,
8230  [2589]=true,
8231  [2590]=true,
8232  [2591]=true,
8233  [2592]=true,
8234  [2593]=true,
8235  [2594]=true,
8236  [2595]=true,
8237  [2596]=true,
8238  [2597]=true,
8239  [2598]=true,
8240  [2599]=true,
8241  [2600]=true,
8242  [2602]=true,
8243  [2603]=true,
8244  [2604]=true,
8245  [2605]=true,
8246  [2606]=true,
8247  [2607]=true,
8248  [2608]=true,
8249  [2610]=true,
8250  [2611]=true,
8251  [2613]=true,
8252  [2614]=true,
8253  [2616]=true,
8254  [2617]=true,
8255  [2649]=true,
8256  [2650]=true,
8257  [2651]=true,
8258  [2652]=true,
8259  [2654]=true,
8260  [2709]=true,
8261  [2710]=true,
8262  [2711]=true,
8263  [2712]=true,
8264  [2713]=true,
8265  [2714]=true,
8266  [2715]=true,
8267  [2716]=true,
8268  [2717]=true,
8269  [2718]=true,
8270  [2719]=true,
8271  [2720]=true,
8272  [2721]=true,
8273  [2722]=true,
8274  [2723]=true,
8275  [2724]=true,
8276  [2725]=true,
8277  [2726]=true,
8278  [2727]=true,
8279  [2728]=true,
8280  [2730]=true,
8281  [2731]=true,
8282  [2732]=true,
8283  [2733]=true,
8284  [2734]=true,
8285  [2735]=true,
8286  [2736]=true,
8287  [2738]=true,
8288  [2739]=true,
8289  [2741]=true,
8290  [2742]=true,
8291  [2743]=true,
8292  [2744]=true,
8293  [2745]=true,
8294  [2837]=true,
8295  [2838]=true,
8296  [2839]=true,
8297  [2840]=true,
8298  [2841]=true,
8299  [2842]=true,
8300  [2843]=true,
8301  [2844]=true,
8302  [2845]=true,
8303  [2846]=true,
8304  [2847]=true,
8305  [2848]=true,
8306  [2849]=true,
8307  [2850]=true,
8308  [2851]=true,
8309  [2852]=true,
8310  [2853]=true,
8311  [2854]=true,
8312  [2855]=true,
8313  [2856]=true,
8314  [2858]=true,
8315  [2859]=true,
8316  [2860]=true,
8317  [2861]=true,
8318  [2862]=true,
8319  [2863]=true,
8320  [2864]=true,
8321  [2866]=true,
8322  [2867]=true,
8323  [2869]=true,
8324  [2870]=true,
8325  [2871]=true,
8326  [2872]=true,
8327  [2873]=true,
8328  [2908]=true,
8329  [2909]=true,
8330  [2929]=true,
8331  [2965]=true,
8332  [2969]=true,
8333  [2970]=true,
8334  [2972]=true,
8335  [2974]=true,
8336  [2975]=true,
8337  [2979]=true,
8338  [2980]=true,
8339  [2984]=true,
8340  [2985]=true,
8341  [2986]=true,
8342  [2990]=true,
8343  [2991]=true,
8344  [2992]=true,
8345  [2993]=true,
8346  [2994]=true,
8347  [2995]=true,
8348  [2996]=true,
8349  [2997]=true,
8350  [2998]=true,
8351  [2999]=true,
8352  [3000]=true,
8353  [3001]=true,
8354  [3093]=true,
8355  [3094]=true,
8356  [3095]=true,
8357  [3096]=true,
8358  [3097]=true,
8359  [3098]=true,
8360  [3099]=true,
8361  [3100]=true,
8362  [3101]=true,
8363  [3102]=true,
8364  [3103]=true,
8365  [3104]=true,
8366  [3105]=true,
8367  [3106]=true,
8368  [3107]=true,
8369  [3108]=true,
8370  [3109]=true,
8371  [3110]=true,
8372  [3111]=true,
8373  [3112]=true,
8374  [3114]=true,
8375  [3115]=true,
8376  [3116]=true,
8377  [3117]=true,
8378  [3118]=true,
8379  [3119]=true,
8380  [3120]=true,
8381  [3121]=true,
8382  [3122]=true,
8383  [3123]=true,
8384  [3124]=true,
8385  [3125]=true,
8386  [3126]=true,
8387  [3127]=true,
8388  [3128]=true,
8389  [3129]=true,
8390  [3133]=true,
8391  [3221]=true,
8392  [3222]=true,
8393  [3223]=true,
8394  [3224]=true,
8395  [3225]=true,
8396  [3226]=true,
8397  [3227]=true,
8398  [3228]=true,
8399  [3229]=true,
8400  [3230]=true,
8401  [3231]=true,
8402  [3232]=true,
8403  [3233]=true,
8404  [3234]=true,
8405  [3235]=true,
8406  [3236]=true,
8407  [3237]=true,
8408  [3238]=true,
8409  [3239]=true,
8410  [3240]=true,
8411  [3242]=true,
8412  [3243]=true,
8413  [3244]=true,
8414  [3245]=true,
8415  [3246]=true,
8416  [3247]=true,
8417  [3248]=true,
8418  [3249]=true,
8419  [3250]=true,
8420  [3251]=true,
8421  [3253]=true,
8422  [3254]=true,
8423  [3255]=true,
8424  [3256]=true,
8425  [3257]=true,
8426  [3294]=true,
8427  [3349]=true,
8428  [3350]=true,
8429  [3351]=true,
8430  [3352]=true,
8431  [3353]=true,
8432  [3354]=true,
8433  [3355]=true,
8434  [3356]=true,
8435  [3357]=true,
8436  [3358]=true,
8437  [3359]=true,
8438  [3360]=true,
8439  [3361]=true,
8440  [3362]=true,
8441  [3363]=true,
8442  [3364]=true,
8443  [3365]=true,
8444  [3366]=true,
8445  [3367]=true,
8446  [3368]=true,
8447  [3369]=true,
8448  [3370]=true,
8449  [3371]=true,
8450  [3372]=true,
8451  [3373]=true,
8452  [3374]=true,
8453  [3375]=true,
8454  [3376]=true,
8455  [3377]=true,
8456  [3378]=true,
8457  [3379]=true,
8458  [3380]=true,
8459  [3381]=true,
8460  [3382]=true,
8461  [3383]=true,
8462  [3384]=true,
8463  [3385]=true,
8464  [3386]=true,
8465  [4096]=true,
8466  [4097]=true,
8467  [4098]=true,
8468  [4099]=true,
8469  [4100]=true,
8470  [4101]=true,
8471  [4102]=true,
8472  [4103]=true,
8473  [4104]=true,
8474  [4105]=true,
8475  [4106]=true,
8476  [4107]=true,
8477  [4108]=true,
8478  [4109]=true,
8479  [4110]=true,
8480  [4111]=true,
8481  [4112]=true,
8482  [4113]=true,
8483  [4114]=true,
8484  [4115]=true,
8485  [4116]=true,
8486  [4117]=true,
8487  [4118]=true,
8488  [4119]=true,
8489  [4120]=true,
8490  [4121]=true,
8491  [4122]=true,
8492  [4123]=true,
8493  [4124]=true,
8494  [4125]=true,
8495  [4126]=true,
8496  [4127]=true,
8497  [4128]=true,
8498  [4155]=true,
8499  [4156]=true,
8500  [4157]=true,
8501  [4158]=true,
8502  [4159]=true,
8503  [4176]=true,
8504  [4177]=true,
8505  [4186]=true,
8506  [4187]=true,
8507  [4188]=true,
8508  [4189]=true,
8509  [4190]=true,
8510  [4191]=true,
8511  [4192]=true,
8512  [4193]=true,
8513  [4197]=true,
8514  [4198]=true,
8515  [4206]=true,
8516  [4207]=true,
8517  [4208]=true,
8518  [4213]=true,
8519  [4214]=true,
8520  [4215]=true,
8521  [4216]=true,
8522  [4217]=true,
8523  [4218]=true,
8524  [4219]=true,
8525  [4220]=true,
8526  [4221]=true,
8527  [4222]=true,
8528  [4223]=true,
8529  [4224]=true,
8530  [4225]=true,
8531  [4226]=true,
8532  [4238]=true,
8533  [5901]=true,
8534  [43488]=true,
8535  [43489]=true,
8536  [43490]=true,
8537  [43491]=true,
8538  [43492]=true,
8539  [43495]=true,
8540  [43496]=true,
8541  [43497]=true,
8542  [43498]=true,
8543  [43499]=true,
8544  [43500]=true,
8545  [43501]=true,
8546  [43502]=true,
8547  [43503]=true,
8548  [43514]=true,
8549  [43515]=true,
8550  [43516]=true,
8551  [43517]=true,
8552  [43518]=true,
8553  [43616]=true,
8554  [43617]=true,
8555  [43618]=true,
8556  [43619]=true,
8557  [43620]=true,
8558  [43621]=true,
8559  [43622]=true,
8560  [43623]=true,
8561  [43624]=true,
8562  [43625]=true,
8563  [43626]=true,
8564  [43628]=true,
8565  [43629]=true,
8566  [43630]=true,
8567  [43631]=true,
8568  [43633]=true,
8569  [43634]=true,
8570  [43635]=true,
8571  [43636]=true,
8572  [43637]=true,
8573  [43638]=true,
8574  [43642]=true,
8575  [43646]=true,
8576  [43647]=true,
8577 },
8578 ["dependent_vowel"]={
8579  [2362]=true,
8580  [2363]=true,
8581  [2366]=true,
8582  [2367]=true,
8583  [2368]=true,
8584  [2369]=true,
8585  [2370]=true,
8586  [2371]=true,
8587  [2372]=true,
8588  [2373]=true,
8589  [2374]=true,
8590  [2375]=true,
8591  [2376]=true,
8592  [2377]=true,
8593  [2378]=true,
8594  [2379]=true,
8595  [2380]=true,
8596  [2382]=true,
8597  [2383]=true,
8598  [2389]=true,
8599  [2390]=true,
8600  [2391]=true,
8601  [2402]=true,
8602  [2403]=true,
8603  [2494]=true,
8604  [2495]=true,
8605  [2497]=true,
8606  [2498]=true,
8607  [2499]=true,
8608  [2500]=true,
8609  [2503]=true,
8610  [2504]=true,
8611  [2507]=true,
8612  [2508]=true,
8613  [2622]=true,
8614  [2623]=true,
8615  [2624]=true,
8616  [2625]=true,
8617  [2626]=true,
8618  [2631]=true,
8619  [2632]=true,
8620  [2635]=true,
8621  [2636]=true,
8622  [2750]=true,
8623  [2751]=true,
8624  [2752]=true,
8625  [2753]=true,
8626  [2754]=true,
8627  [2755]=true,
8628  [2756]=true,
8629  [2757]=true,
8630  [2759]=true,
8631  [2760]=true,
8632  [2761]=true,
8633  [2763]=true,
8634  [2764]=true,
8635  [2878]=true,
8636  [2879]=true,
8637  [2880]=true,
8638  [2881]=true,
8639  [2882]=true,
8640  [2883]=true,
8641  [2884]=true,
8642  [2887]=true,
8643  [2888]=true,
8644  [2891]=true,
8645  [2892]=true,
8646  [2914]=true,
8647  [2915]=true,
8648  [3006]=true,
8649  [3007]=true,
8650  [3008]=true,
8651  [3009]=true,
8652  [3010]=true,
8653  [3014]=true,
8654  [3015]=true,
8655  [3016]=true,
8656  [3018]=true,
8657  [3019]=true,
8658  [3020]=true,
8659  [3134]=true,
8660  [3135]=true,
8661  [3136]=true,
8662  [3137]=true,
8663  [3138]=true,
8664  [3139]=true,
8665  [3140]=true,
8666  [3142]=true,
8667  [3143]=true,
8668  [3144]=true,
8669  [3146]=true,
8670  [3147]=true,
8671  [3148]=true,
8672  [3170]=true,
8673  [3171]=true,
8674  [3262]=true,
8675  [3263]=true,
8676  [3264]=true,
8677  [3265]=true,
8678  [3266]=true,
8679  [3267]=true,
8680  [3268]=true,
8681  [3270]=true,
8682  [3271]=true,
8683  [3272]=true,
8684  [3274]=true,
8685  [3275]=true,
8686  [3276]=true,
8687  [3285]=true,
8688  [3286]=true,
8689  [3298]=true,
8690  [3299]=true,
8691  [3390]=true,
8692  [3391]=true,
8693  [3392]=true,
8694  [3393]=true,
8695  [3394]=true,
8696  [3395]=true,
8697  [3396]=true,
8698  [3398]=true,
8699  [3399]=true,
8700  [3400]=true,
8701  [3402]=true,
8702  [3403]=true,
8703  [3404]=true,
8704  [3415]=true,
8705  [3426]=true,
8706  [3427]=true,
8707  [4139]=true,
8708  [4140]=true,
8709  [4141]=true,
8710  [4142]=true,
8711  [4143]=true,
8712  [4144]=true,
8713  [4145]=true,
8714  [4146]=true,
8715  [4147]=true,
8716  [4148]=true,
8717  [4149]=true,
8718  [4182]=true,
8719  [4183]=true,
8720  [4184]=true,
8721  [4185]=true,
8722  [4194]=true,
8723  [4199]=true,
8724  [4200]=true,
8725  [4209]=true,
8726  [4210]=true,
8727  [4211]=true,
8728  [4212]=true,
8729  [4227]=true,
8730  [4228]=true,
8731  [4229]=true,
8732  [4230]=true,
8733  [4252]=true,
8734  [4253]=true,
8735  [43493]=true,
8736 },
8737 ["halant"]={
8738  [2381]=true,
8739  [2509]=true,
8740  [2637]=true,
8741  [2765]=true,
8742  [2893]=true,
8743  [3021]=true,
8744  [3149]=true,
8745  [3277]=true,
8746  [3405]=true,
8747 },
8748 ["independent_vowel"]={
8749  [2308]=true,
8750  [2309]=true,
8751  [2310]=true,
8752  [2311]=true,
8753  [2312]=true,
8754  [2313]=true,
8755  [2314]=true,
8756  [2315]=true,
8757  [2316]=true,
8758  [2317]=true,
8759  [2318]=true,
8760  [2319]=true,
8761  [2320]=true,
8762  [2321]=true,
8763  [2322]=true,
8764  [2323]=true,
8765  [2324]=true,
8766  [2400]=true,
8767  [2401]=true,
8768  [2418]=true,
8769  [2419]=true,
8770  [2420]=true,
8771  [2421]=true,
8772  [2422]=true,
8773  [2423]=true,
8774  [2437]=true,
8775  [2438]=true,
8776  [2439]=true,
8777  [2440]=true,
8778  [2441]=true,
8779  [2442]=true,
8780  [2443]=true,
8781  [2444]=true,
8782  [2447]=true,
8783  [2448]=true,
8784  [2451]=true,
8785  [2452]=true,
8786  [2528]=true,
8787  [2529]=true,
8788  [2530]=true,
8789  [2531]=true,
8790  [2565]=true,
8791  [2566]=true,
8792  [2567]=true,
8793  [2568]=true,
8794  [2569]=true,
8795  [2570]=true,
8796  [2575]=true,
8797  [2576]=true,
8798  [2579]=true,
8799  [2580]=true,
8800  [2693]=true,
8801  [2694]=true,
8802  [2695]=true,
8803  [2696]=true,
8804  [2697]=true,
8805  [2698]=true,
8806  [2699]=true,
8807  [2700]=true,
8808  [2701]=true,
8809  [2703]=true,
8810  [2704]=true,
8811  [2705]=true,
8812  [2707]=true,
8813  [2708]=true,
8814  [2784]=true,
8815  [2785]=true,
8816  [2786]=true,
8817  [2787]=true,
8818  [2821]=true,
8819  [2822]=true,
8820  [2823]=true,
8821  [2824]=true,
8822  [2825]=true,
8823  [2826]=true,
8824  [2827]=true,
8825  [2828]=true,
8826  [2831]=true,
8827  [2832]=true,
8828  [2835]=true,
8829  [2836]=true,
8830  [2912]=true,
8831  [2913]=true,
8832  [2949]=true,
8833  [2950]=true,
8834  [2951]=true,
8835  [2952]=true,
8836  [2953]=true,
8837  [2954]=true,
8838  [2958]=true,
8839  [2959]=true,
8840  [2960]=true,
8841  [2962]=true,
8842  [2963]=true,
8843  [2964]=true,
8844  [3077]=true,
8845  [3078]=true,
8846  [3079]=true,
8847  [3080]=true,
8848  [3081]=true,
8849  [3082]=true,
8850  [3083]=true,
8851  [3084]=true,
8852  [3086]=true,
8853  [3087]=true,
8854  [3088]=true,
8855  [3090]=true,
8856  [3091]=true,
8857  [3092]=true,
8858  [3165]=true,
8859  [3168]=true,
8860  [3169]=true,
8861  [3205]=true,
8862  [3206]=true,
8863  [3207]=true,
8864  [3208]=true,
8865  [3209]=true,
8866  [3210]=true,
8867  [3211]=true,
8868  [3212]=true,
8869  [3214]=true,
8870  [3215]=true,
8871  [3216]=true,
8872  [3218]=true,
8873  [3219]=true,
8874  [3220]=true,
8875  [3293]=true,
8876  [3296]=true,
8877  [3297]=true,
8878  [3333]=true,
8879  [3334]=true,
8880  [3335]=true,
8881  [3336]=true,
8882  [3337]=true,
8883  [3338]=true,
8884  [3339]=true,
8885  [3340]=true,
8886  [3342]=true,
8887  [3343]=true,
8888  [3344]=true,
8889  [3346]=true,
8890  [3347]=true,
8891  [3348]=true,
8892  [3423]=true,
8893  [3424]=true,
8894  [3425]=true,
8895  [4129]=true,
8896  [4130]=true,
8897  [4131]=true,
8898  [4132]=true,
8899  [4133]=true,
8900  [4134]=true,
8901  [4135]=true,
8902  [4136]=true,
8903  [4137]=true,
8904  [4138]=true,
8905  [4178]=true,
8906  [4179]=true,
8907  [4180]=true,
8908  [4181]=true,
8909 },
8910 ["nukta"]={
8911  [2364]=true,
8912  [2492]=true,
8913  [2620]=true,
8914  [2748]=true,
8915  [2876]=true,
8916  [3132]=true,
8917  [3260]=true,
8918 },
8919 ["post_mark"]={
8920  [2307]=true,
8921  [2363]=true,
8922  [2366]=true,
8923  [2368]=true,
8924  [2377]=true,
8925  [2378]=true,
8926  [2379]=true,
8927  [2380]=true,
8928  [2383]=true,
8929  [2494]=true,
8930  [2496]=true,
8931  [2622]=true,
8932  [2624]=true,
8933  [2750]=true,
8934  [2752]=true,
8935  [2761]=true,
8936  [2763]=true,
8937  [2764]=true,
8938  [2878]=true,
8939  [2880]=true,
8940  [3006]=true,
8941  [3007]=true,
8942  [3137]=true,
8943  [3138]=true,
8944  [3139]=true,
8945  [3140]=true,
8946  [3262]=true,
8947  [3265]=true,
8948  [3266]=true,
8949  [3267]=true,
8950  [3268]=true,
8951  [3276]=true,
8952  [3285]=true,
8953  [3390]=true,
8954  [3391]=true,
8955  [3392]=true,
8956  [3393]=true,
8957  [3394]=true,
8958  [3395]=true,
8959  [3396]=true,
8960  [3415]=true,
8961  [4139]=true,
8962  [4140]=true,
8963  [4152]=true,
8964  [4155]=true,
8965  [4182]=true,
8966  [4183]=true,
8967  [4194]=true,
8968  [4195]=true,
8969  [4196]=true,
8970  [4199]=true,
8971  [4200]=true,
8972  [4201]=true,
8973  [4202]=true,
8974  [4203]=true,
8975  [4204]=true,
8976  [4205]=true,
8977  [4227]=true,
8978  [4231]=true,
8979  [4232]=true,
8980  [4233]=true,
8981  [4234]=true,
8982  [4235]=true,
8983  [4236]=true,
8984  [4239]=true,
8985  [4250]=true,
8986  [4251]=true,
8987  [4252]=true,
8988  [43643]=true,
8989  [43645]=true,
8990 },
8991 ["pre_mark"]={
8992  [2367]=true,
8993  [2382]=true,
8994  [2495]=true,
8995  [2503]=true,
8996  [2504]=true,
8997  [2623]=true,
8998  [2751]=true,
8999  [2887]=true,
9000  [3014]=true,
9001  [3015]=true,
9002  [3016]=true,
9003  [3398]=true,
9004  [3399]=true,
9005  [3400]=true,
9006  [4145]=true,
9007  [4228]=true,
9008 },
9009 ["ra"]={
9010  [2352]=true,
9011  [2480]=true,
9012  [2544]=true,
9013  [2608]=true,
9014  [2736]=true,
9015  [2864]=true,
9016  [2992]=true,
9017  [3120]=true,
9018  [3248]=true,
9019  [3376]=true,
9020  [5901]=true,
9021 },
9022 ["stress_tone_mark"]={
9023  [2385]=true,
9024  [2386]=true,
9025  [2387]=true,
9026  [2388]=true,
9027  [4151]=true,
9028  [4195]=true,
9029  [4196]=true,
9030  [4201]=true,
9031  [4202]=true,
9032  [4203]=true,
9033  [4204]=true,
9034  [4205]=true,
9035  [4231]=true,
9036  [4232]=true,
9037  [4233]=true,
9038  [4234]=true,
9039  [4235]=true,
9040  [4236]=true,
9041  [4237]=true,
9042  [4239]=true,
9043  [4250]=true,
9044  [4251]=true,
9045  [43643]=true,
9046  [43644]=true,
9047  [43645]=true,
9048 },
9049 ["twopart_mark"]={
9050  [2507]={ 2503,2494 },
9051  [2508]={ 2503,2519 },
9052  [2888]={ 2887,2902 },
9053  [2891]={ 2887,2878 },
9054  [2892]={ 2887,2903 },
9055  [3018]={ 3014,3006 },
9056  [3019]={ 3015,3006 },
9057  [3020]={ 3014,3031 },
9058  [3144]={ 3142,3158 },
9059  [3264]={ 3263,3285 },
9060  [3271]={ 3270,3285 },
9061  [3272]={ 3270,3286 },
9062  [3274]={ 3270,3266 },
9063  [3275]={ 3274,3285 },
9064  [3402]={ 3398,3390 },
9065  [3403]={ 3399,3390 },
9066  [3404]={ 3398,3415 },
9067 },
9068 ["vowel_modifier"]={
9069  [2304]=true,
9070  [2305]=true,
9071  [2306]=true,
9072  [2307]=true,
9073  [2433]=true,
9074  [3330]=true,
9075  [3331]=true,
9076  [4150]=true,
9077  [4152]=true,
9078  [4153]=true,
9079  [4154]=true,
9080  [43232]=true,
9081  [43233]=true,
9082  [43234]=true,
9083  [43235]=true,
9084  [43236]=true,
9085  [43237]=true,
9086  [43238]=true,
9087  [43239]=true,
9088  [43240]=true,
9089  [43241]=true,
9090  [43242]=true,
9091  [43243]=true,
9092  [43244]=true,
9093  [43245]=true,
9094  [43246]=true,
9095  [43247]=true,
9096  [43249]=true,
9097 },
9098}
9099
9100end -- closure
9101
9102do -- begin closure to overcome local limits and interference
9103
9104if not modules then modules={} end modules ['font-ini']={
9105 version=1.001,
9106 comment="companion to font-ini.mkiv",
9107 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
9108 copyright="PRAGMA ADE / ConTeXt Development Team",
9109 license="see context related readme files"
9110}
9111local allocate=utilities.storage.allocate
9112local sortedhash=table.sortedhash
9113fonts=fonts or {}
9114local fonts=fonts
9115local identifiers=allocate()
9116fonts.hashes=fonts.hashes  or { identifiers=identifiers }
9117fonts.tables=fonts.tables  or {}
9118fonts.helpers=fonts.helpers or {}
9119fonts.tracers=fonts.tracers or {} 
9120fonts.specifiers=fonts.specifiers or {} 
9121fonts.analyzers={} 
9122fonts.readers={}
9123fonts.definers={ methods={} }
9124fonts.loggers={ register=function() end }
9125if context then
9126
9127--removed
9128
9129end
9130fonts.privateoffsets={
9131 textbase=0xF0000,
9132 textextrabase=0xFD000,
9133 mathextrabase=0xFE000,
9134 mathbase=0xFF000,
9135 keepnames=false,
9136}
9137if node and not tex.getfontoffamily then
9138 tex.getfontoffamily=node.family_font 
9139end
9140
9141end -- closure
9142
9143do -- begin closure to overcome local limits and interference
9144
9145if not modules then modules={} end modules ['luatex-font-mis']={
9146 version=1.001,
9147 comment="companion to luatex-*.tex",
9148 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
9149 copyright="PRAGMA ADE / ConTeXt Development Team",
9150 license="see context related readme files"
9151}
9152if context then
9153--removed
9154
9155end
9156local currentfont=font.current
9157local hashes=fonts.hashes
9158local identifiers=hashes.identifiers or {}
9159local marks=hashes.marks    or {}
9160hashes.identifiers=identifiers
9161hashes.marks=marks
9162table.setmetatableindex(marks,function(t,k)
9163 if k==true then
9164  return marks[currentfont()]
9165 else
9166  local resources=identifiers[k].resources or {}
9167  local marks=resources.marks or {}
9168  t[k]=marks
9169  return marks
9170 end
9171end)
9172function font.each()
9173 return table.sortedhash(fonts.hashes.identifiers)
9174end
9175
9176end -- closure
9177
9178do -- begin closure to overcome local limits and interference
9179
9180if not modules then modules={} end modules ['font-con']={
9181 version=1.001,
9182 comment="companion to font-ini.mkiv",
9183 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
9184 copyright="PRAGMA ADE / ConTeXt Development Team",
9185 license="see context related readme files"
9186}
9187local next,tostring,tonumber,rawget=next,tostring,tonumber,rawget
9188local format,match,lower,gsub,find=string.format,string.match,string.lower,string.gsub,string.find
9189local sort,insert,concat=table.sort,table.insert,table.concat
9190local sortedkeys,sortedhash,serialize,fastcopy=table.sortedkeys,table.sortedhash,table.serialize,table.fastcopy
9191local derivetable=table.derive
9192local ioflush=io.flush
9193local round=math.round
9194local setmetatable,getmetatable,rawget,rawset=setmetatable,getmetatable,rawget,rawset
9195local trace_defining=false  trackers.register("fonts.defining",function(v) trace_defining=v end)
9196local trace_scaling=false  trackers.register("fonts.scaling",function(v) trace_scaling=v end)
9197local report_defining=logs.reporter("fonts","defining")
9198local fonts=fonts
9199local constructors=fonts.constructors or {}
9200fonts.constructors=constructors
9201local handlers=fonts.handlers or {} 
9202fonts.handlers=handlers
9203local allocate=utilities.storage.allocate
9204local setmetatableindex=table.setmetatableindex
9205constructors.dontembed=allocate()
9206constructors.namemode="fullpath" 
9207constructors.version=1.01
9208constructors.cache=containers.define("fonts","constructors",constructors.version,false)
9209constructors.privateoffset=fonts.privateoffsets.textbase or 0xF0000
9210constructors.cacheintex=true 
9211constructors.addtounicode=true
9212constructors.fixprotrusion=true
9213local designsizes=allocate()
9214constructors.designsizes=designsizes
9215local loadedfonts=allocate()
9216constructors.loadedfonts=loadedfonts
9217local factors={
9218 pt=65536.0,
9219 bp=65781.8,
9220}
9221function constructors.setfactor(f)
9222 constructors.factor=factors[f or 'pt'] or factors.pt
9223end
9224constructors.setfactor()
9225function constructors.scaled(scaledpoints,designsize) 
9226 if scaledpoints<0 then
9227  local factor=constructors.factor
9228  if designsize then
9229   if designsize>factor then 
9230    return (- scaledpoints/1000)*designsize 
9231   else
9232    return (- scaledpoints/1000)*designsize*factor
9233   end
9234  else
9235   return (- scaledpoints/1000)*10*factor
9236  end
9237 else
9238  return scaledpoints
9239 end
9240end
9241function constructors.getprivate(tfmdata)
9242 local properties=tfmdata.properties
9243 local private=properties.private
9244 properties.private=private+1
9245 return private
9246end
9247function constructors.setmathparameter(tfmdata,name,value)
9248 local m=tfmdata.mathparameters
9249 local c=tfmdata.MathConstants
9250 if m then
9251  m[name]=value
9252 end
9253 if c and c~=m then
9254  c[name]=value
9255 end
9256end
9257function constructors.getmathparameter(tfmdata,name)
9258 local p=tfmdata.mathparameters or tfmdata.MathConstants
9259 if p then
9260  return p[name]
9261 end
9262end
9263function constructors.cleanuptable(tfmdata)
9264end
9265function constructors.calculatescale(tfmdata,scaledpoints)
9266 local parameters=tfmdata.parameters
9267 if scaledpoints<0 then
9268  scaledpoints=(- scaledpoints/1000)*(tfmdata.designsize or parameters.designsize) 
9269 end
9270 return scaledpoints,scaledpoints/(parameters.units or 1000) 
9271end
9272local unscaled={
9273 ScriptPercentScaleDown=true,
9274 ScriptScriptPercentScaleDown=true,
9275 RadicalDegreeBottomRaisePercent=true,
9276 NoLimitSupFactor=true,
9277 NoLimitSubFactor=true,
9278}
9279function constructors.assignmathparameters(target,original)
9280 local mathparameters=original.mathparameters
9281 if mathparameters and next(mathparameters) then
9282  local targetparameters=target.parameters
9283  local targetproperties=target.properties
9284  local targetmathparameters={}
9285  local factor=targetproperties.math_is_scaled and 1 or targetparameters.factor
9286  for name,value in next,mathparameters do
9287   if unscaled[name] then
9288    targetmathparameters[name]=value
9289   else
9290    targetmathparameters[name]=value*factor
9291   end
9292  end
9293  if not targetmathparameters.FractionDelimiterSize then
9294   targetmathparameters.FractionDelimiterSize=1.01*targetparameters.size
9295  end
9296  if not mathparameters.FractionDelimiterDisplayStyleSize then
9297   targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size
9298  end
9299  if not targetmathparameters.SpaceBeforeScript then
9300   targetmathparameters.SpaceBeforeScript=targetmathparameters.SpaceAfterScript
9301  end
9302  target.mathparameters=targetmathparameters
9303 end
9304end
9305function constructors.beforecopyingcharacters(target,original)
9306end
9307function constructors.aftercopyingcharacters(target,original)
9308end
9309local nofinstances=0
9310local instances=setmetatableindex(function(t,k)
9311 nofinstances=nofinstances+1
9312 t[k]=nofinstances
9313 return nofinstances
9314end)
9315function constructors.trytosharefont(target,tfmdata)
9316 local properties=target.properties
9317 local instance=properties.instance
9318 if instance then
9319  local fullname=target.fullname
9320  local fontname=target.fontname
9321  local psname=target.psname
9322  local format=tfmdata.properties.format
9323  if format=="opentype" then
9324   target.streamprovider=1
9325  elseif format=="truetype" then
9326   target.streamprovider=2
9327  else
9328   target.streamprovider=0
9329  end
9330  if target.streamprovider>0 then
9331   if fullname then
9332    fullname=fullname..":"..instances[instance]
9333    target.fullname=fullname
9334   end
9335   if fontname then
9336    fontname=fontname..":"..instances[instance]
9337    target.fontname=fontname
9338   end
9339   if psname then
9340    psname=psname..":"..instances[instance]
9341    target.psname=psname
9342   end
9343  end
9344 end
9345end
9346local synonyms={
9347 exheight="x_height",
9348 xheight="x_height",
9349 ex="x_height",
9350 emwidth="quad",
9351 em="quad",
9352 spacestretch="space_stretch",
9353 stretch="space_stretch",
9354 spaceshrink="space_shrink",
9355 shrink="space_shrink",
9356 extraspace="extra_space",
9357 xspace="extra_space",
9358 slantperpoint="slant",
9359}
9360function constructors.enhanceparameters(parameters)
9361 local mt=getmetatable(parameters)
9362 local getter=function(t,k)
9363  if not k then
9364   return nil
9365  end
9366  local s=synonyms[k]
9367  if s then
9368   return rawget(t,s) or (mt and mt[s]) or nil
9369  end
9370  if k=="spacing" then
9371   return {
9372    width=t.space,
9373    stretch=t.space_stretch,
9374    shrink=t.space_shrink,
9375    extra=t.extra_space,
9376   }
9377  end
9378  return mt and mt[k] or nil
9379 end
9380 local setter=function(t,k,v)
9381  if not k then
9382   return 0
9383  end
9384  local s=synonyms[k]
9385  if s then
9386   rawset(t,s,v)
9387  elseif k=="spacing" then
9388   if type(v)=="table" then
9389    rawset(t,"space",v.width or 0)
9390    rawset(t,"space_stretch",v.stretch or 0)
9391    rawset(t,"space_shrink",v.shrink or 0)
9392    rawset(t,"extra_space",v.extra or 0)
9393   end
9394  else
9395   rawset(t,k,v)
9396  end
9397 end
9398 setmetatable(parameters,{
9399  __index=getter,
9400  __newindex=setter,
9401 })
9402end
9403local function mathkerns(v,vdelta)
9404 local k={}
9405 for i=1,#v do
9406  local entry=v[i]
9407  local height=entry.height
9408  local kern=entry.kern
9409  k[i]={
9410   height=height and vdelta*height or 0,
9411   kern=kern   and vdelta*kern   or 0,
9412  }
9413 end
9414 return k
9415end
9416local psfake=0
9417local function fixedpsname(psname,fallback)
9418 local usedname=psname
9419 if psname and psname~="" then
9420  if find(psname," ",1,true) then
9421   usedname=gsub(psname,"[%s]+","-")
9422  else
9423  end
9424 elseif not fallback or fallback=="" then
9425  psfake=psfake+1
9426  psname="fakename-"..psfake
9427 else
9428  psname=fallback
9429  usedname=gsub(psname,"[^a-zA-Z0-9]+","-")
9430 end
9431 return usedname,psname~=usedname
9432end
9433function constructors.scale(tfmdata,specification)
9434 local target={}
9435 if tonumber(specification) then
9436  specification={ size=specification }
9437 end
9438 target.specification=specification
9439 local scaledpoints=specification.size
9440 local relativeid=specification.relativeid
9441 local properties=tfmdata.properties  or {}
9442 local goodies=tfmdata.goodies  or {}
9443 local resources=tfmdata.resources   or {}
9444 local descriptions=tfmdata.descriptions   or {} 
9445 local characters=tfmdata.characters  or {} 
9446 local changed=tfmdata.changed  or {} 
9447 local shared=tfmdata.shared   or {}
9448 local parameters=tfmdata.parameters  or {}
9449 local mathparameters=tfmdata.mathparameters or {}
9450 local targetcharacters={}
9451 local targetdescriptions=derivetable(descriptions)
9452 local targetparameters=derivetable(parameters)
9453 local targetproperties=derivetable(properties)
9454 local targetgoodies=goodies      
9455 target.characters=targetcharacters
9456 target.descriptions=targetdescriptions
9457 target.parameters=targetparameters
9458 target.properties=targetproperties
9459 target.goodies=targetgoodies
9460 target.shared=shared
9461 target.resources=resources
9462 target.unscaled=tfmdata
9463 local mathsize=tonumber(specification.mathsize) or 0
9464 local textsize=tonumber(specification.textsize) or scaledpoints
9465 local extrafactor=tonumber(specification.factor  ) or 1
9466 targetparameters.mathsize=mathsize 
9467 targetparameters.textsize=textsize
9468 targetparameters.extrafactor=extrafactor
9469 local addtounicode=constructors.addtounicode
9470 local tounicode=fonts.mappings.tounicode
9471 local unknowncode=tounicode(0xFFFD)
9472 local defaultwidth=resources.defaultwidth  or 0
9473 local defaultheight=resources.defaultheight or 0
9474 local defaultdepth=resources.defaultdepth or 0
9475 local units=parameters.units or 1000
9476 targetproperties.language=properties.language or "dflt" 
9477 targetproperties.script=properties.script   or "dflt" 
9478 targetproperties.mode=properties.mode  or "base" 
9479 targetproperties.method=properties.method
9480 local askedscaledpoints=scaledpoints
9481 local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints,nil,specification)
9482 local hdelta=delta
9483 local vdelta=delta
9484 target.designsize=parameters.designsize 
9485 target.units=units
9486 target.units_per_em=units
9487 local direction=properties.direction or tfmdata.direction or 0 
9488 target.direction=direction
9489 properties.direction=direction
9490 target.size=scaledpoints
9491 target.encodingbytes=properties.encodingbytes or 1
9492 target.subfont=properties.subfont
9493 target.embedding=properties.embedding or "subset"
9494 target.tounicode=1
9495 target.cidinfo=properties.cidinfo
9496 target.format=properties.format
9497 target.cache=constructors.cacheintex and "yes" or "renew"
9498 local original=properties.original or tfmdata.original
9499 local fontname=properties.fontname or tfmdata.fontname
9500 local fullname=properties.fullname or tfmdata.fullname
9501 local filename=properties.filename or tfmdata.filename
9502 local psname=properties.psname   or tfmdata.psname
9503 local name=properties.name  or tfmdata.name
9504 local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename))
9505 target.original=original
9506 target.fontname=fontname
9507 target.fullname=fullname
9508 target.filename=filename
9509 target.psname=psname
9510 target.name=name
9511 properties.fontname=fontname
9512 properties.fullname=fullname
9513 properties.filename=filename
9514 properties.psname=psname
9515 properties.name=name
9516 local expansion=parameters.expansion
9517 if expansion then
9518  target.stretch=expansion.stretch
9519  target.shrink=expansion.shrink
9520  target.step=expansion.step
9521 end
9522 local slantfactor=parameters.slantfactor or 0
9523 if slantfactor~=0 then
9524  target.slant=slantfactor*1000
9525 else
9526  target.slant=0
9527 end
9528 local extendfactor=parameters.extendfactor or 0
9529 if extendfactor~=0 and extendfactor~=1 then
9530  hdelta=hdelta*extendfactor
9531  target.extend=extendfactor*1000
9532 else
9533  target.extend=1000 
9534 end
9535 local squeezefactor=parameters.squeezefactor or 0
9536 if squeezefactor~=0 and squeezefactor~=1 then
9537  vdelta=vdelta*squeezefactor
9538  target.squeeze=squeezefactor*1000
9539 else
9540  target.squeeze=1000 
9541 end
9542 local mode=parameters.mode or 0
9543 if mode~=0 then
9544  target.mode=mode
9545 end
9546 local width=parameters.width or 0
9547 if width~=0 then
9548  target.width=width*delta*1000/655360
9549 end
9550 targetparameters.factor=delta
9551 targetparameters.hfactor=hdelta
9552 targetparameters.vfactor=vdelta
9553 targetparameters.size=scaledpoints
9554 targetparameters.units=units
9555 targetparameters.scaledpoints=askedscaledpoints
9556 targetparameters.mode=mode
9557 targetparameters.width=width
9558 local isvirtual=properties.virtualized or tfmdata.type=="virtual"
9559 local hasquality=parameters.expansion or parameters.protrusion
9560 local hasitalics=properties.hasitalics
9561 local autoitalicamount=properties.autoitalicamount
9562 local stackmath=not properties.nostackmath
9563 local haskerns=properties.haskerns  or properties.mode=="base" 
9564 local hasligatures=properties.hasligatures or properties.mode=="base" 
9565 local writingmode=properties.writingmode or "horizontal"
9566 local identity=properties.identity or "horizontal"
9567 local vfonts=target.fonts
9568 if vfonts and #vfonts>0 then
9569  target.fonts=fastcopy(vfonts) 
9570 elseif isvirtual then
9571  target.fonts={ { id=0 } } 
9572 end
9573 if changed and not next(changed) then
9574  changed=false
9575 end
9576 target.type=isvirtual and "virtual" or "real"
9577 target.writingmode=writingmode=="vertical" and "vertical" or "horizontal"
9578 target.identity=identity=="vertical" and "vertical" or "horizontal"
9579 target.postprocessors=tfmdata.postprocessors
9580 local targetslant=(parameters.slant   or parameters[1] or 0)*factors.pt 
9581 local targetspace=(parameters.space   or parameters[2] or 0)*hdelta
9582 local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta
9583 local targetspace_shrink=(parameters.space_shrink  or parameters[4] or 0)*hdelta
9584 local targetx_height=(parameters.x_height   or parameters[5] or 0)*vdelta
9585 local targetquad=(parameters.quad    or parameters[6] or 0)*hdelta
9586 local targetextra_space=(parameters.extra_space   or parameters[7] or 0)*hdelta
9587 targetparameters.slant=targetslant 
9588 targetparameters.space=targetspace
9589 targetparameters.space_stretch=targetspace_stretch
9590 targetparameters.space_shrink=targetspace_shrink
9591 targetparameters.x_height=targetx_height
9592 targetparameters.quad=targetquad
9593 targetparameters.extra_space=targetextra_space
9594 local hshift=parameters.hshift
9595 if hshift then
9596  targetparameters.hshift=delta*hshift
9597 end
9598 local vshift=parameters.vshift
9599 if vshift then
9600  targetparameters.vshift=delta*vshift
9601 end
9602 local ascender=parameters.ascender
9603 if ascender then
9604  targetparameters.ascender=delta*ascender
9605 end
9606 local descender=parameters.descender
9607 if descender then
9608  targetparameters.descender=delta*descender
9609 end
9610 constructors.enhanceparameters(targetparameters)
9611 local protrusionfactor=constructors.fixprotrusion and ((targetquad~=0 and 1000/targetquad) or 1) or 1
9612 local scaledwidth=defaultwidth*hdelta
9613 local scaledheight=defaultheight*vdelta
9614 local scaleddepth=defaultdepth*vdelta
9615 local hasmath=(properties.hasmath or next(mathparameters)) and true
9616 if hasmath then
9617  constructors.assignmathparameters(target,tfmdata) 
9618  properties.hasmath=true
9619  target.nomath=false
9620  target.MathConstants=target.mathparameters
9621  local oldmath=properties.oldmath
9622  targetproperties.oldmath=oldmath
9623  target.oldmath=oldmath
9624 else
9625  properties.hasmath=false
9626  target.nomath=true
9627  target.mathparameters=nil 
9628 end
9629 if hasmath then
9630  local mathitalics=properties.mathitalics
9631  if mathitalics==false then
9632   if trace_defining then
9633    report_defining("%s italics %s for font %a, fullname %a, filename %a","math",hasitalics and "ignored" or "disabled",name,fullname,filename)
9634   end
9635   hasitalics=false
9636   autoitalicamount=false
9637  end
9638 else
9639  local textitalics=properties.textitalics
9640  if textitalics==false then
9641   if trace_defining then
9642    report_defining("%s italics %s for font %a, fullname %a, filename %a","text",hasitalics and "ignored" or "disabled",name,fullname,filename)
9643   end
9644   hasitalics=false
9645   autoitalicamount=false
9646  end
9647 end
9648 if trace_defining then
9649  report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a",
9650   name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta,
9651   hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled")
9652 end
9653 constructors.beforecopyingcharacters(target,tfmdata)
9654 local sharedkerns={}
9655 for unicode,character in next,characters do
9656  local chr,description,index
9657  if changed then
9658   local c=changed[unicode]
9659   if c and c~=unicode then
9660    local cc=changed[c]
9661    if cc then
9662     while cc do
9663      c=cc
9664      cc=changed[c]
9665     end
9666    end
9667    if c then
9668     description=descriptions[c] or descriptions[unicode] or character
9669     character=characters[c] or character
9670     index=description.index or c
9671    else
9672     description=descriptions[unicode] or character
9673     index=description.index or unicode
9674    end
9675   else
9676    description=descriptions[unicode] or character
9677    index=description.index or unicode
9678   end
9679  else
9680   description=descriptions[unicode] or character
9681   index=description.index or unicode
9682  end
9683  local width=description.width
9684  local height=description.height
9685  local depth=description.depth
9686  local isunicode=description.unicode
9687  if width  then width=hdelta*width  else width=scaledwidth  end
9688  if height then height=vdelta*height else height=scaledheight end
9689  if depth and depth~=0 then
9690   depth=delta*depth
9691   if isunicode then
9692    chr={
9693     index=index,
9694     height=height,
9695     depth=depth,
9696     width=width,
9697     unicode=isunicode,
9698    }
9699   else
9700    chr={
9701     index=index,
9702     height=height,
9703     depth=depth,
9704     width=width,
9705    }
9706   end
9707  else
9708   if isunicode then
9709    chr={
9710     index=index,
9711     height=height,
9712     width=width,
9713     unicode=isunicode,
9714    }
9715   else
9716    chr={
9717     index=index,
9718     height=height,
9719     width=width,
9720    }
9721   end
9722  end
9723  if addtounicode then
9724   chr.tounicode=isunicode and tounicode(isunicode) or unknowncode
9725  end
9726  if hasquality then
9727   local ve=character.expansion_factor
9728   if ve then
9729    chr.expansion_factor=ve*1000 
9730   end
9731   local vl=character.left_protruding
9732   if vl then
9733    chr.left_protruding=protrusionfactor*width*vl
9734   end
9735   local vr=character.right_protruding
9736   if vr then
9737    chr.right_protruding=protrusionfactor*width*vr
9738   end
9739  end
9740  if hasmath then
9741   local vn=character.next
9742   if vn then
9743    chr.next=vn
9744   else
9745    local vv=character.vert_variants
9746    if vv then
9747     local t={}
9748     for i=1,#vv do
9749      local vvi=vv[i]
9750      local s=vvi["start"]   or 0
9751      local e=vvi["end"]  or 0
9752      local a=vvi["advance"] or 0
9753      t[i]={ 
9754       ["start"]=s==0 and 0 or s*vdelta,
9755       ["end"]=e==0 and 0 or e*vdelta,
9756       ["advance"]=a==0 and 0 or a*vdelta,
9757       ["extender"]=vvi["extender"],
9758       ["glyph"]=vvi["glyph"],
9759      }
9760     end
9761     chr.vert_variants=t
9762    else
9763     local hv=character.horiz_variants
9764     if hv then
9765      local t={}
9766      for i=1,#hv do
9767       local hvi=hv[i]
9768       local s=hvi["start"]   or 0
9769       local e=hvi["end"]  or 0
9770       local a=hvi["advance"] or 0
9771       t[i]={ 
9772        ["start"]=s==0 and 0 or s*hdelta,
9773        ["end"]=e==0 and 0 or e*hdelta,
9774        ["advance"]=a==0 and 0 or a*hdelta,
9775        ["extender"]=hvi["extender"],
9776        ["glyph"]=hvi["glyph"],
9777       }
9778      end
9779      chr.horiz_variants=t
9780     end
9781    end
9782   end
9783   local vi=character.vert_italic
9784   if vi and vi~=0 then
9785    chr.vert_italic=vi*hdelta
9786   end
9787   local va=character.accent
9788   if va then
9789    chr.top_accent=vdelta*va
9790   end
9791   if stackmath then
9792    local mk=character.mathkerns
9793    if mk then
9794     local tr=mk.topright
9795     local tl=mk.topleft
9796     local br=mk.bottomright
9797     local bl=mk.bottomleft
9798     chr.mathkern={ 
9799      top_right=tr and mathkerns(tr,vdelta) or nil,
9800      top_left=tl and mathkerns(tl,vdelta) or nil,
9801      bottom_right=br and mathkerns(br,vdelta) or nil,
9802      bottom_left=bl and mathkerns(bl,vdelta) or nil,
9803     }
9804    end
9805   end
9806   if hasitalics then
9807    local vi=character.italic
9808    if vi and vi~=0 then
9809     chr.italic=vi*hdelta
9810    end
9811   end
9812  elseif autoitalicamount then 
9813   local vi=description.italic
9814   if not vi then
9815    local bb=description.boundingbox
9816    if bb then
9817     local vi=bb[3]-description.width+autoitalicamount
9818     if vi>0 then 
9819      chr.italic=vi*hdelta
9820     end
9821    else
9822    end
9823   elseif vi~=0 then
9824    chr.italic=vi*hdelta
9825   end
9826  elseif hasitalics then 
9827   local vi=character.italic
9828   if vi and vi~=0 then
9829    chr.italic=vi*hdelta
9830   end
9831  end
9832  if haskerns then
9833   local vk=character.kerns
9834   if vk then
9835    local s=sharedkerns[vk]
9836    if not s then
9837     s={}
9838     for k,v in next,vk do s[k]=v*hdelta end
9839     sharedkerns[vk]=s
9840    end
9841    chr.kerns=s
9842   end
9843  end
9844  if hasligatures then
9845   local vl=character.ligatures
9846   if vl then
9847    if true then
9848     chr.ligatures=vl 
9849    else
9850     local tt={}
9851     for i,l in next,vl do
9852      tt[i]=l
9853     end
9854     chr.ligatures=tt
9855    end
9856   end
9857  end
9858  if isvirtual then
9859   local vc=character.commands
9860   if vc then
9861    local ok=false
9862    for i=1,#vc do
9863     local key=vc[i][1]
9864     if key=="right" or key=="down" or key=="rule" then
9865      ok=true
9866      break
9867     end
9868    end
9869    if ok then
9870     local tt={}
9871     for i=1,#vc do
9872      local ivc=vc[i]
9873      local key=ivc[1]
9874      if key=="right" then
9875       tt[i]={ key,ivc[2]*hdelta }
9876      elseif key=="down" then
9877       tt[i]={ key,ivc[2]*vdelta }
9878      elseif key=="rule" then
9879       tt[i]={ key,ivc[2]*vdelta,ivc[3]*hdelta }
9880      else 
9881       tt[i]=ivc 
9882      end
9883     end
9884     chr.commands=tt
9885    else
9886     chr.commands=vc
9887    end
9888   end
9889  end
9890  targetcharacters[unicode]=chr
9891 end
9892 properties.setitalics=hasitalics
9893 constructors.aftercopyingcharacters(target,tfmdata)
9894 constructors.trytosharefont(target,tfmdata)
9895 local vfonts=target.fonts
9896 if isvirtual or target.type=="virtual" or properties.virtualized then
9897  properties.virtualized=true
9898  target.type="virtual"
9899  if not vfonts or #vfonts==0 then
9900   target.fonts={ { id=0 } }
9901  end
9902 elseif vfonts then
9903  properties.virtualized=true
9904  target.type="virtual"
9905  if #vfonts==0 then
9906   target.fonts={ { id=0 } }
9907  end
9908 end
9909 return target
9910end
9911function constructors.finalize(tfmdata)
9912 if tfmdata.properties and tfmdata.properties.finalized then
9913  return
9914 end
9915 if not tfmdata.characters then
9916  return nil
9917 end
9918 if not tfmdata.goodies then
9919  tfmdata.goodies={} 
9920 end
9921 local parameters=tfmdata.parameters
9922 if not parameters then
9923  return nil
9924 end
9925 if not parameters.expansion then
9926  parameters.expansion={
9927   stretch=tfmdata.stretch or 0,
9928   shrink=tfmdata.shrink  or 0,
9929   step=tfmdata.step or 0,
9930  }
9931 end
9932 if not parameters.size then
9933  parameters.size=tfmdata.size
9934 end
9935 if not parameters.mode then
9936  parameters.mode=0
9937 end
9938 if not parameters.width then
9939  parameters.width=0
9940 end
9941 if not parameters.slantfactor then
9942  parameters.slantfactor=(tfmdata.slant or 0)/1000
9943 end
9944 if not parameters.extendfactor then
9945  parameters.extendfactor=(tfmdata.extend or 1000)/1000
9946 end
9947 if not parameters.squeezefactor then
9948  parameters.squeezefactor=(tfmdata.squeeze or 1000)/1000
9949 end
9950 local designsize=parameters.designsize
9951 if designsize then
9952  parameters.minsize=tfmdata.minsize or designsize
9953  parameters.maxsize=tfmdata.maxsize or designsize
9954 else
9955  designsize=factors.pt*10
9956  parameters.designsize=designsize
9957  parameters.minsize=designsize
9958  parameters.maxsize=designsize
9959 end
9960 parameters.minsize=tfmdata.minsize or parameters.designsize
9961 parameters.maxsize=tfmdata.maxsize or parameters.designsize
9962 if not parameters.units then
9963  parameters.units=tfmdata.units or tfmdata.units_per_em or 1000
9964 end
9965 if not tfmdata.descriptions then
9966  local descriptions={} 
9967  setmetatableindex(descriptions,function(t,k) local v={} t[k]=v return v end)
9968  tfmdata.descriptions=descriptions
9969 end
9970 local properties=tfmdata.properties
9971 if not properties then
9972  properties={}
9973  tfmdata.properties=properties
9974 end
9975 if not properties.virtualized then
9976  properties.virtualized=tfmdata.type=="virtual"
9977 end
9978 properties.fontname=properties.fontname or tfmdata.fontname
9979 properties.filename=properties.filename or tfmdata.filename
9980 properties.fullname=properties.fullname or tfmdata.fullname
9981 properties.name=properties.name  or tfmdata.name
9982 properties.psname=properties.psname   or tfmdata.psname
9983 properties.encodingbytes=tfmdata.encodingbytes or 1
9984 properties.subfont=tfmdata.subfont    or nil
9985 properties.embedding=tfmdata.embedding  or "subset"
9986 properties.tounicode=tfmdata.tounicode  or 1
9987 properties.cidinfo=tfmdata.cidinfo    or nil
9988 properties.format=tfmdata.format  or "type1"
9989 properties.direction=tfmdata.direction  or 0
9990 properties.writingmode=tfmdata.writingmode   or "horizontal"
9991 properties.identity=tfmdata.identity   or "horizontal"
9992 properties.usedbitmap=tfmdata.usedbitmap
9993 if not tfmdata.resources then
9994  tfmdata.resources={}
9995 end
9996 if not tfmdata.shared then
9997  tfmdata.shared={}
9998 end
9999 if not properties.hasmath then
10000  properties.hasmath=not tfmdata.nomath
10001 end
10002 tfmdata.MathConstants=nil
10003 tfmdata.postprocessors=nil
10004 tfmdata.fontname=nil
10005 tfmdata.filename=nil
10006 tfmdata.fullname=nil
10007 tfmdata.name=nil 
10008 tfmdata.psname=nil
10009 tfmdata.encodingbytes=nil
10010 tfmdata.subfont=nil
10011 tfmdata.embedding=nil
10012 tfmdata.tounicode=nil
10013 tfmdata.cidinfo=nil
10014 tfmdata.format=nil
10015 tfmdata.direction=nil
10016 tfmdata.type=nil
10017 tfmdata.nomath=nil
10018 tfmdata.designsize=nil
10019 tfmdata.size=nil
10020 tfmdata.stretch=nil
10021 tfmdata.shrink=nil
10022 tfmdata.step=nil
10023 tfmdata.slant=nil
10024 tfmdata.extend=nil
10025 tfmdata.squeeze=nil
10026 tfmdata.mode=nil
10027 tfmdata.width=nil
10028 tfmdata.units=nil
10029 tfmdata.units_per_em=nil
10030 tfmdata.cache=nil
10031 properties.finalized=true
10032 return tfmdata
10033end
10034local hashmethods={}
10035constructors.hashmethods=hashmethods
10036function constructors.hashfeatures(specification) 
10037 local features=specification.features
10038 if features then
10039  local t,n={},0
10040  for category,list in sortedhash(features) do
10041   if next(list) then
10042    local hasher=hashmethods[category]
10043    if hasher then
10044     local hash=hasher(list)
10045     if hash then
10046      n=n+1
10047      t[n]=category..":"..hash
10048     end
10049    end
10050   end
10051  end
10052  if n>0 then
10053   return concat(t," & ")
10054  end
10055 end
10056 return "unknown"
10057end
10058hashmethods.normal=function(list)
10059 local s={}
10060 local n=0
10061 for k,v in next,list do
10062  if not k then
10063  elseif k=="number" or k=="features" then
10064  else
10065   n=n+1
10066   if type(v)=="table" then
10067    local t={}
10068    local m=0
10069    for k,v in next,v do
10070     m=m+1
10071     t[m]=k..'='..tostring(v)
10072    end
10073    sort(t)
10074    s[n]=k..'={'..concat(t,",").."}"
10075   else
10076    s[n]=k..'='..tostring(v)
10077   end
10078  end
10079 end
10080 if n>0 then
10081  sort(s)
10082  return concat(s,"+")
10083 end
10084end
10085function constructors.hashinstance(specification,force)
10086 local hash=specification.hash
10087 local size=specification.size
10088 local fallbacks=specification.fallbacks
10089 if force or not hash then
10090  hash=constructors.hashfeatures(specification)
10091  specification.hash=hash
10092 end
10093 if size<1000 and designsizes[hash] then
10094  size=round(constructors.scaled(size,designsizes[hash]))
10095 else
10096  size=round(size)
10097 end
10098 specification.size=size
10099 if fallbacks then
10100  return hash..' @ '..size..' @ '..fallbacks
10101 else
10102  return hash..' @ '..size
10103 end
10104end
10105function constructors.setname(tfmdata,specification) 
10106 if constructors.namemode=="specification" then
10107  local specname=specification.specification
10108  if specname then
10109   tfmdata.properties.name=specname
10110   if trace_defining then
10111    report_otf("overloaded fontname %a",specname)
10112   end
10113  end
10114 end
10115end
10116function constructors.checkedfilename(data)
10117 local foundfilename=data.foundfilename
10118 if not foundfilename then
10119  local askedfilename=data.filename or ""
10120  if askedfilename~="" then
10121   askedfilename=resolvers.resolve(askedfilename) 
10122   foundfilename=resolvers.findbinfile(askedfilename,"") or ""
10123   if foundfilename=="" then
10124    report_defining("source file %a is not found",askedfilename)
10125    foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or ""
10126    if foundfilename~="" then
10127     report_defining("using source file %a due to cache mismatch",foundfilename)
10128    end
10129   end
10130  end
10131  data.foundfilename=foundfilename
10132 end
10133 return foundfilename
10134end
10135local formats=allocate()
10136fonts.formats=formats
10137setmetatableindex(formats,function(t,k)
10138 local l=lower(k)
10139 if rawget(t,k) then
10140  t[k]=l
10141  return l
10142 end
10143 return rawget(t,file.suffix(l))
10144end)
10145do
10146 local function setindeed(mode,source,target,group,name,position)
10147  local action=source[mode]
10148  if not action then
10149   return
10150  end
10151  local t=target[mode]
10152  if not t then
10153   report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
10154   os.exit()
10155  elseif position then
10156   insert(t,position,{ name=name,action=action })
10157  else
10158   for i=1,#t do
10159    local ti=t[i]
10160    if ti.name==name then
10161     ti.action=action
10162     return
10163    end
10164   end
10165   insert(t,{ name=name,action=action })
10166  end
10167 end
10168 local function set(group,name,target,source)
10169  target=target[group]
10170  if not target then
10171   report_defining("fatal target error in setting feature %a, group %a",name,group)
10172   os.exit()
10173  end
10174  local source=source[group]
10175  if not source then
10176   report_defining("fatal source error in setting feature %a, group %a",name,group)
10177   os.exit()
10178  end
10179  local position=source.position
10180  setindeed("node",source,target,group,name,position)
10181  setindeed("base",source,target,group,name,position)
10182  setindeed("plug",source,target,group,name,position)
10183 end
10184 local function register(where,specification)
10185  local name=specification.name
10186  if name and name~="" then
10187   local default=specification.default
10188   local description=specification.description
10189   local initializers=specification.initializers
10190   local processors=specification.processors
10191   local manipulators=specification.manipulators
10192   local modechecker=specification.modechecker
10193   if default then
10194    where.defaults[name]=default
10195   end
10196   if description and description~="" then
10197    where.descriptions[name]=description
10198   end
10199   if initializers then
10200    set('initializers',name,where,specification)
10201   end
10202   if processors then
10203    set('processors',name,where,specification)
10204   end
10205   if manipulators then
10206    set('manipulators',name,where,specification)
10207   end
10208   if modechecker then
10209      where.modechecker=modechecker
10210   end
10211  end
10212 end
10213 constructors.registerfeature=register
10214 function constructors.getfeatureaction(what,where,mode,name)
10215  what=handlers[what].features
10216  if what then
10217   where=what[where]
10218   if where then
10219    mode=where[mode]
10220    if mode then
10221     for i=1,#mode do
10222      local m=mode[i]
10223      if m.name==name then
10224       return m.action
10225      end
10226     end
10227    end
10228   end
10229  end
10230 end
10231 local newfeatures={}
10232 constructors.newfeatures=newfeatures 
10233 constructors.features=newfeatures
10234 local function setnewfeatures(what)
10235  local handler=handlers[what]
10236  local features=handler.features
10237  if not features then
10238   local tables=handler.tables  
10239   local statistics=handler.statistics 
10240   features=allocate {
10241    defaults={},
10242    descriptions=tables and tables.features or {},
10243    used=statistics and statistics.usedfeatures or {},
10244    initializers={ base={},node={},plug={} },
10245    processors={ base={},node={},plug={} },
10246    manipulators={ base={},node={},plug={} },
10247   }
10248   features.register=function(specification) return register(features,specification) end
10249   handler.features=features 
10250  end
10251  return features
10252 end
10253 setmetatable(newfeatures,{
10254  __call=function(t,k) local v=t[k] return v end,
10255  __index=function(t,k) local v=setnewfeatures(k) t[k]=v return v end,
10256 })
10257end
10258do
10259 local newhandler={}
10260 constructors.handlers=newhandler 
10261 constructors.newhandler=newhandler
10262 local function setnewhandler(what) 
10263  local handler=handlers[what]
10264  if not handler then
10265   handler={}
10266   handlers[what]=handler
10267  end
10268  return handler
10269 end
10270 setmetatable(newhandler,{
10271  __call=function(t,k) local v=t[k] return v end,
10272  __index=function(t,k) local v=setnewhandler(k) t[k]=v return v end,
10273 })
10274end
10275do
10276 local newenhancer={}
10277 constructors.enhancers=newenhancer
10278 constructors.newenhancer=newenhancer
10279 local function setnewenhancer(format)
10280  local handler=handlers[format]
10281  local enhancers=handler.enhancers
10282  if not enhancers then
10283   local actions=allocate() 
10284   local before=allocate()
10285   local after=allocate()
10286   local order=allocate()
10287   local known={}
10288   local nofsteps=0
10289   local patches={ before=before,after=after }
10290   local trace=false
10291   local report=logs.reporter("fonts",format.." enhancing")
10292   trackers.register(format..".loading",function(v) trace=v end)
10293   local function enhance(name,data,filename,raw)
10294    local enhancer=actions[name]
10295    if enhancer then
10296     if trace then
10297      report("apply enhancement %a to file %a",name,filename)
10298      ioflush()
10299     end
10300     enhancer(data,filename,raw)
10301    else
10302    end
10303   end
10304   local function apply(data,filename,raw)
10305    local basename=file.basename(lower(filename))
10306    if trace then
10307     report("%s enhancing file %a","start",filename)
10308    end
10309    ioflush() 
10310    for e=1,nofsteps do
10311     local enhancer=order[e]
10312     local b=before[enhancer]
10313     if b then
10314      for pattern,action in next,b do
10315       if find(basename,pattern) then
10316        action(data,filename,raw)
10317       end
10318      end
10319     end
10320     enhance(enhancer,data,filename,raw) 
10321     local a=after[enhancer]
10322     if a then
10323      for pattern,action in next,a do
10324       if find(basename,pattern) then
10325        action(data,filename,raw)
10326       end
10327      end
10328     end
10329     ioflush() 
10330    end
10331    if trace then
10332     report("%s enhancing file %a","stop",filename)
10333    end
10334    ioflush() 
10335   end
10336   local function register(what,action)
10337    if action then
10338     if actions[what] then
10339     else
10340      nofsteps=nofsteps+1
10341      order[nofsteps]=what
10342      known[what]=nofsteps
10343     end
10344     actions[what]=action
10345    else
10346     report("bad enhancer %a",what)
10347    end
10348   end
10349   local function patch(what,where,pattern,action)
10350    local pw=patches[what]
10351    if pw then
10352     local ww=pw[where]
10353     if ww then
10354      ww[pattern]=action
10355     else
10356      pw[where]={ [pattern]=action }
10357      if not known[where] then
10358       nofsteps=nofsteps+1
10359       order[nofsteps]=where
10360       known[where]=nofsteps
10361      end
10362     end
10363    end
10364   end
10365   enhancers={
10366    register=register,
10367    apply=apply,
10368    patch=patch,
10369    report=report,
10370    patches={
10371     register=patch,
10372     report=report,
10373    },
10374   }
10375   handler.enhancers=enhancers
10376  end
10377  return enhancers
10378 end
10379 setmetatable(newenhancer,{
10380  __call=function(t,k) local v=t[k] return v end,
10381  __index=function(t,k) local v=setnewenhancer(k) t[k]=v return v end,
10382 })
10383end
10384function constructors.checkedfeatures(what,features)
10385 local defaults=handlers[what].features.defaults
10386 if features and next(features) then
10387  features=fastcopy(features) 
10388  for key,value in next,defaults do
10389   if features[key]==nil then
10390    features[key]=value
10391   end
10392  end
10393  return features
10394 else
10395  return fastcopy(defaults) 
10396 end
10397end
10398function constructors.initializefeatures(what,tfmdata,features,trace,report)
10399 if features and next(features) then
10400  local properties=tfmdata.properties or {} 
10401  local whathandler=handlers[what]
10402  local whatfeatures=whathandler.features
10403  local whatmodechecker=whatfeatures.modechecker
10404  local mode=properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base"
10405  properties.mode=mode 
10406  features.mode=mode
10407  local done={}
10408  while true do
10409   local redo=false
10410   local initializers=whatfeatures.initializers[mode]
10411   if initializers then
10412    for i=1,#initializers do
10413     local step=initializers[i]
10414     local feature=step.name
10415     local value=features[feature]
10416     if not value then
10417     elseif done[feature] then
10418     else
10419      local action=step.action
10420      if trace then
10421       report("initializing feature %a to %a for mode %a for font %a",feature,
10422        value,mode,tfmdata.properties.fullname)
10423      end
10424      action(tfmdata,value,features) 
10425      if mode~=properties.mode or mode~=features.mode then
10426       if whatmodechecker then
10427        properties.mode=whatmodechecker(tfmdata,features,properties.mode) 
10428        features.mode=properties.mode
10429       end
10430       if mode~=properties.mode then
10431        mode=properties.mode
10432        redo=true
10433       end
10434      end
10435      done[feature]=true
10436     end
10437     if redo then
10438      break
10439     end
10440    end
10441    if not redo then
10442     break
10443    end
10444   else
10445    break
10446   end
10447  end
10448  properties.mode=mode 
10449  return true
10450 else
10451  return false
10452 end
10453end
10454function constructors.collectprocessors(what,tfmdata,features,trace,report)
10455 local processes={}
10456 local nofprocesses=0
10457 if features and next(features) then
10458  local properties=tfmdata.properties
10459  local whathandler=handlers[what]
10460  local whatfeatures=whathandler.features
10461  local whatprocessors=whatfeatures.processors
10462  local mode=properties.mode
10463  local processors=whatprocessors[mode]
10464  if processors then
10465   for i=1,#processors do
10466    local step=processors[i]
10467    local feature=step.name
10468    if features[feature] then
10469     local action=step.action
10470     if trace then
10471      report("installing feature processor %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname)
10472     end
10473     if action then
10474      nofprocesses=nofprocesses+1
10475      processes[nofprocesses]=action
10476     end
10477    end
10478   end
10479  elseif trace then
10480   report("no feature processors for mode %a for font %a",mode,properties.fullname)
10481  end
10482 end
10483 return processes
10484end
10485function constructors.applymanipulators(what,tfmdata,features,trace,report)
10486 if features and next(features) then
10487  local properties=tfmdata.properties
10488  local whathandler=handlers[what]
10489  local whatfeatures=whathandler.features
10490  local whatmanipulators=whatfeatures.manipulators
10491  local mode=properties.mode
10492  local manipulators=whatmanipulators[mode]
10493  if manipulators then
10494   for i=1,#manipulators do
10495    local step=manipulators[i]
10496    local feature=step.name
10497    local value=features[feature]
10498    if value then
10499     local action=step.action
10500     if trace then
10501      report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname)
10502     end
10503     if action then
10504      action(tfmdata,feature,value)
10505     end
10506    end
10507   end
10508  end
10509 end
10510end
10511function constructors.addcoreunicodes(unicodes) 
10512 if not unicodes then
10513  unicodes={}
10514 end
10515 unicodes.space=0x0020
10516 unicodes.hyphen=0x002D
10517 unicodes.zwj=0x200D
10518 unicodes.zwnj=0x200C
10519 return unicodes
10520end
10521
10522end -- closure
10523
10524do -- begin closure to overcome local limits and interference
10525
10526if not modules then modules={} end modules ['luatex-font-enc']={
10527 version=1.001,
10528 comment="companion to luatex-*.tex",
10529 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
10530 copyright="PRAGMA ADE / ConTeXt Development Team",
10531 license="see context related readme files"
10532}
10533if context then
10534--removed
10535
10536end
10537local fonts=fonts
10538local encodings={}
10539fonts.encodings=encodings
10540encodings.agl={}
10541encodings.known={}
10542encodings.glyphlistfilename="font-age.lua"
10543setmetatable(encodings.agl,{ __index=function(t,k)
10544 if k=="unicodes" then
10545  logs.report("fonts","loading (extended) adobe glyph list")
10546  local foundname=resolvers.findfile(encodings.glyphlistfilename) or ""
10547  local unicodes=foundname~="" and dofile(foundname)
10548  if type(unicodes)~="table" then
10549   logs.report("fonts","missing or invalid (extended) adobe glyph list")
10550   unicodes={}
10551  end
10552  encodings.agl={ unicodes=unicodes }
10553  return unicodes
10554 else
10555  return nil
10556 end
10557end })
10558encodings.cache=containers.define("fonts","enc",encodings.version,true)
10559function encodings.load(filename)
10560 local name=file.removesuffix(filename)
10561 local data=containers.read(encodings.cache,name)
10562 if data then
10563  return data
10564 end
10565 local vector,tag,hash,unicodes={},"",{},{}
10566 local foundname=resolvers.findfile(filename,'enc')
10567 if foundname and foundname~="" then
10568  local ok,encoding,size=resolvers.loadbinfile(foundname)
10569  if ok and encoding then
10570   encoding=string.gsub(encoding,"%%(.-)\n","")
10571   local unicoding=encodings.agl.unicodes
10572   local tag,vec=string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def")
10573   local i=0
10574   for ch in string.gmatch(vec,"/([%a%d%.]+)") do
10575    if ch~=".notdef" then
10576     vector[i]=ch
10577     if not hash[ch] then
10578      hash[ch]=i
10579     else
10580     end
10581     local u=unicoding[ch]
10582     if u then
10583      unicodes[u]=i
10584     end
10585    end
10586    i=i+1
10587   end
10588  end
10589 end
10590 local data={
10591  name=name,
10592  tag=tag,
10593  vector=vector,
10594  hash=hash,
10595  unicodes=unicodes
10596 }
10597 return containers.write(encodings.cache,name,data)
10598end
10599
10600end -- closure
10601
10602do -- begin closure to overcome local limits and interference
10603
10604if not modules then modules={} end modules ['font-cid']={
10605 version=1.001,
10606 comment="companion to font-ini.mkiv",
10607 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
10608 copyright="PRAGMA ADE / ConTeXt Development Team",
10609 license="see context related readme files"
10610}
10611local format,match,lower=string.format,string.match,string.lower
10612local tonumber=tonumber
10613local P,S,R,C,V,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.match
10614local fonts,logs,trackers=fonts,logs,trackers
10615local trace_loading=false  trackers.register("otf.loading",function(v) trace_loading=v end)
10616local report_otf=logs.reporter("fonts","otf loading")
10617local cid={}
10618fonts.cid=cid
10619local cidmap={}
10620local cidmax=10
10621local number=C(R("09","af","AF")^1)
10622local space=S(" \n\r\t")
10623local spaces=space^0
10624local period=P(".")
10625local periods=period*period
10626local name=P("/")*C((1-space)^1)
10627local unicodes,names={},{} 
10628local function do_one(a,b)
10629 unicodes[tonumber(a)]=tonumber(b,16)
10630end
10631local function do_range(a,b,c)
10632 c=tonumber(c,16)
10633 for i=tonumber(a),tonumber(b) do
10634  unicodes[i]=c
10635  c=c+1
10636 end
10637end
10638local function do_name(a,b)
10639 names[tonumber(a)]=b
10640end
10641local grammar=P { "start",
10642 start=number*spaces*number*V("series"),
10643 series=(spaces*(V("one")+V("range")+V("named")))^1,
10644 one=(number*spaces*number)/do_one,
10645 range=(number*periods*number*spaces*number)/do_range,
10646 named=(number*spaces*name)/do_name
10647}
10648local function loadcidfile(filename)
10649 local data=io.loaddata(filename)
10650 if data then
10651  unicodes,names={},{}
10652  lpegmatch(grammar,data)
10653  local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$")
10654  return {
10655   supplement=supplement,
10656   registry=registry,
10657   ordering=ordering,
10658   filename=filename,
10659   unicodes=unicodes,
10660   names=names,
10661  }
10662 end
10663end
10664cid.loadfile=loadcidfile 
10665local template="%s-%s-%s.cidmap"
10666local function locate(registry,ordering,supplement)
10667 local filename=format(template,registry,ordering,supplement)
10668 local hashname=lower(filename)
10669 local found=cidmap[hashname]
10670 if not found then
10671  if trace_loading then
10672   report_otf("checking cidmap, registry %a, ordering %a, supplement %a, filename %a",registry,ordering,supplement,filename)
10673  end
10674  local fullname=resolvers.findfile(filename,'cid') or ""
10675  if fullname~="" then
10676   found=loadcidfile(fullname)
10677   if found then
10678    if trace_loading then
10679     report_otf("using cidmap file %a",filename)
10680    end
10681    cidmap[hashname]=found
10682    found.usedname=file.basename(filename)
10683   end
10684  end
10685 end
10686 return found
10687end
10688function cid.getmap(specification)
10689 if not specification then
10690  report_otf("invalid cidinfo specification, table expected")
10691  return
10692 end
10693 local registry=specification.registry
10694 local ordering=specification.ordering
10695 local supplement=specification.supplement
10696 local filename=format(registry,ordering,supplement)
10697 local lowername=lower(filename)
10698 local found=cidmap[lowername]
10699 if found then
10700  return found
10701 end
10702 if ordering=="Identity" then
10703  local found={
10704   supplement=supplement,
10705   registry=registry,
10706   ordering=ordering,
10707   filename=filename,
10708   unicodes={},
10709   names={},
10710  }
10711  cidmap[lowername]=found
10712  return found
10713 end
10714 if trace_loading then
10715  report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement)
10716 end
10717 found=locate(registry,ordering,supplement)
10718 if not found then
10719  local supnum=tonumber(supplement)
10720  local cidnum=nil
10721  if supnum<cidmax then
10722   for s=supnum+1,cidmax do
10723    local c=locate(registry,ordering,s)
10724    if c then
10725     found,cidnum=c,s
10726     break
10727    end
10728   end
10729  end
10730  if not found and supnum>0 then
10731   for s=supnum-1,0,-1 do
10732    local c=locate(registry,ordering,s)
10733    if c then
10734     found,cidnum=c,s
10735     break
10736    end
10737   end
10738  end
10739  registry=lower(registry)
10740  ordering=lower(ordering)
10741  if found and cidnum>0 then
10742   for s=0,cidnum-1 do
10743    local filename=format(template,registry,ordering,s)
10744    if not cidmap[filename] then
10745     cidmap[filename]=found
10746    end
10747   end
10748  end
10749 end
10750 return found
10751end
10752
10753end -- closure
10754
10755do -- begin closure to overcome local limits and interference
10756
10757if not modules then modules={} end modules ['font-map']={
10758 version=1.001,
10759 optimize=true,
10760 comment="companion to font-ini.mkiv",
10761 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
10762 copyright="PRAGMA ADE / ConTeXt Development Team",
10763 license="see context related readme files"
10764}
10765local tonumber,next,type=tonumber,next,type
10766local match,format,find,concat,gsub,lower=string.match,string.format,string.find,table.concat,string.gsub,string.lower
10767local P,R,S,C,Ct,Cc,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.match
10768local formatters=string.formatters
10769local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
10770local idiv=number.idiv
10771local trace_loading=false  trackers.register("fonts.loading",function(v) trace_loading=v end)
10772local trace_mapping=false  trackers.register("fonts.mapping",function(v) trace_mapping=v end)
10773local report_fonts=logs.reporter("fonts","loading")
10774local force_ligatures=false  directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end)
10775local fonts=fonts or {}
10776local mappings=fonts.mappings or {}
10777fonts.mappings=mappings
10778local allocate=utilities.storage.allocate
10779local hex=R("AF","af","09")
10780local hexfour=(hex*hex*hex^-2)/function(s) return tonumber(s,16) end
10781local hexsix=(hex*hex*hex^-4)/function(s) return tonumber(s,16) end
10782local dec=(R("09")^1)/tonumber
10783local period=P(".")
10784local unicode=(P("uni")+P("UNI"))*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true)) 
10785local ucode=(P("u")+P("U")  )*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true)) 
10786local index=P("index")*dec*Cc(false)
10787local parser=unicode+ucode+index
10788local parsers={}
10789local function makenameparser(str)
10790 if not str or str=="" then
10791  return parser
10792 else
10793  local p=parsers[str]
10794  if not p then
10795   p=P(str)*period*dec*Cc(false)
10796   parsers[str]=p
10797  end
10798  return p
10799 end
10800end
10801local f_single=formatters["%04X"]
10802local f_double=formatters["%04X%04X"]
10803local s_unknown="FFFD"
10804local function tounicode16(unicode)
10805 if unicode<0xD7FF or (unicode>0xDFFF and unicode<=0xFFFF) then
10806  return f_single(unicode)
10807 elseif unicode>=0x00E000 and unicode<=0x00F8FF then
10808  return s_unknown
10809 elseif unicode>=0x0F0000 and unicode<=0x0FFFFF then
10810  return s_unknown
10811 elseif unicode>=0x100000 and unicode<=0x10FFFF then
10812  return s_unknown
10813 elseif unicode>=0x00D800 and unicode<=0x00DFFF then
10814  return s_unknown
10815 else
10816  unicode=unicode-0x10000
10817  return f_double(idiv(unicode,0x400)+0xD800,unicode%0x400+0xDC00)
10818 end
10819end
10820local function tounicode16sequence(unicodes)
10821 local t={}
10822 for l=1,#unicodes do
10823  local u=unicodes[l]
10824  if u<0xD7FF or (u>0xDFFF and u<=0xFFFF) then
10825   t[l]=f_single(u)
10826  elseif unicode>=0x00E000 and unicode<=0x00F8FF then
10827   t[l]=s_unknown
10828  elseif unicode>=0x0F0000 and unicode<=0x0FFFFF then
10829   t[l]=s_unknown
10830  elseif unicode>=0x100000 and unicode<=0x10FFFF then
10831   t[l]=s_unknown
10832  elseif unicode>=0x00D7FF and unicode<=0x00DFFF then
10833   t[l]=s_unknown
10834  else
10835   u=u-0x10000
10836   t[l]=f_double(idiv(u,0x400)+0xD800,u%0x400+0xDC00)
10837  end
10838 end
10839 return concat(t)
10840end
10841local hash={}
10842local conc={}
10843table.setmetatableindex(hash,function(t,k)
10844 local v
10845 if k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then
10846  v=f_single(k)
10847 else
10848  local k=k-0x10000
10849  v=f_double(idiv(k,0x400)+0xD800,k%0x400+0xDC00)
10850 end
10851 t[k]=v
10852 return v
10853end)
10854local function tounicode(k)
10855 if type(k)=="table" then
10856  local n=#k
10857  for l=1,n do
10858   conc[l]=hash[k[l]]
10859  end
10860  return concat(conc,"",1,n)
10861 elseif k>=0x00E000 and k<=0x00F8FF then
10862  return s_unknown
10863 elseif k>=0x0F0000 and k<=0x0FFFFF then
10864  return s_unknown
10865 elseif k>=0x100000 and k<=0x10FFFF then
10866  return s_unknown
10867 elseif k>=0x00D7FF and k<=0x00DFFF then
10868  return s_unknown
10869 else
10870  return hash[k]
10871 end
10872end
10873local function fromunicode16(str)
10874 if #str==4 then
10875  return tonumber(str,16)
10876 else
10877  local l,r=match(str,"(....)(....)")
10878  return 0x10000+(tonumber(l,16)-0xD800)*0x400+tonumber(r,16)-0xDC00
10879 end
10880end
10881mappings.makenameparser=makenameparser
10882mappings.tounicode=tounicode
10883mappings.tounicode16=tounicode16
10884mappings.tounicode16sequence=tounicode16sequence
10885mappings.fromunicode16=fromunicode16
10886local ligseparator=P("_")
10887local varseparator=P(".")
10888local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0)
10889do
10890 local overloads={
10891  IJ={ name="I_J",unicode={ 0x49,0x4A },mess=0x0132 },
10892  ij={ name="i_j",unicode={ 0x69,0x6A },mess=0x0133 },
10893  ff={ name="f_f",unicode={ 0x66,0x66 },mess=0xFB00 },
10894  fi={ name="f_i",unicode={ 0x66,0x69 },mess=0xFB01 },
10895  fl={ name="f_l",unicode={ 0x66,0x6C },mess=0xFB02 },
10896  ffi={ name="f_f_i",unicode={ 0x66,0x66,0x69 },mess=0xFB03 },
10897  ffl={ name="f_f_l",unicode={ 0x66,0x66,0x6C },mess=0xFB04 },
10898  fj={ name="f_j",unicode={ 0x66,0x6A } },
10899  fk={ name="f_k",unicode={ 0x66,0x6B } },
10900 }
10901 local o=allocate {}
10902 for k,v in next,overloads do
10903  local name=v.name
10904  local mess=v.mess
10905  if name then
10906   o[name]=v
10907  end
10908  if mess then
10909   o[mess]=v
10910  end
10911  o[k]=v
10912 end
10913 mappings.overloads=o
10914end
10915function mappings.addtounicode(data,filename,checklookups,forceligatures)
10916 local resources=data.resources
10917 local unicodes=resources.unicodes
10918 if not unicodes then
10919  if trace_mapping then
10920   report_fonts("no unicode list, quitting tounicode for %a",filename)
10921  end
10922  return
10923 end
10924 local properties=data.properties
10925 local descriptions=data.descriptions
10926 local overloads=mappings.overloads
10927 unicodes['space']=unicodes['space']  or 32
10928 unicodes['hyphen']=unicodes['hyphen'] or 45
10929 unicodes['zwj']=unicodes['zwj'] or 0x200D
10930 unicodes['zwnj']=unicodes['zwnj']   or 0x200C
10931 local private=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 
10932 local unicodevector=fonts.encodings.agl.unicodes or {} 
10933 local contextvector=fonts.encodings.agl.ctxcodes or {} 
10934 local missing={}
10935 local nofmissing=0
10936 local oparser=nil
10937 local cidnames=nil
10938 local cidcodes=nil
10939 local cidinfo=properties.cidinfo
10940 local usedmap=cidinfo and fonts.cid.getmap(cidinfo)
10941 local uparser=makenameparser() 
10942 if usedmap then
10943  oparser=usedmap and makenameparser(cidinfo.ordering)
10944  cidnames=usedmap.names
10945  cidcodes=usedmap.unicodes
10946 end
10947 local ns=0
10948 local nl=0
10949 local dlist=sortedkeys(descriptions)
10950 for i=1,#dlist do
10951  local du=dlist[i]
10952  local glyph=descriptions[du]
10953  local name=glyph.name
10954  if name then
10955   local overload=overloads[name] or overloads[du]
10956   if overload then
10957    glyph.unicode=overload.unicode
10958   else
10959    local gu=glyph.unicode 
10960    if not gu or gu==-1 or du>=private or (du>=0xE000 and du<=0xF8FF) or du==0xFFFE or du==0xFFFF then
10961     local unicode=unicodevector[name] or contextvector[name]
10962     if unicode then
10963      glyph.unicode=unicode
10964      ns=ns+1
10965     end
10966     if (not unicode) and usedmap then
10967      local foundindex=lpegmatch(oparser,name)
10968      if foundindex then
10969       unicode=cidcodes[foundindex] 
10970       if unicode then
10971        glyph.unicode=unicode
10972        ns=ns+1
10973       else
10974        local reference=cidnames[foundindex] 
10975        if reference then
10976         local foundindex=lpegmatch(oparser,reference)
10977         if foundindex then
10978          unicode=cidcodes[foundindex]
10979          if unicode then
10980           glyph.unicode=unicode
10981           ns=ns+1
10982          end
10983         end
10984         if not unicode or unicode=="" then
10985          local foundcodes,multiple=lpegmatch(uparser,reference)
10986          if foundcodes then
10987           glyph.unicode=foundcodes
10988           if multiple then
10989            nl=nl+1
10990            unicode=true
10991           else
10992            ns=ns+1
10993            unicode=foundcodes
10994           end
10995          end
10996         end
10997        end
10998       end
10999      end
11000     end
11001     if not unicode or unicode=="" then
11002      local split=lpegmatch(namesplitter,name)
11003      local nsplit=split and #split or 0 
11004      if nsplit==0 then
11005      elseif nsplit==1 then
11006       local base=split[1]
11007       local u=unicodes[base] or unicodevector[base] or contextvector[name]
11008       if not u then
11009       elseif type(u)=="table" then
11010        if u[1]<private then
11011         unicode=u
11012         glyph.unicode=unicode
11013        end
11014       elseif u<private then
11015        unicode=u
11016        glyph.unicode=unicode
11017       end
11018      else
11019       local t={}
11020       local n=0
11021       for l=1,nsplit do
11022        local base=split[l]
11023        local u=unicodes[base] or unicodevector[base] or contextvector[name]
11024        if not u then
11025         break
11026        elseif type(u)=="table" then
11027         if u[1]>=private then
11028          break
11029         end
11030         n=n+1
11031         t[n]=u[1]
11032        else
11033         if u>=private then
11034          break
11035         end
11036         n=n+1
11037         t[n]=u
11038        end
11039       end
11040       if n>0 then
11041        if n==1 then
11042         unicode=t[1]
11043        else
11044         unicode=t
11045        end
11046        glyph.unicode=unicode
11047       end
11048      end
11049      nl=nl+1
11050     end
11051     if not unicode or unicode=="" then
11052      local foundcodes,multiple=lpegmatch(uparser,name)
11053      if foundcodes then
11054       glyph.unicode=foundcodes
11055       if multiple then
11056        nl=nl+1
11057        unicode=true
11058       else
11059        ns=ns+1
11060        unicode=foundcodes
11061       end
11062      end
11063     end
11064     local r=overloads[unicode]
11065     if r then
11066      unicode=r.unicode
11067      glyph.unicode=unicode
11068     end
11069     if not unicode then
11070      missing[du]=true
11071      nofmissing=nofmissing+1
11072     end
11073    else
11074    end
11075   end
11076  else
11077   local overload=overloads[du]
11078   if overload then
11079    glyph.unicode=overload.unicode
11080   elseif not glyph.unicode then
11081    missing[du]=true
11082    nofmissing=nofmissing+1
11083   end
11084  end
11085 end
11086 if type(checklookups)=="function" then
11087  checklookups(data,missing,nofmissing)
11088 end
11089 local unicoded=0
11090 local collected=fonts.handlers.otf.readers.getcomponents(data) 
11091 local function resolve(glyph,u)
11092  local n=#u
11093  for i=1,n do
11094   if u[i]>private then
11095    n=0
11096    break
11097   end
11098  end
11099  if n>0 then
11100   if n>1 then
11101    glyph.unicode=u
11102   else
11103    glyph.unicode=u[1]
11104   end
11105   unicoded=unicoded+1
11106  end
11107 end
11108 if not collected then
11109 elseif forceligatures or force_ligatures then
11110  for i=1,#dlist do
11111   local du=dlist[i]
11112   if du>=private or (du>=0xE000 and du<=0xF8FF) then
11113    local u=collected[du] 
11114    if u then
11115     resolve(descriptions[du],u)
11116    end
11117   end
11118  end
11119 else
11120  for i=1,#dlist do
11121   local du=dlist[i]
11122   if du>=private or (du>=0xE000 and du<=0xF8FF) then
11123    local glyph=descriptions[du]
11124    if glyph.class=="ligature" and not glyph.unicode then
11125     local u=collected[du] 
11126     if u then
11127       resolve(glyph,u)
11128     end
11129    end
11130   end
11131  end
11132 end
11133 if trace_mapping and unicoded>0 then
11134  report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded)
11135 end
11136 if trace_mapping then
11137  for i=1,#dlist do
11138   local du=dlist[i]
11139   local glyph=descriptions[du]
11140   local name=glyph.name or "-"
11141   local index=glyph.index or 0
11142   local unicode=glyph.unicode
11143   if unicode then
11144    if type(unicode)=="table" then
11145     local unicodes={}
11146     for i=1,#unicode do
11147      unicodes[i]=formatters("%U",unicode[i])
11148     end
11149     report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,du,unicodes)
11150    else
11151     report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,du,unicode)
11152    end
11153   else
11154    report_fonts("internal slot %U, name %a, unicode %U",index,name,du)
11155   end
11156  end
11157 end
11158 if trace_loading and (ns>0 or nl>0) then
11159  report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns)
11160 end
11161end
11162
11163end -- closure
11164
11165do -- begin closure to overcome local limits and interference
11166
11167if not modules then modules={} end modules ['luatex-fonts-syn']={
11168 version=1.001,
11169 comment="companion to luatex-*.tex",
11170 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
11171 copyright="PRAGMA ADE / ConTeXt Development Team",
11172 license="see context related readme files"
11173}
11174if context then
11175--removed
11176
11177end
11178local fonts=fonts
11179fonts.names=fonts.names or {}
11180fonts.names.version=1.001 
11181fonts.names.basename="luatex-fonts-names"
11182fonts.names.cache=containers.define("fonts","data",fonts.names.version,true)
11183local data=nil
11184local loaded=false
11185local fileformats={ "lua","tex","other text files" }
11186function fonts.names.reportmissingbase()
11187 logs.report("fonts","missing font database, run: mtxrun --script fonts --reload --simple")
11188 fonts.names.reportmissingbase=nil
11189end
11190function fonts.names.reportmissingname()
11191 logs.report("fonts","unknown font in font database, run: mtxrun --script fonts --reload --simple")
11192 fonts.names.reportmissingname=nil
11193end
11194function fonts.names.resolve(name,sub)
11195 if not loaded then
11196  local basename=fonts.names.basename
11197  if basename and basename~="" then
11198   data=containers.read(fonts.names.cache,basename)
11199   if not data then
11200    basename=file.addsuffix(basename,"lua")
11201    for i=1,#fileformats do
11202     local format=fileformats[i]
11203     local foundname=resolvers.findfile(basename,format) or ""
11204     if foundname~="" then
11205      data=dofile(foundname)
11206      logs.report("fonts","font database '%s' loaded",foundname)
11207      break
11208     end
11209    end
11210   end
11211  end
11212  loaded=true
11213 end
11214 if type(data)=="table" and data.version==fonts.names.version then
11215  local condensed=string.gsub(string.lower(name),"[^%a%d]","")
11216  local found=data.mappings and data.mappings[condensed]
11217  if found then
11218   local fontname,filename,subfont=found[1],found[2],found[3]
11219   if subfont then
11220    return filename,fontname
11221   else
11222    return filename,false
11223   end
11224  elseif fonts.names.reportmissingname then
11225   fonts.names.reportmissingname()
11226   return name,false 
11227  end
11228 elseif fonts.names.reportmissingbase then
11229  fonts.names.reportmissingbase()
11230 end
11231end
11232fonts.names.resolvespec=fonts.names.resolve 
11233function fonts.names.getfilename(askedname,suffix)  
11234 return ""
11235end
11236function fonts.names.ignoredfile(filename) 
11237 return false 
11238end
11239
11240end -- closure
11241
11242do -- begin closure to overcome local limits and interference
11243
11244if not modules then modules={} end modules ['font-vfc']={
11245 version=1.001,
11246 comment="companion to font-ini.mkiv and hand-ini.mkiv",
11247 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
11248 copyright="PRAGMA ADE / ConTeXt Development Team",
11249 license="see context related readme files"
11250}
11251local select,type=select,type
11252local insert=table.insert
11253local fonts=fonts
11254local helpers=fonts.helpers
11255local setmetatableindex=table.setmetatableindex
11256local push={ "push" }
11257local pop={ "pop" }
11258local dummy={ "comment" }
11259function helpers.prependcommands(commands,...)
11260 insert(commands,1,push)
11261 for i=select("#",...),1,-1 do
11262  local s=(select(i,...))
11263  if s then
11264   insert(commands,1,s)
11265  end
11266 end
11267 insert(commands,pop)
11268 return commands
11269end
11270function helpers.appendcommands(commands,...)
11271 insert(commands,1,push)
11272 insert(commands,pop)
11273 for i=1,select("#",...) do
11274  local s=(select(i,...))
11275  if s then
11276   insert(commands,s)
11277  end
11278 end
11279 return commands
11280end
11281function helpers.prependcommandtable(commands,t)
11282 insert(commands,1,push)
11283 for i=#t,1,-1 do
11284  local s=t[i]
11285  if s then
11286   insert(commands,1,s)
11287  end
11288 end
11289 insert(commands,pop)
11290 return commands
11291end
11292function helpers.appendcommandtable(commands,t)
11293 insert(commands,1,push)
11294 insert(commands,pop)
11295 for i=1,#t do
11296  local s=t[i]
11297  if s then
11298   insert(commands,s)
11299  end
11300 end
11301 return commands
11302end
11303local char=setmetatableindex(function(t,k)
11304 local v={ "slot",0,k }
11305 t[k]=v
11306 return v
11307end)
11308local right=setmetatableindex(function(t,k)
11309 local v={ "right",k }
11310 t[k]=v
11311 return v
11312end)
11313local left=setmetatableindex(function(t,k)
11314 local v={ "right",-k }
11315 t[k]=v
11316 return v
11317end)
11318local down=setmetatableindex(function(t,k)
11319 local v={ "down",k }
11320 t[k]=v
11321 return v
11322end)
11323local up=setmetatableindex(function(t,k)
11324 local v={ "down",-k }
11325 t[k]=v
11326 return v
11327end)
11328helpers.commands=utilities.storage.allocate {
11329 char=char,
11330 right=right,
11331 left=left,
11332 down=down,
11333 up=up,
11334 push=push,
11335 pop=pop,
11336 dummy=dummy,
11337}
11338
11339end -- closure
11340
11341do -- begin closure to overcome local limits and interference
11342
11343if not modules then modules={} end modules ['font-otr']={
11344 version=1.001,
11345 optimize=true,
11346 comment="companion to font-ini.mkiv",
11347 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
11348 copyright="PRAGMA ADE / ConTeXt Development Team",
11349 license="see context related readme files"
11350}
11351local number=number
11352local next,type,tonumber,rawget=next,type,tonumber,rawget
11353local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub
11354local fullstrip=string.fullstrip
11355local floor,round=math.floor,math.round
11356local P,R,S,C,Cs,Cc,Ct,Carg,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg,lpeg.Cmt
11357local lpegmatch=lpeg.match
11358local rshift=bit32.rshift
11359local setmetatableindex=table.setmetatableindex
11360local sortedkeys=table.sortedkeys
11361local sortedhash=table.sortedhash
11362local stripstring=string.nospaces
11363local utf16_to_utf8_be=utf.utf16_to_utf8_be
11364local report=logs.reporter("otf reader")
11365local report_cmap=logs.reporter("otf reader","cmap")
11366local trace_cmap=false  trackers.register("otf.cmap",function(v) trace_cmap=v end)
11367local trace_cmap_details=false  trackers.register("otf.cmap.details",function(v) trace_cmap_details=v end)
11368fonts=fonts or {}
11369local handlers=fonts.handlers or {}
11370fonts.handlers=handlers
11371local otf=handlers.otf or {}
11372handlers.otf=otf
11373local readers=otf.readers or {}
11374otf.readers=readers
11375local streamreader=utilities.files   
11376local streamwriter=utilities.files
11377readers.streamreader=streamreader
11378readers.streamwriter=streamwriter
11379local openfile=streamreader.open
11380local closefile=streamreader.close
11381local setposition=streamreader.setposition
11382local skipshort=streamreader.skipshort
11383local readbytes=streamreader.readbytes
11384local readstring=streamreader.readstring
11385local readbyte=streamreader.readcardinal1  
11386local readushort=streamreader.readcardinal2  
11387local readuint=streamreader.readcardinal3  
11388local readulong=streamreader.readcardinal4
11389local readshort=streamreader.readinteger2   
11390local readlong=streamreader.readinteger4   
11391local readfixed=streamreader.readfixed4
11392local read2dot14=streamreader.read2dot14  
11393local readfword=readshort       
11394local readufword=readushort      
11395local readoffset=readushort
11396local readcardinaltable=streamreader.readcardinaltable
11397local readintegertable=streamreader.readintegertable
11398function streamreader.readtag(f)
11399 return lower(stripstring(readstring(f,4)))
11400end
11401local short=2
11402local ushort=2
11403local ulong=4
11404directives.register("fonts.streamreader",function()
11405 streamreader=utilities.streams
11406 openfile=streamreader.open
11407 closefile=streamreader.close
11408 setposition=streamreader.setposition
11409 skipshort=streamreader.skipshort
11410 readbytes=streamreader.readbytes
11411 readstring=streamreader.readstring
11412 readbyte=streamreader.readcardinal1
11413 readushort=streamreader.readcardinal2
11414 readuint=streamreader.readcardinal3
11415 readulong=streamreader.readcardinal4
11416 readshort=streamreader.readinteger2
11417 readlong=streamreader.readinteger4
11418 readfixed=streamreader.readfixed4
11419 read2dot14=streamreader.read2dot14
11420 readfword=readshort
11421 readufword=readushort
11422 readoffset=readushort
11423 readcardinaltable=streamreader.readcardinaltable
11424 readintegertable=streamreader.readintegertable
11425 function streamreader.readtag(f)
11426  return lower(stripstring(readstring(f,4)))
11427 end
11428end)
11429local function readlongdatetime(f)
11430 local a,b,c,d,e,f,g,h=readbytes(f,8)
11431 return 0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
11432end
11433local tableversion=0.004
11434readers.tableversion=tableversion
11435local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
11436local reservednames={ [0]="copyright",
11437 "family",
11438 "subfamily",
11439 "uniqueid",
11440 "fullname",
11441 "version",
11442 "postscriptname",
11443 "trademark",
11444 "manufacturer",
11445 "designer",
11446 "description",
11447 "vendorurl",
11448 "designerurl",
11449 "license",
11450 "licenseurl",
11451 "reserved",
11452 "typographicfamily",
11453 "typographicsubfamily",
11454 "compatiblefullname",
11455 "sampletext",
11456 "cidfindfontname",
11457 "wwsfamily",
11458 "wwssubfamily",
11459 "lightbackgroundpalette",
11460 "darkbackgroundpalette",
11461 "variationspostscriptnameprefix",
11462}
11463local platforms={ [0]="unicode",
11464 "macintosh",
11465 "iso",
11466 "windows",
11467 "custom",
11468}
11469local encodings={
11470 unicode={ [0]="unicode 1.0 semantics",
11471  "unicode 1.1 semantics",
11472  "iso/iec 10646",
11473  "unicode 2.0 bmp",
11474  "unicode 2.0 full",
11475  "unicode variation sequences",
11476  "unicode full repertoire",
11477 },
11478 macintosh={ [0]="roman","japanese","chinese (traditional)","korean","arabic","hebrew","greek","russian",
11479  "rsymbol","devanagari","gurmukhi","gujarati","oriya","bengali","tamil","telugu","kannada",
11480  "malayalam","sinhalese","burmese","khmer","thai","laotian","georgian","armenian",
11481  "chinese (simplified)","tibetan","mongolian","geez","slavic","vietnamese","sindhi",
11482  "uninterpreted",
11483 },
11484 iso={ [0]="7-bit ascii",
11485  "iso 10646",
11486  "iso 8859-1",
11487 },
11488 windows={ [0]="symbol",
11489  "unicode bmp",
11490  "shiftjis",
11491  "prc",
11492  "big5",
11493  "wansung",
11494  "johab",
11495  "reserved 7",
11496  "reserved 8",
11497  "reserved 9",
11498  "unicode ucs-4",
11499 },
11500 custom={
11501 }
11502}
11503local decoders={
11504 unicode={},
11505 macintosh={},
11506 iso={},
11507 windows={
11508  ["unicode semantics"]=utf16_to_utf8_be,
11509  ["unicode bmp"]=utf16_to_utf8_be,
11510  ["unicode full"]=utf16_to_utf8_be,
11511  ["unicode 1.0 semantics"]=utf16_to_utf8_be,
11512  ["unicode 1.1 semantics"]=utf16_to_utf8_be,
11513  ["unicode 2.0 bmp"]=utf16_to_utf8_be,
11514  ["unicode 2.0 full"]=utf16_to_utf8_be,
11515  ["unicode variation sequences"]=utf16_to_utf8_be,
11516  ["unicode full repertoire"]=utf16_to_utf8_be,
11517 },
11518 custom={},
11519}
11520local languages={
11521 unicode={
11522  [  0]="english",
11523 },
11524 macintosh={
11525  [  0]="english",
11526 },
11527 iso={},
11528 windows={
11529  [0x0409]="english - united states",
11530 },
11531 custom={},
11532}
11533local standardromanencoding={ [0]=
11534 "notdef",".null","nonmarkingreturn","space","exclam","quotedbl",
11535 "numbersign","dollar","percent","ampersand","quotesingle","parenleft",
11536 "parenright","asterisk","plus","comma","hyphen","period","slash",
11537 "zero","one","two","three","four","five","six","seven","eight",
11538 "nine","colon","semicolon","less","equal","greater","question","at",
11539 "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O",
11540 "P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft",
11541 "backslash","bracketright","asciicircum","underscore","grave","a","b",
11542 "c","d","e","f","g","h","i","j","k","l","m","n","o","p","q",
11543 "r","s","t","u","v","w","x","y","z","braceleft","bar",
11544 "braceright","asciitilde","Adieresis","Aring","Ccedilla","Eacute",
11545 "Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex",
11546 "adieresis","atilde","aring","ccedilla","eacute","egrave",
11547 "ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis",
11548 "ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute",
11549 "ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling",
11550 "section","bullet","paragraph","germandbls","registered","copyright",
11551 "trademark","acute","dieresis","notequal","AE","Oslash","infinity",
11552 "plusminus","lessequal","greaterequal","yen","mu","partialdiff",
11553 "summation","product","pi","integral","ordfeminine","ordmasculine",
11554 "Omega","ae","oslash","questiondown","exclamdown","logicalnot",
11555 "radical","florin","approxequal","Delta","guillemotleft",
11556 "guillemotright","ellipsis","nonbreakingspace","Agrave","Atilde",
11557 "Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright",
11558 "quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis",
11559 "fraction","currency","guilsinglleft","guilsinglright","fi","fl",
11560 "daggerdbl","periodcentered","quotesinglbase","quotedblbase",
11561 "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave",
11562 "Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex",
11563 "apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi",
11564 "circumflex","tilde","macron","breve","dotaccent","ring","cedilla",
11565 "hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron",
11566 "Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn",
11567 "thorn","minus","multiply","onesuperior","twosuperior","threesuperior",
11568 "onehalf","onequarter","threequarters","franc","Gbreve","gbreve",
11569 "Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron",
11570 "dcroat",
11571}
11572local weights={
11573 [100]="thin",
11574 [200]="extralight",
11575 [300]="light",
11576 [400]="normal",
11577 [500]="medium",
11578 [600]="semibold",
11579 [700]="bold",
11580 [800]="extrabold",
11581 [900]="black",
11582}
11583local widths={
11584 "ultracondensed",
11585 "extracondensed",
11586 "condensed",
11587 "semicondensed",
11588 "normal",
11589 "semiexpanded",
11590 "expanded",
11591 "extraexpanded",
11592 "ultraexpanded",
11593}
11594setmetatableindex(weights,function(t,k)
11595 local r=floor((k+50)/100)*100
11596 local v=(r>900 and "black") or rawget(t,r) or "normal"
11597 return v
11598end)
11599setmetatableindex(widths,function(t,k)
11600 return "normal"
11601end)
11602local panoseweights={ [0]="normal",
11603 "normal",
11604 "verylight",
11605 "light",
11606 "thin",
11607 "book",
11608 "medium",
11609 "demi",
11610 "bold",
11611 "heavy",
11612 "black",
11613}
11614local panosewidths={ [0]="normal",
11615 "normal",
11616 "normal",
11617 "normal",
11618 "normal",
11619 "expanded",
11620 "condensed",
11621 "veryexpanded",
11622 "verycondensed",
11623 "monospaced",
11624}
11625local helpers={}
11626readers.helpers=helpers
11627local function gotodatatable(f,fontdata,tag,criterium)
11628 if criterium and f then
11629  local tables=fontdata.tables
11630  if tables then
11631   local datatable=tables[tag]
11632   if datatable then
11633    local tableoffset=datatable.offset
11634    setposition(f,tableoffset)
11635    return tableoffset
11636   end
11637  else
11638   report("no tables")
11639  end
11640 end
11641end
11642local function reportskippedtable(f,fontdata,tag,criterium)
11643 if criterium and f then
11644  local tables=fontdata.tables
11645  if tables then
11646   local datatable=tables[tag]
11647   if datatable then
11648    report("loading of table %a skipped",tag)
11649   end
11650  else
11651   report("no tables")
11652  end
11653 end
11654end
11655local function setvariabledata(fontdata,tag,data)
11656 local variabledata=fontdata.variabledata
11657 if variabledata then
11658  variabledata[tag]=data
11659 else
11660  fontdata.variabledata={ [tag]=data }
11661 end
11662end
11663helpers.gotodatatable=gotodatatable
11664helpers.setvariabledata=setvariabledata
11665helpers.reportskippedtable=reportskippedtable
11666local platformnames={
11667 postscriptname=true,
11668 fullname=true,
11669 family=true,
11670 subfamily=true,
11671 typographicfamily=true,
11672 typographicsubfamily=true,
11673 compatiblefullname=true,
11674}
11675local platformextras={
11676 uniqueid=true,
11677 version=true,
11678 copyright=true,
11679 license=true,
11680 licenseurl=true,
11681 manufacturer=true,
11682 vendorurl=true,
11683}
11684function readers.name(f,fontdata,specification)
11685 local tableoffset=gotodatatable(f,fontdata,"name",true)
11686 if tableoffset then
11687  local format=readushort(f)
11688  local nofnames=readushort(f)
11689  local offset=readushort(f)
11690  local start=tableoffset+offset
11691  local namelists={
11692   unicode={},
11693   windows={},
11694   macintosh={},
11695  }
11696  for i=1,nofnames do
11697   local platform=platforms[readushort(f)]
11698   if platform then
11699    local namelist=namelists[platform]
11700    if namelist then
11701     local encoding=readushort(f)
11702     local language=readushort(f)
11703     local encodings=encodings[platform]
11704     local languages=languages[platform]
11705     if encodings and languages then
11706      local encoding=encodings[encoding]
11707      local language=languages[language]
11708      if encoding and language then
11709       local index=readushort(f)
11710       local name=reservednames[index]
11711       namelist[#namelist+1]={
11712        platform=platform,
11713        encoding=encoding,
11714        language=language,
11715        name=name,
11716        index=index,
11717        length=readushort(f),
11718        offset=start+readushort(f),
11719       }
11720      else
11721       skipshort(f,3)
11722      end
11723     else
11724      skipshort(f,3)
11725     end
11726    else
11727     skipshort(f,5)
11728    end
11729   else
11730    skipshort(f,5)
11731   end
11732  end
11733  local names={}
11734  local done={}
11735  local extras={}
11736  local function decoded(platform,encoding,content)
11737   local decoder=decoders[platform]
11738   if decoder then
11739    decoder=decoder[encoding]
11740   end
11741   if decoder then
11742    return decoder(content)
11743   else
11744    return content
11745   end
11746  end
11747  local function filter(platform,e,l)
11748   local namelist=namelists[platform]
11749   for i=1,#namelist do
11750    local name=namelist[i]
11751    local nametag=name.name
11752    local index=name.index
11753    if not done[nametag or i] then
11754     local encoding=name.encoding
11755     local language=name.language
11756     if (not e or encoding==e) and (not l or language==l) then
11757      setposition(f,name.offset)
11758      local content=decoded(platform,encoding,readstring(f,name.length))
11759      if nametag then
11760       names[nametag]={
11761        content=content,
11762        platform=platform,
11763        encoding=encoding,
11764        language=language,
11765       }
11766      end
11767      extras[index]=content
11768      done[nametag or i]=true
11769     end
11770    end
11771   end
11772  end
11773  filter("windows","unicode bmp","english - united states")
11774  filter("macintosh","roman","english")
11775  filter("windows")
11776  filter("macintosh")
11777  filter("unicode")
11778  fontdata.names=names
11779  fontdata.extras=extras
11780  if specification.platformnames then
11781   local collected={}
11782   local platformextras=specification.platformextras and platformextras
11783   for platform,namelist in next,namelists do
11784    local filtered=false
11785    for i=1,#namelist do
11786     local entry=namelist[i]
11787     local name=entry.name
11788     if platformnames[name] or (platformextras and platformextras[name]) then
11789      setposition(f,entry.offset)
11790      local content=decoded(platform,entry.encoding,readstring(f,entry.length))
11791      if filtered then
11792       filtered[name]=content
11793      else
11794       filtered={ [name]=content }
11795      end
11796     end
11797    end
11798    if filtered then
11799     collected[platform]=filtered
11800    end
11801   end
11802   fontdata.platformnames=collected
11803  end
11804 else
11805  fontdata.names={}
11806 end
11807end
11808local validutf=lpeg.patterns.validutf8
11809local function getname(fontdata,key)
11810 local names=fontdata.names
11811 if names then
11812  local value=names[key]
11813  if value then
11814   local content=value.content
11815   return lpegmatch(validutf,content) and content or nil
11816  end
11817 end
11818end
11819readers["os/2"]=function(f,fontdata)
11820 local tableoffset=gotodatatable(f,fontdata,"os/2",true)
11821 if tableoffset then
11822  local version=readushort(f)
11823  local windowsmetrics={
11824   version=version,
11825   averagewidth=readshort(f),
11826   weightclass=readushort(f),
11827   widthclass=readushort(f),
11828   fstype=readushort(f),
11829   subscriptxsize=readshort(f),
11830   subscriptysize=readshort(f),
11831   subscriptxoffset=readshort(f),
11832   subscriptyoffset=readshort(f),
11833   superscriptxsize=readshort(f),
11834   superscriptysize=readshort(f),
11835   superscriptxoffset=readshort(f),
11836   superscriptyoffset=readshort(f),
11837   strikeoutsize=readshort(f),
11838   strikeoutpos=readshort(f),
11839   familyclass=readshort(f),
11840   panose={ readbytes(f,10) },
11841   unicoderanges={ readulong(f),readulong(f),readulong(f),readulong(f) },
11842   vendor=readstring(f,4),
11843   fsselection=readushort(f),
11844   firstcharindex=readushort(f),
11845   lastcharindex=readushort(f),
11846   typoascender=readshort(f),
11847   typodescender=readshort(f),
11848   typolinegap=readshort(f),
11849   winascent=readushort(f),
11850   windescent=readushort(f),
11851  }
11852  if version>=1 then
11853   windowsmetrics.codepageranges={ readulong(f),readulong(f) }
11854  end
11855  if version>=2 then
11856   windowsmetrics.xheight=readshort(f)
11857   windowsmetrics.capheight=readshort(f)
11858   windowsmetrics.defaultchar=readushort(f)
11859   windowsmetrics.breakchar=readushort(f)
11860  end
11861  windowsmetrics.weight=windowsmetrics.weightclass and weights[windowsmetrics.weightclass]
11862  windowsmetrics.width=windowsmetrics.widthclass and  widths [windowsmetrics.widthclass]
11863  windowsmetrics.panoseweight=panoseweights[windowsmetrics.panose[3]]
11864  windowsmetrics.panosewidth=panosewidths [windowsmetrics.panose[4]]
11865  fontdata.windowsmetrics=windowsmetrics
11866 else
11867  fontdata.windowsmetrics={}
11868 end
11869end
11870readers.head=function(f,fontdata)
11871 local tableoffset=gotodatatable(f,fontdata,"head",true)
11872 if tableoffset then
11873  local version=readulong(f)
11874  local fontversion=readulong(f)
11875  local fontheader={
11876   version=version,
11877   fontversion=number.to16dot16(fontversion),
11878   fontversionnumber=fontversion,
11879   checksum=readushort(f)*0x10000+readushort(f),
11880   magic=readulong(f),
11881   flags=readushort(f),
11882   units=readushort(f),
11883   created=readlongdatetime(f),
11884   modified=readlongdatetime(f),
11885   xmin=readshort(f),
11886   ymin=readshort(f),
11887   xmax=readshort(f),
11888   ymax=readshort(f),
11889   macstyle=readushort(f),
11890   smallpixels=readushort(f),
11891   directionhint=readshort(f),
11892   indextolocformat=readshort(f),
11893   glyphformat=readshort(f),
11894  }
11895  fontdata.fontheader=fontheader
11896 else
11897  fontdata.fontheader={}
11898 end
11899 fontdata.nofglyphs=0
11900end
11901readers.hhea=function(f,fontdata,specification)
11902 local tableoffset=gotodatatable(f,fontdata,"hhea",specification.details)
11903 if tableoffset then
11904  fontdata.horizontalheader={
11905   version=readulong(f),
11906   ascender=readfword(f),
11907   descender=readfword(f),
11908   linegap=readfword(f),
11909   maxadvancewidth=readufword(f),
11910   minleftsidebearing=readfword(f),
11911   minrightsidebearing=readfword(f),
11912   maxextent=readfword(f),
11913   caretsloperise=readshort(f),
11914   caretsloperun=readshort(f),
11915   caretoffset=readshort(f),
11916   reserved_1=readshort(f),
11917   reserved_2=readshort(f),
11918   reserved_3=readshort(f),
11919   reserved_4=readshort(f),
11920   metricdataformat=readshort(f),
11921   nofmetrics=readushort(f),
11922  }
11923 else
11924  fontdata.horizontalheader={
11925   nofmetrics=0,
11926  }
11927 end
11928end
11929readers.vhea=function(f,fontdata,specification)
11930 local tableoffset=gotodatatable(f,fontdata,"vhea",specification.details)
11931 if tableoffset then
11932  fontdata.verticalheader={
11933   version=readulong(f),
11934   ascender=readfword(f),
11935   descender=readfword(f),
11936   linegap=readfword(f),
11937   maxadvanceheight=readufword(f),
11938   mintopsidebearing=readfword(f),
11939   minbottomsidebearing=readfword(f),
11940   maxextent=readfword(f),
11941   caretsloperise=readshort(f),
11942   caretsloperun=readshort(f),
11943   caretoffset=readshort(f),
11944   reserved_1=readshort(f),
11945   reserved_2=readshort(f),
11946   reserved_3=readshort(f),
11947   reserved_4=readshort(f),
11948   metricdataformat=readshort(f),
11949   nofmetrics=readushort(f),
11950  }
11951 else
11952  fontdata.verticalheader={
11953   nofmetrics=0,
11954  }
11955 end
11956end
11957readers.maxp=function(f,fontdata,specification)
11958 local tableoffset=gotodatatable(f,fontdata,"maxp",specification.details)
11959 if tableoffset then
11960  local version=readulong(f)
11961  local nofglyphs=readushort(f)
11962  fontdata.nofglyphs=nofglyphs
11963  if version==0x00005000 then
11964   fontdata.maximumprofile={
11965    version=version,
11966    nofglyphs=nofglyphs,
11967   }
11968  elseif version==0x00010000 then
11969   fontdata.maximumprofile={
11970    version=version,
11971    nofglyphs=nofglyphs,
11972    points=readushort(f),
11973    contours=readushort(f),
11974    compositepoints=readushort(f),
11975    compositecontours=readushort(f),
11976    zones=readushort(f),
11977    twilightpoints=readushort(f),
11978    storage=readushort(f),
11979    functiondefs=readushort(f),
11980    instructiondefs=readushort(f),
11981    stackelements=readushort(f),
11982    sizeofinstructions=readushort(f),
11983    componentelements=readushort(f),
11984    componentdepth=readushort(f),
11985   }
11986  else
11987   fontdata.maximumprofile={
11988    version=version,
11989    nofglyphs=0,
11990   }
11991  end
11992 end
11993end
11994readers.hmtx=function(f,fontdata,specification)
11995 local tableoffset=gotodatatable(f,fontdata,"hmtx",specification.glyphs)
11996 if tableoffset then
11997  local horizontalheader=fontdata.horizontalheader
11998  local nofmetrics=horizontalheader.nofmetrics
11999  local glyphs=fontdata.glyphs
12000  local nofglyphs=fontdata.nofglyphs
12001  local width=0 
12002  local leftsidebearing=0
12003  for i=0,nofmetrics-1 do
12004   local glyph=glyphs[i]
12005   width=readshort(f) 
12006   leftsidebearing=readshort(f)
12007   if width~=0 then
12008    glyph.width=width
12009   end
12010  end
12011  for i=nofmetrics,nofglyphs-1 do
12012   local glyph=glyphs[i]
12013   if width~=0 then
12014    glyph.width=width
12015   end
12016  end
12017 end
12018end
12019readers.vmtx=function(f,fontdata,specification)
12020 local tableoffset=gotodatatable(f,fontdata,"vmtx",specification.glyphs)
12021 if tableoffset then
12022  local verticalheader=fontdata.verticalheader
12023  local nofmetrics=verticalheader.nofmetrics
12024  local glyphs=fontdata.glyphs
12025  local nofglyphs=fontdata.nofglyphs
12026  local vheight=0
12027  local vdefault=verticalheader.ascender-verticalheader.descender
12028  local topsidebearing=0
12029  for i=0,nofmetrics-1 do
12030   local glyph=glyphs[i]
12031   vheight=readushort(f)
12032   topsidebearing=readshort(f)
12033   if vheight~=0 and vheight~=vdefault then
12034    glyph.vheight=vheight
12035   end
12036   if topsidebearing~=0 then
12037    glyph.tsb=topsidebearing
12038   end
12039  end
12040  for i=nofmetrics,nofglyphs-1 do
12041   local glyph=glyphs[i]
12042   if vheight~=0 and vheight~=vdefault then
12043    glyph.vheight=vheight
12044   end
12045  end
12046 end
12047end
12048readers.vorg=function(f,fontdata,specification)
12049 reportskippedtable(f,fontdata,"vorg",specification.glyphs)
12050end
12051readers.post=function(f,fontdata,specification)
12052 local tableoffset=gotodatatable(f,fontdata,"post",true)
12053 if tableoffset then
12054  local version=readulong(f)
12055  fontdata.postscript={
12056   version=version,
12057   italicangle=readfixed(f),
12058   underlineposition=readfword(f),
12059   underlinethickness=readfword(f),
12060   monospaced=readulong(f),
12061   minmemtype42=readulong(f),
12062   maxmemtype42=readulong(f),
12063   minmemtype1=readulong(f),
12064   maxmemtype1=readulong(f),
12065  }
12066  if not specification.glyphs then
12067  elseif version==0x00010000 then
12068   for index=0,#standardromanencoding do
12069    glyphs[index].name=standardromanencoding[index]
12070   end
12071  elseif version==0x00020000 then
12072   local glyphs=fontdata.glyphs
12073   local nofglyphs=readushort(f)
12074   local indices={}
12075   local names={}
12076   local maxnames=0
12077   for i=0,nofglyphs-1 do
12078    local nameindex=readushort(f)
12079    if nameindex>=258 then
12080     maxnames=maxnames+1
12081     nameindex=nameindex-257
12082     indices[nameindex]=i
12083    else
12084     glyphs[i].name=standardromanencoding[nameindex]
12085    end
12086   end
12087   for i=1,maxnames do
12088    local mapping=indices[i]
12089    if not mapping then
12090     report("quit post name fetching at %a of %a: %s",i,maxnames,"no index")
12091     break
12092    else
12093     local length=readbyte(f)
12094     if length>0 then
12095      glyphs[mapping].name=readstring(f,length)
12096     else
12097     end
12098    end
12099   end
12100  end
12101 else
12102  fontdata.postscript={}
12103 end
12104end
12105readers.cff=function(f,fontdata,specification)
12106 reportskippedtable(f,fontdata,"cff",specification.glyphs)
12107end
12108local formatreaders={}
12109local duplicatestoo=true
12110local sequence={
12111 { 3,1,4 },
12112 { 3,10,12 },
12113 { 0,3,4 },
12114 { 0,3,12 },
12115 { 0,1,4 },
12116 { 0,1,12 },
12117 { 0,0,6 },
12118 { 3,0,6 },
12119 { 3,0,4 },
12120 { 0,5,14 },
12121 { 0,4,12 },
12122 { 3,10,13 },
12123}
12124local supported={}
12125for i=1,#sequence do
12126 local si=sequence[i]
12127 local sp,se,sf=si[1],si[2],si[3]
12128 local p=supported[sp]
12129 if not p then
12130  p={}
12131  supported[sp]=p
12132 end
12133 local e=p[se]
12134 if not e then
12135  e={}
12136  p[se]=e
12137 end
12138 e[sf]=true
12139end
12140formatreaders[4]=function(f,fontdata,offset)
12141 setposition(f,offset+2)
12142 local length=readushort(f) 
12143 local language=readushort(f)
12144 local nofsegments=readushort(f)/2
12145 skipshort(f,3)
12146 local mapping=fontdata.mapping
12147 local glyphs=fontdata.glyphs
12148 local duplicates=fontdata.duplicates
12149 local nofdone=0
12150 local endchars=readcardinaltable(f,nofsegments,ushort)
12151 local reserved=readushort(f) 
12152 local startchars=readcardinaltable(f,nofsegments,ushort)
12153 local deltas=readcardinaltable(f,nofsegments,ushort)
12154 local offsets=readcardinaltable(f,nofsegments,ushort)
12155 local size=(length-2*2-5*2-4*2*nofsegments)/2
12156 local indices=readcardinaltable(f,size-1,ushort)
12157 for segment=1,nofsegments do
12158  local startchar=startchars[segment]
12159  local endchar=endchars[segment]
12160  local offset=offsets[segment]
12161  local delta=deltas[segment]
12162  if startchar==0xFFFF and endchar==0xFFFF then
12163  elseif startchar==0xFFFF and offset==0 then
12164  elseif offset==0xFFFF then
12165  elseif offset==0 then
12166   if trace_cmap_details then
12167    report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar+delta)%65536)
12168   end
12169   for unicode=startchar,endchar do
12170    local index=(unicode+delta)%65536
12171    if index and index>0 then
12172     local glyph=glyphs[index]
12173     if glyph then
12174      local gu=glyph.unicode
12175      if not gu then
12176       glyph.unicode=unicode
12177       nofdone=nofdone+1
12178      elseif gu~=unicode then
12179       if duplicatestoo then
12180        local d=duplicates[gu]
12181        if d then
12182         d[unicode]=true
12183        else
12184         duplicates[gu]={ [unicode]=true }
12185        end
12186       else
12187        report("duplicate case 1: %C %04i %s",unicode,index,glyphs[index].name)
12188       end
12189      end
12190      if not mapping[index] then
12191       mapping[index]=unicode
12192      end
12193     end
12194    end
12195   end
12196  else
12197   local shift=(segment-nofsegments+offset/2)-startchar
12198   if trace_cmap_details then
12199    report_cmap("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar+delta)%65536)
12200   end
12201   for unicode=startchar,endchar do
12202    local slot=shift+unicode
12203    local index=indices[slot]
12204    if index and index>0 then
12205     index=(index+delta)%65536
12206     local glyph=glyphs[index]
12207     if glyph then
12208      local gu=glyph.unicode
12209      if not gu then
12210       glyph.unicode=unicode
12211       nofdone=nofdone+1
12212      elseif gu~=unicode then
12213       if duplicatestoo then
12214        local d=duplicates[gu]
12215        if d then
12216         d[unicode]=true
12217        else
12218         duplicates[gu]={ [unicode]=true }
12219        end
12220       else
12221        report("duplicate case 2: %C %04i %s",unicode,index,glyphs[index].name)
12222       end
12223      end
12224      if not mapping[index] then
12225       mapping[index]=unicode
12226      end
12227     end
12228    end
12229   end
12230  end
12231 end
12232 return nofdone
12233end
12234formatreaders[6]=function(f,fontdata,offset)
12235 setposition(f,offset) 
12236 local format=readushort(f)
12237 local length=readushort(f)
12238 local language=readushort(f)
12239 local mapping=fontdata.mapping
12240 local glyphs=fontdata.glyphs
12241 local duplicates=fontdata.duplicates
12242 local start=readushort(f)
12243 local count=readushort(f)
12244 local stop=start+count-1
12245 local nofdone=0
12246 if trace_cmap_details then
12247  report_cmap("format 6 from %C to %C",2,start,stop)
12248 end
12249 for unicode=start,stop do
12250  local index=readushort(f)
12251  if index>0 then
12252   local glyph=glyphs[index]
12253   if glyph then
12254    local gu=glyph.unicode
12255    if not gu then
12256     glyph.unicode=unicode
12257     nofdone=nofdone+1
12258    elseif gu~=unicode then
12259    end
12260    if not mapping[index] then
12261     mapping[index]=unicode
12262    end
12263   end
12264  end
12265 end
12266 return nofdone
12267end
12268formatreaders[12]=function(f,fontdata,offset)
12269 setposition(f,offset+2+2+4+4) 
12270 local mapping=fontdata.mapping
12271 local glyphs=fontdata.glyphs
12272 local duplicates=fontdata.duplicates
12273 local nofgroups=readulong(f)
12274 local nofdone=0
12275 for i=1,nofgroups do
12276  local first=readulong(f)
12277  local last=readulong(f)
12278  local index=readulong(f)
12279  if trace_cmap_details then
12280   report_cmap("format 12 from %C to %C starts at index %i",first,last,index)
12281  end
12282  for unicode=first,last do
12283   local glyph=glyphs[index]
12284   if glyph then
12285    local gu=glyph.unicode
12286    if not gu then
12287     glyph.unicode=unicode
12288     nofdone=nofdone+1
12289    elseif gu~=unicode then
12290     local d=duplicates[gu]
12291     if d then
12292      d[unicode]=true
12293     else
12294      duplicates[gu]={ [unicode]=true }
12295     end
12296    end
12297    if not mapping[index] then
12298     mapping[index]=unicode
12299    end
12300   end
12301   index=index+1
12302  end
12303 end
12304 return nofdone
12305end
12306formatreaders[13]=function(f,fontdata,offset)
12307 setposition(f,offset+2+2+4+4) 
12308 local mapping=fontdata.mapping
12309 local glyphs=fontdata.glyphs
12310 local duplicates=fontdata.duplicates
12311 local nofgroups=readulong(f)
12312 local nofdone=0
12313 for i=1,nofgroups do
12314  local first=readulong(f)
12315  local last=readulong(f)
12316  local index=readulong(f)
12317  if first<privateoffset then
12318   if trace_cmap_details then
12319    report_cmap("format 13 from %C to %C get index %i",first,last,index)
12320   end
12321   local glyph=glyphs[index]
12322   local unicode=glyph.unicode
12323   if not unicode then
12324    unicode=first
12325    glyph.unicode=unicode
12326    first=first+1
12327   end
12328   local list=duplicates[unicode]
12329   mapping[index]=unicode
12330   if not list then
12331    list={}
12332    duplicates[unicode]=list
12333   end
12334   if last>=privateoffset then
12335    local limit=privateoffset-1
12336    report("format 13 from %C to %C pruned to %C",first,last,limit)
12337    last=limit
12338   end
12339   for unicode=first,last do
12340    list[unicode]=true
12341   end
12342   nofdone=nofdone+last-first+1
12343  else
12344   report("format 13 from %C to %C ignored",first,last)
12345  end
12346 end
12347 return nofdone
12348end
12349formatreaders[14]=function(f,fontdata,offset)
12350 if offset and offset~=0 then
12351  setposition(f,offset)
12352  local format=readushort(f)
12353  local length=readulong(f)
12354  local nofrecords=readulong(f)
12355  local records={}
12356  local variants={}
12357  local nofdone=0
12358  fontdata.variants=variants
12359  for i=1,nofrecords do
12360   records[i]={
12361    selector=readuint(f),
12362    default=readulong(f),
12363    other=readulong(f),
12364   }
12365  end
12366  for i=1,nofrecords do
12367   local record=records[i]
12368   local selector=record.selector
12369   local default=record.default
12370   local other=record.other
12371   local other=record.other
12372   if other~=0 then
12373    setposition(f,offset+other)
12374    local mapping={}
12375    local count=readulong(f)
12376    for i=1,count do
12377     mapping[readuint(f)]=readushort(f)
12378    end
12379    nofdone=nofdone+count
12380    variants[selector]=mapping
12381   end
12382  end
12383  return nofdone
12384 else
12385  return 0
12386 end
12387end
12388local function checkcmap(f,fontdata,records,platform,encoding,format)
12389 local pdata=records[platform]
12390 if not pdata then
12391  if trace_cmap_details then
12392   report_cmap("skipped, %s, p=%i e=%i f=%i","no platform",platform,encoding,format)
12393  end
12394  return 0
12395 end
12396 local edata=pdata[encoding]
12397 if not edata then
12398  if trace_cmap_details then
12399   report_cmap("skipped, %s, p=%i e=%i f=%i","no encoding",platform,encoding,format)
12400  end
12401  return 0
12402 end
12403 local fdata=edata[format]
12404 if not fdata then
12405  if trace_cmap_details then
12406   report_cmap("skipped, %s, p=%i e=%i f=%i","no format",platform,encoding,format)
12407  end
12408  return 0
12409 elseif type(fdata)~="number" then
12410  if trace_cmap_details then
12411   report_cmap("skipped, %s, p=%i e=%i f=%i","already done",platform,encoding,format)
12412  end
12413  return 0
12414 end
12415 edata[format]=true 
12416 local reader=formatreaders[format]
12417 if not reader then
12418  if trace_cmap_details then
12419   report_cmap("skipped, %s, p=%i e=%i f=%i","unsupported format",platform,encoding,format)
12420  end
12421  return 0
12422 end
12423 local n=reader(f,fontdata,fdata) or 0
12424 if trace_cmap_details or trace_cmap then
12425  local p=platforms[platform]
12426  local e=encodings[p]
12427  report_cmap("checked, platform %i (%s), encoding %i (%s), format %i, new unicodes %i",
12428   platform,p,encoding,e and e[encoding] or "?",format,n)
12429 end
12430 return n
12431end
12432function readers.cmap(f,fontdata,specification)
12433 local tableoffset=gotodatatable(f,fontdata,"cmap",specification.glyphs)
12434 if tableoffset then
12435  local version=readushort(f) 
12436  local noftables=readushort(f)
12437  local records={}
12438  local unicodecid=false
12439  local variantcid=false
12440  local variants={}
12441  local duplicates=fontdata.duplicates or {}
12442  fontdata.duplicates=duplicates
12443  for i=1,noftables do
12444   local platform=readushort(f)
12445   local encoding=readushort(f)
12446   local offset=readulong(f)
12447   local record=records[platform]
12448   if not record then
12449    records[platform]={
12450     [encoding]={
12451      offsets={ offset },
12452      formats={},
12453     }
12454    }
12455   else
12456    local subtables=record[encoding]
12457    if not subtables then
12458     record[encoding]={
12459      offsets={ offset },
12460      formats={},
12461     }
12462    else
12463     local offsets=subtables.offsets
12464     offsets[#offsets+1]=offset
12465    end
12466   end
12467  end
12468  if trace_cmap then
12469   report("found cmaps:")
12470  end
12471  for platform,record in sortedhash(records) do
12472   local p=platforms[platform]
12473   local e=encodings[p]
12474   local sp=supported[platform]
12475   local ps=p or "?"
12476   if trace_cmap then
12477    if sp then
12478     report("  platform %i: %s",platform,ps)
12479    else
12480     report("  platform %i: %s (unsupported)",platform,ps)
12481    end
12482   end
12483   for encoding,subtables in sortedhash(record) do
12484    local se=sp and sp[encoding]
12485    local es=e and e[encoding] or "?"
12486    if trace_cmap then
12487     if se then
12488      report("    encoding %i: %s",encoding,es)
12489     else
12490      report("    encoding %i: %s (unsupported)",encoding,es)
12491     end
12492    end
12493    local offsets=subtables.offsets
12494    local formats=subtables.formats
12495    for i=1,#offsets do
12496     local offset=tableoffset+offsets[i]
12497     setposition(f,offset)
12498     formats[readushort(f)]=offset
12499    end
12500    record[encoding]=formats
12501    if trace_cmap then
12502     local list=sortedkeys(formats)
12503     for i=1,#list do
12504      if not (se and se[list[i]]) then
12505       list[i]=list[i].." (unsupported)"
12506      end
12507     end
12508     report("      formats: % t",list)
12509    end
12510   end
12511  end
12512  local ok=false
12513  for i=1,#sequence do
12514   local si=sequence[i]
12515   local sp,se,sf=si[1],si[2],si[3]
12516   if checkcmap(f,fontdata,records,sp,se,sf)>0 then
12517    ok=true
12518   end
12519  end
12520  if not ok then
12521   report("no useable unicode cmap found")
12522  end
12523  fontdata.cidmaps={
12524   version=version,
12525   noftables=noftables,
12526   records=records,
12527  }
12528 else
12529  fontdata.cidmaps={}
12530 end
12531end
12532function readers.loca(f,fontdata,specification)
12533 reportskippedtable(f,fontdata,"loca",specification.glyphs)
12534end
12535function readers.glyf(f,fontdata,specification) 
12536 reportskippedtable(f,fontdata,"glyf",specification.glyphs)
12537end
12538function readers.colr(f,fontdata,specification)
12539 reportskippedtable(f,fontdata,"colr",specification.glyphs)
12540end
12541function readers.cpal(f,fontdata,specification)
12542 reportskippedtable(f,fontdata,"cpal",specification.glyphs)
12543end
12544function readers.svg(f,fontdata,specification)
12545 reportskippedtable(f,fontdata,"svg",specification.glyphs)
12546end
12547function readers.sbix(f,fontdata,specification)
12548 reportskippedtable(f,fontdata,"sbix",specification.glyphs)
12549end
12550function readers.cbdt(f,fontdata,specification)
12551 reportskippedtable(f,fontdata,"cbdt",specification.glyphs)
12552end
12553function readers.cblc(f,fontdata,specification)
12554 reportskippedtable(f,fontdata,"cblc",specification.glyphs)
12555end
12556function readers.ebdt(f,fontdata,specification)
12557 reportskippedtable(f,fontdata,"ebdt",specification.glyphs)
12558end
12559function readers.ebsc(f,fontdata,specification)
12560 reportskippedtable(f,fontdata,"ebsc",specification.glyphs)
12561end
12562function readers.eblc(f,fontdata,specification)
12563 reportskippedtable(f,fontdata,"eblc",specification.glyphs)
12564end
12565function readers.kern(f,fontdata,specification)
12566 local tableoffset=gotodatatable(f,fontdata,"kern",specification.kerns)
12567 if tableoffset then
12568  local version=readushort(f)
12569  local noftables=readushort(f)
12570  for i=1,noftables do
12571   local version=readushort(f)
12572   local length=readushort(f)
12573   local coverage=readushort(f)
12574   local format=rshift(coverage,8) 
12575   if format==0 then
12576    local nofpairs=readushort(f)
12577    local searchrange=readushort(f)
12578    local entryselector=readushort(f)
12579    local rangeshift=readushort(f)
12580    local kerns={}
12581    local glyphs=fontdata.glyphs
12582    for i=1,nofpairs do
12583     local left=readushort(f)
12584     local right=readushort(f)
12585     local kern=readfword(f)
12586     local glyph=glyphs[left]
12587     local kerns=glyph.kerns
12588     if kerns then
12589      kerns[right]=kern
12590     else
12591      glyph.kerns={ [right]=kern }
12592     end
12593    end
12594   elseif format==2 then
12595    report("todo: kern classes")
12596   else
12597    report("todo: kerns")
12598   end
12599  end
12600 end
12601end
12602function readers.gdef(f,fontdata,specification)
12603 reportskippedtable(f,fontdata,"gdef",specification.details)
12604end
12605function readers.gsub(f,fontdata,specification)
12606 reportskippedtable(f,fontdata,"gsub",specification.details)
12607end
12608function readers.gpos(f,fontdata,specification)
12609 reportskippedtable(f,fontdata,"gpos",specification.details)
12610end
12611function readers.math(f,fontdata,specification)
12612 reportskippedtable(f,fontdata,"math",specification.details)
12613end
12614local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames)
12615 local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata
12616 local names=fontdata.names
12617 local info=nil
12618 if names then
12619  local metrics=fontdata.windowsmetrics or {}
12620  local postscript=fontdata.postscript  or {}
12621  local fontheader=fontdata.fontheader  or {}
12622  local cffinfo=fontdata.cffinfo  or {}
12623  local verticalheader=fontdata.verticalheader or {}
12624  local filename=fontdata.filename
12625  local weight=getname(fontdata,"weight") or (cffinfo and cffinfo.weight) or (metrics and metrics.weight)
12626  local width=getname(fontdata,"width")  or (cffinfo and cffinfo.width ) or (metrics and metrics.width )
12627  local fontname=getname(fontdata,"postscriptname")
12628  local fullname=getname(fontdata,"fullname")
12629  local family=getname(fontdata,"family")
12630  local subfamily=getname(fontdata,"subfamily")
12631  local familyname=getname(fontdata,"typographicfamily")
12632  local subfamilyname=getname(fontdata,"typographicsubfamily")
12633  local compatiblename=getname(fontdata,"compatiblefullname") 
12634  if rawfamilynames then
12635  else
12636   if not familyname then familyname=family end
12637   if not subfamilyname then subfamilyname=subfamily end
12638  end
12639  if platformnames then
12640   platformnames=fontdata.platformnames
12641  end
12642  if instancenames then
12643   local variabledata=fontdata.variabledata
12644   if variabledata then
12645    local instances=variabledata and variabledata.instances
12646    if instances then
12647     instancenames={}
12648     for i=1,#instances do
12649      instancenames[i]=lower(stripstring(instances[i].subfamily))
12650     end
12651    else
12652     instancenames=nil
12653    end
12654   else
12655    instancenames=nil
12656   end
12657  end
12658  info={ 
12659   subfontindex=fontdata.subfontindex or sub or 0,
12660   version=getname(fontdata,"version"),
12661   fontname=fontname,
12662   fullname=fullname,
12663   family=family,
12664   subfamily=subfamily,
12665   familyname=familyname,
12666   subfamilyname=subfamilyname,
12667   compatiblename=compatiblename,
12668   weight=weight and lower(weight),
12669   width=width and lower(width),
12670   pfmweight=metrics.weightclass or 400,
12671   pfmwidth=metrics.widthclass or 5,
12672   panosewidth=metrics.panosewidth,
12673   panoseweight=metrics.panoseweight,
12674   fstype=metrics.fstype or 0,
12675   italicangle=postscript.italicangle or 0,
12676   units=fontheader.units or 0,
12677   designsize=fontdata.designsize,
12678   minsize=fontdata.minsize,
12679   maxsize=fontdata.maxsize,
12680   boundingbox=fontheader and { fontheader.xmin or 0,fontheader.ymin or 0,fontheader.xmax or 0,fontheader.ymax or 0 } or nil,
12681   monospaced=(tonumber(postscript.monospaced or 0)>0) or metrics.panosewidth=="monospaced",
12682   averagewidth=metrics.averagewidth,
12683   xheight=metrics.xheight,
12684   capheight=metrics.capheight or fontdata.maxy,
12685   ascender=metrics.typoascender,
12686   descender=metrics.typodescender,
12687   ascent=metrics.winascent,
12688   descent=metrics.windescent,
12689   platformnames=platformnames or nil,
12690   instancenames=instancenames or nil,
12691   tableoffsets=fontdata.tableoffsets,
12692   defaultvheight=(verticalheader.ascender or 0)-(verticalheader.descender or 0)
12693  }
12694  if metricstoo then
12695   local keys={
12696    "version",
12697    "ascender","descender","linegap",
12698    "maxadvancewidth","maxadvanceheight","maxextent",
12699    "minbottomsidebearing","mintopsidebearing",
12700   }
12701   local h=fontdata.horizontalheader or {}
12702   local v=fontdata.verticalheader   or {}
12703   if h then
12704    local th={}
12705    local tv={}
12706    for i=1,#keys do
12707     local key=keys[i]
12708     th[key]=h[key] or 0
12709     tv[key]=v[key] or 0
12710    end
12711    info.horizontalmetrics=th
12712    info.verticalmetrics=tv
12713   end
12714  end
12715 elseif n then
12716  info={
12717   filename=fontdata.filename,
12718   comment="there is no info for subfont "..n,
12719  }
12720 else
12721  info={
12722   filename=fontdata.filename,
12723   comment="there is no info",
12724  }
12725 end
12726 return info
12727end
12728local function loadtables(f,specification,offset)
12729 if offset then
12730  setposition(f,offset)
12731 end
12732 local tables={}
12733 local basename=file.basename(specification.filename)
12734 local filesize=specification.filesize
12735 local filetime=specification.filetime
12736 local fontdata={ 
12737  filename=basename,
12738  filesize=filesize,
12739  filetime=filetime,
12740  version=readstring(f,4),
12741  noftables=readushort(f),
12742  searchrange=readushort(f),
12743  entryselector=readushort(f),
12744  rangeshift=readushort(f),
12745  tables=tables,
12746  foundtables=false,
12747 }
12748 for i=1,fontdata.noftables do
12749  local tag=lower(stripstring(readstring(f,4)))
12750  local checksum=readushort(f)*0x10000+readushort(f)
12751  local offset=readulong(f)
12752  local length=readulong(f)
12753  if offset+length>filesize then
12754   report("bad %a table in file %a",tag,basename)
12755  end
12756  tables[tag]={
12757   checksum=checksum,
12758   offset=offset,
12759   length=length,
12760  }
12761 end
12762 fontdata.foundtables=sortedkeys(tables)
12763 if tables.cff or tables.cff2 then
12764  fontdata.format="opentype"
12765 else
12766  fontdata.format="truetype"
12767 end
12768 return fontdata,tables
12769end
12770local function prepareglyps(fontdata)
12771 local glyphs=setmetatableindex(function(t,k)
12772  local v={
12773   index=k,
12774  }
12775  t[k]=v
12776  return v
12777 end)
12778 fontdata.glyphs=glyphs
12779 fontdata.mapping={}
12780end
12781local function readtable(tag,f,fontdata,specification,...)
12782 local reader=readers[tag]
12783 if reader then
12784  reader(f,fontdata,specification,...)
12785 end
12786end
12787local function readdata(f,offset,specification)
12788 local fontdata,tables=loadtables(f,specification,offset)
12789 if specification.glyphs then
12790  prepareglyps(fontdata)
12791 end
12792 fontdata.temporary={}
12793 readtable("name",f,fontdata,specification)
12794 local askedname=specification.askedname
12795 if askedname then
12796  local fullname=getname(fontdata,"fullname") or ""
12797  local cleanname=gsub(askedname,"[^a-zA-Z0-9]","")
12798  local foundname=gsub(fullname,"[^a-zA-Z0-9]","")
12799  if lower(cleanname)~=lower(foundname) then
12800   return 
12801  end
12802 end
12803 readtable("stat",f,fontdata,specification)
12804 readtable("avar",f,fontdata,specification)
12805 readtable("fvar",f,fontdata,specification)
12806 local variabledata=fontdata.variabledata
12807 if variabledata then
12808  local instances=variabledata.instances
12809  local axis=variabledata.axis
12810  if axis and (not instances or #instances==0) then
12811   instances={}
12812   variabledata.instances=instances
12813   local function add(n,subfamily,value)
12814    local values={}
12815    for i=1,#axis do
12816     local a=axis[i]
12817     values[i]={
12818      axis=a.tag,
12819      value=i==n and value or a.default,
12820     }
12821    end
12822    instances[#instances+1]={
12823     subfamily=subfamily,
12824     values=values,
12825    }
12826   end
12827   for i=1,#axis do
12828    local a=axis[i]
12829    local tag=a.tag
12830    add(i,"default"..tag,a.default)
12831    add(i,"minimum"..tag,a.minimum)
12832    add(i,"maximum"..tag,a.maximum)
12833   end
12834  end
12835 end
12836 if not specification.factors then
12837  local instance=specification.instance
12838  if type(instance)=="string" then
12839   local factors=helpers.getfactors(fontdata,instance)
12840   if factors then
12841    specification.factors=factors
12842    fontdata.factors=factors
12843    fontdata.instance=instance
12844    report("user instance: %s, factors: % t",instance,factors)
12845   else
12846    report("user instance: %s, bad factors",instance)
12847   end
12848  end
12849 end
12850 if not fontdata.factors then
12851  if fontdata.variabledata then
12852   local factors=helpers.getfactors(fontdata,true)
12853   if factors then
12854    specification.factors=factors
12855    fontdata.factors=factors
12856   end
12857  else
12858  end
12859 end
12860 readtable("os/2",f,fontdata,specification)
12861 readtable("head",f,fontdata,specification)
12862 readtable("maxp",f,fontdata,specification)
12863 readtable("hhea",f,fontdata,specification)
12864 readtable("vhea",f,fontdata,specification)
12865 readtable("hmtx",f,fontdata,specification)
12866 readtable("vmtx",f,fontdata,specification)
12867 readtable("vorg",f,fontdata,specification)
12868 readtable("post",f,fontdata,specification)
12869 readtable("mvar",f,fontdata,specification)
12870 readtable("hvar",f,fontdata,specification)
12871 readtable("vvar",f,fontdata,specification)
12872 readtable("gdef",f,fontdata,specification)
12873 readtable("cff",f,fontdata,specification)
12874 readtable("cff2",f,fontdata,specification)
12875 readtable("cmap",f,fontdata,specification)
12876 readtable("loca",f,fontdata,specification) 
12877 readtable("glyf",f,fontdata,specification) 
12878 readtable("colr",f,fontdata,specification)
12879 readtable("cpal",f,fontdata,specification)
12880 readtable("svg",f,fontdata,specification)
12881 readtable("sbix",f,fontdata,specification)
12882 readtable("cbdt",f,fontdata,specification)
12883 readtable("cblc",f,fontdata,specification)
12884 readtable("ebdt",f,fontdata,specification)
12885 readtable("eblc",f,fontdata,specification)
12886 readtable("kern",f,fontdata,specification)
12887 readtable("gsub",f,fontdata,specification)
12888 readtable("gpos",f,fontdata,specification)
12889 readtable("math",f,fontdata,specification)
12890 fontdata.locations=nil
12891 fontdata.cidmaps=nil
12892 fontdata.dictionaries=nil
12893 if specification.tableoffsets then
12894  fontdata.tableoffsets=tables
12895  setmetatableindex(tables,{
12896   version=fontdata.version,
12897   noftables=fontdata.noftables,
12898   searchrange=fontdata.searchrange,
12899   entryselector=fontdata.entryselector,
12900   rangeshift=fontdata.rangeshift,
12901  })
12902 end
12903 return fontdata
12904end
12905local function loadfontdata(specification)
12906 local filename=specification.filename
12907 local fileattr=lfs.attributes(filename)
12908 local filesize=fileattr and fileattr.size or 0
12909 local filetime=fileattr and fileattr.modification or 0
12910 local f=openfile(filename,true) 
12911 if not f then
12912  report("unable to open %a",filename)
12913 elseif filesize==0 then
12914  report("empty file %a",filename)
12915  closefile(f)
12916 else
12917  specification.filesize=filesize
12918  specification.filetime=filetime
12919  local version=readstring(f,4)
12920  local fontdata=nil
12921  if version=="OTTO" or version=="true" or version=="\0\1\0\0" then
12922   fontdata=readdata(f,0,specification)
12923  elseif version=="ttcf" then
12924   local subfont=tonumber(specification.subfont)
12925   local ttcversion=readulong(f)
12926   local nofsubfonts=readulong(f)
12927   local offsets=readcardinaltable(f,nofsubfonts,ulong)
12928   if subfont then 
12929    if subfont>=1 and subfont<=nofsubfonts then
12930     fontdata=readdata(f,offsets[subfont],specification)
12931    else
12932     report("no subfont %a in file %a",subfont,filename)
12933    end
12934   else
12935    subfont=specification.subfont
12936    if type(subfont)=="string" and subfont~="" then
12937     specification.askedname=subfont
12938     for i=1,nofsubfonts do
12939      fontdata=readdata(f,offsets[i],specification)
12940      if fontdata then
12941       fontdata.subfontindex=i
12942       report("subfont named %a has index %a",subfont,i)
12943       break
12944      end
12945     end
12946     if not fontdata then
12947      report("no subfont named %a",subfont)
12948     end
12949    else
12950     local subfonts={}
12951     fontdata={
12952      filename=filename,
12953      filesize=filesize,
12954      filetime=filetime,
12955      version=version,
12956      subfonts=subfonts,
12957      ttcversion=ttcversion,
12958      nofsubfonts=nofsubfonts,
12959     }
12960     for i=1,nofsubfonts do
12961      subfonts[i]=readdata(f,offsets[i],specification)
12962     end
12963    end
12964   end
12965  else
12966   report("unknown version %a in file %a",version,filename)
12967  end
12968  closefile(f)
12969  return fontdata or {}
12970 end
12971end
12972local function loadfont(specification,n,instance)
12973 if type(specification)=="string" then
12974  specification={
12975   filename=specification,
12976   info=true,
12977   details=true,
12978   glyphs=true,
12979   shapes=true,
12980   kerns=true,
12981   variable=true,
12982   globalkerns=true,
12983   lookups=true,
12984   subfont=n or true,
12985   tounicode=false,
12986   instance=instance
12987  }
12988 end
12989 if specification.shapes or specification.lookups or specification.kerns then
12990  specification.glyphs=true
12991 end
12992 if specification.glyphs then
12993  specification.details=true
12994 end
12995 if specification.details then
12996  specification.info=true 
12997 end
12998 if specification.platformnames then
12999  specification.platformnames=true 
13000 end
13001 if specification.instance or instance then
13002  specification.variable=true
13003  specification.instance=specification.instance or instance
13004 end
13005 local function message(str)
13006  report("fatal error in file %a: %s\n%s",specification.filename,str,debug and debug.traceback())
13007 end
13008 local ok,result=xpcall(loadfontdata,message,specification)
13009 if ok then
13010  return result
13011 end
13012end
13013function readers.loadshapes(filename,n,instance,streams)
13014 local fontdata=loadfont {
13015  filename=filename,
13016  shapes=true,
13017  streams=streams,
13018  variable=true,
13019  subfont=n,
13020  instance=instance,
13021 }
13022 if fontdata then
13023  for k,v in next,fontdata.glyphs do
13024   v.class=nil
13025   v.index=nil
13026   v.math=nil
13027  end
13028  local names=fontdata.names
13029  if names then
13030   for k,v in next,names do
13031    names[k]=fullstrip(v.content)
13032   end
13033  end
13034 end
13035 return fontdata and {
13036  filename=filename,
13037  format=fontdata.format,
13038  glyphs=fontdata.glyphs,
13039  units=fontdata.fontheader.units,
13040  cffinfo=fontdata.cffinfo,
13041  fontheader=fontdata.fontheader,
13042  horizontalheader=fontdata.horizontalheader,
13043  verticalheader=fontdata.verticalheader,
13044  maximumprofile=fontdata.maximumprofile,
13045  names=fontdata.names,
13046  postscript=fontdata.postscript,
13047 } or {
13048  filename=filename,
13049  format="unknown",
13050  glyphs={},
13051  units=0,
13052 }
13053end
13054function readers.loadfont(filename,n,instance)
13055 local fontdata=loadfont {
13056  filename=filename,
13057  glyphs=true,
13058  shapes=false,
13059  lookups=true,
13060  variable=true,
13061  subfont=n,
13062  instance=instance,
13063 }
13064 if fontdata then
13065  return {
13066   tableversion=tableversion,
13067   creator="context mkiv",
13068   size=fontdata.filesize,
13069   time=fontdata.filetime,
13070   glyphs=fontdata.glyphs,
13071   descriptions=fontdata.descriptions,
13072   format=fontdata.format,
13073   goodies={},
13074   metadata=getinfo(fontdata,n,false,false,true,true),
13075   properties={
13076    hasitalics=fontdata.hasitalics or false,
13077    maxcolorclass=fontdata.maxcolorclass,
13078    hascolor=fontdata.hascolor or false,
13079    instance=fontdata.instance,
13080    factors=fontdata.factors,
13081    nofsubfonts=fontdata.subfonts and #fontdata.subfonts or nil,
13082   },
13083   resources={
13084    filename=filename,
13085    private=privateoffset,
13086    duplicates=fontdata.duplicates  or {},
13087    features=fontdata.features or {},
13088    sublookups=fontdata.sublookups  or {},
13089    marks=fontdata.marks    or {},
13090    markclasses=fontdata.markclasses or {},
13091    marksets=fontdata.marksets or {},
13092    sequences=fontdata.sequences   or {},
13093    variants=fontdata.variants,
13094    version=getname(fontdata,"version"),
13095    cidinfo=fontdata.cidinfo,
13096    mathconstants=fontdata.mathconstants,
13097    colorpalettes=fontdata.colorpalettes,
13098    colorpaintdata=fontdata.colorpaintdata,
13099    colorpaintlist=fontdata.colorpaintlist,
13100    colorlinesdata=fontdata.colorlinesdata,
13101    coloraffinedata=fontdata.coloraffinedata,
13102    svgshapes=fontdata.svgshapes,
13103    pngshapes=fontdata.pngshapes,
13104    variabledata=fontdata.variabledata,
13105    foundtables=fontdata.foundtables,
13106   },
13107  }
13108 end
13109end
13110function readers.getinfo(filename,specification)
13111 local subfont=nil
13112 local platformnames=false
13113 local rawfamilynames=false
13114 local instancenames=true
13115 local tableoffsets=false
13116 if type(specification)=="table" then
13117  subfont=tonumber(specification.subfont)
13118  platformnames=specification.platformnames
13119  rawfamilynames=specification.rawfamilynames
13120  tableoffsets=specification.tableoffsets
13121 else
13122  subfont=tonumber(specification)
13123 end
13124 local fontdata=loadfont {
13125  filename=filename,
13126  details=true,
13127  platformnames=platformnames,
13128  instancenames=true,
13129  tableoffsets=tableoffsets,
13130 }
13131 if fontdata then
13132  local subfonts=fontdata.subfonts
13133  if not subfonts then
13134   return getinfo(fontdata,nil,platformnames,rawfamilynames,false,instancenames)
13135  elseif not subfont then
13136   local info={}
13137   for i=1,#subfonts do
13138    info[i]=getinfo(fontdata,i,platformnames,rawfamilynames,false,instancenames)
13139   end
13140   return info
13141  elseif subfont>=1 and subfont<=#subfonts then
13142   return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames)
13143  else
13144   return {
13145    filename=filename,
13146    comment="there is no subfont "..subfont.." in this file"
13147   }
13148  end
13149 else
13150  return {
13151   filename=filename,
13152   comment="the file cannot be opened for reading",
13153  }
13154 end
13155end
13156function readers.rehash() 
13157 report("the %a helper is not yet implemented","rehash")
13158end
13159function readers.checkhash() 
13160 report("the %a helper is not yet implemented","checkhash")
13161end
13162function readers.pack() 
13163 report("the %a helper is not yet implemented","pack")
13164end
13165function readers.unpack(fontdata)
13166 report("the %a helper is not yet implemented","unpack")
13167end
13168function readers.expand(fontdata)
13169 report("the %a helper is not yet implemented","unpack")
13170end
13171function readers.compact(fontdata)
13172 report("the %a helper is not yet implemented","compact")
13173end
13174function readers.condense(fontdata)
13175 report("the %a helper is not yet implemented","condense")
13176end
13177local extenders={}
13178function readers.registerextender(extender)
13179 extenders[#extenders+1]=extender
13180end
13181function readers.extend(fontdata)
13182 for i=1,#extenders do
13183  local extender=extenders[i]
13184  local name=extender.name or "unknown"
13185  local action=extender.action
13186  if action then
13187   action(fontdata)
13188  end
13189 end
13190end
13191
13192end -- closure
13193
13194do -- begin closure to overcome local limits and interference
13195
13196if not modules then modules={} end modules ['font-cff']={
13197 version=1.001,
13198 optimize=true,
13199 comment="companion to font-ini.mkiv",
13200 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
13201 copyright="PRAGMA ADE / ConTeXt Development Team",
13202 license="see context related readme files"
13203}
13204local next,type,tonumber,rawget=next,type,tonumber,rawget
13205local byte,char,gmatch,sub=string.byte,string.char,string.gmatch,string.sub
13206local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack
13207local floor,abs,round,ceil,min,max=math.floor,math.abs,math.round,math.ceil,math.min,math.max
13208local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct
13209local lpegmatch=lpeg.match
13210local formatters=string.formatters
13211local bytetable=string.bytetable
13212local idiv=number.idiv
13213local rshift,band,extract=bit32.rshift,bit32.band,bit32.extract
13214local readers=fonts.handlers.otf.readers
13215local streamreader=readers.streamreader
13216local readstring=streamreader.readstring
13217local readbyte=streamreader.readcardinal1  
13218local readushort=streamreader.readcardinal2  
13219local readuint=streamreader.readcardinal3  
13220local readulong=streamreader.readcardinal4  
13221local setposition=streamreader.setposition
13222local getposition=streamreader.getposition
13223local readbytetable=streamreader.readbytetable
13224directives.register("fonts.streamreader",function()
13225 streamreader=utilities.streams
13226 readstring=streamreader.readstring
13227 readbyte=streamreader.readcardinal1
13228 readushort=streamreader.readcardinal2
13229 readuint=streamreader.readcardinal3
13230 readulong=streamreader.readcardinal4
13231 setposition=streamreader.setposition
13232 getposition=streamreader.getposition
13233 readbytetable=streamreader.readbytetable
13234end)
13235local setmetatableindex=table.setmetatableindex
13236local trace_charstrings=false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings=v end)
13237local report=logs.reporter("otf reader","cff")
13238local parsedictionaries
13239local parsecharstring
13240local parsecharstrings
13241local resetcharstrings
13242local parseprivates
13243local startparsing
13244local stopparsing
13245local defaultstrings={ [0]=
13246 ".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
13247 "ampersand","quoteright","parenleft","parenright","asterisk","plus",
13248 "comma","hyphen","period","slash","zero","one","two","three","four",
13249 "five","six","seven","eight","nine","colon","semicolon","less",
13250 "equal","greater","question","at","A","B","C","D","E","F","G","H",
13251 "I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W",
13252 "X","Y","Z","bracketleft","backslash","bracketright","asciicircum",
13253 "underscore","quoteleft","a","b","c","d","e","f","g","h","i","j",
13254 "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y",
13255 "z","braceleft","bar","braceright","asciitilde","exclamdown","cent",
13256 "sterling","fraction","yen","florin","section","currency",
13257 "quotesingle","quotedblleft","guillemotleft","guilsinglleft",
13258 "guilsinglright","fi","fl","endash","dagger","daggerdbl",
13259 "periodcentered","paragraph","bullet","quotesinglbase","quotedblbase",
13260 "quotedblright","guillemotright","ellipsis","perthousand","questiondown",
13261 "grave","acute","circumflex","tilde","macron","breve","dotaccent",
13262 "dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash",
13263 "AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae",
13264 "dotlessi","lslash","oslash","oe","germandbls","onesuperior",
13265 "logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn",
13266 "onequarter","divide","brokenbar","degree","thorn","threequarters",
13267 "twosuperior","registered","minus","eth","multiply","threesuperior",
13268 "copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring",
13269 "Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave",
13270 "Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute",
13271 "Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute",
13272 "Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron",
13273 "aacute","acircumflex","adieresis","agrave","aring","atilde",
13274 "ccedilla","eacute","ecircumflex","edieresis","egrave","iacute",
13275 "icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex",
13276 "odieresis","ograve","otilde","scaron","uacute","ucircumflex",
13277 "udieresis","ugrave","yacute","ydieresis","zcaron","exclamsmall",
13278 "Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall",
13279 "Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader",
13280 "onedotenleader","zerooldstyle","oneoldstyle","twooldstyle",
13281 "threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle",
13282 "sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior",
13283 "threequartersemdash","periodsuperior","questionsmall","asuperior",
13284 "bsuperior","centsuperior","dsuperior","esuperior","isuperior",
13285 "lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior",
13286 "tsuperior","ff","ffi","ffl","parenleftinferior","parenrightinferior",
13287 "Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall",
13288 "Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall",
13289 "Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall",
13290 "Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall",
13291 "Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah",
13292 "Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall",
13293 "Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall",
13294 "Dotaccentsmall","Macronsmall","figuredash","hypheninferior",
13295 "Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth",
13296 "threeeighths","fiveeighths","seveneighths","onethird","twothirds",
13297 "zerosuperior","foursuperior","fivesuperior","sixsuperior",
13298 "sevensuperior","eightsuperior","ninesuperior","zeroinferior",
13299 "oneinferior","twoinferior","threeinferior","fourinferior",
13300 "fiveinferior","sixinferior","seveninferior","eightinferior",
13301 "nineinferior","centinferior","dollarinferior","periodinferior",
13302 "commainferior","Agravesmall","Aacutesmall","Acircumflexsmall",
13303 "Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall",
13304 "Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall",
13305 "Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall",
13306 "Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall",
13307 "Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall",
13308 "Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall",
13309 "Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003",
13310 "Black","Bold","Book","Light","Medium","Regular","Roman","Semibold",
13311}
13312local standardnames={ [0]=
13313 false,false,false,false,false,false,false,false,false,false,false,
13314 false,false,false,false,false,false,false,false,false,false,false,
13315 false,false,false,false,false,false,false,false,false,false,
13316 "space","exclam","quotedbl","numbersign","dollar","percent",
13317 "ampersand","quoteright","parenleft","parenright","asterisk","plus",
13318 "comma","hyphen","period","slash","zero","one","two","three","four",
13319 "five","six","seven","eight","nine","colon","semicolon","less",
13320 "equal","greater","question","at","A","B","C","D","E","F","G","H",
13321 "I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W",
13322 "X","Y","Z","bracketleft","backslash","bracketright","asciicircum",
13323 "underscore","quoteleft","a","b","c","d","e","f","g","h","i","j",
13324 "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y",
13325 "z","braceleft","bar","braceright","asciitilde",false,false,false,
13326 false,false,false,false,false,false,false,false,false,false,false,
13327 false,false,false,false,false,false,false,false,false,false,false,
13328 false,false,false,false,false,false,false,false,false,"exclamdown",
13329 "cent","sterling","fraction","yen","florin","section","currency",
13330 "quotesingle","quotedblleft","guillemotleft","guilsinglleft",
13331 "guilsinglright","fi","fl",false,"endash","dagger","daggerdbl",
13332 "periodcentered",false,"paragraph","bullet","quotesinglbase",
13333 "quotedblbase","quotedblright","guillemotright","ellipsis","perthousand",
13334 false,"questiondown",false,"grave","acute","circumflex","tilde",
13335 "macron","breve","dotaccent","dieresis",false,"ring","cedilla",false,
13336 "hungarumlaut","ogonek","caron","emdash",false,false,false,false,
13337 false,false,false,false,false,false,false,false,false,false,false,
13338 false,"AE",false,"ordfeminine",false,false,false,false,"Lslash",
13339 "Oslash","OE","ordmasculine",false,false,false,false,false,"ae",
13340 false,false,false,"dotlessi",false,false,"lslash","oslash","oe",
13341 "germandbls",false,false,false,false
13342}
13343local cffreaders={
13344 readbyte,
13345 readushort,
13346 readuint,
13347 readulong,
13348}
13349directives.register("fonts.streamreader",function()
13350 cffreaders={
13351  readbyte,
13352  readushort,
13353  readuint,
13354  readulong,
13355 }
13356end)
13357local function readheader(f)
13358 local offset=getposition(f)
13359 local major=readbyte(f)
13360 local header={
13361  offset=offset,
13362  major=major,
13363  minor=readbyte(f),
13364  size=readbyte(f),
13365 }
13366 if major==1 then
13367  header.dsize=readbyte(f)   
13368 elseif major==2 then
13369  header.dsize=readushort(f) 
13370 else
13371 end
13372 setposition(f,offset+header.size)
13373 return header
13374end
13375local function readlengths(f,longcount)
13376 local count=longcount and readulong(f) or readushort(f)
13377 if count==0 then
13378  return {}
13379 end
13380 local osize=readbyte(f)
13381 local read=cffreaders[osize]
13382 if not read then
13383  report("bad offset size: %i",osize)
13384  return {}
13385 end
13386 local lengths={}
13387 local previous=read(f)
13388 for i=1,count do
13389  local offset=read(f)
13390  local length=offset-previous
13391  if length<0 then
13392   report("bad offset: %i",length)
13393   length=0
13394  end
13395  lengths[i]=length
13396  previous=offset
13397 end
13398 return lengths
13399end
13400local function readfontnames(f)
13401 local names=readlengths(f)
13402 for i=1,#names do
13403  names[i]=readstring(f,names[i])
13404 end
13405 return names
13406end
13407local function readtopdictionaries(f)
13408 local dictionaries=readlengths(f)
13409 for i=1,#dictionaries do
13410  dictionaries[i]=readstring(f,dictionaries[i])
13411 end
13412 return dictionaries
13413end
13414local function readstrings(f)
13415 local lengths=readlengths(f)
13416 local strings=setmetatableindex({},defaultstrings)
13417 local index=#defaultstrings
13418 for i=1,#lengths do
13419  index=index+1
13420  strings[index]=readstring(f,lengths[i])
13421 end
13422 return strings
13423end
13424do
13425 local stack={}
13426 local top=0
13427 local result={}
13428 local strings={}
13429 local p_single=P("\00")/function()
13430   result.version=strings[stack[top]] or "unset"
13431   top=0
13432  end+P("\01")/function()
13433   result.notice=strings[stack[top]] or "unset"
13434   top=0
13435  end+P("\02")/function()
13436   result.fullname=strings[stack[top]] or "unset"
13437   top=0
13438  end+P("\03")/function()
13439   result.familyname=strings[stack[top]] or "unset"
13440   top=0
13441  end+P("\04")/function()
13442   result.weight=strings[stack[top]] or "unset"
13443   top=0
13444  end+P("\05")/function()
13445   result.fontbbox={ unpack(stack,1,4) }
13446   top=0
13447  end+P("\06")/function()
13448   result.bluevalues={ unpack(stack,1,top) }
13449   top=0
13450  end+P("\07")/function()
13451   result.otherblues={ unpack(stack,1,top) }
13452   top=0
13453  end+P("\08")/function()
13454   result.familyblues={ unpack(stack,1,top) }
13455   top=0
13456  end+P("\09")/function()
13457   result.familyotherblues={ unpack(stack,1,top) }
13458   top=0
13459  end+P("\10")/function()
13460   result.stdhw=stack[top]
13461   top=0
13462  end+P("\11")/function()
13463   result.stdvw=stack[top]
13464   top=0
13465  end+P("\13")/function()
13466   result.uniqueid=stack[top]
13467   top=0
13468  end+P("\14")/function()
13469   result.xuid=concat(stack,"",1,top)
13470   top=0
13471  end+P("\15")/function()
13472   result.charset=stack[top]
13473   top=0
13474  end+P("\16")/function()
13475   result.encoding=stack[top]
13476   top=0
13477  end+P("\17")/function() 
13478   result.charstrings=stack[top]
13479   top=0
13480  end+P("\18")/function()
13481   result.private={
13482    size=stack[top-1],
13483    offset=stack[top],
13484   }
13485   top=0
13486  end+P("\19")/function()
13487   result.subroutines=stack[top]
13488   top=0 
13489  end+P("\20")/function()
13490   result.defaultwidthx=stack[top]
13491   top=0 
13492  end+P("\21")/function()
13493   result.nominalwidthx=stack[top]
13494   top=0 
13495  end
13496+P("\24")/function() 
13497   result.vstore=stack[top]
13498   top=0
13499  end+P("\25")/function() 
13500   result.maxstack=stack[top]
13501   top=0
13502  end
13503 local p_double=P("\12")*(
13504  P("\00")/function()
13505   result.copyright=stack[top]
13506   top=0
13507  end+P("\01")/function()
13508   result.monospaced=stack[top]==1 and true or false 
13509   top=0
13510  end+P("\02")/function()
13511   result.italicangle=stack[top]
13512   top=0
13513  end+P("\03")/function()
13514   result.underlineposition=stack[top]
13515   top=0
13516  end+P("\04")/function()
13517   result.underlinethickness=stack[top]
13518   top=0
13519  end+P("\05")/function()
13520   result.painttype=stack[top]
13521   top=0
13522  end+P("\06")/function()
13523   result.charstringtype=stack[top]
13524   top=0
13525  end+P("\07")/function() 
13526   result.fontmatrix={ unpack(stack,1,6) }
13527   top=0
13528  end+P("\08")/function()
13529   result.strokewidth=stack[top]
13530   top=0
13531  end+P("\09")/function()
13532   result.bluescale=stack[top]
13533   top=0
13534  end+P("\10")/function()
13535   result.blueshift=stack[top]
13536   top=0
13537  end+P("\11")/function()
13538   result.bluefuzz=stack[top]
13539   top=0
13540  end+P("\12")/function()
13541   result.stemsnaph={ unpack(stack,1,top) }
13542   top=0
13543  end+P("\13")/function()
13544   result.stemsnapv={ unpack(stack,1,top) }
13545   top=0
13546  end+P("\20")/function()
13547   result.syntheticbase=stack[top]
13548   top=0
13549  end+P("\21")/function()
13550   result.postscript=strings[stack[top]] or "unset"
13551   top=0
13552  end+P("\22")/function()
13553   result.basefontname=strings[stack[top]] or "unset"
13554   top=0
13555  end+P("\21")/function()
13556   result.basefontblend=stack[top]
13557   top=0
13558  end+P("\30")/function()
13559   result.cid.registry=strings[stack[top-2]] or "unset"
13560   result.cid.ordering=strings[stack[top-1]] or "unset"
13561   result.cid.supplement=stack[top]
13562   top=0
13563  end+P("\31")/function()
13564   result.cid.fontversion=stack[top]
13565   top=0
13566  end+P("\32")/function()
13567   result.cid.fontrevision=stack[top]
13568   top=0
13569  end+P("\33")/function()
13570   result.cid.fonttype=stack[top]
13571   top=0
13572  end+P("\34")/function()
13573   result.cid.count=stack[top]
13574   top=0
13575  end+P("\35")/function()
13576   result.cid.uidbase=stack[top]
13577   top=0
13578  end+P("\36")/function() 
13579   result.cid.fdarray=stack[top]
13580   top=0
13581  end+P("\37")/function() 
13582   result.cid.fdselect=stack[top]
13583   top=0
13584  end+P("\38")/function()
13585   result.cid.fontname=strings[stack[top]] or "unset"
13586   top=0
13587  end
13588 )
13589 local remap_1={
13590  ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0",
13591  ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="1.",["\x1B"]="1E",["\x1C"]="1E-",["\x1D"]="1",["\x1E"]="1-",["\x1F"]="1",
13592  ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="2.",["\x2B"]="2E",["\x2C"]="2E-",["\x2D"]="2",["\x2E"]="2-",["\x2F"]="2",
13593  ["\x30"]="30",["\x31"]="31",["\x32"]="32",["\x33"]="33",["\x34"]="34",["\x35"]="35",["\x36"]="36",["\x37"]="37",["\x38"]="38",["\x39"]="39",["\x3A"]="3.",["\x3B"]="3E",["\x3C"]="3E-",["\x3D"]="3",["\x3E"]="3-",["\x3F"]="3",
13594  ["\x40"]="40",["\x41"]="41",["\x42"]="42",["\x43"]="43",["\x44"]="44",["\x45"]="45",["\x46"]="46",["\x47"]="47",["\x48"]="48",["\x49"]="49",["\x4A"]="4.",["\x4B"]="4E",["\x4C"]="4E-",["\x4D"]="4",["\x4E"]="4-",["\x4F"]="4",
13595  ["\x50"]="50",["\x51"]="51",["\x52"]="52",["\x53"]="53",["\x54"]="54",["\x55"]="55",["\x56"]="56",["\x57"]="57",["\x58"]="58",["\x59"]="59",["\x5A"]="5.",["\x5B"]="5E",["\x5C"]="5E-",["\x5D"]="5",["\x5E"]="5-",["\x5F"]="5",
13596  ["\x60"]="60",["\x61"]="61",["\x62"]="62",["\x63"]="63",["\x64"]="64",["\x65"]="65",["\x66"]="66",["\x67"]="67",["\x68"]="68",["\x69"]="69",["\x6A"]="6.",["\x6B"]="6E",["\x6C"]="6E-",["\x6D"]="6",["\x6E"]="6-",["\x6F"]="6",
13597  ["\x70"]="70",["\x71"]="71",["\x72"]="72",["\x73"]="73",["\x74"]="74",["\x75"]="75",["\x76"]="76",["\x77"]="77",["\x78"]="78",["\x79"]="79",["\x7A"]="7.",["\x7B"]="7E",["\x7C"]="7E-",["\x7D"]="7",["\x7E"]="7-",["\x7F"]="7",
13598  ["\x80"]="80",["\x81"]="81",["\x82"]="82",["\x83"]="83",["\x84"]="84",["\x85"]="85",["\x86"]="86",["\x87"]="87",["\x88"]="88",["\x89"]="89",["\x8A"]="8.",["\x8B"]="8E",["\x8C"]="8E-",["\x8D"]="8",["\x8E"]="8-",["\x8F"]="8",
13599  ["\x90"]="90",["\x91"]="91",["\x92"]="92",["\x93"]="93",["\x94"]="94",["\x95"]="95",["\x96"]="96",["\x97"]="97",["\x98"]="98",["\x99"]="99",["\x9A"]="9.",["\x9B"]="9E",["\x9C"]="9E-",["\x9D"]="9",["\x9E"]="9-",["\x9F"]="9",
13600  ["\xA0"]=".0",["\xA1"]=".1",["\xA2"]=".2",["\xA3"]=".3",["\xA4"]=".4",["\xA5"]=".5",["\xA6"]=".6",["\xA7"]=".7",["\xA8"]=".8",["\xA9"]=".9",["\xAA"]="..",["\xAB"]=".E",["\xAC"]=".E-",["\xAD"]=".",["\xAE"]=".-",["\xAF"]=".",
13601  ["\xB0"]="E0",["\xB1"]="E1",["\xB2"]="E2",["\xB3"]="E3",["\xB4"]="E4",["\xB5"]="E5",["\xB6"]="E6",["\xB7"]="E7",["\xB8"]="E8",["\xB9"]="E9",["\xBA"]="E.",["\xBB"]="EE",["\xBC"]="EE-",["\xBD"]="E",["\xBE"]="E-",["\xBF"]="E",
13602  ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-",
13603  ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-",
13604 }
13605 local remap_2={
13606  ["\x0F"]="0",["\x1F"]="1",["\x2F"]="2",["\x3F"]="3",["\x4F"]="4",
13607  ["\x5F"]="5",["\x6F"]="6",["\x7F"]="7",["\x8F"]="8",["\x9F"]="9",
13608 }
13609 local p_last_1=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")
13610 local p_last_2=R("\xF0\xFF")
13611 local p_nibbles=P("\30")*Cs(((1-(p_last_1+p_last_2))/remap_1)^0*(p_last_1/remap_2+p_last_2/""))/function(n)
13612  top=top+1
13613  stack[top]=tonumber(n) or 0
13614 end
13615 local p_byte=C(R("\32\246"))/function(b0)
13616  top=top+1
13617  stack[top]=byte(b0)-139
13618 end
13619 local p_positive=C(R("\247\250"))*C(1)/function(b0,b1)
13620  top=top+1
13621  stack[top]=(byte(b0)-247)*256+byte(b1)+108
13622 end
13623 local p_negative=C(R("\251\254"))*C(1)/function(b0,b1)
13624  top=top+1
13625  stack[top]=-(byte(b0)-251)*256-byte(b1)-108
13626 end
13627 local p_short=P("\28")*C(1)*C(1)/function(b1,b2)
13628  top=top+1
13629  local n=0x100*byte(b1)+byte(b2)
13630  if n>=0x8000 then
13631   stack[top]=n-0xFFFF-1
13632  else
13633   stack[top]=n
13634  end
13635 end
13636 local p_long=P("\29")*C(1)*C(1)*C(1)*C(1)/function(b1,b2,b3,b4)
13637  top=top+1
13638  local n=0x1000000*byte(b1)+0x10000*byte(b2)+0x100*byte(b3)+byte(b4)
13639  if n>=0x8000000 then
13640   stack[top]=n-0xFFFFFFFF-1
13641  else
13642   stack[top]=n
13643  end
13644 end
13645 local p_unsupported=P(1)/function(detail)
13646  top=0
13647 end
13648 local p_dictionary=(
13649  p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double
13650+p_unsupported
13651 )^1
13652 parsedictionaries=function(data,dictionaries,version)
13653  stack={}
13654  strings=data.strings
13655  if trace_charstrings then
13656   report("charstring format %a",version)
13657  end
13658  for i=1,#dictionaries do
13659   top=0
13660   result=version=="cff" and {
13661    monospaced=false,
13662    italicangle=0,
13663    underlineposition=-100,
13664    underlinethickness=50,
13665    painttype=0,
13666    charstringtype=2,
13667    fontmatrix={ 0.001,0,0,0.001,0,0 },
13668    fontbbox={ 0,0,0,0 },
13669    strokewidth=0,
13670    charset=0,
13671    encoding=0,
13672    cid={
13673     fontversion=0,
13674     fontrevision=0,
13675     fonttype=0,
13676     count=8720,
13677    }
13678   } or {
13679    charstringtype=2,
13680    charset=0,
13681    vstore=0,
13682    cid={
13683    },
13684   }
13685   lpegmatch(p_dictionary,dictionaries[i])
13686   dictionaries[i]=result
13687  end
13688  result={}
13689  top=0
13690  stack={}
13691 end
13692 parseprivates=function(data,dictionaries)
13693  stack={}
13694  strings=data.strings
13695  for i=1,#dictionaries do
13696   local private=dictionaries[i].private
13697   if private and private.data then
13698    top=0
13699    result={
13700     forcebold=false,
13701     languagegroup=0,
13702     expansionfactor=0.06,
13703     initialrandomseed=0,
13704     subroutines=0,
13705     defaultwidthx=0,
13706     nominalwidthx=0,
13707     cid={
13708     },
13709    }
13710    lpegmatch(p_dictionary,private.data)
13711    private.data=result
13712   end
13713  end
13714  result={}
13715  top=0
13716  stack={}
13717 end
13718 local x=0
13719 local y=0
13720 local width=false
13721 local lsb=0
13722 local result={}
13723 local r=0
13724 local stems=0
13725 local globalbias=0
13726 local localbias=0
13727 local nominalwidth=0
13728 local defaultwidth=0
13729 local charset=false
13730 local globals=false
13731 local locals=false
13732 local depth=1
13733 local xmin=0
13734 local xmax=0
13735 local ymin=0
13736 local ymax=0
13737 local checked=false
13738 local keepcurve=false
13739 local version=2
13740 local regions=false
13741 local nofregions=0
13742 local region=false
13743 local factors=false
13744 local axis=false
13745 local vsindex=0
13746 local justpass=false
13747 local seacs={}
13748 local procidx=nil
13749 local function showstate(where,i,n)
13750  if i then
13751   local j=i+n-1
13752   report("%w%-10s : [%s] step",depth*2+2,where,concat(stack," ",i,j<=top and j or top))
13753  else
13754   report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
13755  end
13756 end
13757 local function showvalue(where,value,showstack)
13758  if showstack then
13759   report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top)
13760  else
13761   report("%w%-10s : %s",depth*2,where,tostring(value))
13762  end
13763 end
13764 local function xymoveto()
13765  if keepcurve then
13766   r=r+1
13767   result[r]={ x,y,"m" }
13768  end
13769  if checked then
13770   if x>xmax then xmax=x elseif x<xmin then xmin=x end
13771   if y>ymax then ymax=y elseif y<ymin then ymin=y end
13772  else
13773   xmin=x
13774   ymin=y
13775   xmax=x
13776   ymax=y
13777   checked=true
13778  end
13779 end
13780 local function xmoveto() 
13781  if keepcurve then
13782   r=r+1
13783   result[r]={ x,y,"m" }
13784  end
13785  if not checked then
13786   xmin=x
13787   ymin=y
13788   xmax=x
13789   ymax=y
13790   checked=true
13791  elseif x>xmax then
13792   xmax=x
13793  elseif x<xmin then
13794   xmin=x
13795  end
13796 end
13797 local function ymoveto() 
13798  if keepcurve then
13799   r=r+1
13800   result[r]={ x,y,"m" }
13801  end
13802  if not checked then
13803   xmin=x
13804   ymin=y
13805   xmax=x
13806   ymax=y
13807   checked=true
13808  elseif y>ymax then
13809   ymax=y
13810  elseif y<ymin then
13811   ymin=y
13812  end
13813 end
13814 local function moveto()
13815  if trace_charstrings then
13816   showstate("moveto")
13817  end
13818  top=0 
13819  xymoveto()
13820 end
13821 local function xylineto() 
13822  if keepcurve then
13823   r=r+1
13824   result[r]={ x,y,"l" }
13825  end
13826  if checked then
13827   if x>xmax then xmax=x elseif x<xmin then xmin=x end
13828   if y>ymax then ymax=y elseif y<ymin then ymin=y end
13829  else
13830   xmin=x
13831   ymin=y
13832   xmax=x
13833   ymax=y
13834   checked=true
13835  end
13836 end
13837 local function xlineto() 
13838  if keepcurve then
13839   r=r+1
13840   result[r]={ x,y,"l" }
13841  end
13842  if not checked then
13843   xmin=x
13844   ymin=y
13845   xmax=x
13846   ymax=y
13847   checked=true
13848  elseif x>xmax then
13849   xmax=x
13850  elseif x<xmin then
13851   xmin=x
13852  end
13853 end
13854 local function ylineto() 
13855  if keepcurve then
13856   r=r+1
13857   result[r]={ x,y,"l" }
13858  end
13859  if not checked then
13860   xmin=x
13861   ymin=y
13862   xmax=x
13863   ymax=y
13864   checked=true
13865  elseif y>ymax then
13866   ymax=y
13867  elseif y<ymin then
13868   ymin=y
13869  end
13870 end
13871 local function xycurveto(x1,y1,x2,y2,x3,y3,i,n) 
13872  if trace_charstrings then
13873   showstate("curveto",i,n)
13874  end
13875  if keepcurve then
13876   r=r+1
13877   result[r]={ x1,y1,x2,y2,x3,y3,"c" }
13878  end
13879  if checked then
13880   if x1>xmax then xmax=x1 elseif x1<xmin then xmin=x1 end
13881   if y1>ymax then ymax=y1 elseif y1<ymin then ymin=y1 end
13882  else
13883   xmin=x1
13884   ymin=y1
13885   xmax=x1
13886   ymax=y1
13887   checked=true
13888  end
13889  if x2>xmax then xmax=x2 elseif x2<xmin then xmin=x2 end
13890  if y2>ymax then ymax=y2 elseif y2<ymin then ymin=y2 end
13891  if x3>xmax then xmax=x3 elseif x3<xmin then xmin=x3 end
13892  if y3>ymax then ymax=y3 elseif y3<ymin then ymin=y3 end
13893 end
13894 local function rmoveto()
13895  if not width then
13896   if top>2 then
13897    width=stack[1]
13898    if trace_charstrings then
13899     showvalue("backtrack width",width)
13900    end
13901   else
13902    width=true
13903   end
13904  end
13905  if trace_charstrings then
13906   showstate("rmoveto")
13907  end
13908  x=x+stack[top-1] 
13909  y=y+stack[top]   
13910  top=0
13911  xymoveto()
13912 end
13913 local function hmoveto()
13914  if not width then
13915   if top>1 then
13916    width=stack[1]
13917    if trace_charstrings then
13918     showvalue("backtrack width",width)
13919    end
13920   else
13921    width=true
13922   end
13923  end
13924  if trace_charstrings then
13925   showstate("hmoveto")
13926  end
13927  x=x+stack[top] 
13928  top=0
13929  xmoveto()
13930 end
13931 local function vmoveto()
13932  if not width then
13933   if top>1 then
13934    width=stack[1]
13935    if trace_charstrings then
13936     showvalue("backtrack width",width)
13937    end
13938   else
13939    width=true
13940   end
13941  end
13942  if trace_charstrings then
13943   showstate("vmoveto")
13944  end
13945  y=y+stack[top] 
13946  top=0
13947  ymoveto()
13948 end
13949 local function rlineto()
13950  if trace_charstrings then
13951   showstate("rlineto")
13952  end
13953  for i=1,top,2 do
13954   x=x+stack[i]   
13955   y=y+stack[i+1] 
13956   xylineto()
13957  end
13958  top=0
13959 end
13960 local function hlineto() 
13961  if trace_charstrings then
13962   showstate("hlineto")
13963  end
13964  if top==1 then
13965   x=x+stack[1]
13966   xlineto()
13967  else
13968   local swap=true
13969   for i=1,top do
13970    if swap then
13971     x=x+stack[i]
13972     xlineto()
13973     swap=false
13974    else
13975     y=y+stack[i]
13976     ylineto()
13977     swap=true
13978    end
13979   end
13980  end
13981  top=0
13982 end
13983 local function vlineto() 
13984  if trace_charstrings then
13985   showstate("vlineto")
13986  end
13987  if top==1 then
13988   y=y+stack[1]
13989   ylineto()
13990  else
13991   local swap=false
13992   for i=1,top do
13993    if swap then
13994     x=x+stack[i]
13995     xlineto()
13996     swap=false
13997    else
13998     y=y+stack[i]
13999     ylineto()
14000     swap=true
14001    end
14002   end
14003  end
14004  top=0
14005 end
14006 local function rrcurveto()
14007  if trace_charstrings then
14008   showstate("rrcurveto")
14009  end
14010if top==6 then
14011 local ax=x+stack[1] 
14012 local ay=y+stack[2] 
14013 local bx=ax+stack[3] 
14014 local by=ay+stack[4] 
14015 x=bx+stack[5]  
14016 y=by+stack[6]  
14017 xycurveto(ax,ay,bx,by,x,y,1,6)
14018else
14019  for i=1,top,6 do
14020   local ax=x+stack[i]   
14021   local ay=y+stack[i+1] 
14022   local bx=ax+stack[i+2] 
14023   local by=ay+stack[i+3] 
14024   x=bx+stack[i+4]  
14025   y=by+stack[i+5]  
14026   xycurveto(ax,ay,bx,by,x,y,i,6)
14027  end
14028end
14029  top=0
14030 end
14031 local function hhcurveto()
14032  if trace_charstrings then
14033   showstate("hhcurveto")
14034  end
14035  local s=1
14036  if top%2~=0 then
14037   y=y+stack[1]     
14038   s=2
14039  end
14040if top==4 then
14041   local ax=x+stack[1]  
14042   local ay=y
14043   local bx=ax+stack[2] 
14044   local by=ay+stack[3] 
14045   x=bx+stack[4]  
14046   y=by
14047   xycurveto(ax,ay,bx,by,x,y,1,4)
14048else
14049  for i=s,top,4 do
14050   local ax=x+stack[i] 
14051   local ay=y
14052   local bx=ax+stack[i+1] 
14053   local by=ay+stack[i+2] 
14054   x=bx+stack[i+3]  
14055   y=by
14056   xycurveto(ax,ay,bx,by,x,y,i,4)
14057  end
14058end
14059  top=0
14060 end
14061 local function vvcurveto()
14062  if trace_charstrings then
14063   showstate("vvcurveto")
14064  end
14065  local s=1
14066  local d=0
14067  if top%2~=0 then
14068   d=stack[1]      
14069   s=2
14070  end
14071if top==4 then
14072 local ax=x+d
14073 local ay=y+stack[1]  
14074 local bx=ax+stack[2] 
14075 local by=ay+stack[3] 
14076 x=bx
14077 y=by+stack[4]  
14078 xycurveto(ax,ay,bx,by,x,y,1,4)
14079 d=0
14080else
14081  for i=s,top,4 do
14082   local ax=x+d
14083   local ay=y+stack[i] 
14084   local bx=ax+stack[i+1] 
14085   local by=ay+stack[i+2] 
14086   x=bx
14087   y=by+stack[i+3]  
14088   xycurveto(ax,ay,bx,by,x,y,i,4)
14089   d=0
14090  end
14091end
14092  top=0
14093 end
14094 local function xxcurveto(swap)
14095  local last=top%4~=0 and stack[top]
14096  if last then
14097   top=top-1
14098  end
14099if top==4 then
14100  local ax,ay,bx,by
14101  if swap then
14102   ax=x+stack[1]
14103   ay=y
14104   bx=ax+stack[2]
14105   by=ay+stack[3]
14106   y=by+stack[4]
14107   if last then
14108    x=bx+last
14109   else
14110    x=bx
14111   end
14112  else
14113   ax=x
14114   ay=y+stack[1]
14115   bx=ax+stack[2]
14116   by=ay+stack[3]
14117   x=bx+stack[4]
14118   if last then
14119    y=by+last
14120   else
14121    y=by
14122   end
14123  end
14124  xycurveto(ax,ay,bx,by,x,y,1,4)
14125else
14126  for i=1,top,4 do
14127   local ax,ay,bx,by
14128   if swap then
14129    ax=x+stack[i]
14130    ay=y
14131    bx=ax+stack[i+1]
14132    by=ay+stack[i+2]
14133    y=by+stack[i+3]
14134    if last and i+3==top then
14135     x=bx+last
14136    else
14137     x=bx
14138    end
14139    swap=false
14140   else
14141    ax=x
14142    ay=y+stack[i]
14143    bx=ax+stack[i+1]
14144    by=ay+stack[i+2]
14145    x=bx+stack[i+3]
14146    if last and i+3==top then
14147     y=by+last
14148    else
14149     y=by
14150    end
14151    swap=true
14152   end
14153   xycurveto(ax,ay,bx,by,x,y,i,4)
14154  end
14155end
14156  top=0
14157 end
14158 local function hvcurveto()
14159  if trace_charstrings then
14160   showstate("hvcurveto")
14161  end
14162  xxcurveto(true)
14163 end
14164 local function vhcurveto()
14165  if trace_charstrings then
14166   showstate("vhcurveto")
14167  end
14168  xxcurveto(false)
14169 end
14170 local function rcurveline()
14171  if trace_charstrings then
14172   showstate("rcurveline")
14173  end
14174  for i=1,top-2,6 do
14175   local ax=x+stack[i]   
14176   local ay=y+stack[i+1] 
14177   local bx=ax+stack[i+2] 
14178   local by=ay+stack[i+3] 
14179   x=bx+stack[i+4] 
14180   y=by+stack[i+5] 
14181   xycurveto(ax,ay,bx,by,x,y,i,6)
14182  end
14183  x=x+stack[top-1] 
14184  y=y+stack[top]   
14185  xylineto()
14186  top=0
14187 end
14188 local function rlinecurve()
14189  if trace_charstrings then
14190   showstate("rlinecurve")
14191  end
14192  if top>6 then
14193   for i=1,top-6,2 do
14194    x=x+stack[i]
14195    y=y+stack[i+1]
14196    xylineto()
14197   end
14198  end
14199  local ax=x+stack[top-5]
14200  local ay=y+stack[top-4]
14201  local bx=ax+stack[top-3]
14202  local by=ay+stack[top-2]
14203  x=bx+stack[top-1]
14204  y=by+stack[top]
14205  xycurveto(ax,ay,bx,by,x,y)
14206  top=0
14207 end
14208 local function flex() 
14209  if trace_charstrings then
14210   showstate("flex")
14211  end
14212  local ax=x+stack[1]  
14213  local ay=y+stack[2]  
14214  local bx=ax+stack[3]  
14215  local by=ay+stack[4]  
14216  local cx=bx+stack[5]  
14217  local cy=by+stack[6]  
14218  xycurveto(ax,ay,bx,by,cx,cy)
14219  local dx=cx+stack[7]  
14220  local dy=cy+stack[8]  
14221  local ex=dx+stack[9]  
14222  local ey=dy+stack[10] 
14223  x=ex+stack[11]  
14224  y=ey+stack[12]  
14225  xycurveto(dx,dy,ex,ey,x,y)
14226  top=0
14227 end
14228 local function hflex()
14229  if trace_charstrings then
14230   showstate("hflex")
14231  end
14232  local ax=x+stack[1] 
14233  local ay=y
14234  local bx=ax+stack[2] 
14235  local by=ay+stack[3] 
14236  local cx=bx+stack[4] 
14237  local cy=by
14238  xycurveto(ax,ay,bx,by,cx,cy)
14239  local dx=cx+stack[5] 
14240  local dy=by
14241  local ex=dx+stack[6] 
14242  local ey=y
14243  x=ex+stack[7]  
14244  xycurveto(dx,dy,ex,ey,x,y)
14245  top=0
14246 end
14247 local function hflex1()
14248  if trace_charstrings then
14249   showstate("hflex1")
14250  end
14251  local ax=x+stack[1] 
14252  local ay=y+stack[2] 
14253  local bx=ax+stack[3] 
14254  local by=ay+stack[4] 
14255  local cx=bx+stack[5] 
14256  local cy=by
14257  xycurveto(ax,ay,bx,by,cx,cy)
14258  local dx=cx+stack[6] 
14259  local dy=by
14260  local ex=dx+stack[7] 
14261  local ey=dy+stack[8] 
14262  x=ex+stack[9]  
14263  xycurveto(dx,dy,ex,ey,x,y)
14264  top=0
14265 end
14266 local function flex1()
14267  if trace_charstrings then
14268   showstate("flex1")
14269  end
14270  local ax=x+stack[1]  
14271  local ay=y+stack[2]  
14272  local bx=ax+stack[3]  
14273  local by=ay+stack[4]  
14274  local cx=bx+stack[5]  
14275  local cy=by+stack[6]  
14276  xycurveto(ax,ay,bx,by,cx,cy)
14277  local dx=cx+stack[7]  
14278  local dy=cy+stack[8]  
14279  local ex=dx+stack[9]  
14280  local ey=dy+stack[10] 
14281  if abs(ex-x)>abs(ey-y) then 
14282   x=ex+stack[11]
14283  else
14284   y=ey+stack[11]
14285  end
14286  xycurveto(dx,dy,ex,ey,x,y)
14287  top=0
14288 end
14289 local function getstem()
14290  if top==0 then
14291  elseif top%2~=0 then
14292   if width then
14293    remove(stack,1)
14294   else
14295    width=remove(stack,1)
14296    if trace_charstrings then
14297     showvalue("width",width)
14298    end
14299   end
14300   top=top-1
14301  end
14302  if trace_charstrings then
14303   showstate("stem")
14304  end
14305  stems=stems+idiv(top,2)
14306  top=0
14307 end
14308 local function getmask()
14309  if top==0 then
14310  elseif top%2~=0 then
14311   if width then
14312    remove(stack,1)
14313   else
14314    width=remove(stack,1)
14315    if trace_charstrings then
14316     showvalue("width",width)
14317    end
14318   end
14319   top=top-1
14320  end
14321  if trace_charstrings then
14322   showstate(operator==19 and "hintmark" or "cntrmask")
14323  end
14324  stems=stems+idiv(top,2)
14325  top=0
14326  if stems==0 then
14327  elseif stems<=8 then
14328   return 1
14329  else
14330   return idiv(stems+7,8)
14331  end
14332 end
14333 local function unsupported(t)
14334  if trace_charstrings then
14335   showstate("unsupported "..t)
14336  end
14337  top=0
14338 end
14339 local function unsupportedsub(t)
14340  if trace_charstrings then
14341   showstate("unsupported sub "..t)
14342  end
14343  top=0
14344 end
14345 local function getstem3()
14346  if trace_charstrings then
14347   showstate("stem3")
14348  end
14349  top=0
14350 end
14351 local function divide()
14352  if version=="cff" then
14353   local d=stack[top]
14354   top=top-1
14355   stack[top]=stack[top]/d
14356  end
14357 end
14358 local function closepath()
14359  if version=="cff" then
14360   if trace_charstrings then
14361    showstate("closepath")
14362   end
14363  end
14364  top=0
14365 end
14366 local function hsbw()
14367  if version=="cff" then
14368   if trace_charstrings then
14369    showstate("hsbw")
14370   end
14371   lsb=stack[top-1] or 0
14372   width=stack[top]
14373  end
14374  top=0
14375 end
14376 local function sbw()
14377  if version=="cff" then
14378   if trace_charstrings then
14379    showstate("sbw")
14380   end
14381   lsb=stack[top-3]
14382   width=stack[top-1]
14383  end
14384  top=0
14385 end
14386 local function seac()
14387  if version=="cff" then
14388   if trace_charstrings then
14389    showstate("seac")
14390   end
14391  end
14392  top=0
14393 end
14394 local popped=3
14395 local hints=3
14396 local function callothersubr()
14397  if version=="cff" then
14398   if trace_charstrings then
14399    showstate("callothersubr")
14400   end
14401   if stack[top]==hints then
14402    popped=stack[top-2]
14403   else
14404    popped=3
14405   end
14406   local t=stack[top-1]
14407   if t then
14408    top=top-(t+2)
14409    if top<0 then
14410     top=0
14411    end
14412   else
14413    top=0
14414   end
14415  else
14416   top=0
14417  end
14418 end
14419 local function pop()
14420  if version=="cff" then
14421   if trace_charstrings then
14422    showstate("pop")
14423   end
14424   top=top+1
14425   stack[top]=popped
14426  else
14427   top=0
14428  end
14429 end
14430 local function setcurrentpoint()
14431  if version=="cff" then
14432   if trace_charstrings then
14433    showstate("setcurrentpoint (unsupported)")
14434   end
14435   x=x+stack[top-1]
14436   y=y+stack[top]
14437  end
14438  top=0
14439 end
14440 local reginit=false
14441 local function updateregions(n) 
14442  if regions then
14443   local current=regions[n+1] or regions[1]
14444   nofregions=#current
14445   if axis and n~=reginit then
14446    factors={}
14447    for i=1,nofregions do
14448     local region=current[i]
14449     local s=1
14450     for j=1,#axis do
14451      local f=axis[j]
14452      local r=region[j]
14453      local start=r.start
14454      local peak=r.peak
14455      local stop=r.stop
14456      if start>peak or peak>stop then
14457      elseif start<0 and stop>0 and peak~=0 then
14458      elseif peak==0 then
14459      elseif f<start or f>stop then
14460       s=0
14461       break
14462      elseif f<peak then
14463       s=s*(f-start)/(peak-start)
14464      elseif f>peak then
14465       s=s*(stop-f)/(stop-peak)
14466      else
14467      end
14468     end
14469     factors[i]=s
14470    end
14471   end
14472  end
14473  reginit=n
14474 end
14475 local function setvsindex()
14476  local vsindex=stack[top]
14477  if trace_charstrings then
14478   showstate(formatters["vsindex %i"](vsindex))
14479  end
14480  updateregions(vsindex)
14481  top=top-1
14482 end
14483 local function blend()
14484  local n=stack[top]
14485  top=top-1
14486  if axis then
14487   if trace_charstrings then
14488    local t=top-nofregions*n
14489    local m=t-n
14490    for i=1,n do
14491     local k=m+i
14492     local d=m+n+(i-1)*nofregions
14493     local old=stack[k]
14494     local new=old
14495     for r=1,nofregions do
14496      new=new+stack[d+r]*factors[r]
14497     end
14498     stack[k]=new
14499     showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
14500    end
14501    top=t
14502   elseif n==1 then
14503    top=top-nofregions
14504    local v=stack[top]
14505    for r=1,nofregions do
14506     v=v+stack[top+r]*factors[r]
14507    end
14508    stack[top]=v
14509   else
14510    top=top-nofregions*n
14511    local d=top
14512    local k=top-n
14513    for i=1,n do
14514     k=k+1
14515     local v=stack[k]
14516     for r=1,nofregions do
14517      v=v+stack[d+r]*factors[r]
14518     end
14519     stack[k]=v
14520     d=d+nofregions
14521    end
14522   end
14523  else
14524   top=top-nofregions*n
14525  end
14526 end
14527 local actions={ [0]=unsupported,
14528  getstem,
14529  unsupported,
14530  getstem,
14531  vmoveto,
14532  rlineto,
14533  hlineto,
14534  vlineto,
14535  rrcurveto,
14536  unsupported,
14537  unsupported,
14538  unsupported,
14539  unsupported,
14540  hsbw,
14541  unsupported,
14542  setvsindex,
14543  blend,
14544  unsupported,
14545  getstem,
14546  getmask,
14547  getmask,
14548  rmoveto,
14549  hmoveto,
14550  getstem,
14551  rcurveline,
14552  rlinecurve,
14553  vvcurveto,
14554  hhcurveto,
14555  unsupported,
14556  unsupported,
14557  vhcurveto,
14558  hvcurveto,
14559 }
14560 local reverse={ [0]="unsupported",
14561  "getstem",
14562  "unsupported",
14563  "getstem",
14564  "vmoveto",
14565  "rlineto",
14566  "hlineto",
14567  "vlineto",
14568  "rrcurveto",
14569  "unsupported",
14570  "unsupported",
14571  "unsupported",
14572  "unsupported",
14573  "hsbw",
14574  "unsupported",
14575  "setvsindex",
14576  "blend",
14577  "unsupported",
14578  "getstem",
14579  "getmask",
14580  "getmask",
14581  "rmoveto",
14582  "hmoveto",
14583  "getstem",
14584  "rcurveline",
14585  "rlinecurve",
14586  "vvcurveto",
14587  "hhcurveto",
14588  "unsupported",
14589  "unsupported",
14590  "vhcurveto",
14591  "hvcurveto",
14592 }
14593 local subactions={
14594  [000]=dotsection,
14595  [001]=getstem3,
14596  [002]=getstem3,
14597  [006]=seac,
14598  [007]=sbw,
14599  [012]=divide,
14600  [016]=callothersubr,
14601  [017]=pop,
14602  [033]=setcurrentpoint,
14603  [034]=hflex,
14604  [035]=flex,
14605  [036]=hflex1,
14606  [037]=flex1,
14607 }
14608 local chars=setmetatableindex(function (t,k)
14609  local v=char(k)
14610  t[k]=v
14611  return v
14612 end)
14613 local c_endchar=chars[14]
14614 local encode={}
14615 local typeone=false
14616 setmetatableindex(encode,function(t,i)
14617  for i=-2048,-1130 do
14618   t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF))
14619  end
14620  for i=-1131,-108 do
14621   local v=0xFB00-i-108
14622   t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF))
14623  end
14624  for i=-107,107 do
14625   t[i]=chars[i+139]
14626  end
14627  for i=108,1131 do
14628   local v=0xF700+i-108
14629   t[i]=char(extract(v,8,8),extract(v,0,8))
14630  end
14631  for i=1132,2048 do
14632   t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF))
14633  end
14634  setmetatableindex(encode,function(t,k)
14635   local r=round(k)
14636   local v=rawget(t,r)
14637   if v then
14638    return v
14639   end
14640   local v1=floor(k)
14641   local v2=floor((k-v1)*0x10000)
14642   return char(255,extract(v1,8,8),extract(v1,0,8),extract(v2,8,8),extract(v2,0,8))
14643  end)
14644  return t[i]
14645 end)
14646 readers.cffencoder=encode
14647 local function p_setvsindex()
14648  local vsindex=stack[top]
14649  updateregions(vsindex)
14650  top=top-1
14651 end
14652 local function p_blend()
14653  local n=stack[top]
14654  top=top-1
14655  if not axis then
14656  elseif n==1 then
14657   top=top-nofregions
14658   local v=stack[top]
14659   for r=1,nofregions do
14660    v=v+stack[top+r]*factors[r]
14661   end
14662   stack[top]=round(v)
14663  else
14664   top=top-nofregions*n
14665   local d=top
14666   local k=top-n
14667   for i=1,n do
14668    k=k+1
14669    local v=stack[k]
14670    for r=1,nofregions do
14671     v=v+stack[d+r]*factors[r]
14672    end
14673    stack[k]=round(v)
14674    d=d+nofregions
14675   end
14676  end
14677 end
14678 local function p_getstem()
14679  local n=0
14680  if top%2~=0 then
14681   n=1
14682  end
14683  if top>n then
14684   stems=stems+idiv(top-n,2)
14685  end
14686 end
14687 local function p_getmask()
14688  local n=0
14689  if top%2~=0 then
14690   n=1
14691  end
14692  if top>n then
14693   stems=stems+idiv(top-n,2)
14694  end
14695  if stems==0 then
14696   return 0
14697  elseif stems<=8 then
14698   return 1
14699  else
14700   return idiv(stems+7,8)
14701  end
14702 end
14703 local process
14704 local function call(scope,list,bias) 
14705  depth=depth+1
14706  if top==0 then
14707   showstate(formatters["unknown %s call %s, case %s"](scope,"?",1))
14708   top=0
14709  else
14710   local index=stack[top]+bias
14711   top=top-1
14712   if trace_charstrings then
14713    showvalue(scope,index,true)
14714   end
14715   local tab=list[index]
14716   if tab then
14717    process(tab)
14718   else
14719    showstate(formatters["unknown %s call %s, case %s"](scope,index,2))
14720    top=0
14721   end
14722  end
14723  depth=depth-1
14724 end
14725 process=function(tab)
14726  local i=1
14727  local n=#tab
14728  while i<=n do
14729   local t=tab[i]
14730   if t>=32 then
14731    top=top+1
14732    if t<=246 then
14733     stack[top]=t-139
14734     i=i+1
14735    elseif t<=250 then
14736     stack[top]=t*256-63124+tab[i+1]
14737     i=i+2
14738    elseif t<=254 then
14739     stack[top]=-t*256+64148-tab[i+1]
14740     i=i+2
14741    elseif typeone then
14742     local n=0x1000000*tab[i+1]+0x10000*tab[i+2]+0x100*tab[i+3]+tab[i+4]
14743     if n>=0x8000000 then
14744      n=n-0xFFFFFFFF-1
14745     end
14746     stack[top]=n
14747     i=i+5
14748    else
14749     local n1=0x100*tab[i+1]+tab[i+2]
14750     local n2=0x100*tab[i+3]+tab[i+4]
14751     if n1>=0x8000 then
14752      n1=n1-0x10000
14753     end
14754     stack[top]=n1+n2/0xFFFF
14755     i=i+5
14756    end
14757   elseif t==28 then
14758    top=top+1
14759    local n=0x100*tab[i+1]+tab[i+2]
14760    if n>=0x8000 then
14761     stack[top]=n-0x10000
14762    else
14763     stack[top]=n
14764    end
14765    i=i+3
14766   elseif t==11 then 
14767    if trace_charstrings then
14768     showstate("return")
14769    end
14770    return
14771   elseif t==10 then
14772    call("local",locals,localbias) 
14773    i=i+1
14774   elseif t==14 then 
14775    if width then
14776    elseif top>0 then
14777     width=stack[1]
14778     if trace_charstrings then
14779      showvalue("width",width)
14780     end
14781    else
14782     width=true
14783    end
14784    if trace_charstrings then
14785     showstate("endchar")
14786    end
14787    return
14788   elseif t==29 then
14789    call("global",globals,globalbias) 
14790    i=i+1
14791   elseif t==12 then
14792    i=i+1
14793    local t=tab[i]
14794    if justpass then
14795     if t>=34 and t<=37 then 
14796      for i=1,top do
14797       r=r+1;result[r]=encode[stack[i]]
14798      end
14799      r=r+1;result[r]=chars[12]
14800      r=r+1;result[r]=chars[t]
14801      top=0
14802     elseif t==6 then
14803      seacs[procidx]={
14804       asb=stack[1],
14805       adx=stack[2],
14806       ady=stack[3],
14807       base=stack[4],
14808       accent=stack[5],
14809       width=width,
14810       lsb=lsb,
14811      }
14812      top=0
14813     else
14814      local a=subactions[t]
14815      if a then
14816       a(t)
14817      else
14818       top=0
14819      end
14820     end
14821    else
14822     local a=subactions[t]
14823     if a then
14824      a(t)
14825     else
14826      if trace_charstrings then
14827       showvalue("<subaction>",t)
14828      end
14829      top=0
14830     end
14831    end
14832    i=i+1
14833   elseif justpass then
14834    if t==15 then
14835     p_setvsindex()
14836     i=i+1
14837    elseif t==16 then
14838     local s=p_blend() or 0
14839     i=i+s+1
14840    elseif t==1 or t==3 or t==18 or operation==23 then
14841     p_getstem() 
14842     if version=="cff" then
14843      if top>0 then
14844       for i=1,top do
14845        r=r+1;result[r]=encode[stack[i]]
14846       end
14847       top=0
14848      end
14849      r=r+1;result[r]=chars[t]
14850     else
14851      top=0
14852     end
14853     i=i+1
14854    elseif t==19 or t==20 then
14855     local s=p_getmask() or 0
14856     if true then
14857      if top>0 then
14858       for i=1,top do
14859        r=r+1;result[r]=encode[stack[i]]
14860       end
14861       top=0
14862      end
14863      r=r+1;result[r]=chars[t]
14864      for j=1,s do
14865       i=i+1
14866       r=r+1;result[r]=chars[tab[i]]
14867      end
14868     else
14869      i=i+s
14870      top=0
14871     end
14872     i=i+1
14873    elseif t==9 then
14874     top=0
14875     i=i+1
14876    elseif t==13 then
14877     hsbw()
14878     if true then
14879      r=r+1;result[r]=encode[lsb]
14880      r=r+1;result[r]=chars[22]
14881     else
14882     end
14883     i=i+1
14884    else
14885     if trace_charstrings then
14886      showstate(reverse[t] or "<action>")
14887     end
14888     if top>0 then
14889      if t==8 and top>48 then
14890       local n=0
14891       for i=1,top do
14892        if n==48 then
14893         r=r+1;result[r]=chars[t]
14894         n=1
14895        else
14896         n=n+1
14897        end
14898        r=r+1;result[r]=encode[stack[i]]
14899       end
14900      else
14901       for i=1,top do
14902        r=r+1;result[r]=encode[stack[i]]
14903       end
14904      end
14905      top=0
14906     end
14907     r=r+1;result[r]=chars[t]
14908     i=i+1
14909    end
14910   else
14911    local a=actions[t]
14912    if a then
14913     local s=a(t)
14914     if s then
14915      i=i+s+1
14916     else
14917      i=i+1
14918     end
14919    else
14920     if trace_charstrings then
14921      showstate(reverse[t] or "<action>")
14922     end
14923     top=0
14924     i=i+1
14925    end
14926   end
14927  end
14928 end
14929 local function setbias(globals,locals,nobias)
14930  if nobias then
14931   return 0,0
14932  else
14933   local g=#globals
14934   local l=#locals
14935   return
14936    ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1,
14937    ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1
14938  end
14939 end
14940 local function processshape(glyphs,tab,index,hack)
14941  if not tab then
14942   glyphs[index]={
14943    boundingbox={ 0,0,0,0 },
14944    width=0,
14945    name=charset and charset[index] or nil,
14946   }
14947   return
14948  end
14949  tab=bytetable(tab)
14950  x=0
14951  y=0
14952  width=false
14953  lsb=0
14954  r=0
14955  top=0
14956  stems=0
14957  result={} 
14958  popped=3
14959  procidx=index
14960  xmin=0
14961  xmax=0
14962  ymin=0
14963  ymax=0
14964  checked=false
14965  if trace_charstrings then
14966   report("glyph: %i",index)
14967   report("data : % t",tab)
14968  end
14969  if regions then
14970   updateregions(vsindex)
14971  end
14972  process(tab)
14973  if hack then
14974   return x,y
14975  end
14976  local boundingbox={
14977   round(xmin),
14978   round(ymin),
14979   round(xmax),
14980   round(ymax),
14981  }
14982  if width==true or width==false then
14983   width=defaultwidth
14984  else
14985   width=nominalwidth+width
14986  end
14987  local glyph=glyphs[index] 
14988  if justpass then
14989   r=r+1
14990   result[r]=c_endchar
14991   local stream=concat(result)
14992result=nil
14993   if glyph then
14994    glyph.stream=stream
14995    glyph.width=width
14996   else
14997    glyphs[index]={ stream=stream,width=width }
14998   end
14999  elseif glyph then
15000   glyph.segments=keepcurve~=false and result or nil
15001   glyph.boundingbox=boundingbox
15002   if not glyph.width then
15003    glyph.width=width
15004   end
15005   if charset and not glyph.name then
15006    glyph.name=charset[index]
15007   end
15008  elseif keepcurve then
15009   glyphs[index]={
15010    segments=result,
15011    boundingbox=boundingbox,
15012    width=width,
15013    name=charset and charset[index] or nil,
15014   }
15015result=nil
15016  else
15017   glyphs[index]={
15018    boundingbox=boundingbox,
15019    width=width,
15020    name=charset and charset[index] or nil,
15021   }
15022  end
15023  if trace_charstrings then
15024   report("width      : %s",tostring(width))
15025   report("boundingbox: % t",boundingbox)
15026  end
15027 end
15028 startparsing=function(fontdata,data,streams)
15029  reginit=false
15030  axis=false
15031  regions=data.regions
15032  justpass=streams==true
15033  popped=3
15034  seacs={}
15035  if regions then
15036   regions={}
15037   local deltas=data.deltas
15038   for i=1,#deltas do
15039    regions[i]=deltas[i].regions
15040   end
15041   axis=data.factors or false
15042  end
15043 end
15044 stopparsing=function(fontdata,data)
15045  stack={}
15046  glyphs=false
15047  result={}
15048  top=0
15049  locals=false
15050  globals=false
15051  strings=false
15052  popped=3
15053  seacs={}
15054 end
15055 local function setwidths(private)
15056  if not private then
15057   return 0,0
15058  end
15059  local privatedata=private.data
15060  if not privatedata then
15061   return 0,0
15062  end
15063  return privatedata.nominalwidthx or 0,privatedata.defaultwidthx or 0
15064 end
15065 parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone)
15066  local dictionary=data.dictionaries[1]
15067  local charstrings=dictionary.charstrings
15068  keepcurve=doshapes
15069  version=tversion
15070  typeone=istypeone or false
15071  strings=data.strings
15072  globals=data.routines or {}
15073  locals=dictionary.subroutines or {}
15074  charset=dictionary.charset
15075  vsindex=dictionary.vsindex or 0
15076  local glyphs=glphs or {}
15077  globalbias,localbias=setbias(globals,locals,nobias)
15078  nominalwidth,defaultwidth=setwidths(dictionary.private)
15079  if charstrings then
15080   startparsing(fontdata,data,streams)
15081   for index=1,#charstrings do
15082    processshape(glyphs,charstrings[index],index-1)
15083   end
15084   if justpass and next(seacs) then
15085    local charset=data.dictionaries[1].charset
15086    if charset then
15087     local lookup=table.swapped(charset)
15088     for index,v in next,seacs do
15089      local bindex=lookup[standardnames[v.base]]
15090      local aindex=lookup[standardnames[v.accent]]
15091      local bglyph=bindex and glyphs[bindex]
15092      local aglyph=aindex and glyphs[aindex]
15093      if bglyph and aglyph then
15094       local jp=justpass
15095       justpass=false
15096       local x,y=processshape(glyphs,charstrings[bindex+1],bindex,true)
15097       justpass=jp
15098       local base=bglyph.stream
15099       local accent=aglyph.stream
15100       local moveto=encode[-x-v.asb+v.adx]..chars[22]..encode[-y+v.ady]..chars[ 4]
15101       base=sub(base,1,#base-1)
15102       glyphs[index].stream=base..moveto..accent
15103      end
15104     end
15105    end
15106   end
15107   stopparsing(fontdata,data)
15108  else
15109   report("no charstrings")
15110  end
15111  return glyphs
15112 end
15113 parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams)
15114  keepcurve=doshapes
15115  version=tversion
15116  strings=data.strings
15117  globals=data.routines or {}
15118  locals=dictionary.subroutines or {}
15119  charset=false
15120  vsindex=dictionary.vsindex or 0
15121  local glyphs=glphs or {}
15122  justpass=streams==true
15123  seacs={}
15124  globalbias,localbias=setbias(globals,locals,nobias)
15125  nominalwidth,defaultwidth=setwidths(dictionary.private)
15126  processshape(glyphs,tab,index-1)
15127  return glyphs[index]
15128 end
15129end
15130local function readglobals(f,data,version)
15131 local routines=readlengths(f,version=="cff2")
15132 for i=1,#routines do
15133  routines[i]=readbytetable(f,routines[i])
15134 end
15135 data.routines=routines
15136end
15137local function readencodings(f,data)
15138 data.encodings={}
15139end
15140local function readcharsets(f,data,dictionary)
15141 local header=data.header
15142 local strings=data.strings
15143 local nofglyphs=data.nofglyphs
15144 local charsetoffset=dictionary.charset
15145 if charsetoffset and charsetoffset~=0 then
15146  setposition(f,header.offset+charsetoffset)
15147  local format=readbyte(f)
15148  local charset={ [0]=".notdef" }
15149  dictionary.charset=charset
15150  if format==0 then
15151   for i=1,nofglyphs do
15152    charset[i]=strings[readushort(f)]
15153   end
15154  elseif format==1 or format==2 then
15155   local readcount=format==1 and readbyte or readushort
15156   local i=1
15157   while i<=nofglyphs do
15158    local sid=readushort(f)
15159    local n=readcount(f)
15160    for s=sid,sid+n do
15161     charset[i]=strings[s]
15162     i=i+1
15163     if i>nofglyphs then
15164      break
15165     end
15166    end
15167   end
15168  else
15169   report("cff parser: unsupported charset format %a",format)
15170  end
15171 else
15172  dictionary.nocharset=true
15173  dictionary.charset=nil
15174 end
15175end
15176local function readprivates(f,data)
15177 local header=data.header
15178 local dictionaries=data.dictionaries
15179 local private=dictionaries[1].private
15180 if private then
15181  setposition(f,header.offset+private.offset)
15182  private.data=readstring(f,private.size)
15183 end
15184end
15185local function readlocals(f,data,dictionary,version)
15186 local header=data.header
15187 local private=dictionary.private
15188 if private then
15189  local subroutineoffset=private.data.subroutines
15190  if subroutineoffset~=0 then
15191   setposition(f,header.offset+private.offset+subroutineoffset)
15192   local subroutines=readlengths(f,version=="cff2")
15193   for i=1,#subroutines do
15194    subroutines[i]=readbytetable(f,subroutines[i])
15195   end
15196   dictionary.subroutines=subroutines
15197   private.data.subroutines=nil
15198  else
15199   dictionary.subroutines={}
15200  end
15201 else
15202  dictionary.subroutines={}
15203 end
15204end
15205local function readcharstrings(f,data,version)
15206 local header=data.header
15207 local dictionaries=data.dictionaries
15208 local dictionary=dictionaries[1]
15209 local stringtype=dictionary.charstringtype
15210 local offset=dictionary.charstrings
15211 if type(offset)~="number" then
15212 elseif stringtype==2 then
15213  setposition(f,header.offset+offset)
15214  local charstrings=readlengths(f,version=="cff2")
15215  local nofglyphs=#charstrings
15216  for i=1,nofglyphs do
15217   charstrings[i]=readstring(f,charstrings[i])
15218  end
15219  data.nofglyphs=nofglyphs
15220  dictionary.charstrings=charstrings
15221 else
15222  report("unsupported charstr type %i",stringtype)
15223  data.nofglyphs=0
15224  dictionary.charstrings={}
15225 end
15226end
15227local function readcidprivates(f,data)
15228 local header=data.header
15229 local dictionaries=data.dictionaries[1].cid.dictionaries
15230 for i=1,#dictionaries do
15231  local dictionary=dictionaries[i]
15232  local private=dictionary.private
15233  if private then
15234   setposition(f,header.offset+private.offset)
15235   private.data=readstring(f,private.size)
15236  end
15237 end
15238 parseprivates(data,dictionaries)
15239end
15240readers.parsecharstrings=parsecharstrings 
15241local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
15242 local dictionaries=data.dictionaries
15243 local dictionary=dictionaries[1]
15244 local cid=not dictionary.private and dictionary.cid
15245 readglobals(f,data,version)
15246 readcharstrings(f,data,version)
15247 if version=="cff2" then
15248  dictionary.charset=nil
15249 else
15250  readencodings(f,data)
15251  readcharsets(f,data,dictionary)
15252 end
15253 if cid then
15254  local fdarray=cid.fdarray
15255  if fdarray then
15256   setposition(f,data.header.offset+fdarray)
15257   local dictionaries=readlengths(f,version=="cff2")
15258   local nofdictionaries=#dictionaries
15259   if nofdictionaries>0 then
15260    for i=1,nofdictionaries do
15261     dictionaries[i]=readstring(f,dictionaries[i])
15262    end
15263    parsedictionaries(data,dictionaries)
15264    dictionary.private=dictionaries[1].private
15265    if nofdictionaries>1 then
15266     report("ignoring dictionaries > 1 in cid font")
15267    end
15268   end
15269  end
15270 end
15271 readprivates(f,data)
15272 parseprivates(data,data.dictionaries)
15273 readlocals(f,data,dictionary,version)
15274 startparsing(fontdata,data,streams)
15275 parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false)
15276 stopparsing(fontdata,data)
15277end
15278local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
15279 local header=data.header
15280 local dictionaries=data.dictionaries
15281 local dictionary=dictionaries[1]
15282 local cid=dictionary.cid
15283 local cidselect=cid and cid.fdselect
15284 readglobals(f,data,version)
15285 readcharstrings(f,data,version)
15286 if version~="cff2" then
15287  readencodings(f,data)
15288 end
15289 local charstrings=dictionary.charstrings
15290 local fdindex={}
15291 local nofglyphs=data.nofglyphs
15292 local maxindex=-1
15293 setposition(f,header.offset+cidselect)
15294 local format=readbyte(f)
15295 if format==1 then
15296  for i=0,nofglyphs do 
15297   local index=readbyte(f)
15298   fdindex[i]=index
15299   if index>maxindex then
15300    maxindex=index
15301   end
15302  end
15303 elseif format==3 then
15304  local nofranges=readushort(f)
15305  local first=readushort(f)
15306  local index=readbyte(f)
15307  while true do
15308   local last=readushort(f)
15309   if index>maxindex then
15310    maxindex=index
15311   end
15312   for i=first,last do
15313    fdindex[i]=index
15314   end
15315   if last>=nofglyphs then
15316    break
15317   else
15318    first=last+1
15319    index=readbyte(f)
15320   end
15321  end
15322 else
15323  report("unsupported fd index format %i",format)
15324 end
15325 if maxindex>=0 then
15326  local cidarray=cid.fdarray
15327  if cidarray then
15328   setposition(f,header.offset+cidarray)
15329   local dictionaries=readlengths(f,version=="cff2")
15330   if #dictionaries>0 then
15331    for i=1,#dictionaries do
15332     dictionaries[i]=readstring(f,dictionaries[i])
15333    end
15334    parsedictionaries(data,dictionaries)
15335    cid.dictionaries=dictionaries
15336    readcidprivates(f,data)
15337    for i=1,#dictionaries do
15338     readlocals(f,data,dictionaries[i],version)
15339    end
15340    startparsing(fontdata,data,streams)
15341    for i=1,#charstrings do
15342     local dictionary=dictionaries[fdindex[i]+1]
15343     if dictionary then
15344      parsecharstring(fontdata,data,dictionary,charstrings[i],glyphs,i,doshapes,version,streams)
15345     else
15346     end
15347    end
15348    stopparsing(fontdata,data)
15349   else
15350    report("no cid dictionaries")
15351   end
15352  else
15353   report("no cid array")
15354  end
15355 end
15356end
15357local gotodatatable=readers.helpers.gotodatatable
15358local function cleanup(data,dictionaries)
15359end
15360function readers.cff(f,fontdata,specification)
15361 local tableoffset=gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs)
15362 if tableoffset then
15363  local header=readheader(f)
15364  if header.major~=1 then
15365   report("only version %s is supported for table %a",1,"cff")
15366   return
15367  end
15368  local glyphs=fontdata.glyphs
15369  local names=readfontnames(f)
15370  local dictionaries=readtopdictionaries(f)
15371  local strings=readstrings(f)
15372  local data={
15373   header=header,
15374   names=names,
15375   dictionaries=dictionaries,
15376   strings=strings,
15377   nofglyphs=fontdata.nofglyphs,
15378  }
15379  parsedictionaries(data,dictionaries,"cff")
15380  local dic=dictionaries[1]
15381  local cid=dic.cid
15382  local cffinfo={
15383   familyname=dic.familyname,
15384   fullname=dic.fullname,
15385   boundingbox=dic.boundingbox,
15386   weight=dic.weight,
15387   italicangle=dic.italicangle,
15388   underlineposition=dic.underlineposition,
15389   underlinethickness=dic.underlinethickness,
15390   defaultwidth=dic.defaultwidthx,
15391   nominalwidth=dic.nominalwidthx,
15392   monospaced=dic.monospaced,
15393  }
15394  fontdata.cidinfo=cid and {
15395   registry=cid.registry,
15396   ordering=cid.ordering,
15397   supplement=cid.supplement,
15398  }
15399  fontdata.cffinfo=cffinfo
15400  local all=specification.shapes or specification.streams or false
15401  if specification.glyphs or all then
15402   if cid and cid.fdselect then
15403    readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
15404   else
15405    readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
15406   end
15407  end
15408  local private=dic.private
15409  if private then
15410   local data=private.data
15411   if type(data)=="table" then
15412    cffinfo.defaultwidth=data.defaultwidthx or cffinfo.defaultwidth
15413    cffinfo.nominalwidth=data.nominalwidthx or cffinfo.nominalwidth
15414    cffinfo.bluevalues=data.bluevalues
15415    cffinfo.otherblues=data.otherblues
15416    cffinfo.familyblues=data.familyblues
15417    cffinfo.familyotherblues=data.familyotherblues
15418    cffinfo.bluescale=data.bluescale
15419    cffinfo.blueshift=data.blueshift
15420    cffinfo.bluefuzz=data.bluefuzz
15421    cffinfo.stdhw=data.stdhw
15422    cffinfo.stdvw=data.stdvw
15423    cffinfo.stemsnaph=data.stemsnaph
15424    cffinfo.stemsnapv=data.stemsnapv
15425   end
15426  end
15427  cleanup(data,dictionaries)
15428 end
15429end
15430function readers.cff2(f,fontdata,specification)
15431 local tableoffset=gotodatatable(f,fontdata,"cff2",specification.glyphs)
15432 if tableoffset then
15433  local header=readheader(f)
15434  if header.major~=2 then
15435   report("only version %s is supported for table %a",2,"cff2")
15436   return
15437  end
15438  local glyphs=fontdata.glyphs
15439  local dictionaries={ readstring(f,header.dsize) }
15440  local data={
15441   header=header,
15442   dictionaries=dictionaries,
15443   nofglyphs=fontdata.nofglyphs,
15444  }
15445  parsedictionaries(data,dictionaries,"cff2")
15446  local offset=dictionaries[1].vstore
15447  if offset>0 then
15448   local storeoffset=dictionaries[1].vstore+data.header.offset+2 
15449   local regions,deltas=readers.helpers.readvariationdata(f,storeoffset,factors)
15450   data.regions=regions
15451   data.deltas=deltas
15452  else
15453   data.regions={}
15454   data.deltas={}
15455  end
15456  data.factors=specification.factors
15457  local cid=data.dictionaries[1].cid
15458  local all=specification.shapes or specification.streams or false
15459  if cid and cid.fdselect then
15460   readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
15461  else
15462   readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
15463  end
15464  cleanup(data,dictionaries)
15465 end
15466end
15467
15468end -- closure
15469
15470do -- begin closure to overcome local limits and interference
15471
15472if not modules then modules={} end modules ['font-ttf']={
15473 version=1.001,
15474 optimize=true,
15475 comment="companion to font-ini.mkiv",
15476 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
15477 copyright="PRAGMA ADE / ConTeXt Development Team",
15478 license="see context related readme files"
15479}
15480local next,type,unpack=next,type,unpack
15481local band,rshift=bit32.band,bit32.rshift
15482local sqrt,round,abs,min,max=math.sqrt,math.round,math.abs,math.min,math.max
15483local char,rep=string.char,string.rep
15484local concat=table.concat
15485local idiv=number.idiv
15486local setmetatableindex=table.setmetatableindex
15487local report=logs.reporter("otf reader","ttf")
15488local trace_deltas=false
15489local readers=fonts.handlers.otf.readers
15490local streamreader=readers.streamreader
15491local setposition=streamreader.setposition
15492local getposition=streamreader.getposition
15493local skipbytes=streamreader.skip
15494local readbyte=streamreader.readcardinal1  
15495local readushort=streamreader.readcardinal2  
15496local readulong=streamreader.readcardinal4  
15497local readchar=streamreader.readinteger1   
15498local readshort=streamreader.readinteger2   
15499local read2dot14=streamreader.read2dot14  
15500local readinteger=streamreader.readinteger1
15501local readcardinaltable=streamreader.readcardinaltable
15502local readintegertable=streamreader.readintegertable
15503directives.register("fonts.streamreader",function()
15504 streamreader=utilities.streams
15505 setposition=streamreader.setposition
15506 getposition=streamreader.getposition
15507 skipbytes=streamreader.skip
15508 readbyte=streamreader.readcardinal1
15509 readushort=streamreader.readcardinal2
15510 readulong=streamreader.readcardinal4
15511 readchar=streamreader.readinteger1
15512 readshort=streamreader.readinteger2
15513 read2dot14=streamreader.read2dot14
15514 readinteger=streamreader.readinteger1
15515 readcardinaltable=streamreader.readcardinaltable
15516 readintegertable=streamreader.readintegertable
15517end)
15518local short=2
15519local ushort=2
15520local ulong=4
15521local helpers=readers.helpers
15522local gotodatatable=helpers.gotodatatable
15523local function mergecomposites(glyphs,shapes)
15524 local function merge(index,shape,components)
15525  local contours={}
15526  local points={}
15527  local nofcontours=0
15528  local nofpoints=0
15529  local offset=0
15530  local deltas=shape.deltas
15531  for i=1,#components do
15532   local component=components[i]
15533   local subindex=component.index
15534   local subshape=shapes[subindex]
15535   local subcontours=subshape.contours
15536   local subpoints=subshape.points
15537   if not subcontours then
15538    local subcomponents=subshape.components
15539    if subcomponents then
15540     subcontours,subpoints=merge(subindex,subshape,subcomponents)
15541    end
15542   end
15543   if subpoints then
15544    local matrix=component.matrix
15545    local xscale=matrix[1]
15546    local xrotate=matrix[2]
15547    local yrotate=matrix[3]
15548    local yscale=matrix[4]
15549    local xoffset=matrix[5]
15550    local yoffset=matrix[6]
15551    local count=#subpoints
15552    if xscale==1 and yscale==1 and xrotate==0 and yrotate==0 then
15553     for i=1,count do
15554      local p=subpoints[i]
15555      nofpoints=nofpoints+1
15556      points[nofpoints]={
15557       p[1]+xoffset,
15558       p[2]+yoffset,
15559       p[3]
15560      }
15561     end
15562    else
15563     for i=1,count do
15564      local p=subpoints[i]
15565      local x=p[1]
15566      local y=p[2]
15567      nofpoints=nofpoints+1
15568      points[nofpoints]={
15569       xscale*x+xrotate*y+xoffset,
15570       yscale*y+yrotate*x+yoffset,
15571       p[3]
15572      }
15573     end
15574    end
15575    local subcount=#subcontours
15576    if subcount==1 then
15577     nofcontours=nofcontours+1
15578     contours[nofcontours]=offset+subcontours[1]
15579    else
15580     for i=1,#subcontours do
15581      nofcontours=nofcontours+1
15582      contours[nofcontours]=offset+subcontours[i]
15583     end
15584    end
15585    offset=offset+count
15586   else
15587    report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex)
15588   end
15589  end
15590  shape.points=points 
15591  shape.contours=contours
15592  shape.components=nil
15593  return contours,points
15594 end
15595 for index=0,#glyphs do
15596  local shape=shapes[index]
15597  if shape then
15598   local components=shape.components
15599   if components then
15600    merge(index,shape,components)
15601   end
15602  end
15603 end
15604end
15605local function readnothing(f)
15606 return {
15607  type="nothing",
15608 }
15609end
15610local function curveto(m_x,m_y,l_x,l_y,r_x,r_y) 
15611 return
15612  l_x+2/3*(m_x-l_x),l_y+2/3*(m_y-l_y),
15613  r_x+2/3*(m_x-r_x),r_y+2/3*(m_y-r_y),
15614  r_x,r_y,"c"
15615end
15616local xv={} 
15617local yv={} 
15618local function applyaxis(glyph,shape,deltas,dowidth)
15619 local points=shape.points
15620 if points then
15621  local nofpoints=#points
15622  local dw=0
15623  local dl=0
15624  for i=1,#deltas do
15625   local deltaset=deltas[i]
15626   local xvalues=deltaset.xvalues
15627   local yvalues=deltaset.yvalues
15628   if xvalues and yvalues then
15629    local dpoints=deltaset.points
15630    local factor=deltaset.factor
15631    if dpoints then
15632     local cnt=#dpoints
15633     if dowidth then
15634      cnt=cnt-4
15635     end
15636     if cnt>0 then
15637      local contours=shape.contours
15638      local nofcontours=#contours
15639      local first=1
15640      local firstindex=1
15641      for contour=1,nofcontours do
15642       local last=contours[contour]
15643       if last>=first then
15644        local lastindex=cnt
15645        if firstindex<cnt then
15646         for currentindex=firstindex,cnt do
15647          local found=dpoints[currentindex]
15648          if found<=first then
15649           firstindex=currentindex
15650          end
15651          if found==last then
15652           lastindex=currentindex
15653           break
15654          elseif found>last then
15655           while lastindex>1 and dpoints[lastindex]>last do
15656            lastindex=lastindex-1
15657           end
15658           break
15659          end
15660         end
15661        end
15662        local function find(i)
15663         local prv=lastindex
15664         for j=firstindex,lastindex do
15665          local nxt=dpoints[j] 
15666          if nxt==i then
15667           return false,j,false
15668          elseif nxt>i then
15669           return prv,false,j
15670          end
15671          prv=j
15672         end
15673         return prv,false,firstindex
15674        end
15675        for point=first,last do
15676         local d1,d2,d3=find(point)
15677         local p2=points[point]
15678         if d2 then
15679          xv[point]=xvalues[d2]
15680          yv[point]=yvalues[d2]
15681         else
15682          local n1=dpoints[d1]
15683          local n3=dpoints[d3]
15684          if n1>nofpoints then
15685           n1=nofpoints
15686          end
15687          if n3>nofpoints then
15688           n3=nofpoints
15689          end
15690          local p1=points[n1]
15691          local p3=points[n3]
15692          local p1x=p1[1]
15693          local p2x=p2[1]
15694          local p3x=p3[1]
15695          local p1y=p1[2]
15696          local p2y=p2[2]
15697          local p3y=p3[2]
15698          local x1=xvalues[d1]
15699          local y1=yvalues[d1]
15700          local x3=xvalues[d3]
15701          local y3=yvalues[d3]
15702          local fx
15703          local fy
15704          if p1x==p3x then
15705           if x1==x3 then
15706            fx=x1
15707           else
15708            fx=0
15709           end
15710          elseif p2x<=min(p1x,p3x) then
15711           if p1x<p3x then
15712            fx=x1
15713           else
15714            fx=x3
15715           end
15716          elseif p2x>=max(p1x,p3x) then
15717           if p1x>p3x then
15718            fx=x1
15719           else
15720            fx=x3
15721           end
15722          else
15723           fx=(p2x-p1x)/(p3x-p1x)
15724           fx=(1-fx)*x1+fx*x3
15725          end
15726          if p1y==p3y then
15727           if y1==y3 then
15728            fy=y1
15729           else
15730            fy=0
15731           end
15732          elseif p2y<=min(p1y,p3y) then
15733           if p1y<p3y then
15734            fy=y1
15735           else
15736            fy=y3
15737           end
15738          elseif p2y>=max(p1y,p3y) then
15739           if p1y>p3y then
15740            fy=y1
15741           else
15742            fy=y3
15743           end
15744          else
15745           fy=(p2y-p1y)/(p3y-p1y)
15746           fy=(1-fy)*y1+fy*y3
15747          end
15748          xv[point]=fx
15749          yv[point]=fy
15750         end
15751        end
15752        if lastindex<cnt then
15753         firstindex=lastindex+1
15754        end
15755       end
15756       first=last+1
15757      end
15758      for i=1,nofpoints do
15759       local pi=points[i]
15760       local fx=xv[i]
15761       local fy=yv[i]
15762       if fx~=0 then
15763        pi[1]=pi[1]+factor*fx
15764       end
15765       if fy~=0 then
15766        pi[2]=pi[2]+factor*fy
15767       end
15768      end
15769     else
15770      report("bad deltapoint data, maybe a missing hvar table")
15771     end
15772    else
15773     for i=1,nofpoints do
15774      local p=points[i]
15775      local x=xvalues[i]
15776      if x then
15777       local y=yvalues[i]
15778       if x~=0 then
15779        p[1]=p[1]+factor*x
15780       end
15781       if y~=0 then
15782        p[2]=p[2]+factor*y
15783       end
15784      else
15785       break
15786      end
15787     end
15788    end
15789    if dowidth then
15790     local h=nofpoints+2 
15791     local l=nofpoints+1
15792     local x=xvalues[h]
15793     if x then
15794      dw=dw+factor*x
15795     end
15796     local x=xvalues[l]
15797     if x then
15798      dl=dl+factor*x
15799     end
15800    end
15801   end
15802  end
15803  if dowidth then
15804   local width=glyph.width or 0
15805   glyph.width=width+dw-dl
15806  end
15807 else
15808  report("no points for glyph %a",glyph.name)
15809 end
15810end
15811local quadratic=false
15812local function contours2outlines_normal(glyphs,shapes)
15813 for index=0,#glyphs-1 do
15814  local shape=shapes[index]
15815  if shape then
15816   local glyph=glyphs[index]
15817   local contours=shape.contours
15818   local points=shape.points
15819   if contours then
15820    local nofcontours=#contours
15821    local segments={}
15822    local nofsegments=0
15823    glyph.segments=segments
15824    if nofcontours>0 then
15825     local px=0
15826     local py=0
15827     local first=1
15828     for i=1,nofcontours do
15829      local last=contours[i]
15830      if last>=first then
15831       local first_pt=points[first]
15832       local first_on=first_pt[3]
15833       if first==last then
15834        first_pt[3]="m" 
15835        nofsegments=nofsegments+1
15836        segments[nofsegments]=first_pt
15837       else 
15838        local first_on=first_pt[3]
15839        local last_pt=points[last]
15840        local last_on=last_pt[3]
15841        local start=1
15842        local control_pt=false
15843        if first_on then
15844         start=2
15845        else
15846         if last_on then
15847          first_pt=last_pt
15848         else
15849          first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
15850         end
15851         control_pt=first_pt
15852        end
15853        local x=first_pt[1]
15854        local y=first_pt[2]
15855        if not done then
15856         xmin=x
15857         ymin=y
15858         xmax=x
15859         ymax=y
15860         done=true
15861        end
15862        nofsegments=nofsegments+1
15863        segments[nofsegments]={ x,y,"m" } 
15864        if not quadratic then
15865         px=x
15866         py=y
15867        end
15868        local previous_pt=first_pt
15869        for i=first,last do
15870         local current_pt=points[i]
15871         local current_on=current_pt[3]
15872         local previous_on=previous_pt[3]
15873         if previous_on then
15874          if current_on then
15875           local x,y=current_pt[1],current_pt[2]
15876           nofsegments=nofsegments+1
15877           segments[nofsegments]={ x,y,"l" } 
15878           if not quadratic then
15879            px,py=x,y
15880           end
15881          else
15882           control_pt=current_pt
15883          end
15884         elseif current_on then
15885          local x1=control_pt[1]
15886          local y1=control_pt[2]
15887          local x2=current_pt[1]
15888          local y2=current_pt[2]
15889          nofsegments=nofsegments+1
15890          if quadratic then
15891           segments[nofsegments]={ x1,y1,x2,y2,"q" } 
15892          else
15893           x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
15894           segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" } 
15895          end
15896          control_pt=false
15897         else
15898          local x2=(previous_pt[1]+current_pt[1])/2
15899          local y2=(previous_pt[2]+current_pt[2])/2
15900          local x1=control_pt[1]
15901          local y1=control_pt[2]
15902          nofsegments=nofsegments+1
15903          if quadratic then
15904           segments[nofsegments]={ x1,y1,x2,y2,"q" } 
15905          else
15906           x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
15907           segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" } 
15908          end
15909          control_pt=current_pt
15910         end
15911         previous_pt=current_pt
15912        end
15913        if first_pt==last_pt then
15914        else
15915         nofsegments=nofsegments+1
15916         local x2=first_pt[1]
15917         local y2=first_pt[2]
15918         if not control_pt then
15919          segments[nofsegments]={ x2,y2,"l" } 
15920         elseif quadratic then
15921          local x1=control_pt[1]
15922          local y1=control_pt[2]
15923          segments[nofsegments]={ x1,y1,x2,y2,"q" } 
15924         else
15925          local x1=control_pt[1]
15926          local y1=control_pt[2]
15927          x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
15928          segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
15929         end
15930        end
15931       end
15932      end
15933      first=last+1
15934     end
15935    end
15936   end
15937  end
15938 end
15939end
15940local function contours2outlines_shaped(glyphs,shapes,keepcurve)
15941 for index=0,#glyphs-1 do
15942  local shape=shapes[index]
15943  if shape then
15944   local glyph=glyphs[index]
15945   local contours=shape.contours
15946   local points=shape.points
15947   if contours then
15948    local nofcontours=#contours
15949    local segments=keepcurve and {} or nil
15950    local nofsegments=0
15951    if keepcurve then
15952     glyph.segments=segments
15953    end
15954    if nofcontours>0 then
15955     local xmin,ymin,xmax,ymax,done=0,0,0,0,false
15956     local px,py=0,0 
15957     local first=1
15958     for i=1,nofcontours do
15959      local last=contours[i]
15960      if last>=first then
15961       local first_pt=points[first]
15962       local first_on=first_pt[3]
15963       if first==last then
15964        if keepcurve then
15965         first_pt[3]="m" 
15966         nofsegments=nofsegments+1
15967         segments[nofsegments]=first_pt
15968        end
15969       else 
15970        local first_on=first_pt[3]
15971        local last_pt=points[last]
15972        local last_on=last_pt[3]
15973        local start=1
15974        local control_pt=false
15975        if first_on then
15976         start=2
15977        else
15978         if last_on then
15979          first_pt=last_pt
15980         else
15981          first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
15982         end
15983         control_pt=first_pt
15984        end
15985        local x=first_pt[1]
15986        local y=first_pt[2]
15987        if not done then
15988         xmin,ymin,xmax,ymax=x,y,x,y
15989         done=true
15990        else
15991         if x<xmin then xmin=x elseif x>xmax then xmax=x end
15992         if y<ymin then ymin=y elseif y>ymax then ymax=y end
15993        end
15994        if keepcurve then
15995         nofsegments=nofsegments+1
15996         segments[nofsegments]={ x,y,"m" } 
15997        end
15998        if not quadratic then
15999         px=x
16000         py=y
16001        end
16002        local previous_pt=first_pt
16003        for i=first,last do
16004         local current_pt=points[i]
16005         local current_on=current_pt[3]
16006         local previous_on=previous_pt[3]
16007         if previous_on then
16008          if current_on then
16009           local x=current_pt[1]
16010           local y=current_pt[2]
16011           if x<xmin then xmin=x elseif x>xmax then xmax=x end
16012           if y<ymin then ymin=y elseif y>ymax then ymax=y end
16013           if keepcurve then
16014            nofsegments=nofsegments+1
16015            segments[nofsegments]={ x,y,"l" } 
16016           end
16017           if not quadratic then
16018            px=x
16019            py=y
16020           end
16021          else
16022           control_pt=current_pt
16023          end
16024         elseif current_on then
16025          local x1=control_pt[1]
16026          local y1=control_pt[2]
16027          local x2=current_pt[1]
16028          local y2=current_pt[2]
16029          if quadratic then
16030           if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
16031           if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
16032           if keepcurve then
16033            nofsegments=nofsegments+1
16034            segments[nofsegments]={ x1,y1,x2,y2,"q" } 
16035           end
16036          else
16037           x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
16038           if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
16039           if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
16040           if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
16041           if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
16042           if px<xmin then xmin=px elseif px>xmax then xmax=px end
16043           if py<ymin then ymin=py elseif py>ymax then ymax=py end
16044           if keepcurve then
16045            nofsegments=nofsegments+1
16046            segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" } 
16047           end
16048          end
16049          control_pt=false
16050         else
16051          local x2=(previous_pt[1]+current_pt[1])/2
16052          local y2=(previous_pt[2]+current_pt[2])/2
16053          local x1=control_pt[1]
16054          local y1=control_pt[2]
16055          if quadratic then
16056           if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
16057           if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
16058           if keepcurve then
16059            nofsegments=nofsegments+1
16060            segments[nofsegments]={ x1,y1,x2,y2,"q" } 
16061           end
16062          else
16063           x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
16064           if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
16065           if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
16066           if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
16067           if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
16068           if px<xmin then xmin=px elseif px>xmax then xmax=px end
16069           if py<ymin then ymin=py elseif py>ymax then ymax=py end
16070           if keepcurve then
16071            nofsegments=nofsegments+1
16072            segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" } 
16073           end
16074          end
16075          control_pt=current_pt
16076         end
16077         previous_pt=current_pt
16078        end
16079        if first_pt==last_pt then
16080        elseif not control_pt then
16081         if keepcurve then
16082          nofsegments=nofsegments+1
16083          segments[nofsegments]={ first_pt[1],first_pt[2],"l" } 
16084         end
16085        else
16086         local x1=control_pt[1]
16087         local y1=control_pt[2]
16088         local x2=first_pt[1]
16089         local y2=first_pt[2]
16090         if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
16091         if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
16092         if quadratic then
16093          if keepcurve then
16094           nofsegments=nofsegments+1
16095           segments[nofsegments]={ x1,y1,x2,y2,"q" } 
16096          end
16097         else
16098          x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
16099          if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
16100          if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
16101          if px<xmin then xmin=px elseif px>xmax then xmax=px end
16102          if py<ymin then ymin=py elseif py>ymax then ymax=py end
16103          if keepcurve then
16104           nofsegments=nofsegments+1
16105           segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" } 
16106          end
16107         end
16108        end
16109       end
16110      end
16111      first=last+1
16112     end
16113     xmin=glyph.boundingbox[1]
16114     local dlsb=glyph.dlsb
16115     if dlsb then
16116      xmin=xmin+dlsb
16117      glyph.dlsb=nil 
16118     end
16119     glyph.boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) }
16120    end
16121   end
16122  end
16123 end
16124end
16125local c_zero=char(0)
16126local s_zero=char(0,0)
16127local function toushort(n)
16128 return char(band(rshift(n,8),0xFF),band(n,0xFF))
16129end
16130local function toshort(n)
16131 if n<0 then
16132  n=n+0x10000
16133 end
16134 return char(band(rshift(n,8),0xFF),band(n,0xFF))
16135end
16136local chars=setmetatableindex(function(t,k)
16137 for i=0,255 do local v=char(i) t[i]=v end return t[k]
16138end)
16139local function repackpoints(glyphs,shapes)
16140 local noboundingbox={ 0,0,0,0 }
16141 local result={} 
16142 local xpoints={} 
16143 local ypoints={} 
16144 for index=0,#glyphs do
16145  local shape=shapes[index]
16146  if shape then
16147   local r=0
16148   local glyph=glyphs[index]
16149   local contours=shape.contours
16150   local nofcontours=contours and #contours or 0
16151   local boundingbox=glyph.boundingbox or noboundingbox
16152   r=r+1 result[r]=toshort(nofcontours)
16153   r=r+1 result[r]=toshort(boundingbox[1]) 
16154   r=r+1 result[r]=toshort(boundingbox[2]) 
16155   r=r+1 result[r]=toshort(boundingbox[3]) 
16156   r=r+1 result[r]=toshort(boundingbox[4]) 
16157   if nofcontours>0 then
16158    for i=1,nofcontours do
16159     r=r+1 result[r]=toshort(contours[i]-1)
16160    end
16161    r=r+1 result[r]=s_zero 
16162    local points=shape.points
16163    local currentx=0
16164    local currenty=0
16165    local x=0
16166    local y=0
16167    local lastflag=nil
16168    local nofflags=0
16169    for i=1,#points do
16170     local pt=points[i]
16171     local px=pt[1]
16172     local py=pt[2]
16173     local fl=pt[3] and 0x01 or 0x00
16174     if px==currentx then
16175      fl=fl+0x10
16176     else
16177      local dx=round(px-currentx)
16178      x=x+1
16179      if dx<-255 or dx>255 then
16180       xpoints[x]=toshort(dx)
16181      elseif dx<0 then
16182       fl=fl+0x02
16183       xpoints[x]=chars[-dx]
16184      elseif dx>0 then
16185       fl=fl+0x12
16186       xpoints[x]=chars[dx]
16187      else
16188       fl=fl+0x02
16189       xpoints[x]=c_zero
16190      end
16191     end
16192     if py==currenty then
16193      fl=fl+0x20
16194     else
16195      local dy=round(py-currenty)
16196      y=y+1
16197      if dy<-255 or dy>255 then
16198       ypoints[y]=toshort(dy)
16199      elseif dy<0 then
16200       fl=fl+0x04
16201       ypoints[y]=chars[-dy]
16202      elseif dy>0 then
16203       fl=fl+0x24
16204       ypoints[y]=chars[dy]
16205      else
16206       fl=fl+0x04
16207       ypoints[y]=c_zero
16208      end
16209     end
16210     currentx=px
16211     currenty=py
16212     if lastflag==fl then
16213      if nofflags==255 then
16214       lastflag=lastflag+0x08
16215       r=r+1 result[r]=char(lastflag,nofflags-1)
16216       nofflags=1
16217       lastflag=fl
16218      else
16219       nofflags=nofflags+1
16220      end
16221     else 
16222      if nofflags==1 then
16223       r=r+1 result[r]=chars[lastflag]
16224      elseif nofflags==2 then
16225       r=r+1 result[r]=char(lastflag,lastflag)
16226      elseif nofflags>2 then
16227       lastflag=lastflag+0x08
16228       r=r+1 result[r]=char(lastflag,nofflags-1)
16229      end
16230      nofflags=1
16231      lastflag=fl
16232     end
16233    end
16234    if nofflags==1 then
16235     r=r+1 result[r]=chars[lastflag]
16236    elseif nofflags==2 then
16237     r=r+1 result[r]=char(lastflag,lastflag)
16238    elseif nofflags>2 then
16239     lastflag=lastflag+0x08
16240     r=r+1 result[r]=char(lastflag,nofflags-1)
16241    end
16242    r=r+1 result[r]=concat(xpoints,"",1,x)
16243    r=r+1 result[r]=concat(ypoints,"",1,y)
16244   end
16245   local stream=concat(result,"",1,r)
16246   local length=#stream
16247   local padding=idiv(length+3,4)*4-length
16248   if padding>0 then
16249    if padding==1 then
16250     padding="\0"
16251    elseif padding==2 then
16252     padding="\0\0"
16253    else
16254     padding="\0\0\0"
16255    end
16256    padding=stream..padding
16257   end
16258   glyph.stream=stream
16259  end
16260 end
16261end
16262local flags={}
16263local function readglyph(f,nofcontours) 
16264 local points={}
16265 local contours={} 
16266 for i=1,nofcontours do
16267  contours[i]=readshort(f)+1
16268 end
16269 local nofpoints=contours[nofcontours]
16270 local nofinstructions=readushort(f)
16271 skipbytes(f,nofinstructions)
16272 local i=1
16273 while i<=nofpoints do
16274  local flag=readbyte(f)
16275  flags[i]=flag
16276  if band(flag,0x08)~=0 then
16277   local n=readbyte(f)
16278   if n==1 then
16279    i=i+1
16280    flags[i]=flag
16281   else
16282    for j=1,n do
16283     i=i+1
16284     flags[i]=flag
16285    end
16286   end
16287  end
16288  i=i+1
16289 end
16290 local x=0
16291 for i=1,nofpoints do
16292  local flag=flags[i]
16293  if band(flag,0x02)~=0 then
16294   if band(flag,0x10)~=0 then
16295    x=x+readbyte(f)
16296   else
16297    x=x-readbyte(f)
16298   end
16299  elseif band(flag,0x10)~=0 then
16300  else
16301   x=x+readshort(f)
16302  end
16303  points[i]={ x,0,band(flag,0x01)~=0 }
16304 end
16305 local y=0
16306 for i=1,nofpoints do
16307  local flag=flags[i]
16308  if band(flag,0x04)~=0 then
16309   if band(flag,0x20)~=0 then
16310    y=y+readbyte(f)
16311   else
16312    y=y-readbyte(f)
16313   end
16314  elseif band(flag,0x20)~=0 then
16315  else
16316   y=y+readshort(f)
16317  end
16318  points[i][2]=y
16319 end
16320 return {
16321  type="glyph",
16322  points=points,
16323  contours=contours,
16324  nofpoints=nofpoints,
16325 }
16326end
16327local function readcomposite(f)
16328 local components={}
16329 local nofcomponents=0
16330 local instructions=false
16331 while true do
16332  local flags=readushort(f)
16333  local index=readushort(f)
16334  local f_xyarg=band(flags,0x0002)~=0
16335  local f_offset=band(flags,0x0800)~=0
16336  local xscale=1
16337  local xrotate=0
16338  local yrotate=0
16339  local yscale=1
16340  local xoffset=0
16341  local yoffset=0
16342  local base=false
16343  local reference=false
16344  if f_xyarg then
16345   if band(flags,0x0001)~=0 then 
16346    xoffset=readshort(f)
16347    yoffset=readshort(f)
16348   else
16349    xoffset=readchar(f) 
16350    yoffset=readchar(f) 
16351   end
16352  else
16353   if band(flags,0x0001)~=0 then 
16354    base=readshort(f)
16355    reference=readshort(f)
16356   else
16357    base=readchar(f) 
16358    reference=readchar(f) 
16359   end
16360  end
16361  if band(flags,0x0008)~=0 then 
16362   xscale=read2dot14(f)
16363   yscale=xscale
16364   if f_xyarg and f_offset then
16365    xoffset=xoffset*xscale
16366    yoffset=yoffset*yscale
16367   end
16368  elseif band(flags,0x0040)~=0 then 
16369   xscale=read2dot14(f)
16370   yscale=read2dot14(f)
16371   if f_xyarg and f_offset then
16372    xoffset=xoffset*xscale
16373    yoffset=yoffset*yscale
16374   end
16375  elseif band(flags,0x0080)~=0 then 
16376   xscale=read2dot14(f) 
16377   xrotate=read2dot14(f) 
16378   yrotate=read2dot14(f) 
16379   yscale=read2dot14(f) 
16380   if f_xyarg and f_offset then
16381    xoffset=xoffset*sqrt(xscale^2+yrotate^2) 
16382    yoffset=yoffset*sqrt(xrotate^2+yscale^2) 
16383   end
16384  end
16385  nofcomponents=nofcomponents+1
16386  components[nofcomponents]={
16387   index=index,
16388   usemine=band(flags,0x0200)~=0,
16389   round=band(flags,0x0006)~=0,
16390   base=base,
16391   reference=reference,
16392   matrix={ xscale,xrotate,yrotate,yscale,xoffset,yoffset },
16393  }
16394  if band(flags,0x0100)~=0 then
16395   instructions=true
16396  end
16397  if band(flags,0x0020)==0 then 
16398   break
16399  end
16400 end
16401 return {
16402  type="composite",
16403  components=components,
16404 }
16405end
16406function readers.loca(f,fontdata,specification)
16407 if specification.glyphs then
16408  local datatable=fontdata.tables.loca
16409  if datatable then
16410   local offset=fontdata.tables.glyf.offset
16411   local format=fontdata.fontheader.indextolocformat
16412   local profile=fontdata.maximumprofile
16413   local nofglyphs=profile and profile.nofglyphs
16414   local locations={}
16415   setposition(f,datatable.offset)
16416   if format==1 then
16417    if not nofglyphs then
16418     nofglyphs=idiv(datatable.length,4)-1
16419    end
16420    for i=0,nofglyphs do
16421     locations[i]=offset+readulong(f)
16422    end
16423    fontdata.nofglyphs=nofglyphs
16424   else
16425    if not nofglyphs then
16426     nofglyphs=idiv(datatable.length,2)-1
16427    end
16428    for i=0,nofglyphs do
16429     locations[i]=offset+readushort(f)*2
16430    end
16431   end
16432   fontdata.nofglyphs=nofglyphs
16433   fontdata.locations=locations
16434  end
16435 end
16436end
16437function readers.glyf(f,fontdata,specification) 
16438 local tableoffset=gotodatatable(f,fontdata,"glyf",specification.glyphs)
16439 if tableoffset then
16440  local locations=fontdata.locations
16441  if locations then
16442   local glyphs=fontdata.glyphs
16443   local nofglyphs=fontdata.nofglyphs
16444   local filesize=fontdata.filesize
16445   local nothing={ 0,0,0,0 }
16446   local shapes={}
16447   local loadshapes=specification.shapes or specification.instance or specification.streams
16448   for index=0,nofglyphs-1 do
16449    local location=locations[index]
16450    local length=locations[index+1]-location
16451    if location>=filesize then
16452     report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
16453     fontdata.nofglyphs=index-1
16454     fontdata.badfont=true
16455     break
16456    elseif length>0 then
16457     setposition(f,location)
16458     local nofcontours=readshort(f)
16459     glyphs[index].boundingbox={
16460      readshort(f),
16461      readshort(f),
16462      readshort(f),
16463      readshort(f),
16464     }
16465     if not loadshapes then
16466     elseif nofcontours==0 then
16467      shapes[index]=readnothing(f)
16468     elseif nofcontours>0 then
16469      shapes[index]=readglyph(f,nofcontours)
16470     else
16471      shapes[index]=readcomposite(f,nofcontours)
16472     end
16473    else
16474     if loadshapes then
16475      shapes[index]=readnothing(f)
16476     end
16477     glyphs[index].boundingbox=nothing
16478    end
16479   end
16480   if loadshapes then
16481    if readers.gvar then
16482     readers.gvar(f,fontdata,specification,glyphs,shapes)
16483    end
16484    mergecomposites(glyphs,shapes)
16485    if specification.instance then
16486     if specification.streams then
16487      repackpoints(glyphs,shapes)
16488     else
16489      contours2outlines_shaped(glyphs,shapes,specification.shapes)
16490     end
16491    elseif specification.shapes then
16492     if specification.streams then
16493      repackpoints(glyphs,shapes)
16494     else
16495      contours2outlines_normal(glyphs,shapes)
16496     end
16497    elseif specification.streams then
16498     repackpoints(glyphs,shapes)
16499    end
16500   end
16501  end
16502 end
16503end
16504local function readtuplerecord(f,nofaxis)
16505 local record={}
16506 for i=1,nofaxis do
16507  record[i]=read2dot14(f)
16508 end
16509 return record
16510end
16511local function readpoints(f)
16512 local count=readbyte(f)
16513 if count==0 then
16514  return nil,0 
16515 else
16516  if count<128 then
16517  elseif band(count,0x80)~=0 then
16518   count=band(count,0x7F)*256+readbyte(f)
16519  else
16520  end
16521  local points={}
16522  local p=0
16523  local n=1 
16524  while p<count do
16525   local control=readbyte(f)
16526   local runreader=band(control,0x80)~=0 and readushort or readbyte
16527   local runlength=band(control,0x7F)
16528   for i=1,runlength+1 do
16529    n=n+runreader(f)
16530    p=p+1
16531    points[p]=n
16532   end
16533  end
16534  return points,p
16535 end
16536end
16537local function readdeltas(f,nofpoints)
16538 local deltas={}
16539 local p=0
16540 while nofpoints>0 do
16541  local control=readbyte(f)
16542  if control then
16543   local allzero=band(control,0x80)~=0
16544   local runlength=band(control,0x3F)+1
16545   if allzero then
16546    for i=1,runlength do
16547     p=p+1
16548     deltas[p]=0
16549    end
16550   else
16551    local runreader=band(control,0x40)~=0 and readshort or readinteger
16552    for i=1,runlength do
16553     p=p+1
16554     deltas[p]=runreader(f)
16555    end
16556   end
16557   nofpoints=nofpoints-runlength
16558  else
16559   break
16560  end
16561 end
16562 if p>0 then
16563  return deltas
16564 else
16565 end
16566end
16567function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
16568 local instance=specification.instance
16569 if not instance then
16570  return
16571 end
16572 local factors=specification.factors
16573 if not factors then
16574  return
16575 end
16576 local tableoffset=gotodatatable(f,fontdata,"gvar",specification.variable or specification.shapes)
16577 if tableoffset then
16578  local version=readulong(f) 
16579  local nofaxis=readushort(f)
16580  local noftuples=readushort(f)
16581  local tupleoffset=tableoffset+readulong(f)
16582  local nofglyphs=readushort(f)
16583  local flags=readushort(f)
16584  local dataoffset=tableoffset+readulong(f)
16585  local data={}
16586  local tuples={}
16587  local glyphdata=fontdata.glyphs
16588  local dowidth=not fontdata.variabledata.hvarwidths
16589  if band(flags,0x0001)~=0  then
16590   for i=1,nofglyphs+1 do
16591    data[i]=dataoffset+readulong(f)
16592   end
16593  else
16594   for i=1,nofglyphs+1 do
16595    data[i]=dataoffset+2*readushort(f)
16596   end
16597  end
16598  if noftuples>0 then
16599   setposition(f,tupleoffset)
16600   for i=1,noftuples do
16601    tuples[i]=readtuplerecord(f,nofaxis)
16602   end
16603  end
16604  local nextoffset=false
16605  local startoffset=data[1]
16606  for i=1,nofglyphs do 
16607   nextoffset=data[i+1]
16608   local glyph=glyphdata[i-1]
16609   local name=trace_deltas and glyph.name
16610   if startoffset==nextoffset then
16611    if name then
16612     report("no deltas for glyph %a",name)
16613    end
16614   else
16615    local shape=shapedata[i-1] 
16616    if not shape then
16617     if name then
16618      report("no shape for glyph %a",name)
16619     end
16620    else
16621     lastoffset=startoffset
16622     setposition(f,startoffset)
16623     local flags=readushort(f)
16624     local count=band(flags,0x0FFF)
16625     local offset=startoffset+readushort(f) 
16626     local deltas={}
16627     local allpoints=(shape.nofpoints or 0) 
16628     local shared=false
16629     local nofshared=0
16630     if band(flags,0x8000)~=0  then
16631      local current=getposition(f)
16632      setposition(f,offset)
16633      shared,nofshared=readpoints(f)
16634      offset=getposition(f)
16635      setposition(f,current)
16636     end
16637     for j=1,count do
16638      local size=readushort(f) 
16639      local flags=readushort(f)
16640      local index=band(flags,0x0FFF)
16641      local haspeak=band(flags,0x8000)~=0
16642      local intermediate=band(flags,0x4000)~=0
16643      local private=band(flags,0x2000)~=0
16644      local peak=nil
16645      local start=nil
16646      local stop=nil
16647      local xvalues=nil
16648      local yvalues=nil
16649      local points=shared 
16650      local nofpoints=nofshared
16651      if haspeak then
16652       peak=readtuplerecord(f,nofaxis)
16653      else
16654       if index+1>#tuples then
16655        report("error, bad tuple index",index)
16656       end
16657       peak=tuples[index+1] 
16658      end
16659      if intermediate then
16660       start=readtuplerecord(f,nofaxis)
16661       stop=readtuplerecord(f,nofaxis)
16662      end
16663      if size>0 then
16664       local current=getposition(f)
16665       setposition(f,offset)
16666       if private then
16667        points,nofpoints=readpoints(f)
16668       end 
16669       if nofpoints==0 then
16670        nofpoints=allpoints+4
16671       end
16672       if nofpoints>0 then
16673        xvalues=readdeltas(f,nofpoints)
16674        yvalues=readdeltas(f,nofpoints)
16675       end
16676       offset=offset+size
16677       setposition(f,current)
16678      end
16679      if not xvalues and not yvalues then
16680       points=nil
16681      end
16682      local s=1
16683      for i=1,nofaxis do
16684       local f=factors[i]
16685       local peak=peak  and peak [i] or 0
16686       local start=start and start[i] or (peak<0 and peak or 0)
16687       local stop=stop  and stop [i] or (peak>0 and peak or 0)
16688       if start>peak or peak>stop then
16689       elseif start<0 and stop>0 and peak~=0 then
16690       elseif peak==0 then
16691       elseif f<start or f>stop then
16692        s=0
16693        break
16694       elseif f<peak then
16695        s=s*(f-start)/(peak-start)
16696       elseif f>peak then
16697        s=s*(stop-f)/(stop-peak)
16698       else
16699       end
16700      end
16701      if s==0 then
16702       if name then
16703        report("no deltas applied for glyph %a",name)
16704       end
16705      else
16706       deltas[#deltas+1]={
16707        factor=s,
16708        points=points,
16709        xvalues=xvalues,
16710        yvalues=yvalues,
16711       }
16712      end
16713     end
16714     if shape.type=="glyph" then
16715      applyaxis(glyph,shape,deltas,dowidth)
16716     else
16717      shape.deltas=deltas
16718     end
16719    end
16720   end
16721   startoffset=nextoffset
16722  end
16723 end
16724end
16725
16726end -- closure
16727
16728do -- begin closure to overcome local limits and interference
16729
16730if not modules then modules={} end modules ['font-dsp']={
16731 version=1.001,
16732 optimize=true,
16733 comment="companion to font-ini.mkiv",
16734 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
16735 copyright="PRAGMA ADE / ConTeXt Development Team",
16736 license="see context related readme files"
16737}
16738local next,type,tonumber=next,type,tonumber
16739local band=bit32.band
16740local extract=bit32.extract
16741local bor=bit32.bor
16742local lshift=bit32.lshift
16743local rshift=bit32.rshift
16744local gsub=string.gsub
16745local lower=string.lower
16746local sub=string.sub
16747local strip=string.strip
16748local tohash=table.tohash
16749local concat=table.concat
16750local copy=table.copy
16751local reversed=table.reversed
16752local sort=table.sort
16753local insert=table.insert
16754local round=math.round
16755local settings_to_hash=utilities.parsers.settings_to_hash_colon_too
16756local setmetatableindex=table.setmetatableindex
16757local formatters=string.formatters
16758local sortedkeys=table.sortedkeys
16759local sortedhash=table.sortedhash
16760local sequenced=table.sequenced
16761local report=logs.reporter("otf reader")
16762local readers=fonts.handlers.otf.readers
16763local streamreader=readers.streamreader
16764local setposition=streamreader.setposition
16765local getposition=streamreader.getposition
16766local readuinteger=streamreader.readcardinal1
16767local readushort=streamreader.readcardinal2
16768local readulong=streamreader.readcardinal4
16769local readinteger=streamreader.readinteger1
16770local readshort=streamreader.readinteger2
16771local readstring=streamreader.readstring
16772local readtag=streamreader.readtag
16773local readbytes=streamreader.readbytes
16774local readfixed=streamreader.readfixed4
16775local read2dot14=streamreader.read2dot14
16776local skipshort=streamreader.skipshort
16777local skipbytes=streamreader.skip
16778local readbytetable=streamreader.readbytetable
16779local readbyte=streamreader.readbyte
16780local readcardinaltable=streamreader.readcardinaltable
16781local readintegertable=streamreader.readintegertable
16782local readfword=readshort
16783local short=2
16784local ushort=2
16785local ulong=4
16786directives.register("fonts.streamreader",function()
16787 streamreader=utilities.streams
16788 setposition=streamreader.setposition
16789 getposition=streamreader.getposition
16790 readuinteger=streamreader.readcardinal1
16791 readushort=streamreader.readcardinal2
16792 readulong=streamreader.readcardinal4
16793 readinteger=streamreader.readinteger1
16794 readshort=streamreader.readinteger2
16795 readstring=streamreader.readstring
16796 readtag=streamreader.readtag
16797 readbytes=streamreader.readbytes
16798 readfixed=streamreader.readfixed4
16799 read2dot14=streamreader.read2dot14
16800 skipshort=streamreader.skipshort
16801 skipbytes=streamreader.skip
16802 readbytetable=streamreader.readbytetable
16803 readbyte=streamreader.readbyte
16804 readcardinaltable=streamreader.readcardinaltable
16805 readintegertable=streamreader.readintegertable
16806 readfword=readshort
16807end)
16808local gsubhandlers={}
16809local gposhandlers={}
16810readers.gsubhandlers=gsubhandlers
16811readers.gposhandlers=gposhandlers
16812local helpers=readers.helpers
16813local gotodatatable=helpers.gotodatatable
16814local setvariabledata=helpers.setvariabledata
16815local lookupidoffset=-1 
16816local classes={
16817 "base",
16818 "ligature",
16819 "mark",
16820 "component",
16821}
16822local gsubtypes={
16823 "single",
16824 "multiple",
16825 "alternate",
16826 "ligature",
16827 "context",
16828 "chainedcontext",
16829 "extension",
16830 "reversechainedcontextsingle",
16831}
16832local gpostypes={
16833 "single",
16834 "pair",
16835 "cursive",
16836 "marktobase",
16837 "marktoligature",
16838 "marktomark",
16839 "context",
16840 "chainedcontext",
16841 "extension",
16842}
16843local chaindirections={
16844 context=0,
16845 chainedcontext=1,
16846 reversechainedcontextsingle=-1,
16847}
16848local function setmetrics(data,where,tag,d)
16849 local w=data[where]
16850 if w then
16851  local v=w[tag]
16852  if v then
16853   w[tag]=v+d
16854  end
16855 end
16856end
16857local variabletags={
16858 hasc=function(data,d) setmetrics(data,"windowsmetrics","typoascender",d) end,
16859 hdsc=function(data,d) setmetrics(data,"windowsmetrics","typodescender",d) end,
16860 hlgp=function(data,d) setmetrics(data,"windowsmetrics","typolinegap",d) end,
16861 hcla=function(data,d) setmetrics(data,"windowsmetrics","winascent",d) end,
16862 hcld=function(data,d) setmetrics(data,"windowsmetrics","windescent",d) end,
16863 vasc=function(data,d) setmetrics(data,"vhea not done","ascent",d) end,
16864 vdsc=function(data,d) setmetrics(data,"vhea not done","descent",d) end,
16865 vlgp=function(data,d) setmetrics(data,"vhea not done","linegap",d) end,
16866 xhgt=function(data,d) setmetrics(data,"windowsmetrics","xheight",d) end,
16867 cpht=function(data,d) setmetrics(data,"windowsmetrics","capheight",d) end,
16868 sbxs=function(data,d) setmetrics(data,"windowsmetrics","subscriptxsize",d) end,
16869 sbys=function(data,d) setmetrics(data,"windowsmetrics","subscriptysize",d) end,
16870 sbxo=function(data,d) setmetrics(data,"windowsmetrics","subscriptxoffset",d) end,
16871 sbyo=function(data,d) setmetrics(data,"windowsmetrics","subscriptyoffset",d) end,
16872 spxs=function(data,d) setmetrics(data,"windowsmetrics","superscriptxsize",d) end,
16873 spys=function(data,d) setmetrics(data,"windowsmetrics","superscriptysize",d) end,
16874 spxo=function(data,d) setmetrics(data,"windowsmetrics","superscriptxoffset",d) end,
16875 spyo=function(data,d) setmetrics(data,"windowsmetrics","superscriptyoffset",d) end,
16876 strs=function(data,d) setmetrics(data,"windowsmetrics","strikeoutsize",d) end,
16877 stro=function(data,d) setmetrics(data,"windowsmetrics","strikeoutpos",d) end,
16878 unds=function(data,d) setmetrics(data,"postscript","underlineposition",d) end,
16879 undo=function(data,d) setmetrics(data,"postscript","underlinethickness",d) end,
16880}
16881local read_cardinal={
16882 streamreader.readcardinal1,
16883 streamreader.readcardinal2,
16884 streamreader.readcardinal3,
16885 streamreader.readcardinal4,
16886}
16887local read_integer={
16888 streamreader.readinteger1,
16889 streamreader.readinteger2,
16890 streamreader.readinteger3,
16891 streamreader.readinteger4,
16892}
16893directives.register("fonts.streamreader",function()
16894 read_cardinal={
16895  streamreader.readcardinal1,
16896  streamreader.readcardinal2,
16897  streamreader.readcardinal3,
16898  streamreader.readcardinal4,
16899 }
16900 read_integer={
16901  streamreader.readinteger1,
16902  streamreader.readinteger2,
16903  streamreader.readinteger3,
16904  streamreader.readinteger4,
16905 }
16906end)
16907local lookupnames={
16908 gsub={
16909  single="gsub_single",
16910  multiple="gsub_multiple",
16911  alternate="gsub_alternate",
16912  ligature="gsub_ligature",
16913  context="gsub_context",
16914  chainedcontext="gsub_contextchain",
16915  reversechainedcontextsingle="gsub_reversecontextchain",
16916 },
16917 gpos={
16918  single="gpos_single",
16919  pair="gpos_pair",
16920  cursive="gpos_cursive",
16921  marktobase="gpos_mark2base",
16922  marktoligature="gpos_mark2ligature",
16923  marktomark="gpos_mark2mark",
16924  context="gpos_context",
16925  chainedcontext="gpos_contextchain",
16926 }
16927}
16928local lookupflags=setmetatableindex(function(t,k)
16929 local v={
16930  band(k,0x0008)~=0 and true or false,
16931  band(k,0x0004)~=0 and true or false,
16932  band(k,0x0002)~=0 and true or false,
16933  band(k,0x0001)~=0 and true or false,
16934 }
16935 t[k]=v
16936 return v
16937end)
16938local function axistofactors(str)
16939 local t=settings_to_hash(str)
16940 for k,v in next,t do
16941  t[k]=tonumber(v) or v 
16942 end
16943 return t
16944end
16945local hash=table.setmetatableindex(function(t,k)
16946 local v=sequenced(axistofactors(k),",")
16947 t[k]=v
16948 return v
16949end)
16950helpers.normalizedaxishash=hash
16951local cleanname=fonts.names and fonts.names.cleanname or function(name)
16952 return name and (gsub(lower(name),"[^%a%d]","")) or nil
16953end
16954helpers.cleanname=cleanname
16955function helpers.normalizedaxis(str)
16956 return hash[str] or str
16957end
16958local function getaxisscale(segments,minimum,default,maximum,user)
16959 if not minimum or not default or not maximum then
16960  return false
16961 end
16962 if user<minimum then
16963  user=minimum
16964 elseif user>maximum then
16965  user=maximum
16966 end
16967 if user<default then
16968  default=- (default-user)/(default-minimum)
16969 elseif user>default then
16970  default=(user-default)/(maximum-default)
16971 else
16972  default=0
16973 end
16974 if not segments then
16975  return default
16976 end
16977 local e
16978 for i=1,#segments do
16979  local s=segments[i]
16980  if type(s)~="number" then
16981   return default
16982  elseif s[1]>=default then
16983   if s[2]==default then
16984    return default
16985   else
16986    e=i
16987    break
16988   end
16989  end
16990 end
16991 if e then
16992  local b=segments[e-1]
16993  local e=segments[e]
16994  return b[2]+(e[2]-b[2])*(default-b[1])/(e[1]-b[1])
16995 else
16996  return false
16997 end
16998end
16999local function getfactors(data,instancespec)
17000 if instancespec==true then
17001 elseif type(instancespec)~="string" or instancespec=="" then
17002  return
17003 end
17004 local variabledata=data.variabledata
17005 if not variabledata then
17006  return
17007 end
17008 local instances=variabledata.instances
17009 local axis=variabledata.axis
17010 local segments=variabledata.segments
17011 if instances and axis then
17012  local values
17013  if instancespec==true then
17014   values={}
17015   for i=1,#axis do
17016    values[i]={
17017     value=axis[i].default,
17018    }
17019   end
17020  else
17021   for i=1,#instances do
17022    local instance=instances[i]
17023    if cleanname(instance.subfamily)==instancespec then
17024     values=instance.values
17025     break
17026    end
17027   end
17028  end
17029  if values then
17030   local factors={}
17031   for i=1,#axis do
17032    local a=axis[i]
17033    factors[i]=getaxisscale(segments,a.minimum,a.default,a.maximum,values[i].value)
17034   end
17035   return factors
17036  end
17037  local values=axistofactors(hash[instancespec] or instancespec)
17038  if values then
17039   local factors={}
17040   for i=1,#axis do
17041    local a=axis[i]
17042    local d=a.default
17043    factors[i]=getaxisscale(segments,a.minimum,d,a.maximum,values[a.name or a.tag] or d)
17044   end
17045   return factors
17046  end
17047 end
17048end
17049local function getscales(regions,factors)
17050 local scales={}
17051 for i=1,#regions do
17052  local region=regions[i]
17053  local s=1
17054  for j=1,#region do
17055   local axis=region[j]
17056   local f=factors[j]
17057   local start=axis.start
17058   local peak=axis.peak
17059   local stop=axis.stop
17060   if start>peak or peak>stop then
17061   elseif start<0 and stop>0 and peak~=0 then
17062   elseif peak==0 then
17063   elseif f<start or f>stop then
17064    s=0
17065    break
17066   elseif f<peak then
17067    s=s*(f-start)/(peak-start)
17068   elseif f>peak then
17069    s=s*(stop-f)/(stop-peak)
17070   else
17071   end
17072  end
17073  scales[i]=s
17074 end
17075 return scales
17076end
17077helpers.getaxisscale=getaxisscale
17078helpers.getfactors=getfactors
17079helpers.getscales=getscales
17080helpers.axistofactors=axistofactors
17081local function readvariationdata(f,storeoffset,factors) 
17082 local position=getposition(f)
17083 setposition(f,storeoffset)
17084 local format=readushort(f)
17085 local regionoffset=storeoffset+readulong(f)
17086 local nofdeltadata=readushort(f)
17087 local deltadata=readcardinaltable(f,nofdeltadata,ulong)
17088 setposition(f,regionoffset)
17089 local nofaxis=readushort(f)
17090 local nofregions=readushort(f)
17091 local regions={}
17092 for i=1,nofregions do 
17093  local t={}
17094  for i=1,nofaxis do
17095   t[i]={ 
17096    start=read2dot14(f),
17097    peak=read2dot14(f),
17098    stop=read2dot14(f),
17099   }
17100  end
17101  regions[i]=t
17102 end
17103  for i=1,nofdeltadata do
17104   setposition(f,storeoffset+deltadata[i])
17105   local nofdeltasets=readushort(f)
17106   local nofshorts=readushort(f)
17107   local nofregions=readushort(f)
17108   local usedregions={}
17109   local deltas={}
17110   for i=1,nofregions do
17111    usedregions[i]=regions[readushort(f)+1]
17112   end
17113   for i=1,nofdeltasets do
17114    local t=readintegertable(f,nofshorts,short)
17115    for i=nofshorts+1,nofregions do
17116     t[i]=readinteger(f)
17117    end
17118    deltas[i]=t
17119   end
17120   deltadata[i]={
17121    regions=usedregions,
17122    deltas=deltas,
17123    scales=factors and getscales(usedregions,factors) or nil,
17124   }
17125  end
17126 setposition(f,position)
17127 return regions,deltadata
17128end
17129helpers.readvariationdata=readvariationdata
17130local function readcoverage(f,offset,simple)
17131 setposition(f,offset)
17132 local coverageformat=readushort(f)
17133 if coverageformat==1 then
17134  local nofcoverage=readushort(f)
17135  if simple then
17136   if nofcoverage==1 then
17137    return { readushort(f) }
17138   elseif nofcoverage==2 then
17139    return { readushort(f),readushort(f) }
17140   else
17141    return readcardinaltable(f,nofcoverage,ushort)
17142   end
17143  elseif nofcoverage==1 then
17144   return { [readushort(f)]=0 }
17145  elseif nofcoverage==2 then
17146   return { [readushort(f)]=0,[readushort(f)]=1 }
17147  else
17148   local coverage={}
17149   for i=0,nofcoverage-1 do
17150    coverage[readushort(f)]=i 
17151   end
17152   return coverage
17153  end
17154 elseif coverageformat==2 then
17155  local nofranges=readushort(f)
17156  local coverage={}
17157  local n=simple and 1 or 0 
17158  for i=1,nofranges do
17159   local firstindex=readushort(f)
17160   local lastindex=readushort(f)
17161   local coverindex=readushort(f)
17162   if simple then
17163    for i=firstindex,lastindex do
17164     coverage[n]=i
17165     n=n+1
17166    end
17167   else
17168    for i=firstindex,lastindex do
17169     coverage[i]=n
17170     n=n+1
17171    end
17172   end
17173  end
17174  return coverage
17175 else
17176  report("unknown coverage format %a ",coverageformat)
17177  return {}
17178 end
17179end
17180local function readclassdef(f,offset,preset)
17181 setposition(f,offset)
17182 local classdefformat=readushort(f)
17183 local classdef={}
17184 if type(preset)=="number" then
17185  for k=0,preset-1 do
17186   classdef[k]=1
17187  end
17188 end
17189 if classdefformat==1 then
17190  local index=readushort(f)
17191  local nofclassdef=readushort(f)
17192  for i=1,nofclassdef do
17193   classdef[index]=readushort(f)+1
17194   index=index+1
17195  end
17196 elseif classdefformat==2 then
17197  local nofranges=readushort(f)
17198  local n=0
17199  for i=1,nofranges do
17200   local firstindex=readushort(f)
17201   local lastindex=readushort(f)
17202   local class=readushort(f)+1
17203   for i=firstindex,lastindex do
17204    classdef[i]=class
17205   end
17206  end
17207 else
17208  report("unknown classdef format %a ",classdefformat)
17209 end
17210 if type(preset)=="table" then
17211  for k in next,preset do
17212   if not classdef[k] then
17213    classdef[k]=1
17214   end
17215  end
17216 end
17217 return classdef
17218end
17219local function classtocoverage(defs)
17220 if defs then
17221  local list={}
17222  for index,class in next,defs do
17223   local c=list[class]
17224   if c then
17225    c[#c+1]=index
17226   else
17227    list[class]={ index }
17228   end
17229  end
17230  return list
17231 end
17232end
17233local skips={ [0]=0,
17234 1,
17235 1,
17236 2,
17237 1,
17238 2,
17239 2,
17240 3,
17241 2,
17242 2,
17243 3,
17244 2,
17245 3,
17246 3,
17247 4,
17248}
17249local function readvariation(f,offset)
17250 local p=getposition(f)
17251 setposition(f,offset)
17252 local outer=readushort(f)
17253 local inner=readushort(f)
17254 local format=readushort(f)
17255 setposition(f,p)
17256 if format==0x8000 then
17257  return outer,inner
17258 end
17259end
17260local function readposition(f,format,mainoffset,getdelta)
17261 if format==0 then
17262  return false
17263 end
17264 if format==0x04 then
17265  local h=readshort(f)
17266  if h==0 then
17267   return true 
17268  else
17269   return { 0,0,h,0 }
17270  end
17271 end
17272 if format==0x05 then
17273  local x=readshort(f)
17274  local h=readshort(f)
17275  if x==0 and h==0 then
17276   return true 
17277  else
17278   return { x,0,h,0 }
17279  end
17280 end
17281 if format==0x44 then
17282  local h=readshort(f)
17283  if getdelta then
17284   local d=readshort(f) 
17285   if d>0 then
17286    local outer,inner=readvariation(f,mainoffset+d)
17287    if outer then
17288     h=h+getdelta(outer,inner)
17289    end
17290   end
17291  else
17292   skipshort(f,1)
17293  end
17294  if h==0 then
17295   return true 
17296  else
17297   return { 0,0,h,0 }
17298  end
17299 end
17300 local x=band(format,0x1)~=0 and readshort(f) or 0 
17301 local y=band(format,0x2)~=0 and readshort(f) or 0 
17302 local h=band(format,0x4)~=0 and readshort(f) or 0 
17303 local v=band(format,0x8)~=0 and readshort(f) or 0 
17304 if format>=0x10 then
17305  local X=band(format,0x10)~=0 and skipshort(f) or 0
17306  local Y=band(format,0x20)~=0 and skipshort(f) or 0
17307  local H=band(format,0x40)~=0 and skipshort(f) or 0
17308  local V=band(format,0x80)~=0 and skipshort(f) or 0
17309  local s=skips[extract(format,4,4)]
17310  if s>0 then
17311   skipshort(f,s)
17312  end
17313  if getdelta then
17314   if X>0 then
17315    local outer,inner=readvariation(f,mainoffset+X)
17316    if outer then
17317     x=x+getdelta(outer,inner)
17318    end
17319   end
17320   if Y>0 then
17321    local outer,inner=readvariation(f,mainoffset+Y)
17322    if outer then
17323     y=y+getdelta(outer,inner)
17324    end
17325   end
17326   if H>0 then
17327    local outer,inner=readvariation(f,mainoffset+H)
17328    if outer then
17329     h=h+getdelta(outer,inner)
17330    end
17331   end
17332   if V>0 then
17333    local outer,inner=readvariation(f,mainoffset+V)
17334    if outer then
17335     v=v+getdelta(outer,inner)
17336    end
17337   end
17338  end
17339  return { x,y,h,v }
17340 elseif x==0 and y==0 and h==0 and v==0 then
17341  return true 
17342 else
17343  return { x,y,h,v }
17344 end
17345end
17346local function readanchor(f,offset,getdelta) 
17347 if not offset or offset==0 then
17348  return nil 
17349 end
17350 setposition(f,offset)
17351 local format=readshort(f) 
17352 local x=readshort(f)
17353 local y=readshort(f)
17354 if format==3 then
17355  if getdelta then
17356   local X=readshort(f)
17357   local Y=readshort(f)
17358   if X>0 then
17359    local outer,inner=readvariation(f,offset+X)
17360    if outer then
17361     x=x+getdelta(outer,inner)
17362    end
17363   end
17364   if Y>0 then
17365    local outer,inner=readvariation(f,offset+Y)
17366    if outer then
17367     y=y+getdelta(outer,inner)
17368    end
17369   end
17370  else
17371   skipshort(f,2)
17372  end
17373  return { x,y } 
17374 else
17375  return { x,y }
17376 end
17377end
17378local function readfirst(f,offset)
17379 if offset then
17380  setposition(f,offset)
17381 end
17382 return { readushort(f) }
17383end
17384local function readarray(f,offset)
17385 if offset then
17386  setposition(f,offset)
17387 end
17388 local n=readushort(f)
17389 if n==1 then
17390  return { readushort(f) },1
17391 elseif n>0 then
17392  return readcardinaltable(f,n,ushort),n
17393 end
17394end
17395local function readcoveragearray(f,offset,t,simple)
17396 if not t then
17397  return nil
17398 end
17399 local n=#t
17400 if n==0 then
17401  return nil
17402 end
17403 for i=1,n do
17404  t[i]=readcoverage(f,offset+t[i],simple)
17405 end
17406 return t
17407end
17408local function covered(subset,all)
17409 local used,u
17410 for i=1,#subset do
17411  local s=subset[i]
17412  if all[s] then
17413   if used then
17414    u=u+1
17415    used[u]=s
17416   else
17417    u=1
17418    used={ s }
17419   end
17420  end
17421 end
17422 return used
17423end
17424local function readlookuparray(f,noflookups,nofcurrent)
17425 local lookups={}
17426 if noflookups>0 then
17427  local length=0
17428  for i=1,noflookups do
17429   local index=readushort(f)+1
17430   if index>length then
17431    length=index
17432   end
17433   local lookup=readushort(f)+1
17434   local list=lookups[index]
17435   if list then
17436    list[#list+1]=lookup
17437   else
17438    lookups[index]={ lookup }
17439   end
17440  end
17441  for index=1,length do
17442   if not lookups[index] then
17443    lookups[index]=false
17444   end
17445  end
17446 end
17447 return lookups
17448end
17449local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
17450 local tableoffset=lookupoffset+offset
17451 setposition(f,tableoffset)
17452 local subtype=readushort(f)
17453 if subtype==1 then
17454  local coverage=readushort(f)
17455  local subclasssets=readarray(f)
17456  local rules={}
17457  if subclasssets then
17458   coverage=readcoverage(f,tableoffset+coverage,true)
17459   for i=1,#subclasssets do
17460    local offset=subclasssets[i]
17461    if offset>0 then
17462     local firstcoverage=coverage[i]
17463     local rulesoffset=tableoffset+offset
17464     local subclassrules=readarray(f,rulesoffset)
17465     for rule=1,#subclassrules do
17466      setposition(f,rulesoffset+subclassrules[rule])
17467      local nofcurrent=readushort(f)
17468      local noflookups=readushort(f)
17469      local current={ { firstcoverage } }
17470      for i=2,nofcurrent do
17471       current[i]={ readushort(f) }
17472      end
17473      local lookups=readlookuparray(f,noflookups,nofcurrent)
17474      rules[#rules+1]={
17475       current=current,
17476       lookups=lookups
17477      }
17478     end
17479    end
17480   end
17481  else
17482   report("empty subclassset in %a subtype %i","unchainedcontext",subtype)
17483  end
17484  return {
17485   format="glyphs",
17486   rules=rules,
17487  }
17488 elseif subtype==2 then
17489  local coverage=readushort(f)
17490  local currentclassdef=readushort(f)
17491  local subclasssets=readarray(f)
17492  local rules={}
17493  if subclasssets then
17494   coverage=readcoverage(f,tableoffset+coverage)
17495   currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage)
17496   local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs)
17497   for class=1,#subclasssets do
17498    local offset=subclasssets[class]
17499    if offset>0 then
17500     local firstcoverage=currentclasses[class]
17501     if firstcoverage then
17502      firstcoverage=covered(firstcoverage,coverage) 
17503      if firstcoverage then
17504       local rulesoffset=tableoffset+offset
17505       local subclassrules=readarray(f,rulesoffset)
17506       for rule=1,#subclassrules do
17507        setposition(f,rulesoffset+subclassrules[rule])
17508        local nofcurrent=readushort(f)
17509        local noflookups=readushort(f)
17510        local current={ firstcoverage }
17511        for i=2,nofcurrent do
17512         current[i]=currentclasses[readushort(f)+1]
17513        end
17514        local lookups=readlookuparray(f,noflookups,nofcurrent)
17515        rules[#rules+1]={
17516         current=current,
17517         lookups=lookups
17518        }
17519       end
17520      else
17521       report("no coverage")
17522      end
17523     else
17524      report("no coverage class")
17525     end
17526    end
17527   end
17528  else
17529   report("empty subclassset in %a subtype %i","unchainedcontext",subtype)
17530  end
17531  return {
17532   format="class",
17533   rules=rules,
17534  }
17535 elseif subtype==3 then
17536  local nofglyphs=readushort(f)
17537  local noflookups=readushort(f)
17538  local current=readcardinaltable(f,nofglyphs,ushort)
17539  local lookups=readlookuparray(f,noflookups,#current)
17540  current=readcoveragearray(f,tableoffset,current,true)
17541  return {
17542   format="coverage",
17543   rules={
17544    {
17545     current=current,
17546     lookups=lookups,
17547    }
17548   }
17549  }
17550 else
17551  report("unsupported subtype %a in %a %s",subtype,"unchainedcontext",what)
17552 end
17553end
17554local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
17555 local tableoffset=lookupoffset+offset
17556 setposition(f,tableoffset)
17557 local subtype=readushort(f)
17558 if subtype==1 then
17559  local coverage=readushort(f)
17560  local subclasssets=readarray(f)
17561  local rules={}
17562  if subclasssets then
17563   coverage=readcoverage(f,tableoffset+coverage,true)
17564   for i=1,#subclasssets do
17565    local offset=subclasssets[i]
17566    if offset>0 then
17567     local firstcoverage=coverage[i]
17568     local rulesoffset=tableoffset+offset
17569     local subclassrules=readarray(f,rulesoffset)
17570     for rule=1,#subclassrules do
17571      setposition(f,rulesoffset+subclassrules[rule])
17572      local nofbefore=readushort(f)
17573      local before
17574      if nofbefore>0 then
17575       before={}
17576       for i=1,nofbefore do
17577        before[i]={ readushort(f) }
17578       end
17579      end
17580      local nofcurrent=readushort(f)
17581      local current={ { firstcoverage } }
17582      for i=2,nofcurrent do
17583       current[i]={ readushort(f) }
17584      end
17585      local nofafter=readushort(f)
17586      local after
17587      if nofafter>0 then
17588       after={}
17589       for i=1,nofafter do
17590        after[i]={ readushort(f) }
17591       end
17592      end
17593      local noflookups=readushort(f)
17594      local lookups=readlookuparray(f,noflookups,nofcurrent)
17595      rules[#rules+1]={
17596       before=before,
17597       current=current,
17598       after=after,
17599       lookups=lookups,
17600      }
17601     end
17602    end
17603   end
17604  else
17605   report("empty subclassset in %a subtype %i","chainedcontext",subtype)
17606  end
17607  return {
17608   format="glyphs",
17609   rules=rules,
17610  }
17611 elseif subtype==2 then
17612  local coverage=readushort(f)
17613  local beforeclassdef=readushort(f)
17614  local currentclassdef=readushort(f)
17615  local afterclassdef=readushort(f)
17616  local subclasssets=readarray(f)
17617  local rules={}
17618  if subclasssets then
17619   local coverage=readcoverage(f,tableoffset+coverage)
17620   local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef,nofglyphs)
17621   local currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage)
17622   local afterclassdef=readclassdef(f,tableoffset+afterclassdef,nofglyphs)
17623   local beforeclasses=classtocoverage(beforeclassdef,fontdata.glyphs)
17624   local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs)
17625   local afterclasses=classtocoverage(afterclassdef,fontdata.glyphs)
17626   for class=1,#subclasssets do
17627    local offset=subclasssets[class]
17628    if offset>0 then
17629     local firstcoverage=currentclasses[class]
17630     if firstcoverage then
17631      firstcoverage=covered(firstcoverage,coverage) 
17632      if firstcoverage then
17633       local rulesoffset=tableoffset+offset
17634       local subclassrules=readarray(f,rulesoffset)
17635       for rule=1,#subclassrules do
17636        setposition(f,rulesoffset+subclassrules[rule])
17637        local nofbefore=readushort(f)
17638        local before
17639        if nofbefore>0 then
17640         before={}
17641         for i=1,nofbefore do
17642          before[i]=beforeclasses[readushort(f)+1]
17643         end
17644        end
17645        local nofcurrent=readushort(f)
17646        local current={ firstcoverage }
17647        for i=2,nofcurrent do
17648         current[i]=currentclasses[readushort(f)+1]
17649        end
17650        local nofafter=readushort(f)
17651        local after
17652        if nofafter>0 then
17653         after={}
17654         for i=1,nofafter do
17655          after[i]=afterclasses[readushort(f)+1]
17656         end
17657        end
17658        local noflookups=readushort(f)
17659        local lookups=readlookuparray(f,noflookups,nofcurrent)
17660        rules[#rules+1]={
17661         before=before,
17662         current=current,
17663         after=after,
17664         lookups=lookups,
17665        }
17666       end
17667      else
17668       report("no coverage")
17669      end
17670     else
17671      report("class is not covered")
17672     end
17673    end
17674   end
17675  else
17676   report("empty subclassset in %a subtype %i","chainedcontext",subtype)
17677  end
17678  return {
17679   format="class",
17680   rules=rules,
17681  }
17682 elseif subtype==3 then
17683  local before=readarray(f)
17684  local current=readarray(f)
17685  local after=readarray(f)
17686  local noflookups=readushort(f)
17687  local lookups=readlookuparray(f,noflookups,#current)
17688  before=readcoveragearray(f,tableoffset,before,true)
17689  current=readcoveragearray(f,tableoffset,current,true)
17690  after=readcoveragearray(f,tableoffset,after,true)
17691  return {
17692   format="coverage",
17693   rules={
17694    {
17695     before=before,
17696     current=current,
17697     after=after,
17698     lookups=lookups,
17699    }
17700   }
17701  }
17702 else
17703  report("unsupported subtype %a in %a %s",subtype,"chainedcontext",what)
17704 end
17705end
17706local function extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,types,handlers,what)
17707 local tableoffset=lookupoffset+offset
17708 setposition(f,tableoffset)
17709 local subtype=readushort(f)
17710 if subtype==1 then
17711  local lookuptype=types[readushort(f)]
17712  local faroffset=readulong(f)
17713  local handler=handlers[lookuptype]
17714  if handler then
17715   return handler(f,fontdata,lookupid,tableoffset+faroffset,0,glyphs,nofglyphs),lookuptype
17716  else
17717   report("no handler for lookuptype %a subtype %a in %s %s",lookuptype,subtype,what,"extension")
17718  end
17719 else
17720  report("unsupported subtype %a in %s %s",subtype,what,"extension")
17721 end
17722end
17723function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17724 local tableoffset=lookupoffset+offset
17725 setposition(f,tableoffset)
17726 local subtype=readushort(f)
17727 if subtype==1 then
17728  local coverage=readushort(f)
17729  local delta=readshort(f) 
17730  local coverage=readcoverage(f,tableoffset+coverage) 
17731  for index in next,coverage do
17732   local newindex=(index+delta)%65536 
17733   if index>nofglyphs or newindex>nofglyphs then
17734    report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs)
17735    coverage[index]=nil
17736   else
17737    coverage[index]=newindex
17738   end
17739  end
17740  return {
17741   coverage=coverage
17742  }
17743 elseif subtype==2 then 
17744  local coverage=readushort(f)
17745  local nofreplacements=readushort(f)
17746  local replacements=readcardinaltable(f,nofreplacements,ushort)
17747  local coverage=readcoverage(f,tableoffset+coverage) 
17748  for index,newindex in next,coverage do
17749   newindex=newindex+1
17750   if index>nofglyphs or newindex>nofglyphs then
17751    report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs)
17752    coverage[index]=nil
17753   else
17754    coverage[index]=replacements[newindex]
17755   end
17756  end
17757  return {
17758   coverage=coverage
17759  }
17760 else
17761  report("unsupported subtype %a in %a substitution",subtype,"single")
17762 end
17763end
17764local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what)
17765 local tableoffset=lookupoffset+offset
17766 setposition(f,tableoffset)
17767 local subtype=readushort(f)
17768 if subtype==1 then
17769  local coverage=readushort(f)
17770  local nofsequence=readushort(f)
17771  local sequences=readcardinaltable(f,nofsequence,ushort)
17772  for i=1,nofsequence do
17773   setposition(f,tableoffset+sequences[i])
17774   sequences[i]=readcardinaltable(f,readushort(f),ushort)
17775  end
17776  local coverage=readcoverage(f,tableoffset+coverage)
17777  for index,newindex in next,coverage do
17778   newindex=newindex+1
17779   if index>nofglyphs or newindex>nofglyphs then
17780    report("invalid index in %s format %i: %i -> %i (max %i)",what,subtype,index,newindex,nofglyphs)
17781    coverage[index]=nil
17782   else
17783    coverage[index]=sequences[newindex]
17784   end
17785  end
17786  return {
17787   coverage=coverage
17788  }
17789 else
17790  report("unsupported subtype %a in %a substitution",subtype,what)
17791 end
17792end
17793function gsubhandlers.multiple(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17794 return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"multiple")
17795end
17796function gsubhandlers.alternate(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17797 return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"alternate")
17798end
17799function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17800 local tableoffset=lookupoffset+offset
17801 setposition(f,tableoffset)
17802 local subtype=readushort(f)
17803 if subtype==1 then
17804  local coverage=readushort(f)
17805  local nofsets=readushort(f)
17806  local ligatures=readcardinaltable(f,nofsets,ushort)
17807  for i=1,nofsets do
17808   local offset=lookupoffset+offset+ligatures[i]
17809   setposition(f,offset)
17810   local n=readushort(f)
17811   if n==1 then
17812    ligatures[i]={ offset+readushort(f) }
17813   else
17814    local l={}
17815    for i=1,n do
17816     l[i]=offset+readushort(f)
17817    end
17818    ligatures[i]=l
17819   end
17820  end
17821  local coverage=readcoverage(f,tableoffset+coverage)
17822  for index,newindex in next,coverage do
17823   local hash={}
17824   local ligatures=ligatures[newindex+1]
17825   for i=1,#ligatures do
17826    local offset=ligatures[i]
17827    setposition(f,offset)
17828    local lig=readushort(f)
17829    local cnt=readushort(f)
17830    local hsh=hash
17831    for i=2,cnt do
17832     local c=readushort(f)
17833     local h=hsh[c]
17834     if not h then
17835      h={}
17836      hsh[c]=h
17837     end
17838     hsh=h
17839    end
17840    hsh.ligature=lig
17841   end
17842   coverage[index]=hash
17843  end
17844  return {
17845   coverage=coverage
17846  }
17847 else
17848  report("unsupported subtype %a in %a substitution",subtype,"ligature")
17849 end
17850end
17851function gsubhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17852 return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"context"
17853end
17854function gsubhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17855 return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"chainedcontext"
17856end
17857function gsubhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17858 return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gsubtypes,gsubhandlers,"substitution")
17859end
17860function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17861 local tableoffset=lookupoffset+offset
17862 setposition(f,tableoffset)
17863 local subtype=readushort(f)
17864 if subtype==1 then 
17865  local current=readfirst(f)
17866  local before=readarray(f)
17867  local after=readarray(f)
17868  local replacements=readarray(f)
17869  current=readcoveragearray(f,tableoffset,current,true)
17870  before=readcoveragearray(f,tableoffset,before,true)
17871  after=readcoveragearray(f,tableoffset,after,true)
17872  return {
17873   format="reversecoverage",
17874   rules={
17875    {
17876     before=before,
17877     current=current,
17878     after=after,
17879     replacements=replacements,
17880    }
17881   }
17882  },"reversechainedcontextsingle"
17883 else
17884  report("unsupported subtype %a in %a substitution",subtype,"reversechainedcontextsingle")
17885 end
17886end
17887local function readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
17888 local done={}
17889 for i=1,#sets do
17890  local offset=sets[i]
17891  local reused=done[offset]
17892  if not reused then
17893   offset=tableoffset+offset
17894   setposition(f,offset)
17895   local n=readushort(f)
17896   reused={}
17897   for i=1,n do
17898    reused[i]={
17899     readushort(f),
17900     readposition(f,format1,offset,getdelta),
17901     readposition(f,format2,offset,getdelta),
17902    }
17903   end
17904   done[offset]=reused
17905  end
17906  sets[i]=reused
17907 end
17908 return sets
17909end
17910local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,mainoffset,getdelta)
17911 local classlist1={}
17912 for i=1,nofclasses1 do
17913  local classlist2={}
17914  classlist1[i]=classlist2
17915  for j=1,nofclasses2 do
17916   local one=readposition(f,format1,mainoffset,getdelta)
17917   local two=readposition(f,format2,mainoffset,getdelta)
17918   if one or two then
17919    classlist2[j]={ one,two }
17920   else
17921    classlist2[j]=false
17922   end
17923  end
17924 end
17925 return classlist1
17926end
17927function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17928 local tableoffset=lookupoffset+offset
17929 setposition(f,tableoffset)
17930 local subtype=readushort(f)
17931 local getdelta=fontdata.temporary.getdelta
17932 if subtype==1 then
17933  local coverage=readushort(f)
17934  local format=readushort(f)
17935  local value=readposition(f,format,tableoffset,getdelta)
17936  local coverage=readcoverage(f,tableoffset+coverage)
17937  for index,newindex in next,coverage do
17938   coverage[index]=value 
17939  end
17940  return {
17941   format="single",
17942   coverage=coverage,
17943  }
17944 elseif subtype==2 then
17945  local coverage=readushort(f)
17946  local format=readushort(f)
17947  local nofvalues=readushort(f)
17948  local values={}
17949  for i=1,nofvalues do
17950   values[i]=readposition(f,format,tableoffset,getdelta)
17951  end
17952  local coverage=readcoverage(f,tableoffset+coverage)
17953  for index,newindex in next,coverage do
17954   coverage[index]=values[newindex+1]
17955  end
17956  return {
17957   format="single",
17958   coverage=coverage,
17959  }
17960 else
17961  report("unsupported subtype %a in %a positioning",subtype,"single")
17962 end
17963end
17964function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
17965 local tableoffset=lookupoffset+offset
17966 setposition(f,tableoffset)
17967 local subtype=readushort(f)
17968 local getdelta=fontdata.temporary.getdelta
17969 if subtype==1 then
17970  local coverage=readushort(f)
17971  local format1=readushort(f)
17972  local format2=readushort(f)
17973  local sets=readarray(f)
17974     sets=readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
17975     coverage=readcoverage(f,tableoffset+coverage)
17976  local shared={} 
17977  for index,newindex in next,coverage do
17978   local set=sets[newindex+1]
17979   local hash={}
17980   for i=1,#set do
17981    local value=set[i]
17982    if value then
17983     local other=value[1]
17984     local share=shared[value]
17985     if share==nil then
17986      local first=value[2]
17987      local second=value[3]
17988      if first or second then
17989       share={ first,second or nil } 
17990      else
17991       share=false
17992      end
17993      shared[value]=share
17994     end
17995     hash[other]=share or nil 
17996    end
17997   end
17998   coverage[index]=hash
17999  end
18000  return {
18001   shared=shared and true or nil,
18002   format="pair",
18003   coverage=coverage,
18004  }
18005 elseif subtype==2 then
18006  local coverage=readushort(f)
18007  local format1=readushort(f)
18008  local format2=readushort(f)
18009  local classdef1=readushort(f)
18010  local classdef2=readushort(f)
18011  local nofclasses1=readushort(f) 
18012  local nofclasses2=readushort(f) 
18013  local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
18014     coverage=readcoverage(f,tableoffset+coverage)
18015     classdef1=readclassdef(f,tableoffset+classdef1,coverage)
18016     classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs)
18017  local usedcoverage={}
18018  local shared={} 
18019  for g1,c1 in next,classdef1 do
18020   if coverage[g1] then
18021    local l1=classlist[c1]
18022    if l1 then
18023     local hash={}
18024     for paired,class in next,classdef2 do
18025      local offsets=l1[class]
18026      if offsets then
18027       local first=offsets[1]
18028       local second=offsets[2]
18029       if first or second then
18030        local s1=shared[first]
18031        if s1==nil then
18032         s1={}
18033         shared[first]=s1
18034        end
18035        local s2=s1[second]
18036        if s2==nil then
18037         s2={ first,second or nil }
18038         s1[second]=s2
18039        end
18040        hash[paired]=s2
18041       end
18042      end
18043     end
18044     usedcoverage[g1]=hash
18045    end
18046   end
18047  end
18048  return {
18049   shared=shared and true or nil,
18050   format="pair",
18051   coverage=usedcoverage,
18052  }
18053 elseif subtype==3 then
18054  report("yet unsupported subtype %a in %a positioning",subtype,"pair")
18055 else
18056  report("unsupported subtype %a in %a positioning",subtype,"pair")
18057 end
18058end
18059function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18060 local tableoffset=lookupoffset+offset
18061 setposition(f,tableoffset)
18062 local subtype=readushort(f)
18063 local getdelta=fontdata.temporary.getdelta
18064 if subtype==1 then
18065  local coverage=tableoffset+readushort(f)
18066  local nofrecords=readushort(f)
18067  local records={}
18068  for i=1,nofrecords do
18069   local entry=readushort(f)
18070   local exit=readushort(f)
18071   records[i]={
18072    entry~=0 and (tableoffset+entry) or false,
18073    exit~=0 and (tableoffset+exit ) or nil,
18074   }
18075  end
18076  local cc=(fontdata.temporary.cursivecount or 0)+1
18077  fontdata.temporary.cursivecount=cc
18078  cc="cc-"..cc
18079  coverage=readcoverage(f,coverage)
18080  for i=1,nofrecords do
18081   local r=records[i]
18082   records[i]={
18083    cc,
18084    readanchor(f,r[1],getdelta) or false,
18085    readanchor(f,r[2],getdelta) or nil,
18086   }
18087  end
18088  for index,newindex in next,coverage do
18089   coverage[index]=records[newindex+1]
18090  end
18091  return {
18092   coverage=coverage,
18093  }
18094 else
18095  report("unsupported subtype %a in %a positioning",subtype,"cursive")
18096 end
18097end
18098local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,ligature)
18099 local tableoffset=lookupoffset+offset
18100 setposition(f,tableoffset)
18101 local subtype=readushort(f)
18102 local getdelta=fontdata.temporary.getdelta
18103 if subtype==1 then
18104  local markcoverage=tableoffset+readushort(f)
18105  local basecoverage=tableoffset+readushort(f)
18106  local nofclasses=readushort(f)
18107  local markoffset=tableoffset+readushort(f)
18108  local baseoffset=tableoffset+readushort(f)
18109  local markcoverage=readcoverage(f,markcoverage)
18110  local basecoverage=readcoverage(f,basecoverage,true)
18111  setposition(f,markoffset)
18112  local markclasses={}
18113  local nofmarkclasses=readushort(f)
18114  local lastanchor=fontdata.lastanchor or 0
18115  local usedanchors={}
18116  for i=1,nofmarkclasses do
18117   local class=readushort(f)+1
18118   local offset=readushort(f)
18119   if offset==0 then
18120    markclasses[i]=false
18121   else
18122    markclasses[i]={ class,markoffset+offset }
18123   end
18124   usedanchors[class]=true
18125  end
18126  for i=1,nofmarkclasses do
18127   local mc=markclasses[i]
18128   if mc then
18129    mc[2]=readanchor(f,mc[2],getdelta)
18130   end
18131  end
18132  setposition(f,baseoffset)
18133  local nofbaserecords=readushort(f)
18134  local baserecords={}
18135  if ligature then
18136   for i=1,nofbaserecords do 
18137    local offset=readushort(f)
18138    if offset==0 then
18139     baserecords[i]=false
18140    else
18141     baserecords[i]=baseoffset+offset
18142    end
18143   end
18144   for i=1,nofbaserecords do
18145    local recordoffset=baserecords[i]
18146    if recordoffset then
18147     setposition(f,recordoffset)
18148     local nofcomponents=readushort(f)
18149     local components={}
18150     for i=1,nofcomponents do
18151      local classes={}
18152      for i=1,nofclasses do
18153       local offset=readushort(f)
18154       if offset~=0 then
18155        classes[i]=recordoffset+offset
18156       else
18157        classes[i]=false
18158       end
18159      end
18160      components[i]=classes
18161     end
18162     baserecords[i]=components
18163    end
18164   end
18165   local baseclasses={} 
18166   for i=1,nofclasses do
18167    baseclasses[i]={}
18168   end
18169   for i=1,nofbaserecords do
18170    local components=baserecords[i]
18171    if components then
18172     local b=basecoverage[i]
18173     for c=1,#components do
18174      local classes=components[c]
18175      if classes then
18176       for i=1,nofclasses do
18177        local anchor=readanchor(f,classes[i],getdelta)
18178        local bclass=baseclasses[i]
18179        local bentry=bclass[b]
18180        if bentry then
18181         bentry[c]=anchor
18182        else
18183         bclass[b]={ [c]=anchor }
18184        end
18185       end
18186      end
18187     end
18188    end
18189   end
18190   for index,newindex in next,markcoverage do
18191    markcoverage[index]=markclasses[newindex+1] or nil
18192   end
18193   return {
18194    format="ligature",
18195    baseclasses=baseclasses,
18196    coverage=markcoverage,
18197   }
18198  else
18199   for i=1,nofbaserecords do
18200    local r={}
18201    for j=1,nofclasses do
18202     local offset=readushort(f)
18203     if offset==0 then
18204      r[j]=false
18205     else
18206      r[j]=baseoffset+offset
18207     end
18208    end
18209    baserecords[i]=r
18210   end
18211   local baseclasses={} 
18212   for i=1,nofclasses do
18213    baseclasses[i]={}
18214   end
18215   for i=1,nofbaserecords do
18216    local r=baserecords[i]
18217    local b=basecoverage[i]
18218    for j=1,nofclasses do
18219     baseclasses[j][b]=readanchor(f,r[j],getdelta)
18220    end
18221   end
18222   for index,newindex in next,markcoverage do
18223    markcoverage[index]=markclasses[newindex+1] or nil
18224   end
18225   return {
18226    format="base",
18227    baseclasses=baseclasses,
18228    coverage=markcoverage,
18229   }
18230  end
18231 else
18232  report("unsupported subtype %a in",subtype)
18233 end
18234end
18235function gposhandlers.marktobase(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18236 return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18237end
18238function gposhandlers.marktoligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18239 return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,true)
18240end
18241function gposhandlers.marktomark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18242 return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18243end
18244function gposhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18245 return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"context"
18246end
18247function gposhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18248 return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"chainedcontext"
18249end
18250function gposhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
18251 return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gpostypes,gposhandlers,"positioning")
18252end
18253do
18254 local plugins={}
18255 function plugins.size(f,fontdata,tableoffset,feature)
18256  if fontdata.designsize then
18257  else
18258   local function check(offset)
18259    setposition(f,offset)
18260    local designsize=readushort(f)
18261    if designsize>0 then 
18262     local fontstyleid=readushort(f)
18263     local guimenuid=readushort(f)
18264     local minsize=readushort(f)
18265     local maxsize=readushort(f)
18266     if minsize==0 and maxsize==0 and fontstyleid==0 and guimenuid==0 then
18267      minsize=designsize
18268      maxsize=designsize
18269     end
18270     if designsize>=minsize and designsize<=maxsize then
18271      return minsize,maxsize,designsize
18272     end
18273    end
18274   end
18275   local minsize,maxsize,designsize=check(tableoffset+feature.offset+feature.parameters)
18276   if not designsize then
18277    minsize,maxsize,designsize=check(tableoffset+feature.parameters)
18278    if designsize then
18279     report("bad size feature in %a, falling back to wrong offset",fontdata.filename or "?")
18280    else
18281     report("bad size feature in %a,",fontdata.filename or "?")
18282    end
18283   end
18284   if designsize then
18285    fontdata.minsize=minsize
18286    fontdata.maxsize=maxsize
18287    fontdata.designsize=designsize
18288   end
18289  end
18290 end
18291 local function reorderfeatures(fontdata,scripts,features)
18292  local scriptlangs={}
18293  local featurehash={}
18294  local featureorder={}
18295  for script,languages in next,scripts do
18296   for language,record in next,languages do
18297    local hash={}
18298    local list=record.featureindices
18299    for k=1,#list do
18300     local index=list[k]
18301     local feature=features[index]
18302     local lookups=feature.lookups
18303     local tag=feature.tag
18304     if tag then
18305      hash[tag]=true
18306     end
18307     if lookups then
18308      for i=1,#lookups do
18309       local lookup=lookups[i]
18310       local o=featureorder[lookup]
18311       if o then
18312        local okay=true
18313        for i=1,#o do
18314         if o[i]==tag then
18315          okay=false
18316          break
18317         end
18318        end
18319        if okay then
18320         o[#o+1]=tag
18321        end
18322       else
18323        featureorder[lookup]={ tag }
18324       end
18325       local f=featurehash[lookup]
18326       if f then
18327        local h=f[tag]
18328        if h then
18329         local s=h[script]
18330         if s then
18331          s[language]=true
18332         else
18333          h[script]={ [language]=true }
18334         end
18335        else
18336         f[tag]={ [script]={ [language]=true } }
18337        end
18338       else
18339        featurehash[lookup]={ [tag]={ [script]={ [language]=true } } }
18340       end
18341       local h=scriptlangs[tag]
18342       if h then
18343        local s=h[script]
18344        if s then
18345         s[language]=true
18346        else
18347         h[script]={ [language]=true }
18348        end
18349       else
18350        scriptlangs[tag]={ [script]={ [language]=true } }
18351       end
18352      end
18353     end
18354    end
18355   end
18356  end
18357  return scriptlangs,featurehash,featureorder
18358 end
18359 local function readscriplan(f,fontdata,scriptoffset)
18360  setposition(f,scriptoffset)
18361  local nofscripts=readushort(f)
18362  local scripts={}
18363  for i=1,nofscripts do
18364   scripts[readtag(f)]=scriptoffset+readushort(f)
18365  end
18366  local languagesystems=setmetatableindex("table")
18367  for script,offset in next,scripts do
18368   setposition(f,offset)
18369   local defaultoffset=readushort(f)
18370   local noflanguages=readushort(f)
18371   local languages={}
18372   if defaultoffset>0 then
18373    languages.dflt=languagesystems[offset+defaultoffset]
18374   end
18375   for i=1,noflanguages do
18376    local language=readtag(f)
18377    local offset=offset+readushort(f)
18378    languages[language]=languagesystems[offset]
18379   end
18380   scripts[script]=languages
18381  end
18382  for offset,usedfeatures in next,languagesystems do
18383   if offset>0 then
18384    setposition(f,offset)
18385    local featureindices={}
18386    usedfeatures.featureindices=featureindices
18387    usedfeatures.lookuporder=readushort(f) 
18388    usedfeatures.requiredindex=readushort(f) 
18389    local noffeatures=readushort(f)
18390    for i=1,noffeatures do
18391     featureindices[i]=readushort(f)+1
18392    end
18393   end
18394  end
18395  return scripts
18396 end
18397 local function readfeatures(f,fontdata,featureoffset)
18398  setposition(f,featureoffset)
18399  local features={}
18400  local noffeatures=readushort(f)
18401  for i=1,noffeatures do
18402   features[i]={
18403    tag=readtag(f),
18404    offset=readushort(f)
18405   }
18406  end
18407  for i=1,noffeatures do
18408   local feature=features[i]
18409   local offset=featureoffset+feature.offset
18410   setposition(f,offset)
18411   local parameters=readushort(f) 
18412   local noflookups=readushort(f)
18413   if noflookups>0 then
18414    local lookups=readcardinaltable(f,noflookups,ushort)
18415    feature.lookups=lookups
18416    for j=1,noflookups do
18417     lookups[j]=lookups[j]+1
18418    end
18419   end
18420   if parameters>0 then
18421    feature.parameters=parameters
18422    local plugin=plugins[feature.tag]
18423    if plugin then
18424     plugin(f,fontdata,featureoffset,feature)
18425    end
18426   end
18427  end
18428  return features
18429 end
18430 local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder,nofmarkclasses)
18431  setposition(f,lookupoffset)
18432  local noflookups=readushort(f)
18433  local lookups=readcardinaltable(f,noflookups,ushort)
18434  for lookupid=1,noflookups do
18435   local offset=lookups[lookupid]
18436   setposition(f,lookupoffset+offset)
18437   local subtables={}
18438   local typebits=readushort(f)
18439   local flagbits=readushort(f)
18440   local lookuptype=lookuptypes[typebits]
18441   local lookupflags=lookupflags[flagbits]
18442   local nofsubtables=readushort(f)
18443   for j=1,nofsubtables do
18444    subtables[j]=offset+readushort(f) 
18445   end
18446   local markclass=band(flagbits,0x0010)~=0 
18447   local markset=rshift(flagbits,8)
18448   if markclass then
18449    markclass=readushort(f) 
18450   end
18451   if markset>0 then
18452    markclass=nofmarkclasses+markset
18453   end
18454   lookups[lookupid]={
18455    type=lookuptype,
18456    flags=lookupflags,
18457    name=lookupid,
18458    subtables=subtables,
18459    markclass=markclass,
18460    features=featurehash[lookupid],
18461    order=featureorder[lookupid],
18462   }
18463  end
18464  return lookups
18465 end
18466 local f_lookupname=formatters["%s_%s_%s"]
18467 local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
18468  local sequences=fontdata.sequences  or {}
18469  local sublookuplist=fontdata.sublookups or {}
18470  fontdata.sequences=sequences
18471  fontdata.sublookups=sublookuplist
18472  local nofsublookups=#sublookuplist
18473  local nofsequences=#sequences 
18474  local lastsublookup=nofsublookups
18475  local lastsequence=nofsequences
18476  local lookupnames=lookupnames[what]
18477  local sublookuphash={}
18478  local sublookupcheck={}
18479  local glyphs=fontdata.glyphs
18480  local nofglyphs=fontdata.nofglyphs or #glyphs
18481  local noflookups=#lookups
18482  local lookupprefix=sub(what,2,2)
18483  local usedlookups=false
18484  local allsteps={} 
18485  for lookupid=1,noflookups do
18486   local lookup=lookups[lookupid]
18487   local lookuptype=lookup.type
18488   local subtables=lookup.subtables
18489   local features=lookup.features
18490   local handler=lookuphandlers[lookuptype]
18491   if handler then
18492    local nofsubtables=#subtables
18493    local order=lookup.order
18494    local flags=lookup.flags
18495    if flags[1] then flags[1]="mark" end
18496    if flags[2] then flags[2]="ligature" end
18497    if flags[3] then flags[3]="base" end
18498    local markclass=lookup.markclass
18499    if nofsubtables>0 then
18500     local steps={}
18501     local nofsteps=0
18502     local oldtype=nil
18503     for s=1,nofsubtables do
18504      local step,lt=handler(f,fontdata,lookupid,lookupoffset,subtables[s],glyphs,nofglyphs)
18505      if lt then
18506       lookuptype=lt
18507       if oldtype and lt~=oldtype then
18508        report("messy %s lookup type %a and %a",what,lookuptype,oldtype)
18509       end
18510       oldtype=lookuptype
18511      end
18512      if not step then
18513       report("unsupported %s lookup type %a",what,lookuptype)
18514      else
18515       nofsteps=nofsteps+1
18516       steps[nofsteps]=step
18517       local rules=step.rules
18518       if rules then
18519        allsteps[#allsteps+1]=step 
18520        for i=1,#rules do
18521         local rule=rules[i]
18522         local before=rule.before
18523         local current=rule.current
18524         local after=rule.after
18525         local replacements=rule.replacements
18526         if before then
18527          for i=1,#before do
18528           before[i]=tohash(before[i])
18529          end
18530          rule.before=reversed(before)
18531         end
18532         if current then
18533          if replacements then
18534           local first=current[1]
18535           local hash={}
18536           local repl={}
18537           for i=1,#first do
18538            local c=first[i]
18539            hash[c]=true
18540            repl[c]=replacements[i]
18541           end
18542           rule.current={ hash }
18543           rule.replacements=repl
18544          else
18545           for i=1,#current do
18546            current[i]=tohash(current[i])
18547           end
18548          end
18549         else
18550         end
18551         if after then
18552          for i=1,#after do
18553           after[i]=tohash(after[i])
18554          end
18555         end
18556         if usedlookups then
18557          local lookups=rule.lookups
18558          if lookups then
18559           for k,v in next,lookups do
18560            if v then
18561             for k,v in next,v do
18562              usedlookups[v]=usedlookups[v]+1
18563             end
18564            end
18565           end
18566          end
18567         end
18568        end
18569       end
18570      end
18571     end
18572     if nofsteps~=nofsubtables then
18573      report("bogus subtables removed in %s lookup type %a",what,lookuptype)
18574     end
18575     lookuptype=lookupnames[lookuptype] or lookuptype
18576     if features then
18577      nofsequences=nofsequences+1
18578      local l={
18579       index=nofsequences,
18580       name=f_lookupname(lookupprefix,"s",lookupid+lookupidoffset),
18581       steps=steps,
18582       nofsteps=nofsteps,
18583       type=lookuptype,
18584       markclass=markclass or nil,
18585       flags=flags,
18586       order=order,
18587       features=features,
18588      }
18589      sequences[nofsequences]=l
18590      lookup.done=l
18591     else
18592      nofsublookups=nofsublookups+1
18593      local l={
18594       index=nofsublookups,
18595       name=f_lookupname(lookupprefix,"l",lookupid+lookupidoffset),
18596       steps=steps,
18597       nofsteps=nofsteps,
18598       type=lookuptype,
18599       markclass=markclass or nil,
18600       flags=flags,
18601      }
18602      sublookuplist[nofsublookups]=l
18603      sublookuphash[lookupid]=nofsublookups
18604      sublookupcheck[lookupid]=0
18605      lookup.done=l
18606     end
18607    else
18608     report("no subtables for lookup %a",lookupid)
18609    end
18610   else
18611    report("no handler for lookup %a with type %a",lookupid,lookuptype)
18612   end
18613  end
18614  if usedlookups then
18615   report("used %s lookups: % t",what,sortedkeys(usedlookups))
18616  end
18617  local reported={}
18618  local function report_issue(i,what,step,kind)
18619    report("rule %i in step %i of %s has %s lookups",i,step,what,kind)
18620  end
18621   for s=1,#allsteps do    
18622    local step=allsteps[s] 
18623    local rules=step.rules
18624    if rules then
18625     for i=1,#rules do
18626      local rule=rules[i]
18627      local rlookups=rule.lookups
18628      if not rlookups then
18629       report_issue(i,what,s,"no")
18630      elseif not next(rlookups) then
18631       rule.lookups=nil
18632      else
18633       local length=#rlookups
18634       for index=1,length do
18635        local lookuplist=rlookups[index]
18636        if lookuplist then
18637         local length=#lookuplist
18638         local found={}
18639         local noffound=0
18640         for index=1,length do
18641          local lookupid=lookuplist[index]
18642          if lookupid then
18643           local h=sublookuphash[lookupid]
18644           if not h then
18645            local lookup=lookups[lookupid]
18646            if lookup then
18647             local d=lookup.done
18648             if d then
18649              nofsublookups=nofsublookups+1
18650              local l={
18651               index=nofsublookups,
18652               name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
18653               derived=true,
18654               steps=d.steps,
18655               nofsteps=d.nofsteps,
18656               type=d.lookuptype or "gsub_single",
18657               markclass=d.markclass or nil,
18658               flags=d.flags,
18659              }
18660              sublookuplist[nofsublookups]=copy(l) 
18661              sublookuphash[lookupid]=nofsublookups
18662              sublookupcheck[lookupid]=1
18663              h=nofsublookups
18664             else
18665              report_issue(i,what,s,"missing")
18666              rule.lookups=nil
18667              break
18668             end
18669            else
18670             report_issue(i,what,s,"bad")
18671             rule.lookups=nil
18672             break
18673            end
18674           else
18675            sublookupcheck[lookupid]=sublookupcheck[lookupid]+1
18676           end
18677           if h then
18678            noffound=noffound+1
18679            found[noffound]=h
18680           end
18681          end
18682         end
18683         rlookups[index]=noffound>0 and found or false
18684        else
18685         rlookups[index]=false
18686        end
18687       end
18688      end
18689     end
18690    end
18691   end
18692  for i,n in sortedhash(sublookupcheck) do
18693   local l=lookups[i]
18694   local t=l.type
18695   if n==0 and t~="extension" then
18696    local d=l.done
18697    report("%s lookup %s of type %a is not used",what,d and d.name or l.name,t)
18698   end
18699  end
18700 end
18701 local function loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
18702  setposition(f,variationsoffset)
18703  local version=readulong(f) 
18704  local nofrecords=readulong(f)
18705  local records={}
18706  for i=1,nofrecords do
18707   records[i]={
18708    conditions=readulong(f),
18709    substitutions=readulong(f),
18710   }
18711  end
18712  for i=1,nofrecords do
18713   local record=records[i]
18714   local offset=record.conditions
18715   if offset==0 then
18716    record.condition=nil
18717    record.matchtype="always"
18718   else
18719    local offset=variationsoffset+offset
18720    setposition(f,offset)
18721    local nofconditions=readushort(f)
18722    local conditions={}
18723    for i=1,nofconditions do
18724     conditions[i]=offset+readulong(f)
18725    end
18726    record.conditions=conditions
18727    record.matchtype="condition"
18728   end
18729  end
18730  for i=1,nofrecords do
18731   local record=records[i]
18732   if record.matchtype=="condition" then
18733    local conditions=record.conditions
18734    for i=1,#conditions do
18735     setposition(f,conditions[i])
18736     conditions[i]={
18737      format=readushort(f),
18738      axis=readushort(f),
18739      minvalue=read2dot14(f),
18740      maxvalue=read2dot14(f),
18741     }
18742    end
18743   end
18744  end
18745  for i=1,nofrecords do
18746   local record=records[i]
18747   local offset=record.substitutions
18748   if offset==0 then
18749    record.substitutions={}
18750   else
18751    setposition(f,variationsoffset+offset)
18752    local version=readulong(f)
18753    local nofsubstitutions=readushort(f)
18754    local substitutions={}
18755    for i=1,nofsubstitutions do
18756     substitutions[readushort(f)]=readulong(f)
18757    end
18758    for index,alternates in sortedhash(substitutions) do
18759     if index==0 then
18760      record.substitutions=false
18761     else
18762      local tableoffset=variationsoffset+offset+alternates
18763      setposition(f,tableoffset)
18764      local parameters=readulong(f) 
18765      local noflookups=readushort(f)
18766      local lookups=readcardinaltable(f,noflookups,ushort)
18767      record.substitutions=lookups
18768     end
18769    end
18770   end
18771  end
18772  setvariabledata(fontdata,"features",records)
18773 end
18774 local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
18775  local tableoffset=gotodatatable(f,fontdata,what,true)
18776  if tableoffset then
18777   local version=readulong(f)
18778   local scriptoffset=tableoffset+readushort(f)
18779   local featureoffset=tableoffset+readushort(f)
18780   local lookupoffset=tableoffset+readushort(f)
18781   local variationsoffset=version>0x00010000 and readulong(f) or 0
18782   if not scriptoffset then
18783    return
18784   end
18785   local scripts=readscriplan(f,fontdata,scriptoffset)
18786   local features=readfeatures(f,fontdata,featureoffset)
18787   local scriptlangs,featurehash,featureorder=reorderfeatures(fontdata,scripts,features)
18788   if fontdata.features then
18789    fontdata.features[what]=scriptlangs
18790   else
18791    fontdata.features={ [what]=scriptlangs }
18792   end
18793   if not lookupstoo then
18794    return
18795   end
18796   local nofmarkclasses=(fontdata.markclasses and #fontdata.markclasses or 0)-(fontdata.marksets and #fontdata.marksets or 0)
18797   local lookups=readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder,nofmarkclasses)
18798   if lookups then
18799    resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
18800   end
18801   if variationsoffset>0 then
18802    loadvariations(f,fontdata,tableoffset+variationsoffset,lookuptypes,featurehash,featureorder)
18803   end
18804  end
18805 end
18806 local function checkkerns(f,fontdata,specification)
18807  local datatable=fontdata.tables.kern
18808  if not datatable then
18809   return 
18810  end
18811  local features=fontdata.features
18812  local gposfeatures=features and features.gpos
18813  local name
18814  if not gposfeatures or not gposfeatures.kern then
18815   name="kern"
18816  elseif specification.globalkerns then
18817   name="globalkern"
18818  else
18819   report("ignoring global kern table, using gpos kern feature")
18820   return
18821  end
18822  setposition(f,datatable.offset)
18823  local version=readushort(f)
18824  local noftables=readushort(f)
18825  if noftables>1 then
18826   report("adding global kern table as gpos feature %a",name)
18827   local kerns=setmetatableindex("table")
18828   for i=1,noftables do
18829    local version=readushort(f)
18830    local length=readushort(f)
18831    local coverage=readushort(f)
18832    local format=rshift(coverage,8) 
18833    if format==0 then
18834     local nofpairs=readushort(f)
18835     local searchrange=readushort(f)
18836     local entryselector=readushort(f)
18837     local rangeshift=readushort(f)
18838     for i=1,nofpairs do
18839      kerns[readushort(f)][readushort(f)]=readfword(f)
18840     end
18841    elseif format==2 then
18842    else
18843    end
18844   end
18845   local feature={ dflt={ dflt=true } }
18846   if not features then
18847    fontdata.features={ gpos={ [name]=feature } }
18848   elseif not gposfeatures then
18849    fontdata.features.gpos={ [name]=feature }
18850   else
18851    gposfeatures[name]=feature
18852   end
18853   local sequences=fontdata.sequences
18854   if not sequences then
18855    sequences={}
18856    fontdata.sequences=sequences
18857   end
18858   local nofsequences=#sequences+1
18859   sequences[nofsequences]={
18860    index=nofsequences,
18861    name=name,
18862    steps={
18863     {
18864      coverage=kerns,
18865      format="kern",
18866     },
18867    },
18868    nofsteps=1,
18869    type="gpos_pair",
18870    flags={ false,false,false,false },
18871    order={ name },
18872    features={ [name]=feature },
18873   }
18874  else
18875   report("ignoring empty kern table of feature %a",name)
18876  end
18877 end
18878 function readers.gsub(f,fontdata,specification)
18879  if specification.details then
18880   readscripts(f,fontdata,"gsub",gsubtypes,gsubhandlers,specification.lookups)
18881  end
18882 end
18883 function readers.gpos(f,fontdata,specification)
18884  if specification.details then
18885   readscripts(f,fontdata,"gpos",gpostypes,gposhandlers,specification.lookups)
18886   if specification.lookups then
18887    checkkerns(f,fontdata,specification)
18888   end
18889  end
18890 end
18891end
18892function readers.gdef(f,fontdata,specification)
18893 if not specification.glyphs then
18894  return
18895 end
18896 local datatable=fontdata.tables.gdef
18897 if datatable then
18898  local tableoffset=datatable.offset
18899  setposition(f,tableoffset)
18900  local version=readulong(f)
18901  local classoffset=readushort(f)
18902  local attachmentoffset=readushort(f) 
18903  local ligaturecarets=readushort(f) 
18904  local markclassoffset=readushort(f)
18905  local marksetsoffset=version>=0x00010002 and readushort(f) or 0
18906  local varsetsoffset=version>=0x00010003 and readulong(f) or 0
18907  local glyphs=fontdata.glyphs
18908  local marks={}
18909  local markclasses=setmetatableindex("table")
18910  local marksets=setmetatableindex("table")
18911  fontdata.marks=marks
18912  fontdata.markclasses=markclasses
18913  fontdata.marksets=marksets
18914  if classoffset~=0 then
18915   setposition(f,tableoffset+classoffset)
18916   local classformat=readushort(f)
18917   if classformat==1 then
18918    local firstindex=readushort(f)
18919    local lastindex=firstindex+readushort(f)-1
18920    for index=firstindex,lastindex do
18921     local class=classes[readushort(f)]
18922     if class=="mark" then
18923      marks[index]=true
18924     end
18925     glyphs[index].class=class
18926    end
18927   elseif classformat==2 then
18928    local nofranges=readushort(f)
18929    for i=1,nofranges do
18930     local firstindex=readushort(f)
18931     local lastindex=readushort(f)
18932     local class=classes[readushort(f)]
18933     if class then
18934      for index=firstindex,lastindex do
18935       glyphs[index].class=class
18936       if class=="mark" then
18937        marks[index]=true
18938       end
18939      end
18940     end
18941    end
18942   end
18943  end
18944  if markclassoffset~=0 then
18945   setposition(f,tableoffset+markclassoffset)
18946   local classformat=readushort(f)
18947   if classformat==1 then
18948    local firstindex=readushort(f)
18949    local lastindex=firstindex+readushort(f)-1
18950    for index=firstindex,lastindex do
18951     markclasses[readushort(f)][index]=true
18952    end
18953   elseif classformat==2 then
18954    local nofranges=readushort(f)
18955    for i=1,nofranges do
18956     local firstindex=readushort(f)
18957     local lastindex=readushort(f)
18958     local class=markclasses[readushort(f)]
18959     for index=firstindex,lastindex do
18960      class[index]=true
18961     end
18962    end
18963   end
18964  end
18965  if marksetsoffset~=0 then
18966   local nofmarkclasses=fontdata.markclasses and #fontdata.markclasses or 0
18967   marksetsoffset=tableoffset+marksetsoffset
18968   setposition(f,marksetsoffset)
18969   local format=readushort(f)
18970   if format==1 then
18971    local nofsets=readushort(f)
18972    local sets=readcardinaltable(f,nofsets,ulong)
18973    for i=1,nofsets do
18974     local offset=sets[i]
18975     if offset~=0 then
18976      markclasses[nofmarkclasses+i]=readcoverage(f,marksetsoffset+offset)
18977      marksets[i]={}
18978     end
18979    end
18980   end
18981  end
18982  local factors=specification.factors
18983  if (specification.variable or factors) and varsetsoffset~=0 then
18984   local regions,deltas=readvariationdata(f,tableoffset+varsetsoffset,factors)
18985   if factors then
18986    fontdata.temporary.getdelta=function(outer,inner)
18987     local delta=deltas[outer+1]
18988     if delta then
18989      local d=delta.deltas[inner+1]
18990      if d then
18991       local scales=delta.scales
18992       local dd=0
18993       for i=1,#scales do
18994        local di=d[i]
18995        if di then
18996         dd=dd+scales[i]*di
18997        else
18998         break
18999        end
19000       end
19001       return round(dd)
19002      end
19003     end
19004     return 0
19005    end
19006   end
19007  end
19008 end
19009end
19010local function readmathvalue(f)
19011 local v=readshort(f)
19012 skipshort(f,1) 
19013 return v
19014end
19015local function readmathconstants(f,fontdata,offset)
19016 setposition(f,offset)
19017 fontdata.mathconstants={
19018  ScriptPercentScaleDown=readshort(f),
19019  ScriptScriptPercentScaleDown=readshort(f),
19020  DelimitedSubFormulaMinHeight=readushort(f),
19021  DisplayOperatorMinHeight=readushort(f),
19022  MathLeading=readmathvalue(f),
19023  AxisHeight=readmathvalue(f),
19024  AccentBaseHeight=readmathvalue(f),
19025  FlattenedAccentBaseHeight=readmathvalue(f),
19026  SubscriptShiftDown=readmathvalue(f),
19027  SubscriptTopMax=readmathvalue(f),
19028  SubscriptBaselineDropMin=readmathvalue(f),
19029  SuperscriptShiftUp=readmathvalue(f),
19030  SuperscriptShiftUpCramped=readmathvalue(f),
19031  SuperscriptBottomMin=readmathvalue(f),
19032  SuperscriptBaselineDropMax=readmathvalue(f),
19033  SubSuperscriptGapMin=readmathvalue(f),
19034  SuperscriptBottomMaxWithSubscript=readmathvalue(f),
19035  SpaceAfterScript=readmathvalue(f),
19036  UpperLimitGapMin=readmathvalue(f),
19037  UpperLimitBaselineRiseMin=readmathvalue(f),
19038  LowerLimitGapMin=readmathvalue(f),
19039  LowerLimitBaselineDropMin=readmathvalue(f),
19040  StackTopShiftUp=readmathvalue(f),
19041  StackTopDisplayStyleShiftUp=readmathvalue(f),
19042  StackBottomShiftDown=readmathvalue(f),
19043  StackBottomDisplayStyleShiftDown=readmathvalue(f),
19044  StackGapMin=readmathvalue(f),
19045  StackDisplayStyleGapMin=readmathvalue(f),
19046  StretchStackTopShiftUp=readmathvalue(f),
19047  StretchStackBottomShiftDown=readmathvalue(f),
19048  StretchStackGapAboveMin=readmathvalue(f),
19049  StretchStackGapBelowMin=readmathvalue(f),
19050  FractionNumeratorShiftUp=readmathvalue(f),
19051  FractionNumeratorDisplayStyleShiftUp=readmathvalue(f),
19052  FractionDenominatorShiftDown=readmathvalue(f),
19053  FractionDenominatorDisplayStyleShiftDown=readmathvalue(f),
19054  FractionNumeratorGapMin=readmathvalue(f),
19055  FractionNumeratorDisplayStyleGapMin=readmathvalue(f),
19056  FractionRuleThickness=readmathvalue(f),
19057  FractionDenominatorGapMin=readmathvalue(f),
19058  FractionDenominatorDisplayStyleGapMin=readmathvalue(f),
19059  SkewedFractionHorizontalGap=readmathvalue(f),
19060  SkewedFractionVerticalGap=readmathvalue(f),
19061  OverbarVerticalGap=readmathvalue(f),
19062  OverbarRuleThickness=readmathvalue(f),
19063  OverbarExtraAscender=readmathvalue(f),
19064  UnderbarVerticalGap=readmathvalue(f),
19065  UnderbarRuleThickness=readmathvalue(f),
19066  UnderbarExtraDescender=readmathvalue(f),
19067  RadicalVerticalGap=readmathvalue(f),
19068  RadicalDisplayStyleVerticalGap=readmathvalue(f),
19069  RadicalRuleThickness=readmathvalue(f),
19070  RadicalExtraAscender=readmathvalue(f),
19071  RadicalKernBeforeDegree=readmathvalue(f),
19072  RadicalKernAfterDegree=readmathvalue(f),
19073  RadicalDegreeBottomRaisePercent=readshort(f),
19074 }
19075end
19076local function readmathglyphinfo(f,fontdata,offset)
19077 setposition(f,offset)
19078 local italics=readushort(f)
19079 local accents=readushort(f)
19080 local extensions=readushort(f)
19081 local kerns=readushort(f)
19082 local glyphs=fontdata.glyphs
19083 if italics~=0 then
19084  setposition(f,offset+italics)
19085  local coverage=readushort(f)
19086  local nofglyphs=readushort(f)
19087  coverage=readcoverage(f,offset+italics+coverage,true)
19088  setposition(f,offset+italics+4)
19089  for i=1,nofglyphs do
19090   local italic=readmathvalue(f)
19091   if italic~=0 then
19092    local glyph=glyphs[coverage[i]]
19093    local math=glyph.math
19094    if not math then
19095     glyph.math={ italic=italic }
19096    else
19097     math.italic=italic
19098    end
19099   end
19100  end
19101  fontdata.hasitalics=true
19102 end
19103 if accents~=0 then
19104  setposition(f,offset+accents)
19105  local coverage=readushort(f)
19106  local nofglyphs=readushort(f)
19107  coverage=readcoverage(f,offset+accents+coverage,true)
19108  setposition(f,offset+accents+4)
19109  for i=1,nofglyphs do
19110   local accent=readmathvalue(f)
19111   if accent~=0 then
19112    local glyph=glyphs[coverage[i]]
19113    local math=glyph.math
19114    if not math then
19115     glyph.math={ accent=accent }
19116    else
19117     math.accent=accent 
19118    end
19119   end
19120  end
19121 end
19122 if extensions~=0 then
19123  setposition(f,offset+extensions)
19124 end
19125 if kerns~=0 then
19126  local kernoffset=offset+kerns
19127  setposition(f,kernoffset)
19128  local coverage=readushort(f)
19129  local nofglyphs=readushort(f)
19130  if nofglyphs>0 then
19131   local function get(offset)
19132    setposition(f,kernoffset+offset)
19133    local n=readushort(f)
19134    if n==0 then
19135     local k=readmathvalue(f)
19136     if k==0 then
19137     else
19138      return { { kern=k } }
19139     end
19140    else
19141     local l={}
19142     for i=1,n do
19143      l[i]={ height=readmathvalue(f) }
19144     end
19145     for i=1,n do
19146      l[i].kern=readmathvalue(f)
19147     end
19148     l[n+1]={ kern=readmathvalue(f) }
19149     return l
19150    end
19151   end
19152   local kernsets={}
19153   for i=1,nofglyphs do
19154    local topright=readushort(f)
19155    local topleft=readushort(f)
19156    local bottomright=readushort(f)
19157    local bottomleft=readushort(f)
19158    kernsets[i]={
19159     topright=topright~=0 and topright or nil,
19160     topleft=topleft~=0 and topleft  or nil,
19161     bottomright=bottomright~=0 and bottomright or nil,
19162     bottomleft=bottomleft~=0 and bottomleft  or nil,
19163    }
19164   end
19165   coverage=readcoverage(f,kernoffset+coverage,true)
19166   for i=1,nofglyphs do
19167    local kernset=kernsets[i]
19168    if next(kernset) then
19169     local k=kernset.topright if k then kernset.topright=get(k) end
19170     local k=kernset.topleft  if k then kernset.topleft=get(k) end
19171     local k=kernset.bottomright if k then kernset.bottomright=get(k) end
19172     local k=kernset.bottomleft  if k then kernset.bottomleft=get(k) end
19173     if next(kernset) then
19174      local glyph=glyphs[coverage[i]]
19175      local math=glyph.math
19176      if math then
19177       math.kerns=kernset
19178      else
19179       glyph.math={ kerns=kernset }
19180      end
19181     end
19182    end
19183   end
19184  end
19185 end
19186end
19187local function readmathvariants(f,fontdata,offset)
19188 setposition(f,offset)
19189 local glyphs=fontdata.glyphs
19190 local minoverlap=readushort(f)
19191 local vcoverage=readushort(f)
19192 local hcoverage=readushort(f)
19193 local vnofglyphs=readushort(f)
19194 local hnofglyphs=readushort(f)
19195 local vconstruction=readcardinaltable(f,vnofglyphs,ushort)
19196 local hconstruction=readcardinaltable(f,hnofglyphs,ushort)
19197 fontdata.mathconstants.MinConnectorOverlap=minoverlap
19198 local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic,korientation,orientation)
19199  if coverage~=0 and nofglyphs>0 then
19200   local coverage=readcoverage(f,offset+coverage,true)
19201   for i=1,nofglyphs do
19202    local c=construction[i]
19203    if c~=0 then
19204     local index=coverage[i]
19205     local glyph=glyphs[index]
19206     local math=glyph.math
19207     setposition(f,offset+c)
19208     local assembly=readushort(f)
19209     local nofvariants=readushort(f)
19210     if nofvariants>0 then
19211      local variants,v=nil,0
19212      for i=1,nofvariants do
19213       local variant=readushort(f)
19214       if variant==index then
19215       elseif variants then
19216        v=v+1
19217        variants[v]=variant
19218       else
19219        v=1
19220        variants={ variant }
19221       end
19222       skipshort(f)
19223      end
19224      if not variants then
19225      elseif not math then
19226       math={ [kvariants]=variants }
19227       glyph.math=math
19228      else
19229       math[kvariants]=variants
19230      end
19231     end
19232     if assembly~=0 then
19233      setposition(f,offset+c+assembly)
19234      local italic=readmathvalue(f)
19235      local nofparts=readushort(f)
19236      local parts={}
19237      for i=1,nofparts do
19238       local p={
19239        glyph=readushort(f),
19240        start=readushort(f),
19241        ["end"]=readushort(f),
19242        advance=readushort(f),
19243       }
19244       local flags=readushort(f)
19245       if band(flags,0x0001)~=0 then
19246        p.extender=1 
19247       end
19248       parts[i]=p
19249      end
19250      if not math then
19251       math={
19252        [kparts]=parts
19253       }
19254       glyph.math=math
19255      else
19256       math[kparts]=parts
19257      end
19258      if italic and italic~=0 then
19259       math[kitalic]=italic
19260      end
19261      if orientation then
19262       math[korientation]=orientation
19263      end
19264     end
19265    end
19266   end
19267  end
19268 end
19269 if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
19270  get(offset,hcoverage,hnofglyphs,hconstruction,"variants","parts","partsitalic","partsorientation","horizontal")
19271  get(offset,vcoverage,vnofglyphs,vconstruction,"variants","parts","partsitalic","partsorientation","vertical")
19272 else
19273  get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic")
19274  get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic")
19275 end
19276end
19277function readers.math(f,fontdata,specification)
19278 local tableoffset=gotodatatable(f,fontdata,"math",specification.glyphs)
19279 if tableoffset then
19280  local version=readulong(f)
19281  local constants=readushort(f)
19282  local glyphinfo=readushort(f)
19283  local variants=readushort(f)
19284  if constants==0 then
19285   report("the math table of %a has no constants",fontdata.filename)
19286  else
19287   readmathconstants(f,fontdata,tableoffset+constants)
19288  end
19289  if glyphinfo~=0 then
19290   readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
19291  end
19292  if variants~=0 then
19293   readmathvariants(f,fontdata,tableoffset+variants)
19294  end
19295 end
19296end
19297function readers.colr(f,fontdata,specification)
19298 local tableoffset=gotodatatable(f,fontdata,"colr",specification.glyphs)
19299 if tableoffset then
19300  local version=readushort(f)
19301  if version==0 or version==1 then
19302   report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
19303   return
19304  else
19305  end
19306  if not fontdata.tables.cpal then
19307   report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
19308   fontdata.colorpalettes={}
19309  end
19310  local glyphs=fontdata.glyphs
19311  local nofglyphs=readushort(f)
19312  local baseoffset=readulong(f)
19313  local layeroffset=readulong(f)
19314  local noflayers=readushort(f)
19315  local layerrecords={}
19316  local maxclass=0
19317  setposition(f,tableoffset+layeroffset)
19318  for i=1,noflayers do
19319   local slot=readushort(f)
19320   local class=readushort(f)
19321   if class<0xFFFF then
19322    class=class+1
19323    if class>maxclass then
19324     maxclass=class
19325    end
19326   end
19327   layerrecords[i]={
19328    slot=slot,
19329    class=class,
19330   }
19331  end
19332  fontdata.maxcolorclass=maxclass
19333  setposition(f,tableoffset+baseoffset)
19334  for i=0,nofglyphs-1 do
19335   local glyphindex=readushort(f)
19336   local firstlayer=readushort(f)
19337   local noflayers=readushort(f)
19338   local t={}
19339   for i=1,noflayers do
19340    t[i]=layerrecords[firstlayer+i]
19341   end
19342   glyphs[glyphindex].colors=t
19343  end
19344 end
19345 fontdata.hascolor=true
19346end
19347function readers.cpal(f,fontdata,specification)
19348 local tableoffset=gotodatatable(f,fontdata,"cpal",specification.glyphs)
19349 if tableoffset then
19350  local version=readushort(f)
19351  local nofpaletteentries=readushort(f)
19352  local nofpalettes=readushort(f)
19353  local nofcolorrecords=readushort(f)
19354  local firstcoloroffset=readulong(f)
19355  local colorrecords={}
19356  local palettes=readcardinaltable(f,nofpalettes,ushort)
19357  if version==1 then
19358   local palettettypesoffset=readulong(f)
19359   local palettelabelsoffset=readulong(f)
19360   local paletteentryoffset=readulong(f)
19361  end
19362  setposition(f,tableoffset+firstcoloroffset)
19363  for i=1,nofcolorrecords do
19364   local b,g,r,a=readbytes(f,4)
19365   colorrecords[i]={
19366    r,g,b,a~=255 and a or nil,
19367   }
19368  end
19369  for i=1,nofpalettes do
19370   local p={}
19371   local o=palettes[i]
19372   for j=1,nofpaletteentries do
19373    p[j]=colorrecords[o+j]
19374   end
19375   palettes[i]=p
19376  end
19377  fontdata.colorpalettes=palettes
19378 end
19379end
19380local compress=gzip and gzip.compress
19381local compressed=compress and gzip.compressed
19382function readers.svg(f,fontdata,specification)
19383 local tableoffset=gotodatatable(f,fontdata,"svg",specification.glyphs)
19384 if tableoffset then
19385  local version=readushort(f)
19386  local glyphs=fontdata.glyphs
19387  local indexoffset=tableoffset+readulong(f)
19388  local reserved=readulong(f)
19389  setposition(f,indexoffset)
19390  local nofentries=readushort(f)
19391  local entries={}
19392  for i=1,nofentries do
19393   entries[i]={
19394    first=readushort(f),
19395    last=readushort(f),
19396    offset=indexoffset+readulong(f),
19397    length=readulong(f),
19398   }
19399  end
19400  for i=1,nofentries do
19401   local entry=entries[i]
19402   setposition(f,entry.offset)
19403   local data=readstring(f,entry.length)
19404   if compressed and not compressed(data) then
19405    data=compress(data)
19406   end
19407   entries[i]={
19408    first=entry.first,
19409    last=entry.last,
19410    data=data
19411   }
19412  end
19413  fontdata.svgshapes=entries
19414 end
19415 fontdata.hascolor=true
19416end
19417function readers.sbix(f,fontdata,specification)
19418 local tableoffset=gotodatatable(f,fontdata,"sbix",specification.glyphs)
19419 if tableoffset then
19420  local version=readushort(f)
19421  local flags=readushort(f)
19422  local nofstrikes=readulong(f)
19423  local strikes={}
19424  local nofglyphs=fontdata.nofglyphs
19425  for i=1,nofstrikes do
19426   strikes[i]=readulong(f)
19427  end
19428  local shapes={}
19429  local done=0
19430  for i=1,nofstrikes do
19431   local strikeoffset=strikes[i]+tableoffset
19432   setposition(f,strikeoffset)
19433   strikes[i]={
19434    ppem=readushort(f),
19435    ppi=readushort(f),
19436    offset=strikeoffset
19437   }
19438  end
19439  sort(strikes,function(a,b)
19440   if b.ppem==a.ppem then
19441    return b.ppi<a.ppi
19442   else
19443    return b.ppem<a.ppem
19444   end
19445  end)
19446  local glyphs={}
19447  local delayed=CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 or fonts.handlers.typethree
19448  for i=1,nofstrikes do
19449   local strike=strikes[i]
19450   local strikeppem=strike.ppem
19451   local strikeppi=strike.ppi
19452   local strikeoffset=strike.offset
19453   setposition(f,strikeoffset)
19454   for i=0,nofglyphs do
19455    glyphs[i]=readulong(f)
19456   end
19457   local glyphoffset=glyphs[0]
19458   for i=0,nofglyphs-1 do
19459    local nextoffset=glyphs[i+1]
19460    if not shapes[i] then
19461     local datasize=nextoffset-glyphoffset
19462     if datasize>0 then
19463      setposition(f,strikeoffset+glyphoffset)
19464      local x=readshort(f)
19465      local y=readshort(f)
19466      local tag=readtag(f) 
19467      local size=datasize-8
19468      local data=nil
19469      local offset=nil
19470      if delayed then
19471       offset=getposition(f)
19472       data=nil
19473      else
19474       data=readstring(f,size)
19475       size=nil
19476      end
19477      shapes[i]={
19478       x=x,
19479       y=y,
19480       o=offset,
19481       s=size,
19482       data=data,
19483      }
19484      done=done+1
19485      if done==nofglyphs then
19486       break
19487      end
19488     end
19489    end
19490    glyphoffset=nextoffset
19491   end
19492  end
19493  fontdata.pngshapes=shapes
19494 end
19495end
19496do
19497 local function getmetrics(f)
19498  return {
19499   ascender=readinteger(f),
19500   descender=readinteger(f),
19501   widthmax=readuinteger(f),
19502   caretslopedumerator=readinteger(f),
19503   caretslopedenominator=readinteger(f),
19504   caretoffset=readinteger(f),
19505   minorigin=readinteger(f),
19506   minadvance=readinteger(f),
19507   maxbefore=readinteger(f),
19508   minafter=readinteger(f),
19509   pad1=readinteger(f),
19510   pad2=readinteger(f),
19511  }
19512 end
19513 local function getbigmetrics(f)
19514  return {
19515   height=readuinteger(f),
19516   width=readuinteger(f),
19517   horiBearingX=readinteger(f),
19518   horiBearingY=readinteger(f),
19519   horiAdvance=readuinteger(f),
19520   vertBearingX=readinteger(f),
19521   vertBearingY=readinteger(f),
19522   vertAdvance=readuinteger(f),
19523  }
19524 end
19525 local function getsmallmetrics(f)
19526  return {
19527   height=readuinteger(f),
19528   width=readuinteger(f),
19529   bearingX=readinteger(f),
19530   bearingY=readinteger(f),
19531   advance=readuinteger(f),
19532  }
19533 end
19534 function readers.cblc(f,fontdata,specification)
19535  local ctdttableoffset=gotodatatable(f,fontdata,"cbdt",specification.glyphs)
19536  if not ctdttableoffset then
19537   return
19538  end
19539  local cblctableoffset=gotodatatable(f,fontdata,"cblc",specification.glyphs)
19540  if cblctableoffset then
19541   local majorversion=readushort(f)
19542   local minorversion=readushort(f)
19543   local nofsizetables=readulong(f)
19544   local sizetables={}
19545   local shapes={}
19546   local subtables={}
19547   for i=1,nofsizetables do
19548    sizetables[i]={
19549     subtables=readulong(f),
19550     indexsize=readulong(f),
19551     nofsubtables=readulong(f),
19552     colorref=readulong(f),
19553     hormetrics=getmetrics(f),
19554     vermetrics=getmetrics(f),
19555     firstindex=readushort(f),
19556     lastindex=readushort(f),
19557     ppemx=readbyte(f),
19558     ppemy=readbyte(f),
19559     bitdepth=readbyte(f),
19560     flags=readbyte(f),
19561    }
19562   end
19563   sort(sizetables,function(a,b)
19564    if b.ppemx==a.ppemx then
19565     return b.bitdepth<a.bitdepth
19566    else
19567     return b.ppemx<a.ppemx
19568    end
19569   end)
19570   for i=1,nofsizetables do
19571    local s=sizetables[i]
19572    local d=false
19573    for j=s.firstindex,s.lastindex do
19574     if not shapes[j] then
19575      shapes[j]=i
19576      d=true
19577     end
19578    end
19579    if d then
19580     s.used=true
19581    end
19582   end
19583   for i=1,nofsizetables do
19584    local s=sizetables[i]
19585    if s.used then
19586     local offset=s.subtables
19587     setposition(f,cblctableoffset+offset)
19588     for j=1,s.nofsubtables do
19589      local firstindex=readushort(f)
19590      local lastindex=readushort(f)
19591      local tableoffset=readulong(f)+offset
19592      for k=firstindex,lastindex do
19593       if shapes[k]==i then
19594        local s=subtables[tableoffset]
19595        if not s then
19596         s={
19597          firstindex=firstindex,
19598          lastindex=lastindex,
19599         }
19600         subtables[tableoffset]=s
19601        end
19602        shapes[k]=s
19603       end
19604      end
19605     end
19606    end
19607   end
19608   for offset,subtable in sortedhash(subtables) do
19609    local tabletype=readushort(f)
19610    subtable.format=readushort(f)
19611    local baseoffset=readulong(f)+ctdttableoffset
19612    local offsets={}
19613    local metrics=nil
19614    if tabletype==1 then
19615     for i=subtable.firstindex,subtable.lastindex do
19616      offsets[i]=readulong(f)+baseoffset
19617     end
19618     skipbytes(f,4)
19619    elseif tabletype==2 then
19620     local size=readulong(f)
19621     local done=baseoffset
19622     metrics=getbigmetrics(f)
19623     for i=subtable.firstindex,subtable.lastindex do
19624      offsets[i]=done
19625      done=done+size
19626     end
19627    elseif tabletype==3 then
19628     local n=subtable.lastindex-subtable.firstindex+2
19629     for i=subtable.firstindex,subtable.lastindex do
19630      offsets[i]=readushort(f)+baseoffset
19631     end
19632     if math.odd(n) then
19633      skipbytes(f,4)
19634     else
19635      skipbytes(f,2)
19636     end
19637    elseif tabletype==4 then
19638     for i=1,readulong(f) do
19639      offsets[readushort(f)]=readushort(f)+baseoffset
19640     end
19641    elseif tabletype==5 then
19642     local size=readulong(f)
19643     local done=baseoffset
19644     metrics=getbigmetrics(f)
19645     local n=readulong(f)
19646     for i=1,n do
19647      offsets[readushort(f)]=done
19648      done=done+size
19649     end
19650     if math.odd(n) then
19651      skipbytes(f,2)
19652     end
19653    else
19654     return 
19655    end
19656    subtable.offsets=offsets
19657    subtable.metrics=metrics
19658   end
19659   local default={ width=0,height=0 }
19660   local glyphs=fontdata.glyphs
19661   local delayed=CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 or fonts.handlers.typethree
19662   for index,subtable in sortedhash(shapes) do
19663    if type(subtable)=="table" then
19664     local data=nil
19665     local size=nil
19666     local metrics=default
19667     local format=subtable.format
19668     local offset=subtable.offsets[index]
19669     setposition(f,offset)
19670     if format==17 then
19671      metrics=getsmallmetrics(f)
19672      size=true
19673     elseif format==18 then
19674      metrics=getbigmetrics(f)
19675      size=true
19676     elseif format==19 then
19677      metrics=subtable.metrics
19678      size=true
19679     else
19680     end
19681     if size then
19682      size=readulong(f)
19683      if delayed then
19684       offset=getposition(f)
19685       data=nil
19686      else
19687       offset=nil
19688       data=readstring(f,size)
19689       size=nil
19690      end
19691     else
19692      offset=nil
19693     end
19694     local x=metrics.width
19695     local y=metrics.height
19696     shapes[index]={
19697      x=x,
19698      y=y,
19699      o=offset,
19700      s=size,
19701      data=data,
19702     }
19703     local glyph=glyphs[index]
19704     if not glyph.boundingbox then
19705      local width=glyph.width
19706      local height=width*y/x
19707      glyph.boundingbox={ 0,0,width,height }
19708     end
19709    else
19710     shapes[index]={
19711      x=0,
19712      y=0,
19713      data="",
19714     }
19715    end
19716   end
19717   fontdata.pngshapes=shapes 
19718  end
19719 end
19720 function readers.cbdt(f,fontdata,specification)
19721 end
19722end
19723function readers.stat(f,fontdata,specification)
19724 local tableoffset=gotodatatable(f,fontdata,"stat",true) 
19725 if tableoffset then
19726  local extras=fontdata.extras
19727  local version=readulong(f) 
19728  local axissize=readushort(f)
19729  local nofaxis=readushort(f)
19730  local axisoffset=readulong(f)
19731  local nofvalues=readushort(f)
19732  local valuesoffset=readulong(f)
19733  local fallbackname=extras[readushort(f)] 
19734  local axis={}
19735  local values={}
19736  setposition(f,tableoffset+axisoffset)
19737  for i=1,nofaxis do
19738   local tag=readtag(f)
19739   axis[i]={
19740    tag=tag,
19741    name=lower(extras[readushort(f)] or tag),
19742    ordering=readushort(f),
19743    variants={}
19744   }
19745  end
19746  setposition(f,tableoffset+valuesoffset)
19747  for i=1,nofvalues do
19748   values[i]=readushort(f)
19749  end
19750  for i=1,nofvalues do
19751   setposition(f,tableoffset+valuesoffset+values[i])
19752   local format=readushort(f)
19753   local index=readushort(f)+1
19754   local flags=readushort(f)
19755   local name=lower(extras[readushort(f)] or "no name")
19756   local value=readfixed(f)
19757   local variant
19758   if format==1 then
19759    variant={
19760     flags=flags,
19761     name=name,
19762     value=value,
19763    }
19764   elseif format==2 then
19765    variant={
19766     flags=flags,
19767     name=name,
19768     value=value,
19769     minimum=readfixed(f),
19770     maximum=readfixed(f),
19771    }
19772   elseif format==3 then
19773    variant={
19774     flags=flags,
19775     name=name,
19776     value=value,
19777     link=readfixed(f),
19778    }
19779   end
19780   insert(axis[index].variants,variant)
19781  end
19782  sort(axis,function(a,b)
19783   return a.ordering<b.ordering
19784  end)
19785  for i=1,#axis do
19786   local a=axis[i]
19787   sort(a.variants,function(a,b)
19788    return a.name<b.name
19789   end)
19790   a.ordering=nil
19791  end
19792  setvariabledata(fontdata,"designaxis",axis)
19793  setvariabledata(fontdata,"fallbackname",fallbackname)
19794 end
19795end
19796function readers.avar(f,fontdata,specification)
19797 local tableoffset=gotodatatable(f,fontdata,"avar",true) 
19798 if tableoffset then
19799  local function collect()
19800   local nofvalues=readushort(f)
19801   local values={}
19802   local lastfrom=false
19803   local lastto=false
19804   for i=1,nofvalues do
19805    local from=read2dot14(f)
19806    local to=read2dot14(f)
19807    if lastfrom and from<=lastfrom then
19808    elseif lastto and to>=lastto then
19809    else
19810     values[#values+1]={ from,to }
19811     lastfrom,lastto=from,to
19812    end
19813   end
19814   nofvalues=#values
19815   if nofvalues>2 then
19816    local some=values[1]
19817    if some[1]==-1 and some[2]==-1 then
19818     some=values[nofvalues]
19819     if some[1]==1 and some[2]==1 then
19820      for i=2,nofvalues-1 do
19821       some=values[i]
19822       if some[1]==0 and some[2]==0 then
19823        return values
19824       end
19825      end
19826     end
19827    end
19828   end
19829   return false
19830  end
19831  local version=readulong(f) 
19832  local reserved=readushort(f)
19833  local nofaxis=readushort(f)
19834  local segments={}
19835  for i=1,nofaxis do
19836   segments[i]=collect()
19837  end
19838  setvariabledata(fontdata,"segments",segments)
19839 end
19840end
19841function readers.fvar(f,fontdata,specification)
19842 local tableoffset=gotodatatable(f,fontdata,"fvar",true) 
19843 if tableoffset then
19844  local version=readulong(f) 
19845  local offsettoaxis=tableoffset+readushort(f)
19846  local reserved=skipshort(f)
19847  local nofaxis=readushort(f)
19848  local sizeofaxis=readushort(f)
19849  local nofinstances=readushort(f)
19850  local sizeofinstances=readushort(f)
19851  local extras=fontdata.extras
19852  local axis={}
19853  local instances={}
19854  setposition(f,offsettoaxis)
19855  for i=1,nofaxis do
19856   axis[i]={
19857    tag=readtag(f),
19858    minimum=readfixed(f),
19859    default=readfixed(f),
19860    maximum=readfixed(f),
19861    flags=readushort(f),
19862    name=lower(extras[readushort(f)] or "bad name"),
19863   }
19864   local n=sizeofaxis-20
19865   if n>0 then
19866    skipbytes(f,n)
19867   elseif n<0 then
19868   end
19869  end
19870  local nofbytes=2+2+2+nofaxis*4
19871  local readpsname=nofbytes<=sizeofinstances
19872  local skippable=sizeofinstances-nofbytes
19873  for i=1,nofinstances do
19874   local subfamid=readushort(f)
19875   local flags=readushort(f) 
19876   local values={}
19877   for i=1,nofaxis do
19878    values[i]={
19879     axis=axis[i].tag,
19880     value=readfixed(f),
19881    }
19882   end
19883   local psnameid=readpsname and readushort(f) or 0xFFFF
19884   if subfamid==2 or subfamid==17 then
19885   elseif subfamid==0xFFFF then
19886    subfamid=nil
19887   elseif subfamid<=256 or subfamid>=32768 then
19888    subfamid=nil 
19889   end
19890   if psnameid==6 then
19891   elseif psnameid==0xFFFF then
19892    psnameid=nil
19893   elseif psnameid<=256 or psnameid>=32768 then
19894    psnameid=nil 
19895   end
19896   instances[i]={
19897    subfamily=extras[subfamid],
19898    psname=psnameid and extras[psnameid] or nil,
19899    values=values,
19900   }
19901   if skippable>0 then
19902    skipbytes(f,skippable)
19903   end
19904  end
19905  setvariabledata(fontdata,"axis",axis)
19906  setvariabledata(fontdata,"instances",instances)
19907 end
19908end
19909function readers.hvar(f,fontdata,specification)
19910 local factors=specification.factors
19911 if not factors then
19912  return
19913 end
19914 local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable)
19915 if not tableoffset then
19916  return
19917 end
19918 local version=readulong(f) 
19919 local variationoffset=tableoffset+readulong(f) 
19920 local advanceoffset=tableoffset+readulong(f)
19921 local lsboffset=tableoffset+readulong(f)
19922 local rsboffset=tableoffset+readulong(f)
19923 local regions={}
19924 local variations={}
19925 local innerindex={} 
19926 local outerindex={} 
19927 local deltas={}
19928 if variationoffset>0 then
19929  regions,deltas=readvariationdata(f,variationoffset,factors)
19930 end
19931 if not regions then
19932  return
19933 end
19934 if advanceoffset>0 then
19935  setposition(f,advanceoffset)
19936  local format=readushort(f) 
19937  local mapcount=readushort(f)
19938  local entrysize=rshift(band(format,0x0030),4)+1
19939  local nofinnerbits=band(format,0x000F)+1 
19940  local innermask=lshift(1,nofinnerbits)-1
19941  local readcardinal=read_cardinal[entrysize] 
19942  for i=0,mapcount-1 do
19943   local mapdata=readcardinal(f)
19944   outerindex[i]=rshift(mapdata,nofinnerbits)
19945   innerindex[i]=band(mapdata,innermask)
19946  end
19947  setvariabledata(fontdata,"hvarwidths",true)
19948  local glyphs=fontdata.glyphs
19949  for i=0,fontdata.nofglyphs-1 do
19950   local glyph=glyphs[i]
19951   local width=glyph.width
19952   if width then
19953    local outer=outerindex[i] or 0
19954    local inner=innerindex[i] or i
19955    if outer and inner then 
19956     local delta=deltas[outer+1]
19957     if delta then
19958      local d=delta.deltas[inner+1]
19959      if d then
19960       local scales=delta.scales
19961       local deltaw=0
19962       for i=1,#scales do
19963        local di=d[i]
19964        if di then
19965         deltaw=deltaw+scales[i]*di
19966        else
19967         break 
19968        end
19969       end
19970       glyph.width=width+round(deltaw)
19971      end
19972     end
19973    end
19974   end
19975  end
19976 end
19977end
19978function readers.vvar(f,fontdata,specification)
19979 if not specification.variable then
19980  return
19981 end
19982end
19983function readers.mvar(f,fontdata,specification)
19984 local tableoffset=gotodatatable(f,fontdata,"mvar",specification.variable)
19985 if tableoffset then
19986  local version=readulong(f) 
19987  local reserved=skipshort(f,1)
19988  local recordsize=readushort(f)
19989  local nofrecords=readushort(f)
19990  local offsettostore=tableoffset+readushort(f)
19991  local dimensions={}
19992  local factors=specification.factors
19993  if factors then
19994   local regions,deltas=readvariationdata(f,offsettostore,factors)
19995   for i=1,nofrecords do
19996    local tag=readtag(f)
19997    local var=variabletags[tag]
19998    if var then
19999     local outer=readushort(f)
20000     local inner=readushort(f)
20001     local delta=deltas[outer+1]
20002     if delta then
20003      local d=delta.deltas[inner+1]
20004      if d then
20005       local scales=delta.scales
20006       local dd=0
20007       for i=1,#scales do
20008        dd=dd+scales[i]*d[i]
20009       end
20010       var(fontdata,round(dd))
20011      end
20012     end
20013    else
20014     skipshort(f,2)
20015    end
20016    if recordsize>8 then 
20017     skipbytes(recordsize-8)
20018    end
20019   end
20020  end
20021 end
20022end
20023
20024end -- closure
20025
20026do -- begin closure to overcome local limits and interference
20027
20028if not modules then modules={} end modules ['font-oti']={
20029 version=1.001,
20030 comment="companion to font-ini.mkiv",
20031 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
20032 copyright="PRAGMA ADE / ConTeXt Development Team",
20033 license="see context related readme files"
20034}
20035local lower=string.lower
20036local fonts=fonts
20037local constructors=fonts.constructors
20038local otf=constructors.handlers.otf
20039local otffeatures=constructors.features.otf
20040local registerotffeature=otffeatures.register
20041local otftables=otf.tables or {}
20042otf.tables=otftables
20043local allocate=utilities.storage.allocate
20044registerotffeature {
20045 name="features",
20046 description="initialization of feature handler",
20047 default=true,
20048}
20049local function setmode(tfmdata,value)
20050 if value then
20051  tfmdata.properties.mode=lower(value)
20052 end
20053end
20054otf.modeinitializer=setmode
20055local function setlanguage(tfmdata,value)
20056 if value then
20057  local cleanvalue=lower(value)
20058  local languages=otftables and otftables.languages
20059  local properties=tfmdata.properties
20060  if not languages then
20061   properties.language=cleanvalue
20062  elseif languages[value] then
20063   properties.language=cleanvalue
20064  else
20065   properties.language="dflt"
20066  end
20067 end
20068end
20069local function setscript(tfmdata,value)
20070 if value then
20071  local cleanvalue=lower(value)
20072  local scripts=otftables and otftables.scripts
20073  local properties=tfmdata.properties
20074  if not scripts then
20075   properties.script=cleanvalue
20076  elseif scripts[value] then
20077   properties.script=cleanvalue
20078  else
20079   properties.script="dflt"
20080  end
20081 end
20082end
20083registerotffeature {
20084 name="mode",
20085 description="mode",
20086 initializers={
20087  base=setmode,
20088  node=setmode,
20089  plug=setmode,
20090 }
20091}
20092registerotffeature {
20093 name="language",
20094 description="language",
20095 initializers={
20096  base=setlanguage,
20097  node=setlanguage,
20098  plug=setlanguage,
20099 }
20100}
20101registerotffeature {
20102 name="script",
20103 description="script",
20104 initializers={
20105  base=setscript,
20106  node=setscript,
20107  plug=setscript,
20108 }
20109}
20110otftables.featuretypes=allocate {
20111 gpos_single="position",
20112 gpos_pair="position",
20113 gpos_cursive="position",
20114 gpos_mark2base="position",
20115 gpos_mark2ligature="position",
20116 gpos_mark2mark="position",
20117 gpos_context="position",
20118 gpos_contextchain="position",
20119 gsub_single="substitution",
20120 gsub_multiple="substitution",
20121 gsub_alternate="substitution",
20122 gsub_ligature="substitution",
20123 gsub_context="substitution",
20124 gsub_contextchain="substitution",
20125 gsub_reversecontextchain="substitution",
20126 gsub_reversesub="substitution",
20127}
20128function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
20129 if featuretype=="position" then
20130  local default=scripts.dflt
20131  if default then
20132   if autoscript=="position" or autoscript==true then
20133    return default
20134   else
20135    report_otf("script feature %s not applied, enable default positioning")
20136   end
20137  else
20138  end
20139 elseif featuretype=="substitution" then
20140  local default=scripts.dflt
20141  if default then
20142   if autoscript=="substitution" or autoscript==true then
20143    return default
20144   end
20145  end
20146 end
20147end
20148function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
20149 if featuretype=="position" then
20150  local default=languages.dflt
20151  if default then
20152   if autolanguage=="position" or autolanguage==true then
20153    return default
20154   else
20155    report_otf("language feature %s not applied, enable default positioning")
20156   end
20157  else
20158  end
20159 elseif featuretype=="substitution" then
20160  local default=languages.dflt
20161  if default then
20162   if autolanguage=="substitution" or autolanguage==true then
20163    return default
20164   end
20165  end
20166 end
20167end
20168
20169end -- closure
20170
20171do -- begin closure to overcome local limits and interference
20172
20173if not modules then modules={} end modules ["font-ott"]={
20174 version=1.001,
20175 comment="companion to font-ini.mkiv",
20176 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
20177 copyright="PRAGMA ADE / ConTeXt Development Team",
20178 license="see context related readme files",
20179}
20180local type,next,tonumber,tostring,rawget,rawset=type,next,tonumber,tostring,rawget,rawset
20181local gsub,lower,format,match,gmatch,find=string.gsub,string.lower,string.format,string.match,string.gmatch,string.find
20182local sequenced=table.sequenced
20183local is_boolean=string.is_boolean
20184local setmetatableindex=table.setmetatableindex
20185local setmetatablenewindex=table.setmetatablenewindex
20186local allocate=utilities.storage.allocate
20187local fonts=fonts
20188local otf=fonts.handlers.otf
20189local otffeatures=otf.features
20190local tables=otf.tables or {}
20191otf.tables=tables
20192local statistics=otf.statistics or {}
20193otf.statistics=statistics
20194local scripts=allocate {
20195 ["adlm"]="adlam",
20196 ["aghb"]="caucasian albanian",
20197 ["ahom"]="ahom",
20198 ["arab"]="arabic",
20199 ["armi"]="imperial aramaic",
20200 ["armn"]="armenian",
20201 ["avst"]="avestan",
20202 ["bali"]="balinese",
20203 ["bamu"]="bamum",
20204 ["bass"]="bassa vah",
20205 ["batk"]="batak",
20206 ["beng"]="bengali",
20207 ["bhks"]="bhaiksuki",
20208 ["bng2"]="bengali variant 2",
20209 ["bopo"]="bopomofo",
20210 ["brah"]="brahmi",
20211 ["brai"]="braille",
20212 ["bugi"]="buginese",
20213 ["buhd"]="buhid",
20214 ["byzm"]="byzantine music",
20215 ["cakm"]="chakma",
20216 ["cans"]="canadian syllabics",
20217 ["cari"]="carian",
20218 ["cham"]="cham",
20219 ["cher"]="cherokee",
20220 ["chrs"]="chorasmian",
20221 ["copt"]="coptic",
20222 ["cpmn"]="cypro-minoan",
20223 ["cprt"]="cypriot syllabary",
20224 ["cyrl"]="cyrillic",
20225 ["dev2"]="devanagari variant 2",
20226 ["deva"]="devanagari",
20227 ["diak"]="dives akuru",
20228 ["dogr"]="dogra",
20229 ["dsrt"]="deseret",
20230 ["dupl"]="duployan",
20231 ["egyp"]="egyptian heiroglyphs",
20232 ["elba"]="elbasan",
20233 ["elym"]="elymaic",
20234 ["ethi"]="ethiopic",
20235 ["geor"]="georgian",
20236 ["gjr2"]="gujarati variant 2",
20237 ["glag"]="glagolitic",
20238 ["gong"]="gunjala gondi",
20239 ["gonm"]="masaram gondi",
20240 ["goth"]="gothic",
20241 ["gran"]="grantha",
20242 ["grek"]="greek",
20243 ["gujr"]="gujarati",
20244 ["gur2"]="gurmukhi variant 2",
20245 ["guru"]="gurmukhi",
20246 ["hang"]="hangul",
20247 ["hani"]="cjk ideographic",
20248 ["hano"]="hanunoo",
20249 ["hatr"]="hatran",
20250 ["hebr"]="hebrew",
20251 ["hluw"]="anatolian hieroglyphs",
20252 ["hmng"]="pahawh hmong",
20253 ["hmnp"]="nyiakeng puachue hmong",
20254 ["hung"]="old hungarian",
20255 ["ital"]="old italic",
20256 ["jamo"]="hangul jamo",
20257 ["java"]="javanese",
20258 ["kali"]="kayah li",
20259 ["kana"]="hiragana and katakana",
20260 ["khar"]="kharosthi",
20261 ["khmr"]="khmer",
20262 ["khoj"]="khojki",
20263 ["kits"]="khitan small script",
20264 ["knd2"]="kannada variant 2",
20265 ["knda"]="kannada",
20266 ["kthi"]="kaithi",
20267 ["lana"]="tai tham",
20268 ["lao" ]="lao",
20269 ["latn"]="latin",
20270 ["lepc"]="lepcha",
20271 ["limb"]="limbu",
20272 ["lina"]="linear a",
20273 ["linb"]="linear b",
20274 ["lisu"]="lisu",
20275 ["lyci"]="lycian",
20276 ["lydi"]="lydian",
20277 ["mahj"]="mahajani",
20278 ["maka"]="makasar",
20279 ["mand"]="mandaic and mandaean",
20280 ["mani"]="manichaean",
20281 ["marc"]="marchen",
20282 ["math"]="mathematical alphanumeric symbols",
20283 ["medf"]="medefaidrin",
20284 ["mend"]="mende kikakui",
20285 ["merc"]="meroitic cursive",
20286 ["mero"]="meroitic hieroglyphs",
20287 ["mlm2"]="malayalam variant 2",
20288 ["mlym"]="malayalam",
20289 ["modi"]="modi",
20290 ["mong"]="mongolian",
20291 ["mroo"]="mro",
20292 ["mtei"]="meitei Mayek",
20293 ["mult"]="multani",
20294 ["musc"]="musical symbols",
20295 ["mym2"]="myanmar variant 2",
20296 ["mymr"]="myanmar",
20297 ["nand"]="nandinagari",
20298 ["narb"]="old north arabian",
20299 ["nbat"]="nabataean",
20300 ["newa"]="newa",
20301 ["nko" ]='n"ko',
20302 ["nshu"]="nüshu",
20303 ["ogam"]="ogham",
20304 ["olck"]="ol chiki",
20305 ["orkh"]="old turkic and orkhon runic",
20306 ["ory2"]="odia variant 2",
20307 ["orya"]="odia",
20308 ["osge"]="osage",
20309 ["osma"]="osmanya",
20310 ["ougr"]="old uyghur",
20311 ["palm"]="palmyrene",
20312 ["pauc"]="pau cin hau",
20313 ["perm"]="old permic",
20314 ["phag"]="phags-pa",
20315 ["phli"]="inscriptional pahlavi",
20316 ["phlp"]="psalter pahlavi",
20317 ["phnx"]="phoenician",
20318 ["plrd"]="miao",
20319 ["prti"]="inscriptional parthian",
20320 ["rjng"]="rejang",
20321 ["rohg"]="hanifi rohingya",
20322 ["runr"]="runic",
20323 ["samr"]="samaritan",
20324 ["sarb"]="old south arabian",
20325 ["saur"]="saurashtra",
20326 ["sgnw"]="sign writing",
20327 ["shaw"]="shavian",
20328 ["shrd"]="sharada",
20329 ["sidd"]="siddham",
20330 ["sind"]="khudawadi",
20331 ["sinh"]="sinhala",
20332 ["sogd"]="sogdian",
20333 ["sogo"]="old sogdian",
20334 ["sora"]="sora sompeng",
20335 ["soyo"]="soyombo",
20336 ["sund"]="sundanese",
20337 ["sylo"]="syloti nagri",
20338 ["syrc"]="syriac",
20339 ["tagb"]="tagbanwa",
20340 ["takr"]="takri",
20341 ["tale"]="tai le",
20342 ["talu"]="new tai lue",
20343 ["taml"]="tamil",
20344 ["tang"]="tangut",
20345 ["tavt"]="tai viet",
20346 ["tel2"]="telugu variant 2",
20347 ["telu"]="telugu",
20348 ["tfng"]="tifinagh",
20349 ["tglg"]="tagalog",
20350 ["thaa"]="thaana",
20351 ["thai"]="thai",
20352 ["tibt"]="tibetan",
20353 ["tirh"]="tirhuta",
20354 ["tnsa"]="tangsa",
20355 ["tml2"]="tamil variant 2",
20356 ["toto"]="toto",
20357 ["ugar"]="ugaritic cuneiform",
20358 ["vai" ]="vai",
20359 ["wara"]="warang citi",
20360 ["wcho"]="wancho",
20361 ["xpeo"]="old persian cuneiform",
20362 ["xsux"]="sumero-akkadian cuneiform",
20363 ["yezi"]="yezidi",
20364 ["yi"  ]="yi",
20365 ["zanb"]="zanabazar square",
20366}
20367local languages=allocate {
20368 ["aba" ]="abaza",
20369 ["abk" ]="abkhazian",
20370 ["ach" ]="acholi",
20371 ["acr" ]="achi",
20372 ["ady" ]="adyghe",
20373 ["afk" ]="afrikaans",
20374 ["afr" ]="afar",
20375 ["agw" ]="agaw",
20376 ["aio" ]="aiton",
20377 ["aka" ]="akan",
20378 ["akb" ]="batak angkola",
20379 ["als" ]="alsatian",
20380 ["alt" ]="altai",
20381 ["amh" ]="amharic",
20382 ["ang" ]="anglo-saxon",
20383 ["apph"]="phonetic transcription—americanist conventions",
20384 ["ara" ]="arabic",
20385 ["arg" ]="aragonese",
20386 ["ari" ]="aari",
20387 ["ark" ]="rakhine",
20388 ["asm" ]="assamese",
20389 ["ast" ]="asturian",
20390 ["ath" ]="athapaskan",
20391 ["avn" ]="avatime",
20392 ["avr" ]="avar",
20393 ["awa" ]="awadhi",
20394 ["aym" ]="aymara",
20395 ["azb" ]="torki",
20396 ["aze" ]="azerbaijani",
20397 ["bad" ]="badaga",
20398 ["bad0"]="banda",
20399 ["bag" ]="baghelkhandi",
20400 ["bal" ]="balkar",
20401 ["ban" ]="balinese",
20402 ["bar" ]="bavarian",
20403 ["bau" ]="baulé",
20404 ["bbc" ]="batak toba",
20405 ["bbr" ]="berber",
20406 ["bch" ]="bench",
20407 ["bcr" ]="bible cree",
20408 ["bdy" ]="bandjalang",
20409 ["bel" ]="belarussian",
20410 ["bem" ]="bemba",
20411 ["ben" ]="bengali",
20412 ["bgc" ]="haryanvi",
20413 ["bgq" ]="bagri",
20414 ["bgr" ]="bulgarian",
20415 ["bhi" ]="bhili",
20416 ["bho" ]="bhojpuri",
20417 ["bik" ]="bikol",
20418 ["bil" ]="bilen",
20419 ["bis" ]="bislama",
20420 ["bjj" ]="kanauji",
20421 ["bkf" ]="blackfoot",
20422 ["bli" ]="baluchi",
20423 ["blk" ]="pa'o karen",
20424 ["bln" ]="balante",
20425 ["blt" ]="balti",
20426 ["bmb" ]="bambara (bamanankan)",
20427 ["bml" ]="bamileke",
20428 ["bos" ]="bosnian",
20429 ["bpy" ]="bishnupriya manipuri",
20430 ["bre" ]="breton",
20431 ["brh" ]="brahui",
20432 ["bri" ]="braj bhasha",
20433 ["brm" ]="burmese",
20434 ["brx" ]="bodo",
20435 ["bsh" ]="bashkir",
20436 ["bsk" ]="burushaski",
20437 ["bta" ]="batak alas kluet",
20438 ["btd" ]="batak dairi (pakpak)",
20439 ["bti" ]="beti",
20440 ["btm" ]="batak mandailing",
20441 ["bts" ]="batak simalungun",
20442 ["btx" ]="batak karo",
20443 ["bug" ]="bugis",
20444 ["byv" ]="medumba",
20445 ["cak" ]="kaqchikel",
20446 ["cat" ]="catalan",
20447 ["cbk" ]="zamboanga chavacano",
20448 ["cchn"]="chinantec",
20449 ["ceb" ]="cebuano",
20450 ["cgg" ]="chiga",
20451 ["cha" ]="chamorro",
20452 ["che" ]="chechen",
20453 ["chg" ]="chaha gurage",
20454 ["chh" ]="chattisgarhi",
20455 ["chi" ]="chichewa (chewa, nyanja)",
20456 ["chk" ]="chukchi",
20457 ["chk0"]="chuukese",
20458 ["cho" ]="choctaw",
20459 ["chp" ]="chipewyan",
20460 ["chr" ]="cherokee",
20461 ["chu" ]="chuvash",
20462 ["chy" ]="cheyenne",
20463 ["cja" ]="western cham",
20464 ["cjm" ]="eastern cham",
20465 ["cmr" ]="comorian",
20466 ["cop" ]="coptic",
20467 ["cor" ]="cornish",
20468 ["cos" ]="corsican",
20469 ["cpp" ]="creoles",
20470 ["cre" ]="cree",
20471 ["crr" ]="carrier",
20472 ["crt" ]="crimean tatar",
20473 ["csb" ]="kashubian",
20474 ["csl" ]="church slavonic",
20475 ["csy" ]="czech",
20476 ["ctg" ]="chittagonian",
20477 ["ctt" ]="wayanad chetti",
20478 ["cuk" ]="san blas kuna",
20479 ["dag" ]="dagbani",
20480 ["dan" ]="danish",
20481 ["dar" ]="dargwa",
20482 ["dax" ]="dayi",
20483 ["dcr" ]="woods cree",
20484 ["deu" ]="german",
20485 ["dgo" ]="dogri (individual language)",
20486 ["dgr" ]="dogri (macro language)",
20487 ["dhg" ]="dhangu",
20488 ["dhv" ]="divehi (dhivehi, maldivian)",
20489 ["diq" ]="dimli",
20490 ["div" ]="divehi (dhivehi, maldivian)",
20491 ["djr" ]="zarma",
20492 ["djr0"]="djambarrpuyngu",
20493 ["dng" ]="dangme",
20494 ["dnj" ]="dan",
20495 ["dnk" ]="dinka",
20496 ["dri" ]="dari",
20497 ["duj" ]="dhuwal",
20498 ["dun" ]="dungan",
20499 ["dzn" ]="dzongkha",
20500 ["ebi" ]="ebira",
20501 ["ecr" ]="eastern cree",
20502 ["edo" ]="edo",
20503 ["efi" ]="efik",
20504 ["ell" ]="greek",
20505 ["emk" ]="eastern maninkakan",
20506 ["eng" ]="english",
20507 ["erz" ]="erzya",
20508 ["esp" ]="spanish",
20509 ["esu" ]="central yupik",
20510 ["eti" ]="estonian",
20511 ["euq" ]="basque",
20512 ["evk" ]="evenki",
20513 ["evn" ]="even",
20514 ["ewe" ]="ewe",
20515 ["fan" ]="french antillean",
20516 ["fan0"]=" fang",
20517 ["far" ]="persian",
20518 ["fat" ]="fanti",
20519 ["fin" ]="finnish",
20520 ["fji" ]="fijian",
20521 ["fle" ]="dutch (flemish)",
20522 ["fmp" ]="fe’fe’",
20523 ["fne" ]="forest nenets",
20524 ["fon" ]="fon",
20525 ["fos" ]="faroese",
20526 ["fra" ]="french",
20527 ["frc" ]="cajun french",
20528 ["fri" ]="frisian",
20529 ["frl" ]="friulian",
20530 ["frp" ]="arpitan",
20531 ["fta" ]="futa",
20532 ["ful" ]="fulah",
20533 ["fuv" ]="nigerian fulfulde",
20534 ["gad" ]="ga",
20535 ["gae" ]="scottish gaelic (gaelic)",
20536 ["gag" ]="gagauz",
20537 ["gal" ]="galician",
20538 ["gar" ]="garshuni",
20539 ["gaw" ]="garhwali",
20540 ["gez" ]="ge'ez",
20541 ["gih" ]="githabul",
20542 ["gil" ]="gilyak",
20543 ["gil0"]="kiribati (gilbertese)",
20544 ["gkp" ]="kpelle (guinea)",
20545 ["glk" ]="gilaki",
20546 ["gmz" ]="gumuz",
20547 ["gnn" ]="gumatj",
20548 ["gog" ]="gogo",
20549 ["gon" ]="gondi",
20550 ["grn" ]="greenlandic",
20551 ["gro" ]="garo",
20552 ["gua" ]="guarani",
20553 ["guc" ]="wayuu",
20554 ["guf" ]="gupapuyngu",
20555 ["guj" ]="gujarati",
20556 ["guz" ]="gusii",
20557 ["hai" ]="haitian (haitian creole)",
20558 ["hai0"]="haida",
20559 ["hal" ]="halam",
20560 ["har" ]="harauti",
20561 ["hau" ]="hausa",
20562 ["haw" ]="hawaiian",
20563 ["hay" ]="haya",
20564 ["haz" ]="hazaragi",
20565 ["hmz" ]="hmong shuat",
20566 ["hbn" ]="hammer-banna",
20567 ["hei" ]="heiltsuk",
20568 ["her" ]="herero",
20569 ["hil" ]="hiligaynon",
20570 ["hin" ]="hindi",
20571 ["hma" ]="high mari",
20572 ["hmn" ]="hmong",
20573 ["hmo" ]="hiri motu",
20574 ["hnd" ]="hindko",
20575 ["ho"  ]="ho",
20576 ["hri" ]="harari",
20577 ["hrv" ]="croatian",
20578 ["hun" ]="hungarian",
20579 ["hye" ]="armenian",
20580 ["hye0"]="armenian east",
20581 ["iba" ]="iban",
20582 ["ibb" ]="ibibio",
20583 ["ibo" ]="igbo",
20584 ["ido" ]="ido",
20585 ["ijo" ]="ijo languages",
20586 ["ile" ]="interlingue",
20587 ["ilo" ]="ilokano",
20588 ["ina" ]="interlingua",
20589 ["ind" ]="indonesian",
20590 ["ing" ]="ingush",
20591 ["inu" ]="inuktitut",
20592 ["inuk"]="nunavik inuktitut",
20593 ["ipk" ]="inupiat",
20594 ["ipph"]="phonetic transcription—ipa conventions",
20595 ["iri" ]="irish",
20596 ["irt" ]="irish traditional",
20597 ["uri" ]="irula",
20598 ["isl" ]="icelandic",
20599 ["ism" ]="inari sami",
20600 ["ita" ]="italian",
20601 ["iwr" ]="hebrew",
20602 ["jam" ]="jamaican creole",
20603 ["jan" ]="japanese",
20604 ["jav" ]="javanese",
20605 ["jbo" ]="lojban",
20606 ["jct" ]="krymchak",
20607 ["jii" ]="yiddish",
20608 ["jud" ]="ladino",
20609 ["jul" ]="jula",
20610 ["kab" ]="kabardian",
20611 ["kab0"]="kabyle",
20612 ["kac" ]="kachchi",
20613 ["kal" ]="kalenjin",
20614 ["kan" ]="kannada",
20615 ["kar" ]="karachay",
20616 ["kat" ]="georgian",
20617 ["kaw" ]="kawi (old javanese)",
20618 ["kaz" ]="kazakh",
20619 ["kde" ]="makonde",
20620 ["kea" ]="kabuverdianu (crioulo)",
20621 ["keb" ]="kebena",
20622 ["kek" ]="kekchi",
20623 ["kge" ]="khutsuri georgian",
20624 ["kha" ]="khakass",
20625 ["khk" ]="khanty-kazim",
20626 ["khm" ]="khmer",
20627 ["khs" ]="khanty-shurishkar",
20628 ["kht" ]="khamti shan",
20629 ["khv" ]="khanty-vakhi",
20630 ["khw" ]="khowar",
20631 ["kik" ]="kikuyu (gikuyu)",
20632 ["kir" ]="kirghiz (kyrgyz)",
20633 ["kis" ]="kisii",
20634 ["kiu" ]="kirmanjki",
20635 ["kjd" ]="southern kiwai",
20636 ["kjp" ]="eastern pwo karen",
20637 ["kjz" ]="bumthangkha",
20638 ["kkn" ]="kokni",
20639 ["klm" ]="kalmyk",
20640 ["kmb" ]="kamba",
20641 ["kmn" ]="kumaoni",
20642 ["kmo" ]="komo",
20643 ["kms" ]="komso",
20644 ["kmz" ]="khorasani turkic",
20645 ["knr" ]="kanuri",
20646 ["kod" ]="kodagu",
20647 ["koh" ]="korean old hangul",
20648 ["kok" ]="konkani",
20649 ["kom" ]="komi",
20650 ["kon" ]="kikongo",
20651 ["kon0"]="kongo",
20652 ["kop" ]="komi-permyak",
20653 ["kor" ]="korean",
20654 ["kos" ]="kosraean",
20655 ["koz" ]="komi-zyrian",
20656 ["kpl" ]="kpelle",
20657 ["kri" ]="krio",
20658 ["krk" ]="karakalpak",
20659 ["krl" ]="karelian",
20660 ["krm" ]="karaim",
20661 ["krn" ]="karen",
20662 ["krt" ]="koorete",
20663 ["ksh" ]="kashmiri",
20664 ["ksh0"]="ripuarian",
20665 ["ksi" ]="khasi",
20666 ["ksm" ]="kildin sami",
20667 ["ksw" ]="s’gaw karen",
20668 ["kua" ]="kuanyama",
20669 ["kui" ]="kui",
20670 ["kul" ]="kulvi",
20671 ["kum" ]="kumyk",
20672 ["kur" ]="kurdish",
20673 ["kuu" ]="kurukh",
20674 ["kuy" ]="kuy",
20675 ["kwk" ]="kwakʼwala",
20676 ["kyk" ]="koryak",
20677 ["kyu" ]="western kayah",
20678 ["lad" ]="ladin",
20679 ["lah" ]="lahuli",
20680 ["lak" ]="lak",
20681 ["lam" ]="lambani",
20682 ["lao" ]="lao",
20683 ["lat" ]="latin",
20684 ["laz" ]="laz",
20685 ["lcr" ]="l-cree",
20686 ["ldk" ]="ladakhi",
20687 ["lef" ]="lelemi",
20688 ["lez" ]="lezgi",
20689 ["lij" ]="ligurian",
20690 ["lim" ]="limburgish",
20691 ["lin" ]="lingala",
20692 ["lis" ]="lisu",
20693 ["ljp" ]="lampung",
20694 ["lki" ]="laki",
20695 ["lma" ]="low mari",
20696 ["lmb" ]="limbu",
20697 ["lmo" ]="lombard",
20698 ["lmw" ]="lomwe",
20699 ["lom" ]="loma",
20700 ["lpo" ]="lipo",
20701 ["lrc" ]="luri",
20702 ["lsb" ]="lower sorbian",
20703 ["lsm" ]="lule sami",
20704 ["lth" ]="lithuanian",
20705 ["ltz" ]="luxembourgish",
20706 ["lua" ]="luba-lulua",
20707 ["lub" ]="luba-katanga",
20708 ["lug" ]="ganda",
20709 ["luh" ]="luyia",
20710 ["luo" ]="luo",
20711 ["lvi" ]="latvian",
20712 ["mad" ]="madura",
20713 ["mag" ]="magahi",
20714 ["mah" ]="marshallese",
20715 ["maj" ]="majang",
20716 ["mak" ]="makhuwa",
20717 ["mal" ]="malayalam",
20718 ["mam" ]="mam",
20719 ["man" ]="mansi",
20720 ["map" ]="mapudungun",
20721 ["mar" ]="marathi",
20722 ["maw" ]="marwari",
20723 ["mbn" ]="mbundu",
20724 ["mbo" ]="mbo",
20725 ["mch" ]="manchu",
20726 ["mcr" ]="moose cree",
20727 ["mde" ]="mende",
20728 ["mdr" ]="mandar",
20729 ["men" ]="me'en",
20730 ["mer" ]="meru",
20731 ["mfa" ]="pattani malay",
20732 ["mfe" ]="morisyen",
20733 ["min" ]="minangkabau",
20734 ["miz" ]="mizo",
20735 ["mkd" ]="macedonian",
20736 ["mkr" ]="makasar",
20737 ["mkw" ]="kituba",
20738 ["mle" ]="male",
20739 ["mlg" ]="malagasy",
20740 ["mln" ]="malinke",
20741 ["mlr" ]="malayalam reformed",
20742 ["mly" ]="malay",
20743 ["mnd" ]="mandinka",
20744 ["mng" ]="mongolian",
20745 ["mni" ]="manipuri",
20746 ["mnk" ]="maninka",
20747 ["mnx" ]="manx",
20748 ["moh" ]="mohawk",
20749 ["mok" ]="moksha",
20750 ["mol" ]="moldavian",
20751 ["mon" ]="mon",
20752 ["mnw" ]="thailand mon",
20753 ["mor" ]="moroccan",
20754 ["mos" ]="mossi",
20755 ["mri" ]="maori",
20756 ["mth" ]="maithili",
20757 ["mts" ]="maltese",
20758 ["mun" ]="mundari",
20759 ["mus" ]="muscogee",
20760 ["mwl" ]="mirandese",
20761 ["mww" ]="hmong daw",
20762 ["myn" ]="mayan",
20763 ["mzn" ]="mazanderani",
20764 ["nag" ]="naga-assamese",
20765 ["nah" ]="nahuatl",
20766 ["nan" ]="nanai",
20767 ["nap" ]="neapolitan",
20768 ["nas" ]="naskapi",
20769 ["nau" ]="nauruan",
20770 ["nav" ]="navajo",
20771 ["ncr" ]="n-cree",
20772 ["ndb" ]="ndebele",
20773 ["ndc" ]="ndau",
20774 ["ndg" ]="ndonga",
20775 ["nds" ]="low saxon",
20776 ["nep" ]="nepali",
20777 ["new" ]="newari",
20778 ["nga" ]="ngbaka",
20779 ["ngr" ]="nagari",
20780 ["nhc" ]="norway house cree",
20781 ["nis" ]="nisi",
20782 ["niu" ]="niuean",
20783 ["nkl" ]="nyankole",
20784 ["nko" ]="n'ko",
20785 ["nld" ]="dutch",
20786 ["noe" ]="nimadi",
20787 ["nog" ]="nogai",
20788 ["nor" ]="norwegian",
20789 ["nov" ]="novial",
20790 ["nsm" ]="northern sami",
20791 ["nso" ]="northern sotho",
20792 ["nta" ]="northern tai",
20793 ["nto" ]="esperanto",
20794 ["nym" ]="nyamwezi",
20795 ["nyn" ]="norwegian nynorsk",
20796 ["nza" ]="mbembe tigon",
20797 ["oci" ]="occitan",
20798 ["ocr" ]="oji-cree",
20799 ["ojb" ]="ojibway",
20800 ["ori" ]="odia",
20801 ["oro" ]="oromo",
20802 ["oss" ]="ossetian",
20803 ["paa" ]="palestinian aramaic",
20804 ["pag" ]="pangasinan",
20805 ["pal" ]="pali",
20806 ["pam" ]="pampangan",
20807 ["pan" ]="punjabi",
20808 ["pap" ]="palpa",
20809 ["pap0"]="papiamentu",
20810 ["pas" ]="pashto",
20811 ["pau" ]="palauan",
20812 ["pcc" ]="bouyei",
20813 ["pcd" ]="picard",
20814 ["pdc" ]="pennsylvania german",
20815 ["pgr" ]="polytonic greek",
20816 ["phk" ]="phake",
20817 ["pih" ]="norfolk",
20818 ["pil" ]="filipino",
20819 ["plg" ]="palaung",
20820 ["plk" ]="polish",
20821 ["pms" ]="piemontese",
20822 ["pnb" ]="western panjabi",
20823 ["poh" ]="pocomchi",
20824 ["pon" ]="pohnpeian",
20825 ["pro" ]="provencal",
20826 ["ptg" ]="portuguese",
20827 ["pwo" ]="western pwo karen",
20828 ["qin" ]="chin",
20829 ["quc" ]="k’iche’",
20830 ["quh" ]="quechua (bolivia)",
20831 ["quz" ]="quechua",
20832 ["qvi" ]="quechua (ecuador)",
20833 ["qwh" ]="quechua (peru)",
20834 ["raj" ]="rajasthani",
20835 ["rar" ]="rarotongan",
20836 ["rbu" ]="russian buriat",
20837 ["rcr" ]="r-cree",
20838 ["rej" ]="rejang",
20839 ["rhg" ]="rohingya",
20840 ["ria" ]="riang",
20841 ["rif" ]="tarifit",
20842 ["rit" ]="ritarungo",
20843 ["rkw" ]="arakwal",
20844 ["rms" ]="romansh",
20845 ["rmy" ]="vlax romani",
20846 ["rom" ]="romanian",
20847 ["roy" ]="romany",
20848 ["rsy" ]="rusyn",
20849 ["rtm" ]="rotuman",
20850 ["rua" ]="kinyarwanda",
20851 ["run" ]="rundi",
20852 ["rup" ]="aromanian",
20853 ["rus" ]="russian",
20854 ["sad" ]="sadri",
20855 ["san" ]="sanskrit",
20856 ["sas" ]="sasak",
20857 ["sat" ]="santali",
20858 ["say" ]="sayisi",
20859 ["scn" ]="sicilian",
20860 ["sco" ]="scots",
20861 ["scs" ]="north slavey",
20862 ["sek" ]="sekota",
20863 ["sel" ]="selkup",
20864 ["sfm" ]="small flowery miao",
20865 ["sga" ]="old irish",
20866 ["sgo" ]="sango",
20867 ["sgs" ]="samogitian",
20868 ["shi" ]="tachelhit",
20869 ["shn" ]="shan",
20870 ["sib" ]="sibe",
20871 ["sid" ]="sidamo",
20872 ["sig" ]="silte gurage",
20873 ["sks" ]="skolt sami",
20874 ["sky" ]="slovak",
20875 ["sla" ]="slavey",
20876 ["slv" ]="slovenian",
20877 ["sml" ]="somali",
20878 ["smo" ]="samoan",
20879 ["sna" ]="sena",
20880 ["sna0"]="shona",
20881 ["snd" ]="sindhi",
20882 ["snh" ]="sinhala (sinhalese)",
20883 ["snk" ]="soninke",
20884 ["sog" ]="sodo gurage",
20885 ["sop" ]="songe",
20886 ["sot" ]="southern sotho",
20887 ["sqi" ]="albanian",
20888 ["srb" ]="serbian",
20889 ["srd" ]="sardinian",
20890 ["srk" ]="saraiki",
20891 ["srr" ]="serer",
20892 ["ssl" ]="south slavey",
20893 ["ssm" ]="southern sami",
20894 ["stq" ]="saterland frisian",
20895 ["suk" ]="sukuma",
20896 ["sun" ]="sundanese",
20897 ["sur" ]="suri",
20898 ["sva" ]="svan",
20899 ["sve" ]="swedish",
20900 ["swa" ]="swadaya aramaic",
20901 ["swk" ]="swahili",
20902 ["swz" ]="swati",
20903 ["sxt" ]="sutu",
20904 ["sxu" ]="upper saxon",
20905 ["syl" ]="sylheti",
20906 ["syr" ]="syriac",
20907 ["syre"]="estrangela syriac",
20908 ["syrj"]="western syriac",
20909 ["syrn"]="eastern syriac",
20910 ["szl" ]="silesian",
20911 ["tab" ]="tabasaran",
20912 ["taj" ]="tajiki",
20913 ["tam" ]="tamil",
20914 ["tat" ]="tatar",
20915 ["tcr" ]="th-cree",
20916 ["tdd" ]="dehong dai",
20917 ["tel" ]="telugu",
20918 ["tet" ]="tetum",
20919 ["tgl" ]="tagalog",
20920 ["tgn" ]="tongan",
20921 ["tgr" ]="tigre",
20922 ["tgy" ]="tigrinya",
20923 ["tha" ]="thai",
20924 ["tht" ]="tahitian",
20925 ["tib" ]="tibetan",
20926 ["tiv" ]="tiv",
20927 ["tj;" ]="tai laing",
20928 ["tkm" ]="turkmen",
20929 ["tli" ]="tlingit",
20930 ["tmh" ]="tamashek",
20931 ["tmn" ]="temne",
20932 ["tna" ]="tswana",
20933 ["tne" ]="tundra nenets",
20934 ["tng" ]="tonga",
20935 ["tod" ]="todo",
20936 ["tod0"]="toma",
20937 ["tpi" ]="tok pisin",
20938 ["trk" ]="turkish",
20939 ["tsg" ]="tsonga",
20940 ["tsj" ]="tshangla",
20941 ["tua" ]="turoyo aramaic",
20942 ["tul" ]="tulu",
20943 ["tum" ]="tumbuka",
20944 ["tuv" ]="tuvin",
20945 ["tvl" ]="tuvalu",
20946 ["twi" ]="twi",
20947 ["tyz" ]="tày",
20948 ["tzm" ]="tamazight",
20949 ["tzo" ]="tzotzil",
20950 ["udm" ]="udmurt",
20951 ["ukr" ]="ukrainian",
20952 ["umb" ]="umbundu",
20953 ["urd" ]="urdu",
20954 ["usb" ]="upper sorbian",
20955 ["uyg" ]="uyghur",
20956 ["uzb" ]="uzbek",
20957 ["vec" ]="venetian",
20958 ["ven" ]="venda",
20959 ["vit" ]="vietnamese",
20960 ["vol" ]="volapük",
20961 ["vro" ]="võro",
20962 ["wa"  ]="wa",
20963 ["wag" ]="wagdi",
20964 ["war" ]="waray-waray",
20965 ["wci" ]="waci gbe",
20966 ["wcr" ]="west-cree",
20967 ["wel" ]="welsh",
20968 ["wlf" ]="wolof",
20969 ["wln" ]="walloon",
20970 ["wtm" ]="mewati",
20971 ["xbd" ]="",
20972 ["xhs" ]="xhosa",
20973 ["xjb" ]="minjangbal",
20974 ["xkf" ]="khengkha",
20975 ["xog" ]="soga",
20976 ["xpe" ]="kpelle (liberia)",
20977 ["xub" ]="bette kuruma",
20978 ["xuj" ]="jennu kuruma",
20979 ["yak" ]="sakha",
20980 ["yao" ]="yao",
20981 ["yap" ]="yapese",
20982 ["yba" ]="yoruba",
20983 ["ycr" ]="y-cree",
20984 ["ygp" ]="gepo",
20985 ["yic" ]="yi classic",
20986 ["yim" ]="yi modern",
20987 ["yna" ]="aluo",
20988 ["ywq" ]="wuding-luquan",
20989 ["zea" ]="zealandic",
20990 ["zgh" ]="standard morrocan tamazigh",
20991 ["zha" ]="zhuang",
20992 ["zhh" ]="chinese, hong kong sar",
20993 ["zho" ]="chinese traditional, macao",
20994 ["zhp" ]="chinese phonetic",
20995 ["zhs" ]="chinese simplified",
20996 ["zht" ]="chinese traditional",
20997 ["znd" ]="zande",
20998 ["zul" ]="zulu",
20999 ["zza" ]="zazaki",
21000}
21001local features=allocate {
21002 ["aalt"]="access all alternates",
21003 ["abvf"]="above-base forms",
21004 ["abvm"]="above-base mark positioning",
21005 ["abvs"]="above-base substitutions",
21006 ["afrc"]="alternative fractions",
21007 ["akhn"]="akhands",
21008 ["blwf"]="below-base forms",
21009 ["blwm"]="below-base mark positioning",
21010 ["blws"]="below-base substitutions",
21011 ["c2pc"]="petite capitals from capitals",
21012 ["c2sc"]="small capitals from capitals",
21013 ["calt"]="contextual alternates",
21014 ["case"]="case-sensitive forms",
21015 ["ccmp"]="glyph composition/decomposition",
21016 ["cfar"]="conjunct form after ro",
21017 ["chws"]="contextual half-width spacing",
21018 ["cjct"]="conjunct forms",
21019 ["clig"]="contextual ligatures",
21020 ["cpct"]="centered cjk punctuation",
21021 ["cpsp"]="capital spacing",
21022 ["cswh"]="contextual swash",
21023 ["curs"]="cursive positioning",
21024 ["dflt"]="default processing",
21025 ["dist"]="distances",
21026 ["dlig"]="discretionary ligatures",
21027 ["dnom"]="denominators",
21028 ["dtls"]="dotless forms",
21029 ["expt"]="expert forms",
21030 ["falt"]="final glyph alternates",
21031 ["fin2"]="terminal forms #2",
21032 ["fin3"]="terminal forms #3",
21033 ["fina"]="terminal forms",
21034 ["flac"]="flattened accents over capitals",
21035 ["frac"]="fractions",
21036 ["fwid"]="full width",
21037 ["half"]="half forms",
21038 ["haln"]="halant forms",
21039 ["halt"]="alternate half width",
21040 ["hist"]="historical forms",
21041 ["hkna"]="horizontal kana alternates",
21042 ["hlig"]="historical ligatures",
21043 ["hngl"]="hangul",
21044 ["hojo"]="hojo kanji forms",
21045 ["hwid"]="half width",
21046 ["init"]="initial forms",
21047 ["isol"]="isolated forms",
21048 ["ital"]="italics",
21049 ["jalt"]="justification alternatives",
21050 ["jp04"]="jis2004 forms",
21051 ["jp78"]="jis78 forms",
21052 ["jp83"]="jis83 forms",
21053 ["jp90"]="jis90 forms",
21054 ["kern"]="kerning",
21055 ["lfbd"]="left bounds",
21056 ["liga"]="standard ligatures",
21057 ["ljmo"]="leading jamo forms",
21058 ["lnum"]="lining figures",
21059 ["locl"]="localized forms",
21060 ["ltra"]="left-to-right alternates",
21061 ["ltrm"]="left-to-right mirrored forms",
21062 ["mark"]="mark positioning",
21063 ["med2"]="medial forms #2",
21064 ["medi"]="medial forms",
21065 ["mgrk"]="mathematical greek",
21066 ["mkmk"]="mark to mark positioning",
21067 ["mset"]="mark positioning via substitution",
21068 ["nalt"]="alternate annotation forms",
21069 ["nlck"]="nlc kanji forms",
21070 ["nukt"]="nukta forms",
21071 ["numr"]="numerators",
21072 ["onum"]="old style figures",
21073 ["opbd"]="optical bounds",
21074 ["ordn"]="ordinals",
21075 ["ornm"]="ornaments",
21076 ["palt"]="proportional alternate width",
21077 ["pcap"]="petite capitals",
21078 ["pkna"]="proportional kana",
21079 ["pnum"]="proportional figures",
21080 ["pref"]="pre-base forms",
21081 ["pres"]="pre-base substitutions",
21082 ["pstf"]="post-base forms",
21083 ["psts"]="post-base substitutions",
21084 ["pwid"]="proportional widths",
21085 ["qwid"]="quarter widths",
21086 ["rand"]="randomize",
21087 ["rclt"]="required contextual alternates",
21088 ["rkrf"]="rakar forms",
21089 ["rlig"]="required ligatures",
21090 ["rphf"]="reph form",
21091 ["rtbd"]="right bounds",
21092 ["rtla"]="right-to-left alternates",
21093 ["rtlm"]="right to left mirrored forms",
21094 ["ruby"]="ruby notation forms",
21095 ["rvrn"]="required variation alternates",
21096 ["salt"]="stylistic alternates",
21097 ["sinf"]="scientific inferiors",
21098 ["size"]="optical size",
21099 ["smcp"]="small capitals",
21100 ["smpl"]="simplified forms",
21101 ["ssty"]="script style",
21102 ["stch"]="stretching glyph decomposition",
21103 ["subs"]="subscript",
21104 ["sups"]="superscript",
21105 ["swsh"]="swash",
21106 ["titl"]="titling",
21107 ["tjmo"]="trailing jamo forms",
21108 ["tnam"]="traditional name forms",
21109 ["tnum"]="tabular figures",
21110 ["trad"]="traditional forms",
21111 ["twid"]="third widths",
21112 ["unic"]="unicase",
21113 ["valt"]="alternate vertical metrics",
21114 ["vatu"]="vattu variants",
21115 ["vchw"]="vertical contextual half-width spacing",
21116 ["vert"]="vertical writing",
21117 ["vhal"]="alternate vertical half metrics",
21118 ["vjmo"]="vowel jamo forms",
21119 ["vkna"]="vertical kana alternates",
21120 ["vkrn"]="vertical kerning",
21121 ["vpal"]="proportional alternate vertical metrics",
21122 ["vrtr"]="vertical alternates for rotation",
21123 ["vrt2"]="vertical rotation",
21124 ["zero"]="slashed zero",
21125 ["trep"]="traditional tex replacements",
21126 ["tlig"]="traditional tex ligatures",
21127 ["ss.."]="stylistic set ..",
21128 ["cv.."]="character variant ..",
21129 ["js.."]="justification ..",
21130 ["dv.."]="devanagari ..",
21131 ["ml.."]="malayalam ..",
21132}
21133local baselines=allocate {
21134 ["hang"]="hanging baseline",
21135 ["icfb"]="ideographic character face bottom edge baseline",
21136 ["icft"]="ideographic character face tope edige baseline",
21137 ["ideo"]="ideographic em-box bottom edge baseline",
21138 ["idtp"]="ideographic em-box top edge baseline",
21139 ["math"]="mathematical centered baseline",
21140 ["romn"]="roman baseline"
21141}
21142tables.scripts=scripts
21143tables.languages=languages
21144tables.features=features
21145tables.baselines=baselines
21146local acceptscripts=true  directives.register("otf.acceptscripts",function(v) acceptscripts=v end)
21147local acceptlanguages=true  directives.register("otf.acceptlanguages",function(v) acceptlanguages=v end)
21148local report_checks=logs.reporter("fonts","checks")
21149if otffeatures.features then
21150 for k,v in next,otffeatures.features do
21151  features[k]=v
21152 end
21153 otffeatures.features=features
21154end
21155local function swapped(h)
21156 local r={}
21157 for k,v in next,h do
21158  r[gsub(v,"[^a-z0-9]","")]=k 
21159 end
21160 return r
21161end
21162local verbosescripts=allocate(swapped(scripts  ))
21163local verboselanguages=allocate(swapped(languages))
21164local verbosefeatures=allocate(swapped(features ))
21165local verbosebaselines=allocate(swapped(baselines))
21166local function resolve(t,k)
21167 if k then
21168  k=gsub(lower(k),"[^a-z0-9]","")
21169  local v=rawget(t,k)
21170  if v then
21171   return v
21172  end
21173 end
21174end
21175setmetatableindex(verbosescripts,resolve)
21176setmetatableindex(verboselanguages,resolve)
21177setmetatableindex(verbosefeatures,resolve)
21178setmetatableindex(verbosebaselines,resolve)
21179setmetatableindex(scripts,function(t,k)
21180 if k then
21181  k=lower(k)
21182  if k=="dflt" then
21183   return k
21184  end
21185  local v=rawget(t,k)
21186  if v then
21187   return v
21188  end
21189  k=gsub(k," ","")
21190  v=rawget(t,v)
21191  if v then
21192   return v
21193  elseif acceptscripts then
21194   report_checks("registering extra script %a",k)
21195   rawset(t,k,k)
21196   return k
21197  end
21198 end
21199 return "dflt"
21200end)
21201setmetatableindex(languages,function(t,k)
21202 if k then
21203  k=lower(k)
21204  if k=="dflt" then
21205   return k
21206  end
21207  local v=rawget(t,k)
21208  if v then
21209   return v
21210  end
21211  k=gsub(k," ","")
21212  v=rawget(t,v)
21213  if v then
21214   return v
21215  elseif acceptlanguages then
21216   report_checks("registering extra language %a",k)
21217   rawset(t,k,k)
21218   return k
21219  end
21220 end
21221 return "dflt"
21222end)
21223if setmetatablenewindex then
21224 setmetatablenewindex(languages,"ignore")
21225 setmetatablenewindex(scripts,"ignore")
21226 setmetatablenewindex(baselines,"ignore")
21227end
21228local function resolve(t,k)
21229 if k then
21230  k=lower(k)
21231  local v=rawget(t,k)
21232  if v then
21233   return v
21234  end
21235  k=gsub(k," ","")
21236  local v=rawget(t,k)
21237  if v then
21238   return v
21239  end
21240  local tag,dd=match(k,"(..)(%d+)")
21241  if tag and dd then
21242   local v=rawget(t,tag)
21243   if v then
21244    return v 
21245   else
21246    local v=rawget(t,tag.."..") 
21247    if v then
21248     return (gsub(v,"%.%.",tonumber(dd))) 
21249    end
21250   end
21251  end
21252 end
21253 return k 
21254end
21255setmetatableindex(features,resolve)
21256local function assign(t,k,v)
21257 if k and v then
21258  v=lower(v)
21259  rawset(t,k,v)
21260 end
21261end
21262if setmetatablenewindex then
21263 setmetatablenewindex(features,assign)
21264end
21265local checkers={
21266 rand=function(v)
21267  return v==true and "random" or v
21268 end
21269}
21270if not storage then
21271 return
21272end
21273local usedfeatures=statistics.usedfeatures or {}
21274statistics.usedfeatures=usedfeatures
21275table.setmetatableindex(usedfeatures,function(t,k) if k then local v={} t[k]=v return v end end) 
21276storage.register("fonts/otf/usedfeatures",usedfeatures,"fonts.handlers.otf.statistics.usedfeatures" )
21277local normalizedaxis=otf.readers.helpers.normalizedaxis or function(s) return s end
21278function otffeatures.normalize(features,wrap) 
21279 if features then
21280  local h={}
21281  for key,value in next,features do
21282   local k=lower(key)
21283   if k=="language" then
21284    local v=gsub(lower(value),"[^a-z0-9]","")
21285    h.language=rawget(verboselanguages,v) or (languages[v] and v) or "dflt" 
21286   elseif k=="script" then
21287    local v=gsub(lower(value),"[^a-z0-9]","")
21288    h.script=rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" 
21289   elseif k=="axis" then
21290    h[k]=normalizedaxis(value)
21291   else
21292    local uk=usedfeatures[key]
21293    local uv=uk[value]
21294    if uv then
21295    else
21296     uv=tonumber(value) 
21297     if uv then
21298     elseif type(value)=="string" then
21299      local b=is_boolean(value)
21300      if type(b)=="nil" then
21301       if wrap and find(value,",") then
21302        uv="{"..lower(value).."}"
21303       else
21304        uv=lower(value)
21305       end
21306      else
21307       uv=b
21308      end
21309     elseif type(value)=="table" then
21310      uv=sequenced(t,",")
21311     else
21312      uv=value
21313     end
21314     if not rawget(features,k) then
21315      k=rawget(verbosefeatures,k) or k
21316     end
21317     local c=checkers[k]
21318     if c then
21319      uv=c(uv) or vc
21320     end
21321     uk[value]=uv
21322    end
21323    h[k]=uv
21324   end
21325  end
21326  return h
21327 end
21328end
21329
21330end -- closure
21331
21332do -- begin closure to overcome local limits and interference
21333
21334if not modules then modules={} end modules ['font-otl']={
21335 version=1.001,
21336 comment="companion to font-ini.mkiv",
21337 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
21338 copyright="PRAGMA ADE / ConTeXt Development Team",
21339 license="see context related readme files",
21340}
21341local lower=string.lower
21342local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
21343local abs=math.abs
21344local derivetable,sortedhash=table.derive,table.sortedhash
21345local formatters=string.formatters
21346local setmetatableindex=table.setmetatableindex
21347local allocate=utilities.storage.allocate
21348local registertracker=trackers.register
21349local registerdirective=directives.register
21350local starttiming=statistics.starttiming
21351local stoptiming=statistics.stoptiming
21352local elapsedtime=statistics.elapsedtime
21353local findbinfile=resolvers.findbinfile
21354local trace_loading=false  registertracker("otf.loading",function(v) trace_loading=v end)
21355local trace_features=false  registertracker("otf.features",function(v) trace_features=v end)
21356local trace_defining=false  registertracker("fonts.defining",function(v) trace_defining=v end)
21357local report_otf=logs.reporter("fonts","otf loading")
21358local fonts=fonts
21359local otf=fonts.handlers.otf
21360otf.version=3.135 
21361otf.cache=containers.define("fonts","otl",otf.version,true)
21362otf.svgcache=containers.define("fonts","svg",otf.version,true)
21363otf.pngcache=containers.define("fonts","png",otf.version,true)
21364otf.pdfcache=containers.define("fonts","pdf",otf.version,true)
21365otf.mpscache=containers.define("fonts","mps",otf.version,true)
21366otf.svgenabled=false
21367otf.pngenabled=false
21368local otfreaders=otf.readers
21369local hashes=fonts.hashes
21370local definers=fonts.definers
21371local readers=fonts.readers
21372local constructors=fonts.constructors
21373local otffeatures=constructors.features.otf
21374local registerotffeature=otffeatures.register
21375local otfenhancers=constructors.enhancers.otf
21376local registerotfenhancer=otfenhancers.register
21377local forceload=false
21378local cleanup=0  
21379local syncspace=true
21380local forcenotdef=false
21381local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 
21382local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
21383local wildcard="*"
21384local default="dflt"
21385local formats=fonts.formats
21386formats.otf="opentype"
21387formats.ttf="truetype"
21388formats.ttc="truetype"
21389registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end)
21390registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
21391registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
21392registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
21393registerotfenhancer("check extra features",function() end)
21394local checkmemory=utilities.lua and utilities.lua.checkmemory
21395local threshold=100 
21396local tracememory=false
21397registertracker("fonts.otf.loader.memory",function(v) tracememory=v end)
21398if not checkmemory then 
21399 local collectgarbage=collectgarbage
21400 checkmemory=function(previous,threshold) 
21401  local current=collectgarbage("count")
21402  if previous then
21403   local checked=(threshold or 64)*1024
21404   if current-previous>checked then
21405    collectgarbage("collect")
21406    current=collectgarbage("count")
21407   end
21408  end
21409  return current
21410 end
21411end
21412function otf.load(filename,sub,instance)
21413 local base=file.basename(file.removesuffix(filename))
21414 local name=file.removesuffix(base) 
21415 local attr=lfs.attributes(filename)
21416 local size=attr and attr.size or 0
21417 local time=attr and attr.modification or 0
21418 if sub=="" then
21419  sub=false
21420 end
21421 local hash=name
21422 if sub then
21423  hash=hash.."-"..sub
21424 end
21425 if instance then
21426  hash=hash.."-"..instance
21427 end
21428 hash=containers.cleanname(hash)
21429 local data=containers.read(otf.cache,hash)
21430 local reload=not data or data.size~=size or data.time~=time or data.tableversion~=otfreaders.tableversion
21431 if forceload then
21432  report_otf("forced reload of %a due to hard coded flag",filename)
21433  reload=true
21434 end
21435 if reload then
21436  report_otf("loading %a, hash %a",filename,hash)
21437  starttiming(otfreaders,true)
21438  data=otfreaders.loadfont(filename,sub or 1,instance) 
21439  if data then
21440   local used=checkmemory()
21441   local resources=data.resources
21442   local svgshapes=resources.svgshapes
21443   local pngshapes=resources.pngshapes
21444   if cleanup==0 then
21445    checkmemory(used,threshold,tracememory)
21446   end
21447   if svgshapes then
21448    resources.svgshapes=nil
21449    if otf.svgenabled then
21450     local timestamp=os.date()
21451     containers.write(otf.svgcache,hash,{
21452      svgshapes=svgshapes,
21453      timestamp=timestamp,
21454     })
21455     data.properties.svg={
21456      hash=hash,
21457      timestamp=timestamp,
21458     }
21459    end
21460    if cleanup>1 then
21461     collectgarbage("collect")
21462    else
21463     checkmemory(used,threshold,tracememory)
21464    end
21465   end
21466   if pngshapes then
21467    resources.pngshapes=nil
21468    if otf.pngenabled then
21469     local timestamp=os.date()
21470     containers.write(otf.pngcache,hash,{
21471      pngshapes=pngshapes,
21472      timestamp=timestamp,
21473     })
21474     data.properties.png={
21475      hash=hash,
21476      timestamp=timestamp,
21477     }
21478    end
21479    if cleanup>1 then
21480     collectgarbage("collect")
21481    else
21482     checkmemory(used,threshold,tracememory)
21483    end
21484   end
21485   otfreaders.compact(data)
21486   if cleanup==0 then
21487    checkmemory(used,threshold,tracememory)
21488   end
21489   otfreaders.rehash(data,"unicodes")
21490   otfreaders.addunicodetable(data)
21491   otfreaders.extend(data)
21492   if cleanup==0 then
21493    checkmemory(used,threshold,tracememory)
21494   end
21495   if context then
21496    otfreaders.condense(data)
21497   end
21498   otfreaders.pack(data)
21499   report_otf("loading done")
21500   report_otf("saving %a in cache",filename)
21501   data=containers.write(otf.cache,hash,data)
21502   if cleanup>1 then
21503    collectgarbage("collect")
21504   else
21505    checkmemory(used,threshold,tracememory)
21506   end
21507   stoptiming(otfreaders)
21508   if elapsedtime then
21509    report_otf("loading, optimizing, packing and caching time %s",elapsedtime(otfreaders))
21510   end
21511   if cleanup>3 then
21512    collectgarbage("collect")
21513   else
21514    checkmemory(used,threshold,tracememory)
21515   end
21516   data=containers.read(otf.cache,hash) 
21517   if cleanup>2 then
21518    collectgarbage("collect")
21519   else
21520    checkmemory(used,threshold,tracememory)
21521   end
21522  else
21523   stoptiming(otfreaders)
21524   data=nil
21525   report_otf("loading failed due to read error")
21526  end
21527 end
21528 if data then
21529  if trace_defining then
21530   report_otf("loading from cache using hash %a",hash)
21531  end
21532  otfreaders.unpack(data)
21533  otfreaders.expand(data) 
21534  otfreaders.addunicodetable(data)
21535  otfenhancers.apply(data,filename,data)
21536  if applyruntimefixes then
21537   applyruntimefixes(filename,data) 
21538  end
21539  data.metadata.math=data.resources.mathconstants
21540  local classes=data.resources.classes
21541  if not classes then
21542   local descriptions=data.descriptions
21543   classes=setmetatableindex(function(t,k)
21544    local d=descriptions[k]
21545    local v=(d and d.class or "base") or false
21546    t[k]=v
21547    return v
21548   end)
21549   data.resources.classes=classes
21550  end
21551 end
21552 return data
21553end
21554function otf.setfeatures(tfmdata,features)
21555 local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf)
21556 if okay then
21557  return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf)
21558 else
21559  return {} 
21560 end
21561end
21562local function copytotfm(data,cache_id)
21563 if data then
21564  local metadata=data.metadata
21565  local properties=derivetable(data.properties)
21566  local descriptions=derivetable(data.descriptions)
21567  local goodies=derivetable(data.goodies)
21568  local characters={} 
21569  local parameters={}
21570  local mathparameters={}
21571  local resources=data.resources
21572  local unicodes=resources.unicodes
21573  local spaceunits=500
21574  local spacer="space"
21575  local designsize=metadata.designsize or 100
21576  local minsize=metadata.minsize or designsize
21577  local maxsize=metadata.maxsize or designsize
21578  local mathspecs=metadata.math
21579  if designsize==0 then
21580   designsize=100
21581   minsize=100
21582   maxsize=100
21583  end
21584  if mathspecs then
21585   for name,value in next,mathspecs do
21586    mathparameters[name]=value
21587   end
21588  end
21589  for unicode in next,data.descriptions do 
21590   characters[unicode]={}
21591  end
21592  if mathspecs then
21593   for unicode,character in next,characters do
21594    local d=descriptions[unicode] 
21595    local m=d.math
21596    if m then
21597     local italic=m.italic
21598     local vitalic=m.vitalic
21599     local variants=m.hvariants
21600     local parts=m.hparts
21601     if variants then
21602      local c=character
21603      for i=1,#variants do
21604       local un=variants[i]
21605       c.next=un
21606       c=characters[un]
21607      end 
21608      c.horiz_variants=parts
21609     elseif parts then
21610      character.horiz_variants=parts
21611      italic=m.hitalic
21612     end
21613     local variants=m.vvariants
21614     local parts=m.vparts
21615     if variants then
21616      local c=character
21617      for i=1,#variants do
21618       local un=variants[i]
21619       c.next=un
21620       c=characters[un]
21621      end 
21622      c.vert_variants=parts
21623     elseif parts then
21624      character.vert_variants=parts
21625     end
21626     if italic and italic~=0 then
21627      character.italic=italic
21628     end
21629     if vitalic and vitalic~=0 then
21630      character.vert_italic=vitalic
21631     end
21632     local accent=m.accent 
21633     if accent then
21634      character.accent=accent
21635     end
21636     local kerns=m.kerns
21637     if kerns then
21638      character.mathkerns=kerns
21639     end
21640    end
21641   end
21642  end
21643  local filename=constructors.checkedfilename(resources)
21644  local fontname=metadata.fontname
21645  local fullname=metadata.fullname or fontname
21646  local psname=fontname or fullname
21647  local subfont=metadata.subfontindex
21648  local units=metadata.units or 1000
21649  if units==0 then 
21650   units=1000 
21651   metadata.units=1000
21652   report_otf("changing %a units to %a",0,units)
21653  end
21654  local monospaced=metadata.monospaced
21655  local charwidth=metadata.averagewidth 
21656  local charxheight=metadata.xheight 
21657  local italicangle=metadata.italicangle
21658  local hasitalics=metadata.hasitalics
21659  properties.monospaced=monospaced
21660  properties.hasitalics=hasitalics
21661  parameters.italicangle=italicangle
21662  parameters.charwidth=charwidth
21663  parameters.charxheight=charxheight
21664  local space=0x0020
21665  local emdash=0x2014
21666  if monospaced then
21667   if descriptions[space] then
21668    spaceunits,spacer=descriptions[space].width,"space"
21669   end
21670   if not spaceunits and descriptions[emdash] then
21671    spaceunits,spacer=descriptions[emdash].width,"emdash"
21672   end
21673   if not spaceunits and charwidth then
21674    spaceunits,spacer=charwidth,"charwidth"
21675   end
21676  else
21677   if descriptions[space] then
21678    spaceunits,spacer=descriptions[space].width,"space"
21679   end
21680   if not spaceunits and descriptions[emdash] then
21681    spaceunits,spacer=descriptions[emdash].width/2,"emdash/2"
21682   end
21683   if not spaceunits and charwidth then
21684    spaceunits,spacer=charwidth,"charwidth"
21685   end
21686  end
21687  spaceunits=tonumber(spaceunits) or units/2
21688  parameters.slant=0
21689  parameters.space=spaceunits   
21690  parameters.space_stretch=1*units/2   
21691  parameters.space_shrink=1*units/3   
21692  parameters.x_height=2*units/5   
21693  parameters.quad=units    
21694  if spaceunits<2*units/5 then
21695  end
21696  if italicangle and italicangle~=0 then
21697   parameters.italicangle=italicangle
21698   parameters.italicfactor=math.cos(math.rad(90+italicangle))
21699   parameters.slant=- math.tan(italicangle*math.pi/180)
21700  end
21701  if monospaced then
21702   parameters.space_stretch=0
21703   parameters.space_shrink=0
21704  elseif syncspace then 
21705   parameters.space_stretch=spaceunits/2
21706   parameters.space_shrink=spaceunits/3
21707  end
21708  parameters.extra_space=parameters.space_shrink 
21709  if charxheight then
21710   parameters.x_height=charxheight
21711  else
21712   local x=0x0078
21713   if x then
21714    local x=descriptions[x]
21715    if x then
21716     parameters.x_height=x.height
21717    end
21718   end
21719  end
21720  parameters.designsize=(designsize/10)*65536
21721  parameters.minsize=(minsize/10)*65536
21722  parameters.maxsize=(maxsize/10)*65536
21723  parameters.ascender=abs(metadata.ascender  or 0)
21724  parameters.descender=abs(metadata.descender or 0)
21725  parameters.units=units
21726  parameters.vheight=metadata.defaultvheight
21727  properties.space=spacer
21728  properties.format=data.format or formats.otf
21729  properties.filename=filename
21730  properties.fontname=fontname
21731  properties.fullname=fullname
21732  properties.psname=psname
21733  properties.name=filename or fullname
21734  properties.subfont=subfont
21735if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
21736 properties.encodingbytes=2
21737elseif CONTEXTLMTXMODE then
21738 local duplicates=resources and resources.duplicates
21739 if duplicates then
21740  local maxindex=data.nofglyphs or metadata.nofglyphs
21741  if maxindex then
21742   for u,d in sortedhash(duplicates) do
21743    local du=descriptions[u]
21744    if du then
21745     for uu in sortedhash(d) do
21746      maxindex=maxindex+1
21747      descriptions[uu].dupindex=du.index
21748      descriptions[uu].index=maxindex
21749     end
21750    else
21751    end
21752   end
21753  end
21754 end
21755end
21756  properties.private=properties.private or data.private or privateoffset
21757  return {
21758   characters=characters,
21759   descriptions=descriptions,
21760   parameters=parameters,
21761   mathparameters=mathparameters,
21762   resources=resources,
21763   properties=properties,
21764   goodies=goodies,
21765  }
21766 end
21767end
21768local converters={
21769 woff={
21770  cachename="webfonts",
21771  action=otf.readers.woff2otf,
21772 }
21773}
21774local function checkconversion(specification)
21775 local filename=specification.filename
21776 local converter=converters[lower(file.suffix(filename))]
21777 if converter then
21778  local base=file.basename(filename)
21779  local name=file.removesuffix(base)
21780  local attr=lfs.attributes(filename)
21781  local size=attr and attr.size or 0
21782  local time=attr and attr.modification or 0
21783  if size>0 then
21784   local cleanname=containers.cleanname(name)
21785   local cachename=caches.setfirstwritablefile(cleanname,converter.cachename)
21786   if not io.exists(cachename) or (time~=lfs.attributes(cachename).modification) then
21787    report_otf("caching font %a in %a",filename,cachename)
21788    converter.action(filename,cachename) 
21789    lfs.touch(cachename,time,time)
21790   end
21791   specification.filename=cachename
21792  end
21793 end
21794end
21795local function otftotfm(specification)
21796 local cache_id=specification.hash
21797 local tfmdata=containers.read(constructors.cache,cache_id)
21798 if not tfmdata then
21799  checkconversion(specification) 
21800  local name=specification.name
21801  local sub=specification.sub
21802  local subindex=specification.subindex
21803  local filename=specification.filename
21804  local features=specification.features.normal
21805  local instance=specification.instance or (features and features.axis)
21806  local rawdata=otf.load(filename,sub,instance)
21807  if rawdata and next(rawdata) then
21808   local descriptions=rawdata.descriptions
21809   rawdata.lookuphash={} 
21810   tfmdata=copytotfm(rawdata,cache_id)
21811   if tfmdata and next(tfmdata) then
21812    local features=constructors.checkedfeatures("otf",features)
21813    local shared=tfmdata.shared
21814    if not shared then
21815     shared={}
21816     tfmdata.shared=shared
21817    end
21818    shared.rawdata=rawdata
21819    shared.dynamics={}
21820    tfmdata.changed={}
21821    shared.features=features
21822    shared.processes=otf.setfeatures(tfmdata,features)
21823   end
21824  end
21825  containers.write(constructors.cache,cache_id,tfmdata)
21826 end
21827 return tfmdata
21828end
21829local function read_from_otf(specification)
21830 local tfmdata=otftotfm(specification)
21831 if tfmdata then
21832  tfmdata.properties.name=specification.name
21833  tfmdata.properties.sub=specification.sub
21834  tfmdata.properties.id=specification.id
21835  tfmdata=constructors.scale(tfmdata,specification)
21836  local allfeatures=tfmdata.shared.features or specification.features.normal
21837  constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf)
21838  constructors.setname(tfmdata,specification) 
21839  fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification)
21840 end
21841 return tfmdata
21842end
21843function otf.collectlookups(rawdata,kind,script,language)
21844 if not kind then
21845  return
21846 end
21847 if not script then
21848  script=default
21849 end
21850 if not language then
21851  language=default
21852 end
21853 local lookupcache=rawdata.lookupcache
21854 if not lookupcache then
21855  lookupcache={}
21856  rawdata.lookupcache=lookupcache
21857 end
21858 local kindlookup=lookupcache[kind]
21859 if not kindlookup then
21860  kindlookup={}
21861  lookupcache[kind]=kindlookup
21862 end
21863 local scriptlookup=kindlookup[script]
21864 if not scriptlookup then
21865  scriptlookup={}
21866  kindlookup[script]=scriptlookup
21867 end
21868 local languagelookup=scriptlookup[language]
21869 if not languagelookup then
21870  local sequences=rawdata.resources.sequences
21871  local featuremap={}
21872  local featurelist={}
21873  if sequences then
21874   for s=1,#sequences do
21875    local sequence=sequences[s]
21876    local features=sequence.features
21877    if features then
21878     features=features[kind]
21879     if features then
21880      features=features[script] or features[wildcard]
21881      if features then
21882       features=features[language] or features[wildcard]
21883       if features then
21884        if not featuremap[sequence] then
21885         featuremap[sequence]=true
21886         featurelist[#featurelist+1]=sequence
21887        end
21888       end
21889      end
21890     end
21891    end
21892   end
21893   if #featurelist==0 then
21894    featuremap,featurelist=false,false
21895   end
21896  else
21897   featuremap,featurelist=false,false
21898  end
21899  languagelookup={ featuremap,featurelist }
21900  scriptlookup[language]=languagelookup
21901 end
21902 return unpack(languagelookup)
21903end
21904local function getgsub(tfmdata,k,kind,value)
21905 local shared=tfmdata.shared
21906 local rawdata=shared and shared.rawdata
21907 if rawdata then
21908  local sequences=rawdata.resources.sequences
21909  if sequences then
21910   local properties=tfmdata.properties
21911   local validlookups,lookuplist=otf.collectlookups(rawdata,kind,properties.script,properties.language)
21912   if validlookups then
21913    for i=1,#lookuplist do
21914     local lookup=lookuplist[i]
21915     local steps=lookup.steps
21916     local nofsteps=lookup.nofsteps
21917     for i=1,nofsteps do
21918      local coverage=steps[i].coverage
21919      if coverage then
21920       local found=coverage[k]
21921       if found then
21922        return found,lookup.type
21923       end
21924      end
21925     end
21926    end
21927   end
21928  end
21929 end
21930end
21931otf.getgsub=getgsub 
21932function otf.getsubstitution(tfmdata,k,kind,value)
21933 local found,kind=getgsub(tfmdata,k,kind,value)
21934 if not found then
21935 elseif kind=="gsub_single" then
21936  return found
21937 elseif kind=="gsub_alternate" then
21938  local choice=tonumber(value) or 1 
21939  return found[choice] or found[1] or k
21940 end
21941 return k
21942end
21943otf.getalternate=otf.getsubstitution
21944function otf.getmultiple(tfmdata,k,kind)
21945 local found,kind=getgsub(tfmdata,k,kind)
21946 if found and kind=="gsub_multiple" then
21947  return found
21948 end
21949 return { k }
21950end
21951function otf.getkern(tfmdata,left,right,kind)
21952 local kerns=getgsub(tfmdata,left,kind or "kern",true) 
21953 if kerns then
21954  local found=kerns[right]
21955  local kind=type(found)
21956  if kind=="table" then
21957   found=found[1][3] 
21958  elseif kind~="number" then
21959   found=false
21960  end
21961  if found then
21962   return found*tfmdata.parameters.factor
21963  end
21964 end
21965 return 0
21966end
21967local function check_otf(forced,specification,suffix)
21968 local name=specification.name
21969 if forced then
21970  name=specification.forcedname 
21971 end
21972 local fullname=findbinfile(name,suffix) or ""
21973 if fullname=="" then
21974  fullname=fonts.names.getfilename(name,suffix) or ""
21975 end
21976 if fullname~="" and not fonts.names.ignoredfile(fullname) then
21977  specification.filename=fullname
21978  return read_from_otf(specification)
21979 end
21980end
21981local function opentypereader(specification,suffix)
21982 local forced=specification.forced or ""
21983 if formats[forced] then
21984  return check_otf(true,specification,forced)
21985 else
21986  return check_otf(false,specification,suffix)
21987 end
21988end
21989readers.opentype=opentypereader 
21990function readers.otf(specification) return opentypereader(specification,"otf") end
21991function readers.ttf(specification) return opentypereader(specification,"ttf") end
21992function readers.ttc(specification) return opentypereader(specification,"ttf") end
21993function readers.woff(specification)
21994 checkconversion(specification)
21995 opentypereader(specification,"")
21996end
21997function otf.scriptandlanguage(tfmdata,attr)
21998 local properties=tfmdata.properties
21999 return properties.script or "dflt",properties.language or "dflt"
22000end
22001local function justset(coverage,unicode,replacement)
22002 coverage[unicode]=replacement
22003end
22004otf.coverup={
22005 stepkey="steps",
22006 actions={
22007  chainsubstitution=justset,
22008  chainposition=justset,
22009  substitution=justset,
22010  alternate=justset,
22011  multiple=justset,
22012  kern=justset,
22013  pair=justset,
22014  single=justset,
22015  ligature=function(coverage,unicode,ligature)
22016   local first=ligature[1]
22017   local tree=coverage[first]
22018   if not tree then
22019    tree={}
22020    coverage[first]=tree
22021   end
22022   for i=2,#ligature do
22023    local l=ligature[i]
22024    local t=tree[l]
22025    if not t then
22026     t={}
22027     tree[l]=t
22028    end
22029    tree=t
22030   end
22031   tree.ligature=unicode
22032  end,
22033 },
22034 register=function(coverage,featuretype,format)
22035  return {
22036   format=format,
22037   coverage=coverage,
22038  }
22039 end
22040}
22041
22042end -- closure
22043
22044do -- begin closure to overcome local limits and interference
22045
22046if not modules then modules={} end modules ['font-oto']={ 
22047 version=1.001,
22048 comment="companion to font-ini.mkiv",
22049 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
22050 copyright="PRAGMA ADE / ConTeXt Development Team",
22051 license="see context related readme files"
22052}
22053local concat,unpack=table.concat,table.unpack
22054local insert,remove=table.insert,table.remove
22055local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip
22056local type,next,tonumber,tostring=type,next,tonumber,tostring
22057local trace_baseinit=false  trackers.register("otf.baseinit",function(v) trace_baseinit=v end)
22058local trace_singles=false  trackers.register("otf.singles",function(v) trace_singles=v end)
22059local trace_multiples=false  trackers.register("otf.multiples",function(v) trace_multiples=v end)
22060local trace_alternatives=false  trackers.register("otf.alternatives",function(v) trace_alternatives=v end)
22061local trace_ligatures=false  trackers.register("otf.ligatures",function(v) trace_ligatures=v end)
22062local trace_kerns=false  trackers.register("otf.kerns",function(v) trace_kerns=v end)
22063local trace_preparing=false  trackers.register("otf.preparing",function(v) trace_preparing=v end)
22064local report_prepare=logs.reporter("fonts","otf prepare")
22065local fonts=fonts
22066local otf=fonts.handlers.otf
22067local otffeatures=otf.features
22068local registerotffeature=otffeatures.register
22069otf.defaultbasealternate="none" 
22070local getprivate=fonts.constructors.getprivate
22071local wildcard="*"
22072local default="dflt"
22073local formatters=string.formatters
22074local f_unicode=formatters["%U"]
22075local f_uniname=formatters["%U (%s)"]
22076local f_unilist=formatters["% t (% t)"]
22077local function gref(descriptions,n)
22078 if type(n)=="number" then
22079  local name=descriptions[n].name
22080  if name then
22081   return f_uniname(n,name)
22082  else
22083   return f_unicode(n)
22084  end
22085 elseif n then
22086  local num={}
22087  local nam={}
22088  local j=0
22089  for i=1,#n do
22090   local ni=n[i]
22091   if tonumber(ni) then 
22092    j=j+1
22093    local di=descriptions[ni]
22094    num[j]=f_unicode(ni)
22095    nam[j]=di and di.name or "-"
22096   end
22097  end
22098  return f_unilist(num,nam)
22099 else
22100  return "<error in base mode tracing>"
22101 end
22102end
22103local function cref(feature,sequence)
22104 return formatters["feature %a, type %a, (chain) lookup %a"](feature,sequence.type,sequence.name)
22105end
22106local function report_substitution(feature,sequence,descriptions,unicode,substitution)
22107 if unicode==substitution then
22108  report_prepare("%s: base substitution %s maps onto itself",
22109   cref(feature,sequence),
22110   gref(descriptions,unicode))
22111 else
22112  report_prepare("%s: base substitution %s => %S",
22113   cref(feature,sequence),
22114   gref(descriptions,unicode),
22115   gref(descriptions,substitution))
22116 end
22117end
22118local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
22119 if unicode==replacement then
22120  report_prepare("%s: base alternate %s maps onto itself",
22121   cref(feature,sequence),
22122   gref(descriptions,unicode))
22123 else
22124  report_prepare("%s: base alternate %s => %s (%S => %S)",
22125   cref(feature,sequence),
22126   gref(descriptions,unicode),
22127   replacement and gref(descriptions,replacement),
22128   value,
22129   comment)
22130 end
22131end
22132local function report_ligature(feature,sequence,descriptions,unicode,ligature)
22133 report_prepare("%s: base ligature %s => %S",
22134  cref(feature,sequence),
22135  gref(descriptions,ligature),
22136  gref(descriptions,unicode))
22137end
22138local function report_kern(feature,sequence,descriptions,unicode,otherunicode,value)
22139 report_prepare("%s: base kern %s + %s => %S",
22140  cref(feature,sequence),
22141  gref(descriptions,unicode),
22142  gref(descriptions,otherunicode),
22143  value)
22144end
22145local basehash,basehashes,applied={},1,{}
22146local function registerbasehash(tfmdata)
22147 local properties=tfmdata.properties
22148 local hash=concat(applied," ")
22149 local base=basehash[hash]
22150 if not base then
22151  basehashes=basehashes+1
22152  base=basehashes
22153  basehash[hash]=base
22154 end
22155 properties.basehash=base
22156 properties.fullname=(properties.fullname or properties.name).."-"..base
22157 applied={}
22158end
22159local function registerbasefeature(feature,value)
22160 applied[#applied+1]=feature.."="..tostring(value)
22161end
22162local function makefake(tfmdata,name,present)
22163 local private=getprivate(tfmdata)
22164 local character={ intermediate=true,ligatures={} }
22165 tfmdata.resources.unicodes[name]=private
22166 tfmdata.characters[private]=character
22167 tfmdata.descriptions[private]={ name=name }
22168 present[name]=private
22169 return character
22170end
22171local function make_1(present,tree,name)
22172 if tonumber(tree) then
22173  present[name]=v
22174 else
22175  for k,v in next,tree do
22176   if k=="ligature" then
22177    present[name]=v
22178   else
22179    make_1(present,v,name.."_"..k)
22180   end
22181  end
22182 end
22183end
22184local function make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
22185 local character=characters[preceding]
22186 if not character then
22187  if trace_baseinit then
22188   report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding)
22189  end
22190  character=makefake(tfmdata,name,present)
22191 end
22192 local ligatures=character.ligatures
22193 if ligatures then
22194  ligatures[unicode]={ char=v }
22195 else
22196  character.ligatures={ [unicode]={ char=v } }
22197 end
22198 if done then
22199  local d=done[name]
22200  if not d then
22201   done[name]={ "dummy",v }
22202  else
22203   d[#d+1]=v
22204  end
22205 end
22206end
22207local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done)
22208 if tonumber(tree) then
22209  make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,tree)
22210 else
22211  for k,v in next,tree do
22212   if k=="ligature" then
22213    make_3(present,tfmdata,characters,tree,name,preceding,unicode,done,v)
22214   else
22215    local code=present[name] or unicode
22216    local name=name.."_"..k
22217    make_2(present,tfmdata,characters,v,name,code,k,done)
22218   end
22219  end
22220 end
22221end
22222local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
22223 local characters=tfmdata.characters
22224 local descriptions=tfmdata.descriptions
22225 local resources=tfmdata.resources
22226 local changed=tfmdata.changed
22227 local ligatures={}
22228 local alternate=tonumber(value) or true and 1
22229 local defaultalt=otf.defaultbasealternate
22230 local trace_singles=trace_baseinit and trace_singles
22231 local trace_alternatives=trace_baseinit and trace_alternatives
22232 local trace_ligatures=trace_baseinit and trace_ligatures
22233 if not changed then
22234  changed={}
22235  tfmdata.changed=changed
22236 end
22237 for i=1,#lookuplist do
22238  local sequence=lookuplist[i]
22239  local steps=sequence.steps
22240  local kind=sequence.type
22241  if kind=="gsub_single" then
22242   for i=1,#steps do
22243    for unicode,data in next,steps[i].coverage do
22244     if unicode~=data and not changed[unicode] then
22245      changed[unicode]=data
22246     end
22247     if trace_singles then
22248      report_substitution(feature,sequence,descriptions,unicode,data)
22249     end
22250    end
22251   end
22252  elseif kind=="gsub_alternate" then
22253   for i=1,#steps do
22254    for unicode,data in next,steps[i].coverage do
22255     local replacement=data[alternate]
22256     if replacement then
22257      if unicode~=replacement and not changed[unicode] then
22258       changed[unicode]=replacement
22259      end
22260      if trace_alternatives then
22261       report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
22262      end
22263     elseif defaultalt=="first" then
22264      replacement=data[1]
22265      if unicode~=replacement and not changed[unicode] then
22266       changed[unicode]=replacement
22267      end
22268      if trace_alternatives then
22269       report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
22270      end
22271     elseif defaultalt=="last" then
22272      replacement=data[#data]
22273      if unicode~=replacement and not changed[unicode] then
22274       changed[unicode]=replacement
22275      end
22276      if trace_alternatives then
22277       report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
22278      end
22279     else
22280      if trace_alternatives then
22281       report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
22282      end
22283     end
22284    end
22285   end
22286  elseif kind=="gsub_ligature" then
22287   for i=1,#steps do
22288    for unicode,data in next,steps[i].coverage do
22289     ligatures[#ligatures+1]={ unicode,data,"" } 
22290     if trace_ligatures then
22291      report_ligature(feature,sequence,descriptions,unicode,data)
22292     end
22293    end
22294   end
22295  end
22296 end
22297 local nofligatures=#ligatures
22298 if nofligatures>0 then
22299  local characters=tfmdata.characters
22300  local present={}
22301  local done=trace_baseinit and trace_ligatures and {}
22302  for i=1,nofligatures do
22303   local ligature=ligatures[i]
22304   local unicode=ligature[1]
22305   local tree=ligature[2]
22306   make_1(present,tree,"ctx_"..unicode)
22307  end
22308  for i=1,nofligatures do
22309   local ligature=ligatures[i]
22310   local unicode=ligature[1]
22311   local tree=ligature[2]
22312   local lookupname=ligature[3]
22313   make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence)
22314  end
22315 end
22316end
22317local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
22318 local characters=tfmdata.characters
22319 local descriptions=tfmdata.descriptions
22320 local resources=tfmdata.resources
22321 local properties=tfmdata.properties
22322 local traceindeed=trace_baseinit and trace_kerns
22323 for i=1,#lookuplist do
22324  local sequence=lookuplist[i]
22325  local steps=sequence.steps
22326  local kind=sequence.type
22327  local format=sequence.format
22328  if kind=="gpos_pair" then
22329   for i=1,#steps do
22330    local step=steps[i]
22331    local format=step.format
22332    if format=="kern" or format=="move" then
22333     for unicode,data in next,steps[i].coverage do
22334      local character=characters[unicode]
22335      local kerns=character.kerns
22336      if not kerns then
22337       kerns={}
22338       character.kerns=kerns
22339      end
22340      if traceindeed then
22341       for otherunicode,kern in next,data do
22342        if not kerns[otherunicode] and kern~=0 then
22343         kerns[otherunicode]=kern
22344         report_kern(feature,sequence,descriptions,unicode,otherunicode,kern)
22345        end
22346       end
22347      else
22348       for otherunicode,kern in next,data do
22349        if not kerns[otherunicode] and kern~=0 then
22350         kerns[otherunicode]=kern
22351        end
22352       end
22353      end
22354     end
22355    else
22356     for unicode,data in next,steps[i].coverage do
22357      local character=characters[unicode]
22358      local kerns=character.kerns
22359      for otherunicode,kern in next,data do
22360       local other=kern[2]
22361       if other==true or (not other and not (kerns and kerns[otherunicode])) then
22362        local kern=kern[1]
22363        if kern==true then
22364        elseif kern[1]~=0 or kern[2]~=0 or kern[4]~=0 then
22365        else
22366         kern=kern[3]
22367         if kern~=0 then
22368          if kerns then
22369           kerns[otherunicode]=kern
22370          else
22371           kerns={ [otherunicode]=kern }
22372           character.kerns=kerns
22373          end
22374          if traceindeed then
22375           report_kern(feature,sequence,descriptions,unicode,otherunicode,kern)
22376          end
22377         end
22378        end
22379       end
22380      end
22381     end
22382    end
22383   end
22384  end
22385 end
22386end
22387local function initializehashes(tfmdata)
22388end
22389local function checkmathreplacements(tfmdata,fullname,fixitalics)
22390 if tfmdata.mathparameters then
22391  local characters=tfmdata.characters
22392  local changed=tfmdata.changed
22393  if next(changed) then
22394   if trace_preparing or trace_baseinit then
22395    report_prepare("checking math replacements for %a",fullname)
22396   end
22397   for unicode,replacement in next,changed do
22398    local u=characters[unicode]
22399    local r=characters[replacement]
22400    if u and r then
22401     local n=u.next
22402     local v=u.vert_variants
22403     local h=u.horiz_variants
22404     if fixitalics then
22405      local ui=u.italic
22406      if ui and not r.italic then
22407       if trace_preparing then
22408        report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
22409       end
22410       r.italic=ui 
22411      end
22412     end
22413     if n and not r.next then
22414      if trace_preparing then
22415       report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
22416      end
22417      r.next=n
22418     end
22419     if v and not r.vert_variants then
22420      if trace_preparing then
22421       report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
22422      end
22423      r.vert_variants=v
22424     end
22425     if h and not r.horiz_variants then
22426      if trace_preparing then
22427       report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
22428      end
22429      r.horiz_variants=h
22430     end
22431    else
22432     if trace_preparing then
22433      report_prepare("error replacing %C by %U",unicode,replacement)
22434     end
22435    end
22436   end
22437  end
22438 end
22439end
22440local function featuresinitializer(tfmdata,value)
22441 if true then 
22442  local starttime=trace_preparing and os.clock()
22443  local features=tfmdata.shared.features
22444  local fullname=tfmdata.properties.fullname or "?"
22445  if features then
22446   initializehashes(tfmdata)
22447   local collectlookups=otf.collectlookups
22448   local rawdata=tfmdata.shared.rawdata
22449   local properties=tfmdata.properties
22450   local script=properties.script
22451   local language=properties.language
22452   local rawresources=rawdata.resources
22453   local rawfeatures=rawresources and rawresources.features
22454   local basesubstitutions=rawfeatures and rawfeatures.gsub
22455   local basepositionings=rawfeatures and rawfeatures.gpos
22456   local substitutionsdone=false
22457   local positioningsdone=false
22458   if basesubstitutions or basepositionings then
22459    local sequences=tfmdata.resources.sequences
22460    for s=1,#sequences do
22461     local sequence=sequences[s]
22462     local sfeatures=sequence.features
22463     if sfeatures then
22464      local order=sequence.order
22465      if order then
22466       for i=1,#order do 
22467        local feature=order[i]
22468        local value=features[feature]
22469        if value then
22470         local validlookups,lookuplist=collectlookups(rawdata,feature,script,language)
22471         if not validlookups then
22472         elseif basesubstitutions and basesubstitutions[feature] then
22473          if trace_preparing then
22474           report_prepare("filtering base %s feature %a for %a with value %a","sub",feature,fullname,value)
22475          end
22476          preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
22477          registerbasefeature(feature,value)
22478          substitutionsdone=true
22479         elseif basepositionings and basepositionings[feature] then
22480          if trace_preparing then
22481           report_prepare("filtering base %a feature %a for %a with value %a","pos",feature,fullname,value)
22482          end
22483          preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
22484          registerbasefeature(feature,value)
22485          positioningsdone=true
22486         end
22487        end
22488       end
22489      end
22490     end
22491    end
22492   end
22493   if substitutionsdone then
22494    checkmathreplacements(tfmdata,fullname,features.fixitalics)
22495   end
22496   registerbasehash(tfmdata)
22497  end
22498  if trace_preparing then
22499   report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,fullname)
22500  end
22501 end
22502end
22503registerotffeature {
22504 name="features",
22505 description="features",
22506 default=true,
22507 initializers={
22508  base=featuresinitializer,
22509 }
22510}
22511otf.basemodeinitializer=featuresinitializer
22512
22513end -- closure
22514
22515do -- begin closure to overcome local limits and interference
22516
22517if not modules then modules={} end modules ['font-otj']={
22518 version=1.001,
22519 optimize=true,
22520 comment="companion to font-lib.mkiv",
22521 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
22522 copyright="PRAGMA ADE / ConTeXt Development Team",
22523 license="see context related readme files",
22524}
22525if not nodes.properties then return end
22526local next,rawget,tonumber=next,rawget,tonumber
22527local fastcopy=table.fastcopy
22528local registertracker=trackers.register
22529local registerdirective=directives.register
22530local trace_injections=false  registertracker("fonts.injections",function(v) trace_injections=v end)
22531local trace_marks=false  registertracker("fonts.injections.marks",function(v) trace_marks=v end)
22532local trace_cursive=false  registertracker("fonts.injections.cursive",function(v) trace_cursive=v end)
22533local trace_spaces=false  registertracker("fonts.injections.spaces",function(v) trace_spaces=v end)
22534local report_injections=logs.reporter("fonts","injections")
22535local report_spaces=logs.reporter("fonts","spaces")
22536local attributes,nodes,node=attributes,nodes,node
22537fonts=fonts
22538local hashes=fonts.hashes
22539local fontdata=hashes.identifiers
22540local fontmarks=hashes.marks
22541nodes.injections=nodes.injections or {}
22542local injections=nodes.injections
22543local tracers=nodes.tracers
22544local setcolor=tracers and tracers.colors.set
22545local resetcolor=tracers and tracers.colors.reset
22546local nodecodes=nodes.nodecodes
22547local glyph_code=nodecodes.glyph
22548local disc_code=nodecodes.disc
22549local kern_code=nodecodes.kern
22550local glue_code=nodecodes.glue
22551local nuts=nodes.nuts
22552local nodepool=nuts.pool
22553local tonode=nuts.tonode
22554local tonut=nuts.tonut
22555local setfield=nuts.setfield
22556local getnext=nuts.getnext
22557local getprev=nuts.getprev
22558local getid=nuts.getid
22559local getfont=nuts.getfont
22560local getchar=nuts.getchar
22561local getoffsets=nuts.getoffsets
22562local getboth=nuts.getboth
22563local getdisc=nuts.getdisc
22564local setdisc=nuts.setdisc
22565local getreplace=nuts.getreplace
22566local setreplace=nuts.setreplace
22567local setoffsets=nuts.setoffsets
22568local ischar=nuts.ischar
22569local getkern=nuts.getkern
22570local setkern=nuts.setkern
22571local setlink=nuts.setlink
22572local setwidth=nuts.setwidth
22573local getwidth=nuts.getwidth
22574local nextchar=nuts.traversers.char
22575local nextglue=nuts.traversers.glue
22576local insertnodebefore=nuts.insertbefore
22577local insertnodeafter=nuts.insertafter
22578local properties=nodes.properties.data
22579local fontkern=nuts.pool and nuts.pool.fontkern   
22580local italickern=nuts.pool and nuts.pool.italickern 
22581local useitalickerns=false 
22582directives.register("fonts.injections.useitalics",function(v)
22583 if v then
22584  report_injections("using italics for space kerns (tracing only)")
22585 end
22586 useitalickerns=v
22587end)
22588if not fontkern then 
22589 local thekern=nuts.new("kern",0) 
22590 local setkern=nuts.setkern
22591 local copy_node=nuts.copy
22592 fontkern=function(k)
22593  local n=copy_node(thekern)
22594  setkern(n,k)
22595  return n
22596 end
22597end
22598if not italickern then 
22599 local thekern=nuts.new("kern",3) 
22600 local setkern=nuts.setkern
22601 local copy_node=nuts.copy
22602 italickern=function(k)
22603  local n=copy_node(thekern)
22604  setkern(n,k)
22605  return n
22606 end
22607end
22608function injections.installnewkern() end 
22609local nofregisteredkerns=0
22610local nofregisteredpositions=0
22611local nofregisteredmarks=0
22612local nofregisteredcursives=0
22613local keepregisteredcounts=false
22614function injections.keepcounts()
22615 keepregisteredcounts=true
22616end
22617function injections.resetcounts()
22618 nofregisteredkerns=0
22619 nofregisteredpositions=0
22620 nofregisteredmarks=0
22621 nofregisteredcursives=0
22622 keepregisteredcounts=false
22623end
22624function injections.reset(n)
22625 local p=rawget(properties,n)
22626 if p then
22627  p.injections=false 
22628 else
22629  properties[n]=false 
22630 end
22631end
22632function injections.copy(target,source)
22633 local sp=rawget(properties,source)
22634 if sp then
22635  local tp=rawget(properties,target)
22636  local si=sp.injections
22637  if si then
22638   si=fastcopy(si)
22639   if tp then
22640    tp.injections=si
22641   else
22642    properties[target]={
22643     injections=si,
22644    }
22645   end
22646  elseif tp then
22647   tp.injections=false 
22648  else
22649   properties[target]={ injections={} }
22650  end
22651 else
22652  local tp=rawget(properties,target)
22653  if tp then
22654   tp.injections=false 
22655  else
22656   properties[target]=false 
22657  end
22658 end
22659end
22660function injections.setligaindex(n,index) 
22661 local p=rawget(properties,n)
22662 if p then
22663  local i=p.injections
22664  if i then
22665   i.ligaindex=index
22666  else
22667   p.injections={
22668    ligaindex=index
22669   }
22670  end
22671 else
22672  properties[n]={
22673   injections={
22674    ligaindex=index
22675   }
22676  }
22677 end
22678end
22679function injections.getligaindex(n,default)
22680 local p=rawget(properties,n)
22681 if p then
22682  local i=p.injections
22683  if i then
22684   return i.ligaindex or default
22685  end
22686 end
22687 return default
22688end
22689function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext,r2lflag)
22690 local dx=factor*(exit[1]-entry[1])
22691 local dy=-factor*(exit[2]-entry[2])
22692 local ws=tfmstart.width
22693 local wn=tfmnext.width
22694 nofregisteredcursives=nofregisteredcursives+1
22695 if rlmode<0 then
22696  dx=-(dx+wn)
22697 else
22698  dx=dx-ws
22699 end
22700 if dx==0 then
22701  dx=0
22702 end
22703 local p=rawget(properties,start)
22704 if p then
22705  local i=p.injections
22706  if i then
22707   i.cursiveanchor=true
22708  else
22709   p.injections={
22710    cursiveanchor=true,
22711   }
22712  end
22713 else
22714  properties[start]={
22715   injections={
22716    cursiveanchor=true,
22717   },
22718  }
22719 end
22720 local p=rawget(properties,nxt)
22721 if p then
22722  local i=p.injections
22723  if i then
22724   i.cursivex=dx
22725   i.cursivey=dy
22726  else
22727   p.injections={
22728    cursivex=dx,
22729    cursivey=dy,
22730   }
22731  end
22732 else
22733  properties[nxt]={
22734   injections={
22735    cursivex=dx,
22736    cursivey=dy,
22737   },
22738  }
22739 end
22740 return dx,dy,nofregisteredcursives
22741end
22742function injections.setposition(kind,current,factor,rlmode,spec,injection)
22743 local x=factor*(spec[1] or 0)
22744 local y=factor*(spec[2] or 0)
22745 local w=factor*(spec[3] or 0)
22746 local h=factor*(spec[4] or 0)
22747 if x~=0 or w~=0 or y~=0 or h~=0 then 
22748  local yoffset=y-h
22749  local leftkern=x   
22750  local rightkern=w-x  
22751  if leftkern~=0 or rightkern~=0 or yoffset~=0 then
22752   nofregisteredpositions=nofregisteredpositions+1
22753   if rlmode and rlmode<0 then
22754    leftkern,rightkern=rightkern,leftkern
22755   end
22756   if not injection then
22757    injection="injections"
22758   end
22759   local p=rawget(properties,current)
22760   if p then
22761    local i=p[injection]
22762    if i then
22763     if leftkern~=0 then
22764      i.leftkern=(i.leftkern  or 0)+leftkern
22765     end
22766     if rightkern~=0 then
22767      i.rightkern=(i.rightkern or 0)+rightkern
22768     end
22769     if yoffset~=0 then
22770      i.yoffset=(i.yoffset or 0)+yoffset
22771     end
22772    elseif leftkern~=0 or rightkern~=0 then
22773     p[injection]={
22774      leftkern=leftkern,
22775      rightkern=rightkern,
22776      yoffset=yoffset,
22777     }
22778    else
22779     p[injection]={
22780      yoffset=yoffset,
22781     }
22782    end
22783   elseif leftkern~=0 or rightkern~=0 then
22784    properties[current]={
22785     [injection]={
22786      leftkern=leftkern,
22787      rightkern=rightkern,
22788      yoffset=yoffset,
22789     },
22790    }
22791   else
22792    properties[current]={
22793     [injection]={
22794      yoffset=yoffset,
22795     },
22796    }
22797   end
22798   return x,y,w,h,nofregisteredpositions
22799   end
22800 end
22801 return x,y,w,h 
22802end
22803function injections.setkern(current,factor,rlmode,x,injection)
22804 local dx=factor*x
22805 if dx~=0 then
22806  nofregisteredkerns=nofregisteredkerns+1
22807  local p=rawget(properties,current)
22808  if not injection then
22809   injection="injections"
22810  end
22811  if p then
22812   local i=p[injection]
22813   if i then
22814    i.leftkern=dx+(i.leftkern or 0)
22815   else
22816    p[injection]={
22817     leftkern=dx,
22818    }
22819   end
22820  else
22821   properties[current]={
22822    [injection]={
22823     leftkern=dx,
22824    },
22825   }
22826  end
22827  return dx,nofregisteredkerns
22828 else
22829  return 0,0
22830 end
22831end
22832function injections.setmove(current,factor,rlmode,x,injection)
22833 local dx=factor*x
22834 if dx~=0 then
22835  nofregisteredkerns=nofregisteredkerns+1
22836  local p=rawget(properties,current)
22837  if not injection then
22838   injection="injections"
22839  end
22840  if rlmode and rlmode<0 then
22841   if p then
22842    local i=p[injection]
22843    if i then
22844     i.rightkern=dx+(i.rightkern or 0)
22845    else
22846     p[injection]={
22847      rightkern=dx,
22848     }
22849    end
22850   else
22851    properties[current]={
22852     [injection]={
22853      rightkern=dx,
22854     },
22855    }
22856   end
22857  else
22858   if p then
22859    local i=p[injection]
22860    if i then
22861     i.leftkern=dx+(i.leftkern or 0)
22862    else
22863     p[injection]={
22864      leftkern=dx,
22865     }
22866    end
22867   else
22868    properties[current]={
22869     [injection]={
22870      leftkern=dx,
22871     },
22872    }
22873   end
22874  end
22875  return dx,nofregisteredkerns
22876 else
22877  return 0,0
22878 end
22879end
22880function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) 
22881 local dx=factor*(ba[1]-ma[1])
22882 local dy=factor*(ba[2]-ma[2])
22883 nofregisteredmarks=nofregisteredmarks+1
22884 if rlmode>=0 then
22885  dx=tfmbase.width-dx 
22886 end
22887 local p=rawget(properties,start)
22888 if p then
22889  local i=p.injections
22890  if i then
22891   if i.markmark then
22892   else
22893    i.markx=dx
22894    i.marky=dy
22895    i.markdir=rlmode or 0
22896    i.markbase=nofregisteredmarks
22897    i.markbasenode=base
22898    i.markmark=mkmk
22899    i.checkmark=checkmark
22900   end
22901  else
22902   p.injections={
22903    markx=dx,
22904    marky=dy,
22905    markdir=rlmode or 0,
22906    markbase=nofregisteredmarks,
22907    markbasenode=base,
22908    markmark=mkmk,
22909    checkmark=checkmark,
22910   }
22911  end
22912 else
22913  properties[start]={
22914   injections={
22915    markx=dx,
22916    marky=dy,
22917    markdir=rlmode or 0,
22918    markbase=nofregisteredmarks,
22919    markbasenode=base,
22920    markmark=mkmk,
22921    checkmark=checkmark,
22922   },
22923  }
22924 end
22925 return dx,dy,nofregisteredmarks
22926end
22927local function dir(n)
22928 return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
22929end
22930local function showchar(n,nested)
22931 local char=getchar(n)
22932 report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char)
22933end
22934local function show(n,what,nested,symbol)
22935 if n then
22936  local p=rawget(properties,n)
22937  if p then
22938   local i=p[what]
22939   if i then
22940    local leftkern=i.leftkern  or 0
22941    local rightkern=i.rightkern or 0
22942    local yoffset=i.yoffset   or 0
22943    local markx=i.markx  or 0
22944    local marky=i.marky  or 0
22945    local markdir=i.markdir   or 0
22946    local markbase=i.markbase  or 0
22947    local cursivex=i.cursivex  or 0
22948    local cursivey=i.cursivey  or 0
22949    local ligaindex=i.ligaindex or 0
22950    local cursbase=i.cursiveanchor
22951    local margin=nested and 4 or 2
22952    if rightkern~=0 or yoffset~=0 then
22953     report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset)
22954    elseif leftkern~=0 then
22955     report_injections("%w%s kern: dx %p",margin,symbol,leftkern)
22956    end
22957    if markx~=0 or marky~=0 or markbase~=0 then
22958     report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase~=0 and "yes" or "no")
22959    end
22960    if cursivex~=0 or cursivey~=0 then
22961     if cursbase then
22962      report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey)
22963     else
22964      report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
22965     end
22966    elseif cursbase then
22967     report_injections("%w%s curs: base",margin,symbol)
22968    end
22969    if ligaindex~=0 then
22970     report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
22971    end
22972   end
22973  end
22974 end
22975end
22976local function showsub(n,what,where)
22977 report_injections("begin subrun: %s",where)
22978 for n in nextchar,n do
22979  showchar(n,where)
22980  show(n,what,where," ")
22981 end
22982 report_injections("end subrun")
22983end
22984local function trace(head,where)
22985 report_injections()
22986 report_injections("begin run %s: %s kerns, %s positions, %s marks and %s cursives registered",
22987  where or "",nofregisteredkerns,nofregisteredpositions,nofregisteredmarks,nofregisteredcursives)
22988 local n=head
22989 while n do
22990  local id=getid(n)
22991  if id==glyph_code then
22992   showchar(n)
22993   show(n,"injections",false," ")
22994   show(n,"preinjections",false,"<")
22995   show(n,"postinjections",false,">")
22996   show(n,"replaceinjections",false,"=")
22997   show(n,"emptyinjections",false,"*")
22998  elseif id==disc_code then
22999   local pre,post,replace=getdisc(n)
23000   if pre then
23001    showsub(pre,"preinjections","pre")
23002   end
23003   if post then
23004    showsub(post,"postinjections","post")
23005   end
23006   if replace then
23007    showsub(replace,"replaceinjections","replace")
23008   end
23009   show(n,"emptyinjections",false,"*")
23010  end
23011  n=getnext(n)
23012 end
23013 report_injections("end run")
23014end
23015local function show_result(head)
23016 local current=head
23017 local skipping=false
23018 while current do
23019  local id=getid(current)
23020  if id==glyph_code then
23021   local w=getwidth(current)
23022   local x,y=getoffsets(current)
23023   report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y)
23024   skipping=false
23025  elseif id==kern_code then
23026   report_injections("kern: %p",getkern(current))
23027   skipping=false
23028  elseif not skipping then
23029   report_injections()
23030   skipping=true
23031  end
23032  current=getnext(current)
23033 end
23034 report_injections()
23035end
23036local function inject_kerns_only(head,where)
23037 if trace_injections then
23038  trace(head,"kerns")
23039 end
23040 local current=head
23041 local prev=nil
23042 local next=nil
23043 local prevdisc=nil
23044 local pre=nil 
23045 local post=nil 
23046 local replace=nil 
23047 local pretail=nil 
23048 local posttail=nil 
23049 local replacetail=nil 
23050 while current do
23051  local next=getnext(current)
23052  local char,id=ischar(current)
23053  if char then
23054   local p=rawget(properties,current)
23055   if p then
23056    local i=p.injections
23057    if i then
23058     local leftkern=i.leftkern
23059     if leftkern and leftkern~=0 then
23060      if prev and getid(prev)==glue_code then
23061       if useitalickerns then
23062        head=insertnodebefore(head,current,italickern(leftkern))
23063       else
23064        setwidth(prev,getwidth(prev)+leftkern)
23065       end
23066      else
23067       head=insertnodebefore(head,current,fontkern(leftkern))
23068      end
23069     end
23070    end
23071    if prevdisc then
23072     local done=false
23073     if post then
23074      local i=p.postinjections
23075      if i then
23076       local leftkern=i.leftkern
23077       if leftkern and leftkern~=0 then
23078        setlink(posttail,fontkern(leftkern))
23079        done=true
23080       end
23081      end
23082     end
23083     if replace then
23084      local i=p.replaceinjections
23085      if i then
23086       local leftkern=i.leftkern
23087       if leftkern and leftkern~=0 then
23088        setlink(replacetail,fontkern(leftkern))
23089        done=true
23090       end
23091      end
23092     else
23093      local i=p.emptyinjections
23094      if i then
23095       local leftkern=i.leftkern
23096       if leftkern and leftkern~=0 then
23097        replace=fontkern(leftkern)
23098        done=true
23099       end
23100      end
23101     end
23102     if done then
23103      setdisc(prevdisc,pre,post,replace)
23104     end
23105    end
23106   end
23107   prevdisc=nil
23108  elseif char==false then
23109   prevdisc=nil
23110  elseif id==disc_code then
23111   pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
23112   local done=false
23113   if pre then
23114    for n in nextchar,pre do
23115     local p=rawget(properties,n)
23116     if p then
23117      local i=p.injections or p.preinjections
23118      if i then
23119       local leftkern=i.leftkern
23120       if leftkern and leftkern~=0 then
23121        pre=insertnodebefore(pre,n,fontkern(leftkern))
23122        done=true
23123       end
23124      end
23125     end
23126    end
23127   end
23128   if post then
23129    for n in nextchar,post do
23130     local p=rawget(properties,n)
23131     if p then
23132      local i=p.injections or p.postinjections
23133      if i then
23134       local leftkern=i.leftkern
23135       if leftkern and leftkern~=0 then
23136        post=insertnodebefore(post,n,fontkern(leftkern))
23137        done=true
23138       end
23139      end
23140     end
23141    end
23142   end
23143   if replace then
23144    for n in nextchar,replace do
23145     local p=rawget(properties,n)
23146     if p then
23147      local i=p.injections or p.replaceinjections
23148      if i then
23149       local leftkern=i.leftkern
23150       if leftkern and leftkern~=0 then
23151        replace=insertnodebefore(replace,n,fontkern(leftkern))
23152        done=true
23153       end
23154      end
23155     end
23156    end
23157   end
23158   if done then
23159    setdisc(current,pre,post,replace)
23160   end
23161   prevdisc=current
23162  else
23163   prevdisc=nil
23164  end
23165  prev=current
23166  current=next
23167 end
23168 if keepregisteredcounts then
23169  keepregisteredcounts=false
23170 else
23171  nofregisteredkerns=0
23172 end
23173 if trace_injections then
23174  show_result(head)
23175 end
23176 return head
23177end
23178local function inject_positions_only(head,where)
23179 if trace_injections then
23180  trace(head,"positions")
23181 end
23182 local current=head
23183 local prev=nil
23184 local next=nil
23185 local prevdisc=nil
23186 local prevglyph=nil
23187 local pre=nil 
23188 local post=nil 
23189 local replace=nil 
23190 local pretail=nil 
23191 local posttail=nil 
23192 local replacetail=nil 
23193 while current do
23194  local next=getnext(current)
23195  local char,id=ischar(current)
23196  if char then
23197   local p=rawget(properties,current)
23198   if p then
23199    local i=p.injections
23200    if i then
23201     local yoffset=i.yoffset
23202     if yoffset and yoffset~=0 then
23203      setoffsets(current,false,yoffset)
23204     end
23205     local leftkern=i.leftkern
23206     local rightkern=i.rightkern
23207     if leftkern and leftkern~=0 then
23208      if rightkern and leftkern==-rightkern then
23209       setoffsets(current,leftkern,false)
23210       rightkern=0
23211      elseif prev and getid(prev)==glue_code then
23212       if useitalickerns then
23213        head=insertnodebefore(head,current,italickern(leftkern))
23214       else
23215        setwidth(prev,getwidth(prev)+leftkern)
23216       end
23217      else
23218       head=insertnodebefore(head,current,fontkern(leftkern))
23219      end
23220     end
23221     if rightkern and rightkern~=0 then
23222      if next and getid(next)==glue_code then
23223       if useitalickerns then
23224        insertnodeafter(head,current,italickern(rightkern))
23225       else
23226        setwidth(next,getwidth(next)+rightkern)
23227       end
23228      else
23229       insertnodeafter(head,current,fontkern(rightkern))
23230      end
23231     end
23232    elseif next then
23233     local i=p.emptyinjections
23234     if i then
23235      local rightkern=i.rightkern
23236      if rightkern and rightkern~=0 and getid(next)==disc_code then
23237       local replace=getreplace(next)
23238       if replace then
23239       else
23240        setreplace(next,fontkern(rightkern))
23241       end
23242      end
23243     end
23244    end
23245    if prevdisc then
23246     local done=false
23247     if post then
23248      local i=p.postinjections
23249      if i then
23250       local leftkern=i.leftkern
23251       if leftkern and leftkern~=0 then
23252        setlink(posttail,fontkern(leftkern))
23253        done=true
23254       end
23255      end
23256     end
23257     if replace then
23258      local i=p.replaceinjections
23259      if i then
23260       local leftkern=i.leftkern
23261       if leftkern and leftkern~=0 then
23262        setlink(replacetail,fontkern(leftkern))
23263        done=true
23264       end
23265      end
23266     else
23267      local i=p.emptyinjections
23268      if i then
23269       local leftkern=i.leftkern
23270       if leftkern and leftkern~=0 then
23271        replace=fontkern(leftkern)
23272        done=true
23273       end
23274      end
23275     end
23276     if done then
23277      setdisc(prevdisc,pre,post,replace)
23278     end
23279    end
23280   end
23281   prevdisc=nil
23282   prevglyph=current
23283  elseif char==false then
23284   prevdisc=nil
23285   prevglyph=current
23286  elseif id==disc_code then
23287   pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
23288   local done=false
23289   if pre then
23290    for n in nextchar,pre do
23291     local p=rawget(properties,n)
23292     if p then
23293      local i=p.injections or p.preinjections
23294      if i then
23295       local yoffset=i.yoffset
23296       if yoffset and yoffset~=0 then
23297        setoffsets(n,false,yoffset)
23298       end
23299       local leftkern=i.leftkern
23300       if leftkern and leftkern~=0 then
23301        pre=insertnodebefore(pre,n,fontkern(leftkern))
23302        done=true
23303       end
23304       local rightkern=i.rightkern
23305       if rightkern and rightkern~=0 then
23306        insertnodeafter(pre,n,fontkern(rightkern))
23307        done=true
23308       end
23309      end
23310     end
23311    end
23312   end
23313   if post then
23314    for n in nextchar,post do
23315     local p=rawget(properties,n)
23316     if p then
23317      local i=p.injections or p.postinjections
23318      if i then
23319       local yoffset=i.yoffset
23320       if yoffset and yoffset~=0 then
23321        setoffsets(n,false,yoffset)
23322       end
23323       local leftkern=i.leftkern
23324       if leftkern and leftkern~=0 then
23325        post=insertnodebefore(post,n,fontkern(leftkern))
23326        done=true
23327       end
23328       local rightkern=i.rightkern
23329       if rightkern and rightkern~=0 then
23330        insertnodeafter(post,n,fontkern(rightkern))
23331        done=true
23332       end
23333      end
23334     end
23335    end
23336   end
23337   if replace then
23338    for n in nextchar,replace do
23339     local p=rawget(properties,n)
23340     if p then
23341      local i=p.injections or p.replaceinjections
23342      if i then
23343       local yoffset=i.yoffset
23344       if yoffset and yoffset~=0 then
23345        setoffsets(n,false,yoffset)
23346       end
23347       local leftkern=i.leftkern
23348       if leftkern and leftkern~=0 then
23349        replace=insertnodebefore(replace,n,fontkern(leftkern))
23350        done=true
23351       end
23352       local rightkern=i.rightkern
23353       if rightkern and rightkern~=0 then
23354        insertnodeafter(replace,n,fontkern(rightkern))
23355        done=true
23356       end
23357      end
23358     end
23359    end
23360   end
23361   if prevglyph then
23362    if pre then
23363     local p=rawget(properties,prevglyph)
23364     if p then
23365      local i=p.preinjections
23366      if i then
23367       local rightkern=i.rightkern
23368       if rightkern and rightkern~=0 then
23369        pre=insertnodebefore(pre,pre,fontkern(rightkern))
23370        done=true
23371       end
23372      end
23373     end
23374    end
23375    if replace then
23376     local p=rawget(properties,prevglyph)
23377     if p then
23378      local i=p.replaceinjections
23379      if i then
23380       local rightkern=i.rightkern
23381       if rightkern and rightkern~=0 then
23382        replace=insertnodebefore(replace,replace,fontkern(rightkern))
23383        done=true
23384       end
23385      end
23386     end
23387    end
23388   end
23389   if done then
23390    setdisc(current,pre,post,replace)
23391   end
23392   prevglyph=nil
23393   prevdisc=current
23394  else
23395   prevglyph=nil
23396   prevdisc=nil
23397  end
23398  prev=current
23399  current=next
23400 end
23401 if keepregisteredcounts then
23402  keepregisteredcounts=false
23403 else
23404  nofregisteredpositions=0
23405 end
23406 if trace_injections then
23407  show_result(head)
23408 end
23409 return head
23410end
23411local function showoffset(n,flag)
23412 local x,y=getoffsets(n)
23413 if x~=0 or y~=0 then
23414  setcolor(n,"darkgray")
23415 end
23416end
23417local function inject_everything(head,where)
23418 if trace_injections then
23419  trace(head,"everything")
23420 end
23421 local hascursives=nofregisteredcursives>0
23422 local hasmarks=nofregisteredmarks>0
23423 local current=head
23424 local last=nil
23425 local prev=nil
23426 local next=nil
23427 local prevdisc=nil
23428 local prevglyph=nil
23429 local pre=nil 
23430 local post=nil 
23431 local replace=nil 
23432 local pretail=nil 
23433 local posttail=nil 
23434 local replacetail=nil
23435 local cursiveanchor=nil
23436 local minc=0
23437 local maxc=0
23438 local glyphs={}
23439 local marks={}
23440 local nofmarks=0
23441 local function processmark(p,n,pn) 
23442  local px,py=getoffsets(p)
23443  local nx,ny=getoffsets(n)
23444  local ox=0
23445  local rightkern=nil
23446  local pp=rawget(properties,p)
23447  if pp then
23448   pp=pp.injections
23449   if pp then
23450    rightkern=pp.rightkern
23451   end
23452  end
23453  local markdir=pn.markdir
23454  if rightkern then 
23455   ox=px-(pn.markx or 0)-rightkern
23456   if markdir and markdir<0 then
23457    if not pn.markmark then
23458     ox=ox+(pn.leftkern or 0)
23459    end
23460   else
23461    if false then
23462     local leftkern=pp.leftkern
23463     if leftkern then
23464      ox=ox-leftkern
23465     end
23466    end
23467   end
23468  else
23469   ox=px-(pn.markx or 0)
23470   if markdir and markdir<0 then
23471    if not pn.markmark then
23472     local leftkern=pn.leftkern
23473     if leftkern then
23474      ox=ox+leftkern 
23475     end
23476    end
23477   end
23478   if pn.checkmark then
23479    local wn=getwidth(n) 
23480    if wn and wn~=0 then
23481     wn=wn/2
23482     if trace_injections then
23483      report_injections("correcting non zero width mark %C",getchar(n))
23484     end
23485     insertnodebefore(n,n,fontkern(-wn))
23486     insertnodeafter(n,n,fontkern(-wn))
23487    end
23488   end
23489  end
23490  local oy=ny+py+(pn.marky or 0)
23491  if not pn.markmark then
23492   local yoffset=pn.yoffset
23493   if yoffset then
23494    oy=oy+yoffset 
23495   end
23496  end
23497  setoffsets(n,ox,oy)
23498  if trace_marks then
23499   showoffset(n,true)
23500  end
23501 end
23502 while current do
23503  local next=getnext(current)
23504  local char,id=ischar(current)
23505  if char then
23506   local p=rawget(properties,current)
23507   if p then
23508    local i=p.injections
23509    if i then
23510     local pm=i.markbasenode
23511     if pm then
23512      nofmarks=nofmarks+1
23513      marks[nofmarks]=current
23514     else
23515      local yoffset=i.yoffset
23516      if yoffset and yoffset~=0 then
23517       setoffsets(current,false,yoffset)
23518      end
23519      if hascursives then
23520       local cursivex=i.cursivex
23521       if cursivex then
23522        if cursiveanchor then
23523         if cursivex~=0 then
23524          i.leftkern=(i.leftkern or 0)+cursivex
23525         end
23526         if maxc==0 then
23527          minc=1
23528          maxc=1
23529          glyphs[1]=cursiveanchor
23530         else
23531          maxc=maxc+1
23532          glyphs[maxc]=cursiveanchor
23533         end
23534         properties[cursiveanchor].cursivedy=i.cursivey 
23535         last=current
23536        else
23537         maxc=0
23538        end
23539       elseif maxc>0 then
23540        local nx,ny=getoffsets(current)
23541        for i=maxc,minc,-1 do
23542         local ti=glyphs[i]
23543         ny=ny+properties[ti].cursivedy
23544         setoffsets(ti,false,ny) 
23545         if trace_cursive then
23546          showoffset(ti)
23547         end
23548        end
23549        maxc=0
23550        cursiveanchor=nil
23551       end
23552       if i.cursiveanchor then
23553        cursiveanchor=current 
23554       else
23555        if maxc>0 then
23556         local nx,ny=getoffsets(current)
23557         for i=maxc,minc,-1 do
23558          local ti=glyphs[i]
23559          ny=ny+properties[ti].cursivedy
23560          setoffsets(ti,false,ny) 
23561          if trace_cursive then
23562           showoffset(ti)
23563          end
23564         end
23565         maxc=0
23566        end
23567        cursiveanchor=nil
23568       end
23569      end
23570      local leftkern=i.leftkern
23571      local rightkern=i.rightkern
23572      if leftkern and leftkern~=0 then
23573       if rightkern and leftkern==-rightkern then
23574        setoffsets(current,leftkern,false)
23575        rightkern=0
23576       elseif prev and getid(prev)==glue_code then
23577        if useitalickerns then
23578         head=insertnodebefore(head,current,italickern(leftkern))
23579        else
23580         setwidth(prev,getwidth(prev)+leftkern)
23581        end
23582       else
23583        head=insertnodebefore(head,current,fontkern(leftkern))
23584       end
23585      end
23586      if rightkern and rightkern~=0 then
23587       if next and getid(next)==glue_code then
23588        if useitalickerns then
23589         insertnodeafter(head,current,italickern(rightkern))
23590        else
23591         setwidth(next,getwidth(next)+rightkern)
23592        end
23593       else
23594        insertnodeafter(head,current,fontkern(rightkern))
23595       end
23596      end
23597     end
23598    elseif next then
23599     local i=p.emptyinjections
23600     if i then
23601      local rightkern=i.rightkern
23602      if rightkern and rightkern~=0 and getid(next)==disc_code then
23603       local replace=getreplace(next)
23604       if replace then
23605       else
23606        setreplace(next,fontkern(rightkern))
23607       end
23608      end
23609     end
23610    end
23611    if prevdisc then
23612     if p then
23613      local done=false
23614      if post then
23615       local i=p.postinjections
23616       if i then
23617        local leftkern=i.leftkern
23618        if leftkern and leftkern~=0 then
23619         setlink(posttail,fontkern(leftkern))
23620         done=true
23621        end
23622       end
23623      end
23624      if replace then
23625       local i=p.replaceinjections
23626       if i then
23627        local leftkern=i.leftkern
23628        if leftkern and leftkern~=0 then
23629         setlink(replacetail,fontkern(leftkern))
23630         done=true
23631        end
23632       end
23633      else
23634       local i=p.emptyinjections
23635       if i then
23636        local leftkern=i.leftkern
23637        if leftkern and leftkern~=0 then
23638         replace=fontkern(leftkern)
23639         done=true
23640        end
23641       end
23642      end
23643      if done then
23644       setdisc(prevdisc,pre,post,replace)
23645      end
23646     end
23647    end
23648   else
23649    if hascursives and maxc>0 then
23650     local nx,ny=getoffsets(current)
23651     for i=maxc,minc,-1 do
23652      local ti=glyphs[i]
23653      ny=ny+properties[ti].cursivedy
23654      local xi,yi=getoffsets(ti)
23655      setoffsets(ti,xi,yi+ny) 
23656     end
23657     maxc=0
23658     cursiveanchor=nil
23659    end
23660   end
23661   prevdisc=nil
23662   prevglyph=current
23663  elseif char==false then
23664   prevdisc=nil
23665   prevglyph=current
23666  elseif id==disc_code then
23667   pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
23668   local done=false
23669   if pre then
23670    for n in nextchar,pre do
23671     local p=rawget(properties,n)
23672     if p then
23673      local i=p.injections or p.preinjections
23674      if i then
23675       local yoffset=i.yoffset
23676       if yoffset and yoffset~=0 then
23677        setoffsets(n,false,yoffset)
23678       end
23679       local leftkern=i.leftkern
23680       if leftkern and leftkern~=0 then
23681        pre=insertnodebefore(pre,n,fontkern(leftkern))
23682        done=true
23683       end
23684       local rightkern=i.rightkern
23685       if rightkern and rightkern~=0 then
23686        insertnodeafter(pre,n,fontkern(rightkern))
23687        done=true
23688       end
23689       if hasmarks then
23690        local pm=i.markbasenode
23691        if pm then
23692         processmark(pm,n,i)
23693        end
23694       end
23695      end
23696     end
23697    end
23698   end
23699   if post then
23700    for n in nextchar,post do
23701     local p=rawget(properties,n)
23702     if p then
23703      local i=p.injections or p.postinjections
23704      if i then
23705       local yoffset=i.yoffset
23706       if yoffset and yoffset~=0 then
23707        setoffsets(n,false,yoffset)
23708       end
23709       local leftkern=i.leftkern
23710       if leftkern and leftkern~=0 then
23711        post=insertnodebefore(post,n,fontkern(leftkern))
23712        done=true
23713       end
23714       local rightkern=i.rightkern
23715       if rightkern and rightkern~=0 then
23716        insertnodeafter(post,n,fontkern(rightkern))
23717        done=true
23718       end
23719       if hasmarks then
23720        local pm=i.markbasenode
23721        if pm then
23722         processmark(pm,n,i)
23723        end
23724       end
23725      end
23726     end
23727    end
23728   end
23729   if replace then
23730    for n in nextchar,replace do
23731     local p=rawget(properties,n)
23732     if p then
23733      local i=p.injections or p.replaceinjections
23734      if i then
23735       local yoffset=i.yoffset
23736       if yoffset and yoffset~=0 then
23737        setoffsets(n,false,yoffset)
23738       end
23739       local leftkern=i.leftkern
23740       if leftkern and leftkern~=0 then
23741        replace=insertnodebefore(replace,n,fontkern(leftkern))
23742        done=true
23743       end
23744       local rightkern=i.rightkern
23745       if rightkern and rightkern~=0 then
23746        insertnodeafter(replace,n,fontkern(rightkern))
23747        done=true
23748       end
23749       if hasmarks then
23750        local pm=i.markbasenode
23751        if pm then
23752         processmark(pm,n,i)
23753        end
23754       end
23755      end
23756     end
23757    end
23758   end
23759   if prevglyph then
23760    if pre then
23761     local p=rawget(properties,prevglyph)
23762     if p then
23763      local i=p.preinjections
23764      if i then
23765       local rightkern=i.rightkern
23766       if rightkern and rightkern~=0 then
23767        pre=insertnodebefore(pre,pre,fontkern(rightkern))
23768        done=true
23769       end
23770      end
23771     end
23772    end
23773    if replace then
23774     local p=rawget(properties,prevglyph)
23775     if p then
23776      local i=p.replaceinjections
23777      if i then
23778       local rightkern=i.rightkern
23779       if rightkern and rightkern~=0 then
23780        replace=insertnodebefore(replace,replace,fontkern(rightkern))
23781        done=true
23782       end
23783      end
23784     end
23785    end
23786   end
23787   if done then
23788    setdisc(current,pre,post,replace)
23789   end
23790   prevglyph=nil
23791   prevdisc=current
23792  else
23793   prevglyph=nil
23794   prevdisc=nil
23795  end
23796  prev=current
23797  current=next
23798 end
23799 if hascursives and maxc>0 then
23800  local nx,ny=getoffsets(last)
23801  for i=maxc,minc,-1 do
23802   local ti=glyphs[i]
23803   ny=ny+properties[ti].cursivedy
23804   setoffsets(ti,false,ny) 
23805   if trace_cursive then
23806    showoffset(ti)
23807   end
23808  end
23809 end
23810 if nofmarks>0 then
23811  for i=1,nofmarks do
23812   local m=marks[i]
23813   local p=rawget(properties,m)
23814   local i=p.injections
23815   local b=i.markbasenode
23816   processmark(b,m,i)
23817  end
23818 elseif hasmarks then
23819 end
23820 if keepregisteredcounts then
23821  keepregisteredcounts=false
23822 else
23823  nofregisteredkerns=0
23824  nofregisteredpositions=0
23825  nofregisteredmarks=0
23826  nofregisteredcursives=0
23827 end
23828 if trace_injections then
23829  show_result(head)
23830 end
23831 return head
23832end
23833local triggers=false
23834function nodes.injections.setspacekerns(font,sequence)
23835 if triggers then
23836  triggers[font]=sequence
23837 else
23838  triggers={ [font]=sequence }
23839 end
23840end
23841local getthreshold
23842if context then
23843
23844--removed
23845
23846else
23847 injections.threshold=0
23848 getthreshold=function(font)
23849  local p=fontdata[font].parameters
23850  local f=p.factor
23851  local s=p.spacing
23852  local t=injections.threshold*(s and s.width or p.space or 0)-2
23853  return t>0 and t or 0,f
23854 end
23855end
23856injections.getthreshold=getthreshold
23857function injections.isspace(n,threshold,id)
23858 if (id or getid(n))==glue_code then
23859  local w=getwidth(n)
23860  if threshold and w>threshold then 
23861   return 32
23862  end
23863 end
23864end
23865local getspaceboth=getboth
23866function injections.installgetspaceboth(gb)
23867 getspaceboth=gb or getboth
23868end
23869local function injectspaces(head)
23870 if not triggers then
23871  return head
23872 end
23873 local lastfont=nil
23874 local spacekerns=nil
23875 local leftkerns=nil
23876 local rightkerns=nil
23877 local factor=0
23878 local threshold=0
23879 local leftkern=false
23880 local rightkern=false
23881 local function updatefont(font,trig)
23882  leftkerns=trig.left
23883  rightkerns=trig.right
23884  lastfont=font
23885  threshold,
23886  factor=getthreshold(font)
23887 end
23888 for n in nextglue,head do
23889  local prev,next=getspaceboth(n)
23890  local prevchar=prev and ischar(prev)
23891  local nextchar=next and ischar(next)
23892  if nextchar then
23893   local font=getfont(next)
23894   local trig=triggers[font]
23895   if trig then
23896    if lastfont~=font then
23897     updatefont(font,trig)
23898    end
23899    if rightkerns then
23900     rightkern=rightkerns[nextchar]
23901    end
23902   end
23903  end
23904  if prevchar then
23905   local font=getfont(prev)
23906   local trig=triggers[font]
23907   if trig then
23908    if lastfont~=font then
23909     updatefont(font,trig)
23910    end
23911    if leftkerns then
23912     leftkern=leftkerns[prevchar]
23913    end
23914   end
23915  end
23916  if leftkern then
23917   local old=getwidth(n)
23918   if old>threshold then
23919    if rightkern then
23920     if useitalickerns then
23921      local lnew=leftkern*factor
23922      local rnew=rightkern*factor
23923      if trace_spaces then
23924       report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
23925      end
23926      head=insertnodebefore(head,n,italickern(lnew))
23927      insertnodeafter(head,n,italickern(rnew))
23928     else
23929      local new=old+(leftkern+rightkern)*factor
23930      if trace_spaces then
23931       report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
23932      end
23933      setwidth(n,new)
23934     end
23935     rightkern=false
23936    else
23937     if useitalickerns then
23938      local new=leftkern*factor
23939      if trace_spaces then
23940       report_spaces("%C [%p + %p]",prevchar,old,new)
23941      end
23942      insertnodeafter(head,n,italickern(new)) 
23943     else
23944      local new=old+leftkern*factor
23945      if trace_spaces then
23946       report_spaces("%C [%p -> %p]",prevchar,old,new)
23947      end
23948      setwidth(n,new)
23949     end
23950    end
23951   end
23952   leftkern=false
23953  elseif rightkern then
23954   local old=getwidth(n)
23955   if old>threshold then
23956    if useitalickerns then
23957     local new=rightkern*factor
23958     if trace_spaces then
23959      report_spaces("[%p + %p] %C",old,new,nextchar)
23960     end
23961     insertnodeafter(head,n,italickern(new))
23962    else
23963     local new=old+rightkern*factor
23964     if trace_spaces then
23965      report_spaces("[%p -> %p] %C",old,new,nextchar)
23966     end
23967     setwidth(n,new)
23968    end
23969   else
23970   end
23971   rightkern=false
23972  end
23973 end
23974 triggers=false
23975 return head
23976end
23977function injections.handler(head,where)
23978 if triggers then
23979  head=injectspaces(head)
23980 end
23981 if nofregisteredmarks>0 or nofregisteredcursives>0 then
23982  if trace_injections then
23983   report_injections("injection variant %a","everything")
23984  end
23985  return inject_everything(head,where)
23986 elseif nofregisteredpositions>0 then
23987  if trace_injections then
23988   report_injections("injection variant %a","positions")
23989  end
23990  return inject_positions_only(head,where)
23991 elseif nofregisteredkerns>0 then
23992  if trace_injections then
23993   report_injections("injection variant %a","kerns")
23994  end
23995  return inject_kerns_only(head,where)
23996 else
23997  return head
23998 end
23999end
24000
24001end -- closure
24002
24003do -- begin closure to overcome local limits and interference
24004
24005if not modules then modules={} end modules ['font-oup']={
24006 version=1.001,
24007 comment="companion to font-ini.mkiv",
24008 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
24009 copyright="PRAGMA ADE / ConTeXt Development Team",
24010 license="see context related readme files"
24011}
24012local next,type=next,type
24013local P,R,S=lpeg.P,lpeg.R,lpeg.S
24014local lpegmatch=lpeg.match
24015local insert,remove,copy,unpack=table.insert,table.remove,table.copy,table.unpack
24016local find=string.find
24017local formatters=string.formatters
24018local sortedkeys=table.sortedkeys
24019local sortedhash=table.sortedhash
24020local tohash=table.tohash
24021local setmetatableindex=table.setmetatableindex
24022local report_error=logs.reporter("otf reader","error")
24023local report_markwidth=logs.reporter("otf reader","markwidth")
24024local report_cleanup=logs.reporter("otf reader","cleanup")
24025local report_optimizations=logs.reporter("otf reader","merges")
24026local report_unicodes=logs.reporter("otf reader","unicodes")
24027local trace_markwidth=false  trackers.register("otf.markwidth",function(v) trace_markwidth=v end)
24028local trace_cleanup=false  trackers.register("otf.cleanups",function(v) trace_cleanups=v end)
24029local trace_optimizations=false  trackers.register("otf.optimizations",function(v) trace_optimizations=v end)
24030local trace_unicodes=false  trackers.register("otf.unicodes",function(v) trace_unicodes=v end)
24031local readers=fonts.handlers.otf.readers
24032local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 
24033local f_private=formatters["P%05X"]
24034local f_unicode=formatters["U%05X"]
24035local f_index=formatters["I%05X"]
24036local f_character_y=formatters["%C"]
24037local f_character_n=formatters["[ %C ]"]
24038local check_duplicates=true 
24039local check_soft_hyphen=context 
24040directives.register("otf.checksofthyphen",function(v)
24041 check_soft_hyphen=v 
24042end)
24043local function replaced(list,index,replacement)
24044 if type(list)=="number" then
24045  return replacement
24046 elseif type(replacement)=="table" then
24047  local t={}
24048  local n=index-1
24049  for i=1,n do
24050   t[i]=list[i]
24051  end
24052  for i=1,#replacement do
24053   n=n+1
24054   t[n]=replacement[i]
24055  end
24056  for i=index+1,#list do
24057   n=n+1
24058   t[n]=list[i]
24059  end
24060 else
24061  list[index]=replacement
24062  return list
24063 end
24064end
24065local function unifyresources(fontdata,indices)
24066 local descriptions=fontdata.descriptions
24067 local resources=fontdata.resources
24068 if not descriptions or not resources then
24069  return
24070 end
24071 local nofindices=#indices
24072 local variants=fontdata.resources.variants
24073 if variants then
24074  for selector,unicodes in next,variants do
24075   for unicode,index in next,unicodes do
24076    unicodes[unicode]=indices[index]
24077   end
24078  end
24079 end
24080 local function remark(marks)
24081  if marks then
24082   local newmarks={}
24083   for k,v in next,marks do
24084    local u=indices[k]
24085    if u then
24086     newmarks[u]=v
24087    elseif trace_optimizations then
24088     report_optimizations("discarding mark %i",k)
24089    end
24090   end
24091   return newmarks
24092  end
24093 end
24094 local marks=resources.marks
24095 if marks then
24096  resources.marks=remark(marks)
24097 end
24098 local markclasses=resources.markclasses
24099 if markclasses then
24100  for class,marks in next,markclasses do
24101   markclasses[class]=remark(marks)
24102  end
24103 end
24104 local marksets=resources.marksets
24105 if marksets then
24106  for class,marks in next,marksets do
24107   marksets[class]=remark(marks)
24108  end
24109 end
24110 local done={}
24111 local duplicates=check_duplicates and resources.duplicates
24112 if duplicates and not next(duplicates) then
24113  duplicates=false
24114 end
24115 local function recover(cover) 
24116  for i=1,#cover do
24117   local c=cover[i]
24118   if not done[c] then
24119    local t={}
24120    for k,v in next,c do
24121     local ug=indices[k]
24122     if ug then
24123      t[ug]=v
24124     else
24125      report_error("case %i, bad index in unifying %s: %s of %s",1,"coverage",k,nofindices)
24126     end
24127    end
24128    cover[i]=t
24129    done[c]=d
24130   end
24131  end
24132 end
24133 local function recursed(c,kind) 
24134  local t={}
24135  for g,d in next,c do
24136   if type(d)=="table" then
24137    local ug=indices[g]
24138    if ug then
24139     t[ug]=recursed(d,kind)
24140    else
24141     report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g,nofindices)
24142    end
24143   else
24144    t[g]=indices[d] 
24145   end
24146  end
24147  return t
24148 end
24149 local function unifythem(sequences)
24150  if not sequences then
24151   return
24152  end
24153  for i=1,#sequences do
24154   local sequence=sequences[i]
24155   local kind=sequence.type
24156   local steps=sequence.steps
24157   local features=sequence.features
24158   if steps then
24159    for i=1,#steps do
24160     local step=steps[i]
24161     if kind=="gsub_single" then
24162      local c=step.coverage
24163      if c then
24164       local t1=done[c]
24165       if not t1 then
24166        t1={}
24167        if duplicates then
24168         for g1,d1 in next,c do
24169          local ug1=indices[g1]
24170          if ug1 then
24171           local ud1=indices[d1]
24172           if ud1 then
24173            t1[ug1]=ud1
24174            local dg1=duplicates[ug1]
24175            if dg1 then
24176             for u in next,dg1 do
24177              t1[u]=ud1
24178             end
24179            end
24180           else
24181            report_error("case %i, bad index in unifying %s: %s of %s",3,kind,d1,nofindices)
24182           end
24183          else
24184           report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
24185          end
24186         end
24187        else
24188         for g1,d1 in next,c do
24189          local ug1=indices[g1]
24190          if ug1 then
24191           t1[ug1]=indices[d1]
24192          else
24193           report_error("fuzzy case %i in unifying %s: %i",2,kind,g1)
24194          end
24195         end
24196        end
24197        done[c]=t1
24198       end
24199       step.coverage=t1
24200      end
24201     elseif kind=="gpos_pair" then
24202      local c=step.coverage
24203      if c then
24204       local t1=done[c]
24205       if not t1 then
24206        t1={}
24207        for g1,d1 in next,c do
24208         local ug1=indices[g1]
24209         if ug1 then
24210          local t2=done[d1]
24211          if not t2 then
24212           t2={}
24213           for g2,d2 in next,d1 do
24214            local ug2=indices[g2]
24215            if ug2 then
24216             t2[ug2]=d2
24217            else
24218             report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g2,nofindices,nofindices)
24219            end
24220           end
24221           done[d1]=t2
24222          end
24223          t1[ug1]=t2
24224         else
24225          report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
24226         end
24227        end
24228        done[c]=t1
24229       end
24230       step.coverage=t1
24231      end
24232     elseif kind=="gsub_ligature" then
24233      local c=step.coverage
24234      if c then
24235       step.coverage=recursed(c,kind)
24236      end
24237     elseif kind=="gsub_alternate" or kind=="gsub_multiple" then
24238      local c=step.coverage
24239      if c then
24240       local t1=done[c]
24241       if not t1 then
24242        t1={}
24243        if duplicates then
24244         for g1,d1 in next,c do
24245          for i=1,#d1 do
24246           local d1i=d1[i]
24247           local d1u=indices[d1i]
24248           if d1u then
24249            d1[i]=d1u
24250           else
24251            report_error("case %i, bad index in unifying %s: %s of %s",1,kind,i,d1i,nofindices)
24252           end
24253          end
24254          local ug1=indices[g1]
24255          if ug1 then
24256           t1[ug1]=d1
24257           local dg1=duplicates[ug1]
24258           if dg1 then
24259            for u in next,dg1 do
24260             t1[u]=copy(d1)
24261            end
24262           end
24263          else
24264           report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
24265          end
24266         end
24267        else
24268         for g1,d1 in next,c do
24269          for i=1,#d1 do
24270           local d1i=d1[i]
24271           local d1u=indices[d1i]
24272           if d1u then
24273            d1[i]=d1u
24274           else
24275            report_error("case %i, bad index in unifying %s: %s of %s",2,kind,d1i,nofindices)
24276           end
24277          end
24278          t1[indices[g1]]=d1
24279         end
24280        end
24281        done[c]=t1
24282       end
24283       step.coverage=t1
24284      end
24285     elseif kind=="gpos_single" then
24286      local c=step.coverage
24287      if c then
24288       local t1=done[c]
24289       if not t1 then
24290        t1={}
24291        if duplicates then
24292         for g1,d1 in next,c do
24293          local ug1=indices[g1]
24294          if ug1 then
24295           t1[ug1]=d1
24296           local dg1=duplicates[ug1]
24297           if dg1 then
24298            for u in next,dg1 do
24299             t1[u]=d1
24300            end
24301           end
24302          else
24303           report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
24304          end
24305         end
24306        else
24307         for g1,d1 in next,c do
24308          local ug1=indices[g1]
24309          if ug1 then
24310           t1[ug1]=d1
24311          else
24312           report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
24313          end
24314         end
24315        end
24316        done[c]=t1
24317       end
24318       step.coverage=t1
24319      end
24320     elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" or kind=="gpos_mark2ligature" then
24321      local c=step.coverage
24322      if c then
24323       local t1=done[c]
24324       if not t1 then
24325        t1={}
24326        for g1,d1 in next,c do
24327         local ug1=indices[g1]
24328         if ug1 then
24329          t1[ug1]=d1
24330         else
24331          report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
24332         end
24333        end
24334        done[c]=t1
24335       end
24336       step.coverage=t1
24337      end
24338      local c=step.baseclasses
24339      if c then
24340       local t1=done[c]
24341       if not t1 then
24342        for g1,d1 in next,c do
24343         local t2=done[d1]
24344         if not t2 then
24345          t2={}
24346          for g2,d2 in next,d1 do
24347           local ug2=indices[g2]
24348           if ug2 then
24349            t2[ug2]=d2
24350           else
24351            report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g2,nofindices)
24352           end
24353          end
24354          done[d1]=t2
24355         end
24356         c[g1]=t2
24357        end
24358        done[c]=c
24359       end
24360      end
24361     elseif kind=="gpos_cursive" then
24362      local c=step.coverage
24363      if c then
24364       local t1=done[c]
24365       if not t1 then
24366        t1={}
24367        if duplicates then
24368         for g1,d1 in next,c do
24369          local ug1=indices[g1]
24370          if ug1 then
24371           t1[ug1]=d1
24372           local dg1=duplicates[ug1]
24373           if dg1 then
24374            for u in next,dg1 do
24375             t1[u]=copy(d1)
24376            end
24377           end
24378          else
24379           report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices)
24380          end
24381         end
24382        else
24383         for g1,d1 in next,c do
24384          local ug1=indices[g1]
24385          if ug1 then
24386           t1[ug1]=d1
24387          else
24388           report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices)
24389          end
24390         end
24391        end
24392        done[c]=t1
24393       end
24394       step.coverage=t1
24395      end
24396     end
24397     local rules=step.rules
24398     if rules then
24399      for i=1,#rules do
24400       local rule=rules[i]
24401       local before=rule.before   if before  then recover(before)  end
24402       local after=rule.after if after   then recover(after)   end
24403       local current=rule.current  if current then recover(current) end
24404       local replacements=rule.replacements
24405       if replacements then
24406        if not done[replacements] then
24407         local r={}
24408         for k,v in next,replacements do
24409          r[indices[k]]=indices[v]
24410         end
24411         rule.replacements=r
24412         done[replacements]=r
24413        end
24414       end
24415      end
24416     end
24417    end
24418   end
24419    end
24420 end
24421 unifythem(resources.sequences)
24422 unifythem(resources.sublookups)
24423end
24424local function copyduplicates(fontdata)
24425 if check_duplicates then
24426  local descriptions=fontdata.descriptions
24427  local resources=fontdata.resources
24428  local duplicates=resources.duplicates
24429  if check_soft_hyphen then
24430   local dh=descriptions[0x2D]
24431   if dh then
24432    local ds=descriptions[0xAD]
24433    if not ds or ds.width~=dh.width then
24434     descriptions[0xAD]=nil
24435     if ds then
24436      if trace_unicodes then
24437       report_unicodes("patching soft hyphen")
24438      end
24439     else
24440      if trace_unicodes then
24441       report_unicodes("adding soft hyphen")
24442      end
24443     end
24444     if not duplicates then
24445      duplicates={}
24446      resources.duplicates=duplicates
24447     end
24448     local d=duplicates[0x2D]
24449     if d then
24450      d[0xAD]=true
24451     else
24452      duplicates[0x2D]={ [0xAD]=true }
24453     end
24454    end
24455   end
24456  end
24457  if duplicates then
24458     for u,d in next,duplicates do
24459    local du=descriptions[u]
24460    if du then
24461     local t={ f_character_y(u),"@",f_index(du.index),"->" }
24462     local n=0
24463     local m=25
24464     for u in next,d do
24465      if descriptions[u] then
24466       if n<m then
24467        t[n+4]=f_character_n(u)
24468       end
24469      else
24470       local c=copy(du)
24471       c.unicode=u 
24472       descriptions[u]=c
24473       if n<m then
24474        t[n+4]=f_character_y(u)
24475       end
24476      end
24477      n=n+1
24478     end
24479     if trace_unicodes then
24480      if n<=m then
24481       report_unicodes("%i : % t",n,t)
24482      else
24483       report_unicodes("%i : % t ...",n,t)
24484      end
24485     end
24486    else
24487    end
24488   end
24489  end
24490 end
24491end
24492local ignore={ 
24493 ["notdef"]=true,
24494 [".notdef"]=true,
24495 ["null"]=true,
24496 [".null"]=true,
24497 ["nonmarkingreturn"]=true,
24498}
24499local function checklookups(fontdata,missing,nofmissing)
24500 local descriptions=fontdata.descriptions
24501 local resources=fontdata.resources
24502 if missing and nofmissing and nofmissing<=0 then
24503  return
24504 end
24505 local singles={}
24506 local alternates={}
24507 local ligatures={}
24508 if not missing then
24509  missing={}
24510  nofmissing=0
24511  for u,d in next,descriptions do
24512   if not d.unicode then
24513    nofmissing=nofmissing+1
24514    missing[u]=true
24515   end
24516  end
24517 end
24518 local function collectthem(sequences)
24519  if not sequences then
24520   return
24521  end
24522  for i=1,#sequences do
24523   local sequence=sequences[i]
24524   local kind=sequence.type
24525   local steps=sequence.steps
24526   if steps then
24527    for i=1,#steps do
24528     local step=steps[i]
24529     if kind=="gsub_single" then
24530      local c=step.coverage
24531      if c then
24532       singles[#singles+1]=c
24533      end
24534     elseif kind=="gsub_alternate" then
24535      local c=step.coverage
24536      if c then
24537       alternates[#alternates+1]=c
24538      end
24539     elseif kind=="gsub_ligature" then
24540      local c=step.coverage
24541      if c then
24542       ligatures[#ligatures+1]=c
24543      end
24544     end
24545    end
24546   end
24547  end
24548 end
24549 collectthem(resources.sequences)
24550 collectthem(resources.sublookups)
24551 local loops=0
24552 while true do
24553  loops=loops+1
24554  local old=nofmissing
24555  for i=1,#singles do
24556   local c=singles[i]
24557   for g1,g2 in next,c do
24558    if missing[g1] then
24559     local u2=descriptions[g2].unicode
24560     if u2 then
24561      missing[g1]=false
24562      descriptions[g1].unicode=u2
24563      nofmissing=nofmissing-1
24564     end
24565    end
24566    if missing[g2] then
24567     local u1=descriptions[g1].unicode
24568     if u1 then
24569      missing[g2]=false
24570      descriptions[g2].unicode=u1
24571      nofmissing=nofmissing-1
24572     end
24573    end
24574   end
24575  end
24576  for i=1,#alternates do
24577   local c=alternates[i]
24578   for g1,d1 in next,c do
24579    if missing[g1] then
24580     for i=1,#d1 do
24581      local g2=d1[i]
24582      local u2=descriptions[g2].unicode
24583      if u2 then
24584       missing[g1]=false
24585       descriptions[g1].unicode=u2
24586       nofmissing=nofmissing-1
24587      end
24588     end
24589    end
24590    if not missing[g1] then
24591     for i=1,#d1 do
24592      local g2=d1[i]
24593      if missing[g2] then
24594       local u1=descriptions[g1].unicode
24595       if u1 then
24596        missing[g2]=false
24597        descriptions[g2].unicode=u1
24598        nofmissing=nofmissing-1
24599       end
24600      end
24601     end
24602    end
24603   end
24604  end
24605  if nofmissing<=0 then
24606   if trace_unicodes then
24607    report_unicodes("all missings done in %s loops",loops)
24608   end
24609   return
24610  elseif old==nofmissing then
24611   break
24612  end
24613 end
24614 local t,n 
24615 local function recursed(c)
24616  for g,d in next,c do
24617   if g~="ligature" then
24618    local u=descriptions[g].unicode
24619    if u then
24620     n=n+1
24621     t[n]=u
24622     recursed(d)
24623     n=n-1
24624    end
24625   elseif missing[d] then
24626    local l={}
24627    local m=0
24628    for i=1,n do
24629     local u=t[i]
24630     if type(u)=="table" then
24631      for i=1,#u do
24632       m=m+1
24633       l[m]=u[i]
24634      end
24635     else
24636      m=m+1
24637      l[m]=u
24638     end
24639    end
24640    missing[d]=false
24641    descriptions[d].unicode=l
24642    nofmissing=nofmissing-1
24643   end
24644  end
24645 end
24646 if nofmissing>0 then
24647  t={}
24648  n=0
24649  local loops=0
24650  while true do
24651   loops=loops+1
24652   local old=nofmissing
24653   for i=1,#ligatures do
24654    recursed(ligatures[i])
24655   end
24656   if nofmissing<=0 then
24657    if trace_unicodes then
24658     report_unicodes("all missings done in %s loops",loops)
24659    end
24660    return
24661   elseif old==nofmissing then
24662    break
24663   end
24664  end
24665  t=nil
24666  n=0
24667 end
24668 if trace_unicodes and nofmissing>0 then
24669  local done={}
24670  for i,r in next,missing do
24671   if r then
24672    local data=descriptions[i]
24673    local name=data and data.name or f_index(i)
24674    if not ignore[name] then
24675     done[name]=true
24676    end
24677   end
24678  end
24679  if next(done) then
24680   report_unicodes("not unicoded: % t",sortedkeys(done))
24681  end
24682 end
24683end
24684local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
24685local puafirst=0xE000
24686local pualast=0xF8FF
24687local function unifymissing(fontdata)
24688 if not fonts.mappings then
24689  require("font-map")
24690  require("font-agl")
24691 end
24692 local unicodes={}
24693 local resources=fontdata.resources
24694 resources.unicodes=unicodes
24695 for unicode,d in next,fontdata.descriptions do
24696  if unicode<privateoffset then
24697   if unicode>=puafirst and unicode<=pualast then
24698   else
24699    local name=d.name
24700    if name then
24701     unicodes[name]=unicode
24702    end
24703   end
24704  else
24705  end
24706 end
24707 fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups)
24708 resources.unicodes=nil
24709end
24710local function unifyglyphs(fontdata,usenames)
24711 local private=fontdata.private or privateoffset
24712 local glyphs=fontdata.glyphs
24713 local indices={}
24714 local descriptions={}
24715 local names=usenames and {}
24716 local resources=fontdata.resources
24717 local zero=glyphs[0]
24718 local zerocode=zero.unicode
24719 local nofglyphs=#glyphs
24720 if not zerocode then
24721  zerocode=private
24722  zero.unicode=zerocode
24723  private=private+1
24724 end
24725 descriptions[zerocode]=zero
24726 if names then
24727  local name=glyphs[0].name or f_private(zerocode)
24728  indices[0]=name
24729  names[name]=zerocode
24730 else
24731  indices[0]=zerocode
24732 end
24733 if names then
24734  for index=1,nofglyphs do
24735   local glyph=glyphs[index]
24736   local unicode=glyph.unicode 
24737   if not unicode then
24738    unicode=private
24739    local name=glyph.name or f_private(unicode)
24740    indices[index]=name
24741    names[name]=unicode
24742    private=private+1
24743   elseif unicode>=firstprivate then
24744    unicode=private
24745    local name=glyph.name or f_private(unicode)
24746    indices[index]=name
24747    names[name]=unicode
24748    private=private+1
24749   elseif unicode>=puafirst and unicode<=pualast then
24750    local name=glyph.name or f_private(unicode)
24751    indices[index]=name
24752    names[name]=unicode
24753   elseif descriptions[unicode] then
24754    unicode=private
24755    local name=glyph.name or f_private(unicode)
24756    indices[index]=name
24757    names[name]=unicode
24758    private=private+1
24759   else
24760    local name=glyph.name or f_unicode(unicode)
24761    indices[index]=name
24762    names[name]=unicode
24763   end
24764   descriptions[unicode]=glyph
24765  end
24766 elseif trace_unicodes then
24767  for index=1,nofglyphs do
24768   local glyph=glyphs[index]
24769   local unicode=glyph.unicode 
24770   if not unicode then
24771    unicode=private
24772    indices[index]=unicode
24773    private=private+1
24774   elseif unicode>=firstprivate then
24775    local name=glyph.name
24776    if name then
24777     report_unicodes("moving glyph %a indexed %05X from private %U to %U ",name,index,unicode,private)
24778    else
24779     report_unicodes("moving glyph indexed %05X from private %U to %U ",index,unicode,private)
24780    end
24781    unicode=private
24782    indices[index]=unicode
24783    private=private+1
24784   elseif unicode>=puafirst and unicode<=pualast then
24785    local name=glyph.name
24786    if name then
24787     report_unicodes("keeping private unicode %U for glyph %a indexed %05X",unicode,name,index)
24788    else
24789     report_unicodes("keeping private unicode %U for glyph indexed %05X",unicode,index)
24790    end
24791    indices[index]=unicode
24792   elseif descriptions[unicode] then
24793    local name=glyph.name
24794    if name then
24795     report_unicodes("assigning duplicate unicode %U to %U for glyph %a indexed %05X ",unicode,private,name,index)
24796    else
24797     report_unicodes("assigning duplicate unicode %U to %U for glyph indexed %05X ",unicode,private,index)
24798    end
24799    unicode=private
24800    indices[index]=unicode
24801    private=private+1
24802   else
24803    indices[index]=unicode
24804   end
24805   descriptions[unicode]=glyph
24806  end
24807 else
24808  for index=1,nofglyphs do
24809   local glyph=glyphs[index]
24810   local unicode=glyph.unicode 
24811   if not unicode then
24812    unicode=private
24813    indices[index]=unicode
24814    private=private+1
24815   elseif unicode>=firstprivate then
24816    local name=glyph.name
24817    unicode=private
24818    indices[index]=unicode
24819    private=private+1
24820   elseif unicode>=puafirst and unicode<=pualast then
24821    local name=glyph.name
24822    indices[index]=unicode
24823   elseif descriptions[unicode] then
24824    local name=glyph.name
24825    unicode=private
24826    indices[index]=unicode
24827    private=private+1
24828   else
24829    indices[index]=unicode
24830   end
24831   descriptions[unicode]=glyph
24832  end
24833 end
24834 if LUATEXENGINE=="luametatex" then
24835  for index=1,nofglyphs do
24836   local math=glyphs[index].math
24837   if math then
24838    local list=math.parts
24839    if list then
24840     for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
24841    end
24842    local list=math.variants
24843    if list then
24844     for i=1,#list do list[i]=indices[list[i]] end
24845    end
24846   end
24847  end
24848 else
24849  for index=1,nofglyphs do
24850   local math=glyphs[index].math
24851   if math then
24852    local list=math.vparts
24853    if list then
24854     for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
24855    end
24856    local list=math.hparts
24857    if list then
24858     for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end
24859    end
24860    local list=math.vvariants
24861    if list then
24862     for i=1,#list do list[i]=indices[list[i]] end
24863    end
24864    local list=math.hvariants
24865    if list then
24866     for i=1,#list do list[i]=indices[list[i]] end
24867    end
24868   end
24869  end
24870 end
24871 local colorpalettes=resources.colorpalettes
24872 if colorpalettes then
24873  for index=1,nofglyphs do
24874   local colors=glyphs[index].colors
24875   if colors then
24876    for i=1,#colors do
24877     local c=colors[i]
24878     if c then 
24879      c.slot=indices[c.slot]
24880     end
24881    end
24882   end
24883  end
24884 end
24885 fontdata.private=private
24886 fontdata.glyphs=nil
24887 fontdata.names=names
24888 fontdata.descriptions=descriptions
24889 fontdata.hashmethod=hashmethod
24890 fontdata.nofglyphs=nofglyphs
24891 return indices,names
24892end
24893local stripredundant  do
24894 local p_hex=R("af","AF","09")
24895 local p_digit=R("09")
24896 local p_done=S("._-")^0+P(-1)
24897 local p_style=P(".")
24898 local p_alpha=R("az","AZ")
24899 local p_ALPHA=R("AZ")
24900 local p_crappyname=(
24901  lpeg.utfchartabletopattern({ "uni","u" },true)*S("Xx_")^0*p_hex^1
24902+lpeg.utfchartabletopattern({ "identity","glyph","jamo" },true)*p_hex^1
24903+lpeg.utfchartabletopattern({ "index","afii" },true)*p_digit^1
24904+p_digit*p_hex^3+p_alpha*p_digit^1
24905+P("aj")*p_digit^1+P("eh_")*(p_digit^1+p_ALPHA*p_digit^1)+(1-P("_"))^1*P("_uni")*p_hex^1+P("_")*P(1)^1
24906 )*p_done
24907 if context then
24908  local forcekeep=false
24909  directives.register("otf.keepnames",function(v)
24910   report_cleanup("keeping weird glyph names, expect larger files and more memory usage")
24911   forcekeep=v
24912  end)
24913  local function stripvariants(descriptions,list)
24914   local n=list and #list or 0
24915   if n>0 then
24916    for i=1,n do
24917     local g=list[i]
24918     if g then
24919      local d=descriptions[g]
24920      if d and d.name then
24921       d.name=nil
24922       n=n+1
24923      end
24924     end
24925    end
24926   end
24927   return n
24928  end
24929  local function stripparts(descriptions,list)
24930   local n=list and #list or 0
24931   if n>0 then
24932    for i=1,n do
24933     local g=list[i].glyph
24934     if g then
24935      local d=descriptions[g]
24936      if d and d.name then
24937       d.name=nil
24938       n=n+1
24939      end
24940     end
24941    end
24942   end
24943   return n
24944  end
24945  local function collectsimple(fontdata)
24946   return nil
24947  end
24948  stripredundant=function(fontdata)
24949   local descriptions=fontdata.descriptions
24950   if descriptions then
24951    local n=0
24952    local c=0
24953    for unicode,d in next,descriptions do
24954     local m=d.math
24955     if m then
24956      n=n+stripvariants(descriptions,m.vvariants)
24957      n=n+stripvariants(descriptions,m.hvariants)
24958      n=n+stripparts   (descriptions,m.vparts)
24959      n=n+stripparts   (descriptions,m.hparts)
24960     end
24961    end
24962    if forcekeep then
24963     for unicode,d in next,descriptions do
24964      if d.class=="base" then
24965       d.class=nil
24966       c=c+1
24967      end
24968     end
24969    else
24970     local keeplist=collectsimple(fontdata)
24971     for unicode,d in next,descriptions do
24972      local name=d.name
24973      if name then
24974       if keeplist and keeplist[name] then
24975       elseif lpegmatch(p_crappyname,name) then
24976        d.name=nil
24977        n=n+1
24978       end
24979      end
24980      if d.class=="base" then
24981       d.class=nil
24982       c=c+1
24983      end
24984     end
24985    end
24986    if trace_cleanup then
24987     if n>0 then
24988      report_cleanup("%s bogus names removed (verbose unicode)",n)
24989     end
24990     if c>0 then
24991      report_cleanup("%s base class tags removed (default is base)",c)
24992     end
24993    end
24994   end
24995  end
24996 else
24997  stripredundant=function(fontdata)
24998   local descriptions=fontdata.descriptions
24999   if descriptions then
25000    if fonts.privateoffsets.keepnames then
25001     for unicode,d in next,descriptions do
25002      if d.class=="base" then
25003       d.class=nil
25004      end
25005     end
25006    else
25007     for unicode,d in next,descriptions do
25008      local name=d.name
25009      if name then
25010       if lpegmatch(p_crappyname,name) then
25011        d.name=nil
25012       end
25013      end
25014      if d.class=="base" then
25015       d.class=nil
25016      end
25017     end
25018    end
25019   end
25020  end
25021 end
25022 readers.stripredundant=stripredundant
25023end
25024function readers.getcomponents(fontdata) 
25025 local resources=fontdata.resources
25026 if resources then
25027  local sequences=resources.sequences
25028  if sequences then
25029   local collected={}
25030   for i=1,#sequences do
25031    local sequence=sequences[i]
25032    if sequence.type=="gsub_ligature" then
25033     local steps=sequence.steps
25034     if steps then
25035      local l={}
25036      local function traverse(p,k,v)
25037       if k=="ligature" then
25038        collected[v]={ unpack(l) }
25039       elseif tonumber(v) then
25040        insert(l,k)
25041        collected[v]={ unpack(l) }
25042        remove(l)
25043       else
25044        insert(l,k)
25045        for k,vv in next,v do
25046         traverse(p,k,vv)
25047        end
25048        remove(l)
25049       end
25050      end
25051      for i=1,#steps do
25052       local c=steps[i].coverage
25053       if c then
25054        for k,v in next,c do
25055         traverse(k,k,v)
25056        end
25057       end
25058      end
25059     end
25060    end
25061   end
25062   if next(collected) then
25063    while true do
25064     local done=false
25065     for k,v in next,collected do
25066      for i=1,#v do
25067       local vi=v[i]
25068       if vi==k then
25069        collected[k]=nil
25070        break
25071       else
25072        local c=collected[vi]
25073        if c then
25074         done=true
25075         local t={}
25076         local n=i-1
25077         for j=1,n do
25078          t[j]=v[j]
25079         end
25080         for j=1,#c do
25081          n=n+1
25082          t[n]=c[j]
25083         end
25084         for j=i+1,#v do
25085          n=n+1
25086          t[n]=v[j]
25087         end
25088         collected[k]=t
25089         break
25090        end
25091       end
25092      end
25093     end
25094     if not done then
25095      break
25096     end
25097    end
25098    return collected
25099   end
25100  end
25101 end
25102end
25103readers.unifymissing=unifymissing
25104function readers.rehash(fontdata,hashmethod) 
25105 if not (fontdata and fontdata.glyphs) then
25106  return
25107 elseif hashmethod=="indices" then
25108  fontdata.hashmethod="indices"
25109 elseif hashmethod=="names" then
25110  fontdata.hashmethod="names"
25111  local indices=unifyglyphs(fontdata,true)
25112  unifyresources(fontdata,indices)
25113  copyduplicates(fontdata)
25114  unifymissing(fontdata)
25115 else
25116  fontdata.hashmethod="unicodes"
25117  local indices=unifyglyphs(fontdata)
25118  unifyresources(fontdata,indices)
25119  copyduplicates(fontdata)
25120  unifymissing(fontdata)
25121  stripredundant(fontdata)
25122 end
25123end
25124function readers.checkhash(fontdata)
25125 local hashmethod=fontdata.hashmethod
25126 if hashmethod=="unicodes" then
25127  fontdata.names=nil 
25128 elseif hashmethod=="names" and fontdata.names then
25129  unifyresources(fontdata,fontdata.names)
25130  copyduplicates(fontdata)
25131  fontdata.hashmethod="unicodes"
25132  fontdata.names=nil 
25133 else
25134  readers.rehash(fontdata,"unicodes")
25135 end
25136end
25137function readers.addunicodetable(fontdata)
25138 local resources=fontdata.resources
25139 local unicodes=resources.unicodes
25140 if not unicodes then
25141  local descriptions=fontdata.descriptions
25142  if descriptions then
25143   unicodes={}
25144   resources.unicodes=unicodes
25145   for u,d in next,descriptions do
25146    local n=d.name
25147    if n then
25148     unicodes[n]=u
25149    end
25150   end
25151  end
25152 end
25153end
25154local concat,sort=table.concat,table.sort
25155local next,type,tostring=next,type,tostring
25156local criterium=1
25157local threshold=0
25158local trace_packing=false  trackers.register("otf.packing",function(v) trace_packing=v end)
25159local trace_loading=false  trackers.register("otf.loading",function(v) trace_loading=v end)
25160local report_otf=logs.reporter("fonts","otf loading")
25161local function tabstr_normal(t)
25162 local s={}
25163 local n=0
25164 for k,v in next,t do
25165  n=n+1
25166  if type(v)=="table" then
25167   s[n]=k..">"..tabstr_normal(v)
25168  elseif v==true then
25169   s[n]=k.."+" 
25170  elseif v then
25171   s[n]=k.."="..v
25172  else
25173   s[n]=k.."-" 
25174  end
25175 end
25176 if n==0 then
25177  return ""
25178 elseif n==1 then
25179  return s[1]
25180 else
25181  sort(s) 
25182  return concat(s,",")
25183 end
25184end
25185local function tabstr_flat(t)
25186 local s={}
25187 local n=0
25188 for k,v in next,t do
25189  n=n+1
25190  s[n]=k.."="..v
25191 end
25192 if n==0 then
25193  return ""
25194 elseif n==1 then
25195  return s[1]
25196 else
25197  sort(s) 
25198  return concat(s,",")
25199 end
25200end
25201local function tabstr_mixed(t) 
25202 local n=#t
25203 if n==0 then
25204  return ""
25205 elseif n==1 then
25206  local k=t[1]
25207  if k==true then
25208   return "++" 
25209  elseif k==false then
25210   return "--" 
25211  else
25212   return tostring(k) 
25213  end
25214 else
25215  local s={}
25216  for i=1,n do
25217   local k=t[i]
25218   if k==true then
25219    s[i]="++" 
25220   elseif k==false then
25221    s[i]="--" 
25222   else
25223    s[i]=k 
25224   end
25225  end
25226  return concat(s,",")
25227 end
25228end
25229local function tabstr_boolean(t)
25230 local s={}
25231 local n=0
25232 for k,v in next,t do
25233  n=n+1
25234  if v then
25235   s[n]=k.."+"
25236  else
25237   s[n]=k.."-"
25238  end
25239 end
25240 if n==0 then
25241  return ""
25242 elseif n==1 then
25243  return s[1]
25244 else
25245  sort(s) 
25246  return concat(s,",")
25247 end
25248end
25249function readers.pack(data)
25250 if data then
25251  local h,t,c={},{},{}
25252  local hh,tt,cc={},{},{}
25253  local nt,ntt=0,0
25254  local function pack_normal(v)
25255   local tag=tabstr_normal(v)
25256   local ht=h[tag]
25257   if ht then
25258    c[ht]=c[ht]+1
25259    return ht
25260   else
25261    nt=nt+1
25262    t[nt]=v
25263    h[tag]=nt
25264    c[nt]=1
25265    return nt
25266   end
25267  end
25268  local function pack_normal_cc(v)
25269   local tag=tabstr_normal(v)
25270   local ht=h[tag]
25271   if ht then
25272    c[ht]=c[ht]+1
25273    return ht
25274   else
25275    v[1]=0
25276    nt=nt+1
25277    t[nt]=v
25278    h[tag]=nt
25279    c[nt]=1
25280    return nt
25281   end
25282  end
25283  local function pack_flat(v)
25284   local tag=tabstr_flat(v)
25285   local ht=h[tag]
25286   if ht then
25287    c[ht]=c[ht]+1
25288    return ht
25289   else
25290    nt=nt+1
25291    t[nt]=v
25292    h[tag]=nt
25293    c[nt]=1
25294    return nt
25295   end
25296  end
25297  local function pack_indexed(v)
25298   local tag=concat(v," ")
25299   local ht=h[tag]
25300   if ht then
25301    c[ht]=c[ht]+1
25302    return ht
25303   else
25304    nt=nt+1
25305    t[nt]=v
25306    h[tag]=nt
25307    c[nt]=1
25308    return nt
25309   end
25310  end
25311  local function pack_mixed(v)
25312   local tag=tabstr_mixed(v)
25313   local ht=h[tag]
25314   if ht then
25315    c[ht]=c[ht]+1
25316    return ht
25317   else
25318    nt=nt+1
25319    t[nt]=v
25320    h[tag]=nt
25321    c[nt]=1
25322    return nt
25323   end
25324  end
25325  local function pack_boolean(v)
25326   local tag=tabstr_boolean(v)
25327   local ht=h[tag]
25328   if ht then
25329    c[ht]=c[ht]+1
25330    return ht
25331   else
25332    nt=nt+1
25333    t[nt]=v
25334    h[tag]=nt
25335    c[nt]=1
25336    return nt
25337   end
25338  end
25339  local function pack_final(v)
25340   if c[v]<=criterium then
25341    return t[v]
25342   else
25343    local hv=hh[v]
25344    if hv then
25345     return hv
25346    else
25347     ntt=ntt+1
25348     tt[ntt]=t[v]
25349     hh[v]=ntt
25350     cc[ntt]=c[v]
25351     return ntt
25352    end
25353   end
25354  end
25355  local function pack_final_cc(v)
25356   if c[v]<=criterium then
25357    return t[v]
25358   else
25359    local hv=hh[v]
25360    if hv then
25361     return hv
25362    else
25363     ntt=ntt+1
25364     tt[ntt]=t[v]
25365     hh[v]=ntt
25366     cc[ntt]=c[v]
25367     return ntt
25368    end
25369   end
25370  end
25371  local function success(stage,pass)
25372   if nt==0 then
25373    if trace_loading or trace_packing then
25374     report_otf("pack quality: nothing to pack")
25375    end
25376    return false
25377   elseif nt>=threshold then
25378    local one=0
25379    local two=0
25380    local rest=0
25381    if pass==1 then
25382     for k,v in next,c do
25383      if v==1 then
25384       one=one+1
25385      elseif v==2 then
25386       two=two+1
25387      else
25388       rest=rest+1
25389      end
25390     end
25391    else
25392     for k,v in next,cc do
25393      if v>20 then
25394       rest=rest+1
25395      elseif v>10 then
25396       two=two+1
25397      else
25398       one=one+1
25399      end
25400     end
25401     data.tables=tt
25402    end
25403    if trace_loading or trace_packing then
25404     report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)",
25405      stage,pass,one+two+rest,one,two,rest,criterium)
25406    end
25407    return true
25408   else
25409    if trace_loading or trace_packing then
25410     report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)",
25411      stage,pass,nt,threshold)
25412    end
25413    return false
25414   end
25415  end
25416  local function packers(pass)
25417   if pass==1 then
25418    return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc
25419   else
25420    return pack_final,pack_final,pack_final,pack_final,pack_final,pack_final_cc
25421   end
25422  end
25423  local resources=data.resources
25424  local sequences=resources.sequences
25425  local sublookups=resources.sublookups
25426  local features=resources.features
25427  local palettes=resources.colorpalettes
25428  local variable=resources.variabledata
25429  local chardata=characters and characters.data
25430  local descriptions=data.descriptions or data.glyphs
25431  if not descriptions then
25432   return
25433  end
25434  for pass=1,2 do
25435   if trace_packing then
25436    report_otf("start packing: stage 1, pass %s",pass)
25437   end
25438   local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
25439   for unicode,description in next,descriptions do
25440    local boundingbox=description.boundingbox
25441    if boundingbox then
25442     description.boundingbox=pack_indexed(boundingbox)
25443    end
25444    local math=description.math
25445    if math then
25446     local kerns=math.kerns
25447     if kerns then
25448      for tag,kern in next,kerns do
25449       kerns[tag]=pack_normal(kern)
25450      end
25451     end
25452    end
25453   end
25454   local function packthem(sequences)
25455    for i=1,#sequences do
25456     local sequence=sequences[i]
25457     local kind=sequence.type
25458     local steps=sequence.steps
25459     local order=sequence.order
25460     local features=sequence.features
25461     local flags=sequence.flags
25462     if steps then
25463      for i=1,#steps do
25464       local step=steps[i]
25465       if kind=="gpos_pair" then
25466        local c=step.coverage
25467        if c then
25468         if step.format~="pair" then
25469          for g1,d1 in next,c do
25470           c[g1]=pack_normal(d1)
25471          end
25472         elseif step.shared then
25473          local shared={}
25474          for g1,d1 in next,c do
25475           for g2,d2 in next,d1 do
25476            if not shared[d2] then
25477             local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
25478             local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
25479             shared[d2]=true
25480            end
25481           end
25482          end
25483          if pass==2 then
25484           step.shared=nil 
25485          end
25486         else
25487          for g1,d1 in next,c do
25488           for g2,d2 in next,d1 do
25489            local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
25490            local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
25491           end
25492          end
25493         end
25494        end
25495       elseif kind=="gpos_single" then
25496        local c=step.coverage
25497        if c then
25498         if step.format=="single" then
25499          for g1,d1 in next,c do
25500           if d1 and d1~=true then
25501            c[g1]=pack_indexed(d1)
25502           end
25503          end
25504         else
25505          step.coverage=pack_normal(c)
25506         end
25507        end
25508       elseif kind=="gpos_cursive" then
25509        local c=step.coverage
25510        if c then
25511         for g1,d1 in next,c do
25512          local f=d1[2] if f then d1[2]=pack_indexed(f) end
25513          local s=d1[3] if s then d1[3]=pack_indexed(s) end
25514         end
25515        end
25516       elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
25517        local c=step.baseclasses
25518        if c then
25519         for g1,d1 in next,c do
25520          for g2,d2 in next,d1 do
25521           d1[g2]=pack_indexed(d2)
25522          end
25523         end
25524        end
25525        local c=step.coverage
25526        if c then
25527         for g1,d1 in next,c do
25528          d1[2]=pack_indexed(d1[2])
25529         end
25530        end
25531       elseif kind=="gpos_mark2ligature" then
25532        local c=step.baseclasses
25533        if c then
25534         for g1,d1 in next,c do
25535          for g2,d2 in next,d1 do
25536           for g3,d3 in next,d2 do
25537            d2[g3]=pack_indexed(d3)
25538           end
25539          end
25540         end
25541        end
25542        local c=step.coverage
25543        if c then
25544         for g1,d1 in next,c do
25545          d1[2]=pack_indexed(d1[2])
25546         end
25547        end
25548       end
25549       local rules=step.rules
25550       if rules then
25551        for i=1,#rules do
25552         local rule=rules[i]
25553         local r=rule.before    if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
25554         local r=rule.after  if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
25555         local r=rule.current   if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
25556         local r=rule.replacements if r then rule.replacements=pack_flat   (r) end
25557        end
25558       end
25559      end
25560     end
25561     if order then
25562      sequence.order=pack_indexed(order)
25563     end
25564     if features then
25565      for script,feature in next,features do
25566       features[script]=pack_normal(feature)
25567      end
25568     end
25569     if flags then
25570      sequence.flags=pack_normal(flags)
25571     end
25572      end
25573   end
25574   if sequences then
25575    packthem(sequences)
25576   end
25577   if sublookups then
25578    packthem(sublookups)
25579   end
25580   if features then
25581    for k,list in next,features do
25582     for feature,spec in next,list do
25583      list[feature]=pack_normal(spec)
25584     end
25585    end
25586   end
25587   if palettes then
25588    for i=1,#palettes do
25589     local p=palettes[i]
25590     for j=1,#p do
25591      p[j]=pack_indexed(p[j])
25592     end
25593    end
25594   end
25595   if variable then
25596    local instances=variable.instances
25597    if instances then
25598     for i=1,#instances do
25599      local v=instances[i].values
25600      for j=1,#v do
25601       v[j]=pack_normal(v[j])
25602      end
25603     end
25604    end
25605    local function packdeltas(main)
25606     if main then
25607      local deltas=main.deltas
25608      if deltas then
25609       for i=1,#deltas do
25610        local di=deltas[i]
25611        local d=di.deltas
25612        for j=1,#d do
25613         d[j]=pack_indexed(d[j])
25614        end
25615        di.regions=pack_indexed(di.regions)
25616       end
25617      end
25618      local regions=main.regions
25619      if regions then
25620       for i=1,#regions do
25621        local r=regions[i]
25622        for j=1,#r do
25623         r[j]=pack_normal(r[j])
25624        end
25625       end
25626      end
25627     end
25628    end
25629    packdeltas(variable.global)
25630    packdeltas(variable.horizontal)
25631    packdeltas(variable.vertical)
25632    packdeltas(variable.metrics)
25633   end
25634   if not success(1,pass) then
25635    return
25636   end
25637  end
25638  if nt>0 then
25639   for pass=1,2 do
25640    if trace_packing then
25641     report_otf("start packing: stage 2, pass %s",pass)
25642    end
25643    local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
25644    for unicode,description in next,descriptions do
25645     local math=description.math
25646     if math then
25647      local kerns=math.kerns
25648      if kerns then
25649       math.kerns=pack_normal(kerns)
25650      end
25651     end
25652    end
25653    local function packthem(sequences)
25654     for i=1,#sequences do
25655      local sequence=sequences[i]
25656      local kind=sequence.type
25657      local steps=sequence.steps
25658      local features=sequence.features
25659      if steps then
25660       for i=1,#steps do
25661        local step=steps[i]
25662        if kind=="gpos_pair" then
25663         local c=step.coverage
25664         if c then
25665          if step.format=="pair" then
25666           for g1,d1 in next,c do
25667            for g2,d2 in next,d1 do
25668             d1[g2]=pack_normal(d2)
25669            end
25670           end
25671          end
25672         end
25673        elseif kind=="gpos_mark2ligature" then
25674         local c=step.baseclasses 
25675         if c then
25676          for g1,d1 in next,c do
25677           for g2,d2 in next,d1 do
25678            d1[g2]=pack_normal(d2)
25679           end
25680          end
25681         end
25682        end
25683        local rules=step.rules
25684        if rules then
25685         for i=1,#rules do
25686          local rule=rules[i]
25687          local r=rule.before  if r then rule.before=pack_normal(r) end
25688          local r=rule.after   if r then rule.after=pack_normal(r) end
25689          local r=rule.current if r then rule.current=pack_normal(r) end
25690         end
25691        end
25692       end
25693      end
25694      if features then
25695       sequence.features=pack_normal(features)
25696      end
25697       end
25698    end
25699    if sequences then
25700     packthem(sequences)
25701    end
25702    if sublookups then
25703     packthem(sublookups)
25704    end
25705    if variable then
25706     local function unpackdeltas(main)
25707      if main then
25708       local regions=main.regions
25709       if regions then
25710        main.regions=pack_normal(regions)
25711       end
25712      end
25713     end
25714     unpackdeltas(variable.global)
25715     unpackdeltas(variable.horizontal)
25716     unpackdeltas(variable.vertical)
25717     unpackdeltas(variable.metrics)
25718    end
25719   end
25720   for pass=1,2 do
25721    if trace_packing then
25722     report_otf("start packing: stage 3, pass %s",pass)
25723    end
25724    local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
25725    local function packthem(sequences)
25726     for i=1,#sequences do
25727      local sequence=sequences[i]
25728      local kind=sequence.type
25729      local steps=sequence.steps
25730      local features=sequence.features
25731      if steps then
25732       for i=1,#steps do
25733        local step=steps[i]
25734        if kind=="gpos_pair" then
25735         local c=step.coverage
25736         if c then
25737          if step.format=="pair" then
25738           for g1,d1 in next,c do
25739            c[g1]=pack_normal(d1)
25740           end
25741          end
25742         end
25743        elseif kind=="gpos_cursive" then
25744         local c=step.coverage
25745         if c then
25746          for g1,d1 in next,c do
25747           c[g1]=pack_normal_cc(d1)
25748          end
25749         end
25750        end
25751       end
25752      end
25753     end
25754    end
25755    if sequences then
25756     packthem(sequences)
25757    end
25758    if sublookups then
25759     packthem(sublookups)
25760    end
25761   end
25762  end
25763 end
25764end
25765local unpacked_mt={
25766 __index=function(t,k)
25767   t[k]=false
25768   return k 
25769  end
25770}
25771function readers.unpack(data)
25772 if data then
25773  local tables=data.tables
25774  if tables then
25775   local resources=data.resources
25776   local descriptions=data.descriptions or data.glyphs
25777   local sequences=resources.sequences
25778   local sublookups=resources.sublookups
25779   local features=resources.features
25780   local palettes=resources.colorpalettes
25781   local variable=resources.variabledata
25782   local unpacked={}
25783   setmetatable(unpacked,unpacked_mt)
25784   for unicode,description in next,descriptions do
25785    local tv=tables[description.boundingbox]
25786    if tv then
25787     description.boundingbox=tv
25788    end
25789    local math=description.math
25790    if math then
25791     local kerns=math.kerns
25792     if kerns then
25793      local tm=tables[kerns]
25794      if tm then
25795       math.kerns=tm
25796       kerns=unpacked[tm]
25797      end
25798      if kerns then
25799       for k,kern in next,kerns do
25800        local tv=tables[kern]
25801        if tv then
25802         kerns[k]=tv
25803        end
25804       end
25805      end
25806     end
25807    end
25808   end
25809   local function unpackthem(sequences)
25810    for i=1,#sequences do
25811     local sequence=sequences[i]
25812     local kind=sequence.type
25813     local steps=sequence.steps
25814     local order=sequence.order
25815     local features=sequence.features
25816     local flags=sequence.flags
25817     local markclass=sequence.markclass
25818     if features then
25819      local tv=tables[features]
25820      if tv then
25821       sequence.features=tv
25822       features=tv
25823      end
25824      for script,feature in next,features do
25825       local tv=tables[feature]
25826       if tv then
25827        features[script]=tv
25828       end
25829      end
25830     end
25831     if steps then
25832      for i=1,#steps do
25833       local step=steps[i]
25834       if kind=="gpos_pair" then
25835        local c=step.coverage
25836        if c then
25837         if step.format=="pair" then
25838          for g1,d1 in next,c do
25839           local tv=tables[d1]
25840           if tv then
25841            c[g1]=tv
25842            d1=tv
25843           end
25844           for g2,d2 in next,d1 do
25845            local tv=tables[d2]
25846            if tv then
25847             d1[g2]=tv
25848             d2=tv
25849            end
25850            local f=tables[d2[1]] if f then d2[1]=f end
25851            local s=tables[d2[2]] if s then d2[2]=s end
25852           end
25853          end
25854         else
25855          for g1,d1 in next,c do
25856           local tv=tables[d1]
25857           if tv then
25858            c[g1]=tv
25859           end
25860          end
25861         end
25862        end
25863       elseif kind=="gpos_single" then
25864        local c=step.coverage
25865        if c then
25866         if step.format=="single" then
25867          for g1,d1 in next,c do
25868           local tv=tables[d1]
25869           if tv then
25870            c[g1]=tv
25871           end
25872          end
25873         else
25874          local tv=tables[c]
25875          if tv then
25876           step.coverage=tv
25877          end
25878         end
25879        end
25880       elseif kind=="gpos_cursive" then
25881        local c=step.coverage
25882        if c then
25883         for g1,d1 in next,c do
25884          local tv=tables[d1]
25885          if tv then
25886           d1=tv
25887           c[g1]=d1
25888          end
25889          local f=tables[d1[2]] if f then d1[2]=f end
25890          local s=tables[d1[3]] if s then d1[3]=s end
25891         end
25892        end
25893       elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then
25894        local c=step.baseclasses
25895        if c then
25896         for g1,d1 in next,c do
25897          for g2,d2 in next,d1 do
25898           local tv=tables[d2]
25899           if tv then
25900            d1[g2]=tv
25901           end
25902          end
25903         end
25904        end
25905        local c=step.coverage
25906        if c then
25907         for g1,d1 in next,c do
25908          local tv=tables[d1[2]]
25909          if tv then
25910           d1[2]=tv
25911          end
25912         end
25913        end
25914       elseif kind=="gpos_mark2ligature" then
25915        local c=step.baseclasses
25916        if c then
25917         for g1,d1 in next,c do
25918          for g2,d2 in next,d1 do
25919           local tv=tables[d2] 
25920           if tv then
25921            d2=tv
25922            d1[g2]=d2
25923           end
25924           for g3,d3 in next,d2 do
25925            local tv=tables[d2[g3]]
25926            if tv then
25927             d2[g3]=tv
25928            end
25929           end
25930          end
25931         end
25932        end
25933        local c=step.coverage
25934        if c then
25935         for g1,d1 in next,c do
25936          local tv=tables[d1[2]]
25937          if tv then
25938           d1[2]=tv
25939          end
25940         end
25941        end
25942       end
25943       local rules=step.rules
25944       if rules then
25945        for i=1,#rules do
25946         local rule=rules[i]
25947         local before=rule.before
25948         if before then
25949          local tv=tables[before]
25950          if tv then
25951           rule.before=tv
25952           before=tv
25953          end
25954          for i=1,#before do
25955           local tv=tables[before[i]]
25956           if tv then
25957            before[i]=tv
25958           end
25959          end
25960         end
25961         local after=rule.after
25962         if after then
25963          local tv=tables[after]
25964          if tv then
25965           rule.after=tv
25966           after=tv
25967          end
25968          for i=1,#after do
25969           local tv=tables[after[i]]
25970           if tv then
25971            after[i]=tv
25972           end
25973          end
25974         end
25975         local current=rule.current
25976         if current then
25977          local tv=tables[current]
25978          if tv then
25979           rule.current=tv
25980           current=tv
25981          end
25982          for i=1,#current do
25983           local tv=tables[current[i]]
25984           if tv then
25985            current[i]=tv
25986           end
25987          end
25988         end
25989         local replacements=rule.replacements
25990         if replacements then
25991          local tv=tables[replacements]
25992          if tv then
25993           rule.replacements=tv
25994          end
25995         end
25996        end
25997       end
25998      end
25999     end
26000     if order then
26001      local tv=tables[order]
26002      if tv then
26003       sequence.order=tv
26004      end
26005     end
26006     if flags then
26007      local tv=tables[flags]
26008      if tv then
26009       sequence.flags=tv
26010      end
26011     end
26012      end
26013   end
26014   if sequences then
26015    unpackthem(sequences)
26016   end
26017   if sublookups then
26018    unpackthem(sublookups)
26019   end
26020   if features then
26021    for k,list in next,features do
26022     for feature,spec in next,list do
26023      local tv=tables[spec]
26024      if tv then
26025       list[feature]=tv
26026      end
26027     end
26028    end
26029   end
26030   if palettes then
26031    for i=1,#palettes do
26032     local p=palettes[i]
26033     for j=1,#p do
26034      local tv=tables[p[j]]
26035      if tv then
26036       p[j]=tv
26037      end
26038     end
26039    end
26040   end
26041   if variable then
26042    local instances=variable.instances
26043    if instances then
26044     for i=1,#instances do
26045      local v=instances[i].values
26046      for j=1,#v do
26047       local tv=tables[v[j]]
26048       if tv then
26049        v[j]=tv
26050       end
26051      end
26052     end
26053    end
26054    local function unpackdeltas(main)
26055     if main then
26056      local deltas=main.deltas
26057      if deltas then
26058       for i=1,#deltas do
26059        local di=deltas[i]
26060        local d=di.deltas
26061        local r=di.regions
26062        for j=1,#d do
26063         local tv=tables[d[j]]
26064         if tv then
26065          d[j]=tv
26066         end
26067        end
26068        local tv=di.regions
26069        if tv then
26070         di.regions=tv
26071        end
26072       end
26073      end
26074      local regions=main.regions
26075      if regions then
26076       local tv=tables[regions]
26077       if tv then
26078        main.regions=tv
26079        regions=tv
26080       end
26081       for i=1,#regions do
26082        local r=regions[i]
26083        for j=1,#r do
26084         local tv=tables[r[j]]
26085         if tv then
26086          r[j]=tv
26087         end
26088        end
26089       end
26090      end
26091     end
26092    end
26093    unpackdeltas(variable.global)
26094    unpackdeltas(variable.horizontal)
26095    unpackdeltas(variable.vertical)
26096    unpackdeltas(variable.metrics)
26097   end
26098   data.tables=nil
26099  end
26100 end
26101end
26102local mt={
26103 __index=function(t,k) 
26104  if k=="height" then
26105   local ht=t.boundingbox[4]
26106   return ht<0 and 0 or ht
26107  elseif k=="depth" then
26108   local dp=-t.boundingbox[2]
26109   return dp<0 and 0 or dp
26110  elseif k=="width" then
26111   return 0
26112  elseif k=="name" then 
26113   return forcenotdef and ".notdef"
26114  end
26115 end
26116}
26117local function sameformat(sequence,steps,first,nofsteps,kind)
26118 return true
26119end
26120local function mergesteps_1(lookup,strict)
26121 local steps=lookup.steps
26122 local nofsteps=lookup.nofsteps
26123 local first=steps[1]
26124 if strict then
26125  local f=first.format
26126  for i=2,nofsteps do
26127   if steps[i].format~=f then
26128    if trace_optimizations then
26129     report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
26130    end
26131    return 0
26132   end
26133  end
26134 end
26135 if trace_optimizations then
26136  report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
26137 end
26138 local target=first.coverage
26139 for i=2,nofsteps do
26140  local c=steps[i].coverage
26141  if c then
26142   for k,v in next,c do
26143    if not target[k] then
26144     target[k]=v
26145    end
26146   end
26147  end
26148 end
26149 lookup.nofsteps=1
26150 lookup.merged=true
26151 lookup.steps={ first }
26152 return nofsteps-1
26153end
26154local function mergesteps_2(lookup)
26155 local steps=lookup.steps
26156 local nofsteps=lookup.nofsteps
26157 local first=steps[1]
26158 if strict then
26159  local f=first.format
26160  for i=2,nofsteps do
26161   if steps[i].format~=f then
26162    if trace_optimizations then
26163     report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name)
26164    end
26165    return 0
26166   end
26167  end
26168 end
26169 if trace_optimizations then
26170  report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
26171 end
26172 local target=first.coverage
26173 for i=2,nofsteps do
26174  local c=steps[i].coverage
26175  if c then
26176   for k,v in next,c do
26177    local tk=target[k]
26178    if tk then
26179     for kk,vv in next,v do
26180      if tk[kk]==nil then
26181       tk[kk]=vv
26182      end
26183     end
26184    else
26185     target[k]=v
26186    end
26187   end
26188  end
26189 end
26190 lookup.nofsteps=1
26191 lookup.merged=true
26192 lookup.steps={ first }
26193 return nofsteps-1
26194end
26195local function mergesteps_3(lookup,strict) 
26196 local steps=lookup.steps
26197 local nofsteps=lookup.nofsteps
26198 if trace_optimizations then
26199  report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
26200 end
26201 local coverage={}
26202 for i=1,nofsteps do
26203  local c=steps[i].coverage
26204  if c then
26205   for k,v in next,c do
26206    local tk=coverage[k] 
26207    if tk then
26208     if trace_optimizations then
26209      report_optimizations("quitting merge due to multiple checks")
26210     end
26211     return nofsteps
26212    else
26213     coverage[k]=v
26214    end
26215   end
26216  end
26217 end
26218 local first=steps[1]
26219 local baseclasses={} 
26220 for i=1,nofsteps do
26221  local offset=i*10  
26222  local step=steps[i]
26223  for k,v in sortedhash(step.baseclasses) do
26224   baseclasses[offset+k]=v
26225  end
26226  for k,v in next,step.coverage do
26227   v[1]=offset+v[1]
26228  end
26229 end
26230 first.baseclasses=baseclasses
26231 first.coverage=coverage
26232 lookup.nofsteps=1
26233 lookup.merged=true
26234 lookup.steps={ first }
26235 return nofsteps-1
26236end
26237local function nested(old,new)
26238 for k,v in next,old do
26239  if k=="ligature" then
26240   if not new.ligature then
26241    new.ligature=v
26242   end
26243  else
26244   local n=new[k]
26245   if n then
26246    nested(v,n)
26247   else
26248    new[k]=v
26249   end
26250  end
26251 end
26252end
26253local function mergesteps_4(lookup) 
26254 local steps=lookup.steps
26255 local nofsteps=lookup.nofsteps
26256 local first=steps[1]
26257 if trace_optimizations then
26258  report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
26259 end
26260 local target=first.coverage
26261 for i=2,nofsteps do
26262  local c=steps[i].coverage
26263  if c then
26264   for k,v in next,c do
26265    local tk=target[k]
26266    if tk then
26267     nested(v,tk)
26268    else
26269     target[k]=v
26270    end
26271   end
26272  end
26273 end
26274 lookup.nofsteps=1
26275 lookup.steps={ first }
26276 return nofsteps-1
26277end
26278local function mergesteps_5(lookup) 
26279 local steps=lookup.steps
26280 local nofsteps=lookup.nofsteps
26281 local first=steps[1]
26282 if trace_optimizations then
26283  report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
26284 end
26285 local target=first.coverage
26286 local hash=nil
26287 for k,v in next,target do
26288  hash=v[1]
26289  break
26290 end
26291 for i=2,nofsteps do
26292  local c=steps[i].coverage
26293  if c then
26294   for k,v in next,c do
26295    local tk=target[k]
26296    if tk then
26297     if not tk[2] then
26298      tk[2]=v[2]
26299     end
26300     if not tk[3] then
26301      tk[3]=v[3]
26302     end
26303    else
26304     target[k]=v
26305     v[1]=hash
26306    end
26307   end
26308  end
26309 end
26310 lookup.nofsteps=1
26311 lookup.merged=true
26312 lookup.steps={ first }
26313 return nofsteps-1
26314end
26315local function checkkerns(lookup)
26316 local steps=lookup.steps
26317 local nofsteps=lookup.nofsteps
26318 local kerned=0
26319 for i=1,nofsteps do
26320  local step=steps[i]
26321  if step.format=="pair" then
26322   local coverage=step.coverage
26323   local kerns=true
26324   for g1,d1 in next,coverage do
26325    if d1==true then
26326    elseif not d1 then
26327    elseif d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
26328     kerns=false
26329     break
26330    end
26331   end
26332   if kerns then
26333    if trace_optimizations then
26334     report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
26335    end
26336    local c={}
26337    for g1,d1 in next,coverage do
26338     if d1 and d1~=true then
26339      c[g1]=d1[3]
26340     end
26341    end
26342    step.coverage=c
26343    step.format="move"
26344    kerned=kerned+1
26345   end
26346  end
26347 end
26348 return kerned
26349end
26350local strip_pairs=true
26351local compact_pairs=true
26352local compact_singles=true
26353local merge_pairs=true
26354local merge_singles=true
26355local merge_substitutions=true
26356local merge_alternates=true
26357local merge_multiples=true
26358local merge_ligatures=true
26359local merge_cursives=true
26360local merge_marks=true
26361directives.register("otf.strip.pairs",function(v) strip_pairs=v end)
26362directives.register("otf.compact.pairs",function(v) compact_pairs=v end)
26363directives.register("otf.compact.singles",function(v) compact_singles=v end)
26364directives.register("otf.merge.pairs",function(v) merge_pairs=v end)
26365directives.register("otf.merge.singles",function(v) merge_singles=v end)
26366directives.register("otf.merge.substitutions",function(v) merge_substitutions=v end)
26367directives.register("otf.merge.alternates",function(v) merge_alternates=v end)
26368directives.register("otf.merge.multiples",function(v) merge_multiples=v end)
26369directives.register("otf.merge.ligatures",function(v) merge_ligatures=v end)
26370directives.register("otf.merge.cursives",function(v) merge_cursives=v end)
26371directives.register("otf.merge.marks",function(v) merge_marks=v end)
26372local function checkpairs(lookup)
26373 local steps=lookup.steps
26374 local nofsteps=lookup.nofsteps
26375 local kerned=0
26376 local function onlykerns(step)
26377  local coverage=step.coverage
26378  for g1,d1 in next,coverage do
26379   for g2,d2 in next,d1 do
26380    if d2[2] then
26381     return false
26382    else
26383     local v=d2[1]
26384     if v==true then
26385     elseif v and (v[1]~=0 or v[2]~=0 or v[4]~=0) then
26386      return false
26387     end
26388    end
26389   end
26390  end
26391  return coverage
26392 end
26393 for i=1,nofsteps do
26394  local step=steps[i]
26395  if step.format=="pair" then
26396   local coverage=onlykerns(step)
26397   if coverage then
26398    if trace_optimizations then
26399     report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
26400    end
26401    for g1,d1 in next,coverage do
26402     local d={}
26403     for g2,d2 in next,d1 do
26404      local v=d2[1]
26405      if v==true then
26406      elseif v then
26407       d[g2]=v[3] 
26408      end
26409     end
26410     coverage[g1]=d
26411    end
26412    step.format="move"
26413    kerned=kerned+1
26414   end
26415  end
26416 end
26417 return kerned
26418end
26419local function strippairs(lookup)
26420 local steps=lookup.steps
26421 local nofsteps=lookup.nofsteps
26422 local stripped=0
26423 for i=1,nofsteps do
26424  local step=steps[i]
26425  if step.format=="pair" then
26426   local coverage=step.coverage
26427   for g1,d1 in next,coverage do
26428    for g2,d2 in next,d1 do
26429     if d2[2] then
26430     elseif d2[1]==true then
26431      d1[g2]=nil
26432      stripped=stripped+1
26433     end
26434    end
26435   end
26436  end
26437 end
26438 return stripped
26439end
26440function readers.compact(data)
26441 if not data or data.compacted then
26442  return
26443 else
26444  data.compacted=true
26445 end
26446 local resources=data.resources
26447 local stripped=0
26448 local merged=0
26449 local kerned=0
26450 local allsteps=0
26451 local function compact(what)
26452  local lookups=resources[what]
26453  if lookups then
26454   for i=1,#lookups do
26455    local lookup=lookups[i]
26456    local nofsteps=lookup.nofsteps
26457    local kind=lookup.type
26458    allsteps=allsteps+nofsteps
26459    if nofsteps>1 then
26460     local merg=merged
26461     if kind=="gsub_single" then
26462      if merge_substitutions then
26463       merged=merged+mergesteps_1(lookup)
26464      end
26465     elseif kind=="gsub_alternate" then
26466      if merge_alternates then
26467       merged=merged+mergesteps_1(lookup)
26468      end
26469     elseif kind=="gsub_multiple" then
26470      if merge_multiples then
26471       merged=merged+mergesteps_1(lookup)
26472      end
26473     elseif kind=="gsub_ligature" then
26474      if merge_ligatures then
26475       merged=merged+mergesteps_4(lookup)
26476      end
26477     elseif kind=="gpos_single" then
26478      if merge_singles then
26479       merged=merged+mergesteps_1(lookup,true)
26480      end
26481      if compact_singles then
26482       kerned=kerned+checkkerns(lookup)
26483      end
26484     elseif kind=="gpos_pair" then
26485      if strip_pairs then
26486       stripped=stripped+strippairs(lookup) 
26487      end
26488      if merge_pairs then
26489       merged=merged+mergesteps_2(lookup)
26490      end
26491      if compact_pairs then
26492       kerned=kerned+checkpairs(lookup)
26493      end
26494     elseif kind=="gpos_cursive" then
26495      if merge_cursives then
26496       merged=merged+mergesteps_5(lookup)
26497      end
26498     elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then
26499      if merge_marks then
26500       merged=merged+mergesteps_3(lookup)
26501      end
26502     end
26503     if merg~=merged then
26504      lookup.merged=true
26505     end
26506    elseif nofsteps==1 then
26507     local kern=kerned
26508     if kind=="gpos_single" then
26509      if compact_singles then
26510       kerned=kerned+checkkerns(lookup)
26511      end
26512     elseif kind=="gpos_pair" then
26513      if compact_pairs then
26514       kerned=kerned+checkpairs(lookup)
26515      end
26516     end
26517     if kern~=kerned then
26518     end
26519    end
26520   end
26521  elseif trace_optimizations then
26522   report_optimizations("no lookups in %a",what)
26523  end
26524 end
26525 compact("sequences")
26526 compact("sublookups")
26527 if trace_optimizations then
26528  if stripped>0 then
26529   report_optimizations("%i zero positions stripped before merging",stripped)
26530  end
26531  if merged>0 then
26532   report_optimizations("%i steps of %i removed due to merging",merged,allsteps)
26533  end
26534  if kerned>0 then
26535   report_optimizations("%i steps of %i steps turned from pairs into kerns",kerned,allsteps)
26536  end
26537 end
26538end
26539if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then
26540 local done=0
26541 local function condense_1(k,v,t)
26542  if type(v)=="table" then
26543   local u=false
26544   local l=false
26545   for k,v in next,v do
26546    if k=="ligature" then
26547     l=v
26548     if u then
26549      break
26550     end
26551    elseif u then
26552     break
26553    else
26554     u=true
26555    end
26556   end
26557   if l and not u then
26558    t[k]=l
26559    done=done+1
26560   end
26561   if u then
26562    for k,vv in next,v do
26563     if k~="ligature" then
26564      condense_1(k,vv,v)
26565     end
26566    end
26567   end
26568  end
26569 end
26570 local function condensesteps_1(lookup)
26571  done=0
26572  if lookup.type=="gsub_ligature" then
26573   local steps=lookup.steps
26574   if steps then
26575    for i=1,#steps do
26576     local step=steps[i]
26577     local coverage=step.coverage
26578     if coverage then
26579      for k,v in next,coverage do
26580       if condense_1(k,v,coverage) then
26581        coverage[k]=v.ligature
26582        done=done+1
26583       end
26584      end
26585     end
26586    end
26587   end
26588  end
26589  return done
26590 end
26591 function readers.condense(data)
26592  if not data or data.condensed then
26593   return
26594  else
26595   data.condensed=true
26596  end
26597  local resources=data.resources
26598  local condensed=0
26599  local function condense(what)
26600   local lookups=resources[what]
26601   if lookups then
26602    for i=1,#lookups do
26603     condensed=condensed+condensesteps_1(lookups[i])
26604    end
26605   elseif trace_optimizations then
26606    report_optimizations("no lookups in %a",what)
26607   end
26608  end
26609  condense("sequences")
26610  condense("sublookups")
26611  if trace_optimizations then
26612   if condensed>0 then
26613    report_optimizations("%i ligatures condensed",condensed)
26614   end
26615  end
26616 end
26617end
26618local function mergesteps(t,k)
26619 if k=="merged" then
26620  local merged={}
26621  for i=1,#t do
26622   local step=t[i]
26623   local coverage=step.coverage
26624   for k in next,coverage do
26625    local m=merged[k]
26626    if m then
26627     m[2]=i
26628    else
26629     merged[k]={ i,i }
26630    end
26631   end
26632  end
26633  t.merged=merged
26634  return merged
26635 end
26636end
26637local function checkmerge(sequence)
26638 local steps=sequence.steps
26639 if steps then
26640  setmetatableindex(steps,mergesteps)
26641 end
26642end
26643local function checkflags(sequence,resources)
26644 if not sequence.skiphash then
26645  local flags=sequence.flags
26646  if flags then
26647   local skipmark=flags[1]
26648   local skipligature=flags[2]
26649   local skipbase=flags[3]
26650   local markclass=sequence.markclass
26651   local skipsome=skipmark or skipligature or skipbase or markclass or false
26652   if skipsome then
26653    sequence.skiphash=setmetatableindex(function(t,k)
26654     local c=resources.classes[k] 
26655     local v=c==skipmark
26656         or (markclass and c=="mark" and not markclass[k])
26657         or c==skipligature
26658         or c==skipbase
26659         or false
26660     t[k]=v
26661     return v
26662    end)
26663   else
26664    sequence.skiphash=false
26665   end
26666  else
26667   sequence.skiphash=false
26668  end
26669 end
26670end
26671local function checksteps(sequence)
26672 local steps=sequence.steps
26673 if steps then
26674  for i=1,#steps do
26675   steps[i].index=i
26676  end
26677 end
26678end
26679if fonts.helpers then
26680 fonts.helpers.checkmerge=checkmerge
26681 fonts.helpers.checkflags=checkflags
26682 fonts.helpers.checksteps=checksteps 
26683end
26684function readers.expand(data)
26685 if not data or data.expanded then
26686  return
26687 else
26688  data.expanded=true
26689 end
26690 local resources=data.resources
26691 local sublookups=resources.sublookups
26692 local sequences=resources.sequences 
26693 local markclasses=resources.markclasses
26694 local descriptions=data.descriptions
26695 if descriptions then
26696  local defaultwidth=resources.defaultwidth  or 0
26697  local defaultheight=resources.defaultheight or 0
26698  local defaultdepth=resources.defaultdepth  or 0
26699  local basename=trace_markwidth and file.basename(resources.filename)
26700  for u,d in next,descriptions do
26701   local bb=d.boundingbox
26702   local wd=d.width
26703   if not wd then
26704    d.width=defaultwidth
26705   elseif trace_markwidth and wd~=0 and d.class=="mark" then
26706    report_markwidth("mark %a with width %b found in %a",d.name or "<noname>",wd,basename)
26707   end
26708   if bb then
26709    local ht=bb[4]
26710    local dp=-bb[2]
26711    if ht==0 or ht<0 then
26712    else
26713     d.height=ht
26714    end
26715    if dp==0 or dp<0 then
26716    else
26717     d.depth=dp
26718    end
26719   end
26720  end
26721 end
26722 local function expandlookups(sequences,whatever)
26723  if sequences then
26724   for i=1,#sequences do
26725    local sequence=sequences[i]
26726    local steps=sequence.steps
26727    if steps then
26728     local nofsteps=sequence.nofsteps
26729     local kind=sequence.type
26730     local markclass=sequence.markclass
26731     if markclass then
26732      if not markclasses then
26733       report_warning("missing markclasses")
26734       sequence.markclass=false
26735      else
26736       sequence.markclass=markclasses[markclass]
26737      end
26738     end
26739     for i=1,nofsteps do
26740      local step=steps[i]
26741      local baseclasses=step.baseclasses
26742      if baseclasses then
26743       local coverage=step.coverage
26744       for k,v in next,coverage do
26745        v[1]=baseclasses[v[1]] 
26746       end
26747      elseif kind=="gpos_cursive" then
26748       local coverage=step.coverage
26749       for k,v in next,coverage do
26750        v[1]=coverage 
26751       end
26752      end
26753      local rules=step.rules
26754      if rules then
26755       local rulehash={ n=0 } 
26756       local rulesize=0
26757       local coverage={}
26758       local lookuptype=sequence.type
26759       local nofrules=#rules
26760       step.coverage=coverage 
26761       for currentrule=1,nofrules do
26762        local rule=rules[currentrule]
26763        local current=rule.current
26764        local before=rule.before
26765        local after=rule.after
26766        local replacements=rule.replacements or false
26767        local sequence={}
26768        local nofsequences=0
26769        if before then
26770         for n=1,#before do
26771          nofsequences=nofsequences+1
26772          sequence[nofsequences]=before[n]
26773         end
26774        end
26775        local start=nofsequences+1
26776        for n=1,#current do
26777         nofsequences=nofsequences+1
26778         sequence[nofsequences]=current[n]
26779        end
26780        local stop=nofsequences
26781        if after then
26782         for n=1,#after do
26783          nofsequences=nofsequences+1
26784          sequence[nofsequences]=after[n]
26785         end
26786        end
26787        local lookups=rule.lookups or false
26788        local subtype=nil
26789        if lookups then
26790         for i=1,#lookups do
26791          local lookups=lookups[i]
26792          if lookups then
26793           for k,v in next,lookups do 
26794            local lookup=sublookups[v]
26795if not lookup and whatever then
26796 lookup=whatever[v]
26797end
26798            if lookup then
26799             lookups[k]=lookup
26800             if not subtype then
26801              subtype=lookup.type
26802             end
26803            else
26804            end
26805           end
26806          end
26807         end
26808        end
26809        if sequence[1] then 
26810         sequence.n=#sequence 
26811         local ruledata={
26812          currentrule,
26813          lookuptype,
26814          sequence,
26815          start,
26816          stop,
26817          lookups,
26818          replacements,
26819          subtype,
26820         }
26821         rulesize=rulesize+1
26822         rulehash[rulesize]=ruledata
26823         rulehash.n=rulesize
26824         if true then 
26825          for unic in next,sequence[start] do
26826           local cu=coverage[unic]
26827           if cu then
26828            local n=#cu+1
26829            cu[n]=ruledata
26830            cu.n=n
26831           else
26832            coverage[unic]={ ruledata,n=1 }
26833           end
26834          end
26835         else
26836          for unic in next,sequence[start] do
26837           local cu=coverage[unic]
26838           if cu then
26839           else
26840            coverage[unic]=rulehash
26841           end
26842          end
26843         end
26844        end
26845       end
26846      end
26847     end
26848     checkmerge(sequence)
26849     checkflags(sequence,resources)
26850     checksteps(sequence)
26851    end
26852   end
26853  end
26854 end
26855 expandlookups(sequences)
26856 expandlookups(sublookups,sequences)
26857end
26858
26859end -- closure
26860
26861do -- begin closure to overcome local limits and interference
26862
26863if not modules then modules={} end modules ['font-ota']={
26864 version=1.001,
26865 comment="companion to font-ini.mkiv",
26866 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
26867 copyright="PRAGMA ADE / ConTeXt Development Team",
26868 license="see context related readme files"
26869}
26870local type=type
26871local setmetatableindex=table.setmetatableindex
26872if not trackers then trackers={ register=function() end } end
26873local fonts,nodes,node=fonts,nodes,node
26874local allocate=utilities.storage.allocate
26875local otf=fonts.handlers.otf
26876local analyzers=fonts.analyzers
26877local initializers=allocate()
26878local methods=allocate()
26879analyzers.initializers=initializers
26880analyzers.methods=methods
26881local nuts=nodes.nuts
26882local tonut=nuts.tonut
26883local getnext=nuts.getnext
26884local getprev=nuts.getprev
26885local getprev=nuts.getprev
26886local getprop=nuts.getprop
26887local setprop=nuts.setprop
26888local getsubtype=nuts.getsubtype
26889local getchar=nuts.getchar
26890local ischar=nuts.ischar
26891local endofmath=nuts.endofmath
26892local nodecodes=nodes.nodecodes
26893local disc_code=nodecodes.disc
26894local math_code=nodecodes.math
26895local fontdata=fonts.hashes.identifiers
26896local categories=characters and characters.categories or {} 
26897local chardata=characters and characters.data
26898local otffeatures=fonts.constructors.features.otf
26899local registerotffeature=otffeatures.register
26900local setstate=nuts.setstate
26901local getstate=nuts.getstate
26902if not setstate or not getstate then
26903 setstate=function(n,v)
26904  setprop(n,"state",v)
26905 end
26906 getstate=function(n,v)
26907  local s=getprop(n,"state")
26908  if v then
26909   return s==v
26910  else
26911   return s
26912  end
26913 end
26914 nuts.setstate=setstate
26915 nuts.getstate=getstate
26916end
26917local s_init=1 local s_rphf=7
26918local s_medi=2 local s_half=8
26919local s_fina=3 local s_pref=9
26920local s_isol=4 local s_blwf=10
26921local s_mark=5 local s_pstf=11
26922local s_rest=6
26923local states=allocate {
26924 init=s_init,
26925 medi=s_medi,
26926 med2=s_medi,
26927 fina=s_fina,
26928 fin2=s_fina,
26929 fin3=s_fina,
26930 isol=s_isol,
26931 mark=s_mark,
26932 rest=s_rest,
26933 rphf=s_rphf,
26934 half=s_half,
26935 pref=s_pref,
26936 blwf=s_blwf,
26937 pstf=s_pstf,
26938}
26939local features=allocate {
26940 init=s_init,
26941 medi=s_medi,
26942 med2=s_medi,
26943 fina=s_fina,
26944 fin2=s_fina,
26945 fin3=s_fina,
26946 isol=s_isol,
26947 rphf=s_rphf,
26948 half=s_half,
26949 pref=s_pref,
26950 blwf=s_blwf,
26951 pstf=s_pstf,
26952}
26953analyzers.states=states
26954analyzers.features=features
26955analyzers.useunicodemarks=false
26956function analyzers.setstate(head,font)
26957 local useunicodemarks=analyzers.useunicodemarks
26958 local tfmdata=fontdata[font]
26959 local descriptions=tfmdata.descriptions
26960 local first,last,current,n,done=nil,nil,head,0,false 
26961 current=tonut(current)
26962 while current do
26963  local char,id=ischar(current,font)
26964  if char and not getstate(current) then
26965   done=true
26966   local d=descriptions[char]
26967   if d then
26968    if d.class=="mark" then
26969     done=true
26970     setstate(current,s_mark)
26971    elseif useunicodemarks and categories[char]=="mn" then
26972     done=true
26973     setstate(current,s_mark)
26974    elseif n==0 then
26975     first,last,n=current,current,1
26976     setstate(current,s_init)
26977    else
26978     last,n=current,n+1
26979     setstate(current,s_medi)
26980    end
26981   else 
26982    if first and first==last then
26983     setstate(last,s_isol)
26984    elseif last then
26985     setstate(last,s_fina)
26986    end
26987    first,last,n=nil,nil,0
26988   end
26989  elseif char==false then
26990   if first and first==last then
26991    setstate(last,s_isol)
26992   elseif last then
26993    setstate(last,s_fina)
26994   end
26995   first,last,n=nil,nil,0
26996   if id==math_code then
26997    current=endofmath(current)
26998   end
26999  elseif id==disc_code then
27000   setstate(current,s_medi)
27001   last=current
27002  else 
27003   if first and first==last then
27004    setstate(last,s_isol)
27005   elseif last then
27006    setstate(last,s_fina)
27007   end
27008   first,last,n=nil,nil,0
27009   if id==math_code then
27010    current=endofmath(current)
27011   end
27012  end
27013  current=getnext(current)
27014 end
27015 if first and first==last then
27016  setstate(last,s_isol)
27017 elseif last then
27018  setstate(last,s_fina)
27019 end
27020 return head,done
27021end
27022local function analyzeinitializer(tfmdata,value) 
27023 local script,language=otf.scriptandlanguage(tfmdata) 
27024 local action=initializers[script]
27025 if not action then
27026 elseif type(action)=="function" then
27027  return action(tfmdata,value)
27028 else
27029  local action=action[language]
27030  if action then
27031   return action(tfmdata,value)
27032  end
27033 end
27034end
27035local function analyzeprocessor(head,font,attr)
27036 local tfmdata=fontdata[font]
27037 local script,language=otf.scriptandlanguage(tfmdata,attr)
27038 local action=methods[script]
27039 if not action then
27040 elseif type(action)=="function" then
27041  return action(head,font,attr)
27042 else
27043  action=action[language]
27044  if action then
27045   return action(head,font,attr)
27046  end
27047 end
27048 return head,false
27049end
27050registerotffeature {
27051 name="analyze",
27052 description="analysis of character classes",
27053 default=true,
27054 initializers={
27055  node=analyzeinitializer,
27056 },
27057 processors={
27058  position=1,
27059  node=analyzeprocessor,
27060 }
27061}
27062methods.latn=analyzers.setstate
27063local arab_warned={}
27064local function warning(current,what)
27065 local char=getchar(current)
27066 if not arab_warned[char] then
27067  log.report("analyze","arab: character %C has no %a class",char,what)
27068  arab_warned[char]=true
27069 end
27070end
27071local mappers=allocate {
27072 l=s_init,
27073 d=s_medi,
27074 c=s_medi,
27075 r=s_fina,
27076 u=s_isol,
27077}
27078local classifiers=characters.classifiers
27079if not classifiers then
27080 local f_arabic,l_arabic=characters.blockrange("arabic")
27081 local f_syriac,l_syriac=characters.blockrange("syriac")
27082 local f_mandiac,l_mandiac=characters.blockrange("mandiac")
27083 local f_nko,l_nko=characters.blockrange("nko")
27084 local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda")
27085 classifiers=setmetatableindex(function(t,k)
27086  if type(k)=="number" then
27087   local c=chardata[k]
27088   local v=false
27089   if c then
27090    local arabic=c.arabic
27091    if arabic then
27092     v=mappers[arabic]
27093     if not v then
27094      log.report("analyze","error in mapping arabic %C",k)
27095      v=false
27096     end
27097    elseif (k>=f_arabic  and k<=l_arabic)  or
27098        (k>=f_syriac  and k<=l_syriac)  or
27099        (k>=f_mandiac and k<=l_mandiac) or
27100        (k>=f_nko  and k<=l_nko)  or
27101        (k>=f_ext_a   and k<=l_ext_a)   then
27102     if categories[k]=="mn" then
27103      v=s_mark
27104     else
27105      v=s_rest
27106     end
27107    end
27108   end
27109   t[k]=v
27110   return v
27111  end
27112 end)
27113 characters.classifiers=classifiers
27114end
27115function methods.arab(head,font,attr)
27116 local first,last,c_first,c_last
27117 local current=head
27118 local done=false
27119 current=tonut(current)
27120 while current do
27121  local char,id=ischar(current,font)
27122  if char and not getstate(current) then
27123   done=true
27124   local classifier=classifiers[char]
27125   if not classifier then
27126    if last then
27127     if c_last==s_medi or c_last==s_fina then
27128      setstate(last,s_fina)
27129     else
27130      warning(last,"fina")
27131      setstate(last,s_error)
27132     end
27133     first,last=nil,nil
27134    elseif first then
27135     if c_first==s_medi or c_first==s_fina then
27136      setstate(first,s_isol)
27137     else
27138      warning(first,"isol")
27139      setstate(first,s_error)
27140     end
27141     first=nil
27142    end
27143   elseif classifier==s_mark then
27144    setstate(current,s_mark)
27145   elseif classifier==s_isol then
27146    if last then
27147     if c_last==s_medi or c_last==s_fina then
27148      setstate(last,s_fina)
27149     else
27150      warning(last,"fina")
27151      setstate(last,s_error)
27152     end
27153     first,last=nil,nil
27154    elseif first then
27155     if c_first==s_medi or c_first==s_fina then
27156      setstate(first,s_isol)
27157     else
27158      warning(first,"isol")
27159      setstate(first,s_error)
27160     end
27161     first=nil
27162    end
27163    setstate(current,s_isol)
27164   elseif classifier==s_medi then
27165    if first then
27166     last=current
27167     c_last=classifier
27168     setstate(current,s_medi)
27169    else
27170     setstate(current,s_init)
27171     first=current
27172     c_first=classifier
27173    end
27174   elseif classifier==s_fina then
27175    if last then
27176     if getstate(last)~=s_init then
27177      setstate(last,s_medi)
27178     end
27179     setstate(current,s_fina)
27180     first,last=nil,nil
27181    elseif first then
27182     setstate(current,s_fina)
27183     first=nil
27184    else
27185     setstate(current,s_isol)
27186    end
27187   else 
27188    setstate(current,s_rest)
27189    if last then
27190     if c_last==s_medi or c_last==s_fina then
27191      setstate(last,s_fina)
27192     else
27193      warning(last,"fina")
27194      setstate(last,s_error)
27195     end
27196     first,last=nil,nil
27197    elseif first then
27198     if c_first==s_medi or c_first==s_fina then
27199      setstate(first,s_isol)
27200     else
27201      warning(first,"isol")
27202      setstate(first,s_error)
27203     end
27204     first=nil
27205    end
27206   end
27207  else
27208   if last then
27209    if c_last==s_medi or c_last==s_fina then
27210     setstate(last,s_fina)
27211    else
27212     warning(last,"fina")
27213     setstate(last,s_error)
27214    end
27215    first,last=nil,nil
27216   elseif first then
27217    if c_first==s_medi or c_first==s_fina then
27218     setstate(first,s_isol)
27219    else
27220     warning(first,"isol")
27221     setstate(first,s_error)
27222    end
27223    first=nil
27224   end
27225   if id==math_code then 
27226    current=endofmath(current)
27227   end
27228  end
27229  current=getnext(current)
27230 end
27231 if last then
27232  if c_last==s_medi or c_last==s_fina then
27233   setstate(last,s_fina)
27234  else
27235   warning(last,"fina")
27236   setstate(last,s_error)
27237  end
27238 elseif first then
27239  if c_first==s_medi or c_first==s_fina then
27240   setstate(first,s_isol)
27241  else
27242   warning(first,"isol")
27243   setstate(first,s_error)
27244  end
27245 end
27246 return head,done
27247end
27248methods.syrc=methods.arab
27249methods.mand=methods.arab
27250methods.nko=methods.arab
27251do
27252 local joining=setmetatableindex(function(t,k)
27253  if type(k)=="number" then
27254   local c=chardata[k]
27255   local v=false
27256   if c then
27257    local mongolian=c.mongolian
27258    v=mongolian
27259   end
27260   t[k]=v
27261   return v
27262  end
27263 end)
27264 function methods.mong(head,font,attr)
27265  local first,last
27266  local current=head
27267  local done=false
27268  local prevjoin=nil
27269  local prestate=nil
27270  current=tonut(current)
27271  local function wrapup()
27272   if last then
27273    if last~=first then
27274     local s=getstate(last)
27275     if s==s_medi then
27276      setstate(last,s_fina)
27277     elseif s==s_init then
27278      setstate(last,s_isol)
27279     end
27280    end
27281    last=nil
27282    first=nil
27283    prevjoin=nil
27284    prestate=nil
27285   end
27286  end
27287  while current do
27288   local char,id=ischar(current,font)
27289   if char and not getstate(current) then
27290    local currjoin=joining[char]
27291    done=true
27292    if not last then
27293     setstate(current,s_isol)
27294     prevjoin=currjoin
27295     first=current
27296     last=current
27297     prevstate=s_isol
27298    elseif currjoin=="t" then
27299     last=current
27300    elseif prevjoin=="d" or prevjoin=="jc" or prevjoin=="l" then
27301     if currjoin=="d" or prevjoin=="jc" or prevjoin=="r" then
27302      local s=getstate(last)
27303      if s==s_isol then
27304       setstate(last,s_init)
27305      elseif s==s_fina then
27306       setstate(last,s_medi)
27307      end
27308      setstate(current,s_fina)
27309      prevstate=s_fina
27310     elseif prevjoin=="nj" or prevjoin=="l" then
27311      local s=getstate(last)
27312      if s==s_medi then
27313       setstate(last,s_fina)
27314      elseif s==s_init then
27315       setstate(last,s_isol)
27316      end
27317      setstate(current,s_isol)
27318      prevstate=s_isol
27319     end
27320     prevjoin=currjoin
27321     last=current
27322    elseif prevjoin=="nj" or prevjoin=="r" then
27323     if s==s_medi then
27324      setstate(last,s_fina)
27325     elseif s==s_init then
27326      setstate(last,s_isol)
27327     end
27328     setstate(current,s_isol)
27329     prevjoin=currjoin
27330     prevstate=s_isol
27331     last=current
27332    elseif last then
27333     wrapup()
27334    end
27335   else
27336    if last then
27337     wrapup()
27338    end
27339    if id==math_code then 
27340     current=endofmath(current)
27341    end
27342   end
27343   current=getnext(current)
27344  end
27345  if last then
27346   wrapup()
27347  end
27348  return head,done
27349 end
27350end
27351directives.register("otf.analyze.useunicodemarks",function(v)
27352 analyzers.useunicodemarks=v
27353end)
27354
27355end -- closure
27356
27357do -- begin closure to overcome local limits and interference
27358
27359if not modules then modules={} end modules ['font-ots']={ 
27360 version=1.001,
27361 optimize=true,
27362 comment="companion to font-ini.mkiv",
27363 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
27364 copyright="PRAGMA ADE / ConTeXt Development Team",
27365 license="see context related readme files",
27366}
27367local type,next,tonumber=type,next,tonumber
27368local random=math.random
27369local formatters=string.formatters
27370local insert=table.insert
27371local registertracker=trackers.register
27372local logs=logs
27373local trackers=trackers
27374local nodes=nodes
27375local attributes=attributes
27376local fonts=fonts
27377local otf=fonts.handlers.otf
27378local tracers=nodes.tracers
27379local trace_singles=false  registertracker("otf.singles",function(v) trace_singles=v end)
27380local trace_multiples=false  registertracker("otf.multiples",function(v) trace_multiples=v end)
27381local trace_alternatives=false  registertracker("otf.alternatives",function(v) trace_alternatives=v end)
27382local trace_ligatures=false  registertracker("otf.ligatures",function(v) trace_ligatures=v end)
27383local trace_contexts=false  registertracker("otf.contexts",function(v) trace_contexts=v end)
27384local trace_marks=false  registertracker("otf.marks",function(v) trace_marks=v end)
27385local trace_kerns=false  registertracker("otf.kerns",function(v) trace_kerns=v end)
27386local trace_cursive=false  registertracker("otf.cursive",function(v) trace_cursive=v end)
27387local trace_preparing=false  registertracker("otf.preparing",function(v) trace_preparing=v end)
27388local trace_bugs=false  registertracker("otf.bugs",function(v) trace_bugs=v end)
27389local trace_details=false  registertracker("otf.details",function(v) trace_details=v end)
27390local trace_steps=false  registertracker("otf.steps",function(v) trace_steps=v end)
27391local trace_skips=false  registertracker("otf.skips",function(v) trace_skips=v end)
27392local trace_plugins=false  registertracker("otf.plugins",function(v) trace_plugins=v end)
27393local trace_chains=false  registertracker("otf.chains",function(v) trace_chains=v end)
27394local trace_kernruns=false  registertracker("otf.kernruns",function(v) trace_kernruns=v end)
27395local trace_compruns=false  registertracker("otf.compruns",function(v) trace_compruns=v end)
27396local trace_testruns=false  registertracker("otf.testruns",function(v) trace_testruns=v end)
27397local forcediscretionaries=false
27398local forcepairadvance=false 
27399local repeatablemultiples=context or false
27400directives.register("otf.forcediscretionaries",function(v) forcediscretionaries=v end)
27401directives.register("otf.forcepairadvance",function(v) forcepairadvance=v end)
27402local report_direct=logs.reporter("fonts","otf direct")
27403local report_subchain=logs.reporter("fonts","otf subchain")
27404local report_chain=logs.reporter("fonts","otf chain")
27405local report_process=logs.reporter("fonts","otf process")
27406local report_warning=logs.reporter("fonts","otf warning")
27407local report_run=logs.reporter("fonts","otf run")
27408registertracker("otf.substitutions","otf.singles","otf.multiples","otf.alternatives","otf.ligatures")
27409registertracker("otf.positions","otf.marks","otf.kerns","otf.cursive")
27410registertracker("otf.actions","otf.substitutions","otf.positions")
27411registertracker("otf.sample","otf.steps","otf.substitutions","otf.positions","otf.analyzing")
27412registertracker("otf.sample.silent","otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing")
27413local nuts=nodes.nuts
27414local getnext=nuts.getnext
27415local setnext=nuts.setnext
27416local getprev=nuts.getprev
27417local setprev=nuts.setprev
27418local getboth=nuts.getboth
27419local setboth=nuts.setboth
27420local getid=nuts.getid
27421local getstate=nuts.getstate
27422local getsubtype=nuts.getsubtype
27423local getchar=nuts.getchar
27424local setchar=nuts.setchar
27425local getdisc=nuts.getdisc
27426local setdisc=nuts.setdisc
27427local getreplace=nuts.getreplace
27428local setlink=nuts.setlink
27429local getwidth=nuts.getwidth
27430local getattr=nuts.getattr
27431local getglyphdata=nuts.getglyphdata
27432local components=nuts.components
27433local copynocomponents=components.copynocomponents
27434local copyonlyglyphs=components.copyonlyglyphs
27435local countcomponents=components.count
27436local setcomponents=components.set
27437local getcomponents=components.get
27438local flushcomponents=components.flush
27439local ischar=nuts.ischar
27440local usesfont=nuts.usesfont
27441local insertnodeafter=nuts.insertafter
27442local copynode=nuts.copy
27443local copynodelist=nuts.copylist
27444local removenode=nuts.remove
27445local findnodetail=nuts.tail
27446local flushnodelist=nuts.flushlist
27447local flushnode=nuts.flushnode
27448local endofmath=nuts.endofmath
27449local startofpar=nuts.startofpar
27450local setmetatable=setmetatable
27451local setmetatableindex=table.setmetatableindex
27452local nextnode=nuts.traversers.node
27453local nodecodes=nodes.nodecodes
27454local glyphcodes=nodes.glyphcodes
27455local glyph_code=nodecodes.glyph
27456local glue_code=nodecodes.glue
27457local disc_code=nodecodes.disc
27458local math_code=nodecodes.math
27459local dir_code=nodecodes.dir
27460local par_code=nodecodes.par
27461local lefttoright_code=nodes.dirvalues.lefttoright
27462local righttoleft_code=nodes.dirvalues.righttoleft
27463local discretionarydisc_code=nodes.disccodes.discretionary
27464local a_noligature=attributes.private("noligature")
27465local injections=nodes.injections
27466local setmark=injections.setmark
27467local setcursive=injections.setcursive
27468local setkern=injections.setkern
27469local setmove=injections.setmove
27470local setposition=injections.setposition
27471local resetinjection=injections.reset
27472local copyinjection=injections.copy
27473local setligaindex=injections.setligaindex
27474local getligaindex=injections.getligaindex
27475local fontdata=fonts.hashes.identifiers
27476local fontfeatures=fonts.hashes.features
27477local otffeatures=fonts.constructors.features.otf
27478local registerotffeature=otffeatures.register
27479local onetimemessage=fonts.loggers.onetimemessage or function() end
27480local getrandom=utilities and utilities.randomizer and utilities.randomizer.get
27481otf.defaultnodealternate="none"
27482local tfmdata=false
27483local characters=false
27484local descriptions=false
27485local marks=false
27486local classes=false
27487local currentfont=false
27488local factor=0
27489local threshold=0
27490local checkmarks=false
27491local discs=false
27492local spaces=false
27493local sweepnode=nil
27494local sweephead={} 
27495local notmatchpre={} 
27496local notmatchpost={} 
27497local notmatchreplace={} 
27498local handlers={}
27499local isspace=injections.isspace
27500local getthreshold=injections.getthreshold
27501local checkstep=(tracers and tracers.steppers.check) or function() end
27502local registerstep=(tracers and tracers.steppers.register) or function() end
27503local registermessage=(tracers and tracers.steppers.message)  or function() end
27504local function logprocess(...)
27505 if trace_steps then
27506  registermessage(...)
27507  if trace_steps=="silent" then
27508   return
27509  end
27510 end
27511 report_direct(...)
27512end
27513local function logwarning(...)
27514 report_direct(...)
27515end
27516local gref  do
27517 local f_unicode=formatters["U+%X"]   
27518 local f_uniname=formatters["U+%X (%s)"] 
27519 local f_unilist=formatters["% t"]
27520 gref=function(n) 
27521  if type(n)=="number" then
27522   local description=descriptions[n]
27523   local name=description and description.name
27524   if name then
27525    return f_uniname(n,name)
27526   else
27527    return f_unicode(n)
27528   end
27529  elseif n then
27530   local t={}
27531   for i=1,#n do
27532    local ni=n[i]
27533    if tonumber(ni) then 
27534     local di=descriptions[ni]
27535     local nn=di and di.name
27536     if nn then
27537      t[#t+1]=f_uniname(ni,nn)
27538     else
27539      t[#t+1]=f_unicode(ni)
27540     end
27541    end
27542   end
27543   return f_unilist(t)
27544  else
27545   return "<error in node mode tracing>"
27546  end
27547 end
27548end
27549local function cref(dataset,sequence,index)
27550 if not dataset then
27551  return "no valid dataset"
27552 end
27553 local merged=sequence.merged and "merged " or ""
27554 if index and index>1 then
27555  return formatters["feature %a, type %a, %schain lookup %a, index %a"](
27556   dataset[4],sequence.type,merged,sequence.name,index)
27557 else
27558  return formatters["feature %a, type %a, %schain lookup %a"](
27559   dataset[4],sequence.type,merged,sequence.name)
27560 end
27561end
27562local function pref(dataset,sequence)
27563 return formatters["feature %a, type %a, %slookup %a"](
27564  dataset[4],sequence.type,sequence.merged and "merged " or "",sequence.name)
27565end
27566local function mref(rlmode)
27567 if not rlmode or rlmode>=0 then
27568  return "l2r"
27569 else
27570  return "r2l"
27571 end
27572end
27573local function flattendisk(head,disc)
27574 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
27575 local prev,next=getboth(disc)
27576 local ishead=head==disc
27577 setdisc(disc)
27578 flushnode(disc)
27579 if pre then
27580  flushnodelist(pre)
27581 end
27582 if post then
27583  flushnodelist(post)
27584 end
27585 if ishead then
27586  if replace then
27587   if next then
27588    setlink(replacetail,next)
27589   end
27590   return replace,replace
27591  elseif next then
27592   return next,next
27593  else
27594  end
27595 else
27596  if replace then
27597   if next then
27598    setlink(replacetail,next)
27599   end
27600   setlink(prev,replace)
27601   return head,replace
27602  else
27603   setlink(prev,next) 
27604   return head,next
27605  end
27606 end
27607end
27608local function appenddisc(disc,list)
27609 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
27610 local posthead=list
27611 local replacehead=copynodelist(list)
27612 if post then
27613  setlink(posttail,posthead)
27614 else
27615  post=posthead
27616 end
27617 if replace then
27618  setlink(replacetail,replacehead)
27619 else
27620  replace=replacehead
27621 end
27622 setdisc(disc,pre,post,replace)
27623end
27624local function markstoligature(head,start,stop,char)
27625 if start==stop and getchar(start)==char then
27626  return head,start
27627 else
27628  local prev=getprev(start)
27629  local next=getnext(stop)
27630  setprev(start)
27631  setnext(stop)
27632  local base=copynocomponents(start,copyinjection)
27633  if head==start then
27634   head=base
27635  end
27636  resetinjection(base)
27637  setchar(base,char)
27638  setcomponents(base,start)
27639  setlink(prev,base,next)
27640  flushcomponents(start)
27641  return head,base
27642 end
27643end
27644local no_left_ligature_code=1
27645local no_right_ligature_code=2
27646local no_left_kern_code=4
27647local no_right_kern_code=8
27648local hasglyphoption=function(n,c)
27649 if c==no_left_ligature_code or c==no_right_ligature_code then
27650  return getattr(n,a_noligature)==1
27651 else
27652  return false
27653 end
27654end
27655local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) 
27656 if hasglyphoption(start,no_right_ligature_code) then
27657  return head,start
27658 end
27659 if start==stop and getchar(start)==char then
27660  resetinjection(start)
27661  setchar(start,char)
27662  return head,start
27663 end
27664 local prev=getprev(start)
27665 local next=getnext(stop)
27666 local comp=start
27667 setprev(start)
27668 setnext(stop)
27669 local base=copynocomponents(start,copyinjection)
27670 if start==head then
27671  head=base
27672 end
27673 resetinjection(base)
27674 setchar(base,char)
27675 setcomponents(base,comp)
27676 setlink(prev,base,next)
27677 if not discfound then
27678  local deletemarks=not skiphash or hasmarks
27679  local components=start 
27680  local baseindex=0
27681  local componentindex=0
27682  local head=base
27683  local current=base
27684  while start do
27685   local char=getchar(start)
27686   if not marks[char] then
27687    baseindex=baseindex+componentindex
27688    componentindex=countcomponents(start,marks)
27689   elseif not deletemarks then
27690    setligaindex(start,baseindex+getligaindex(start,componentindex))
27691    if trace_marks then
27692     logwarning("%s: keep ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
27693    end
27694    local n=copynode(start)
27695    copyinjection(n,start) 
27696    head,current=insertnodeafter(head,current,n) 
27697   elseif trace_marks then
27698    logwarning("%s: delete ligature mark %s",pref(dataset,sequence),gref(char))
27699   end
27700   start=getnext(start)
27701  end
27702  local start=getnext(current)
27703  while start do
27704   local char=ischar(start)
27705   if char then
27706    if marks[char] then
27707     setligaindex(start,baseindex+getligaindex(start,componentindex))
27708     if trace_marks then
27709      logwarning("%s: set ligature mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
27710     end
27711     start=getnext(start)
27712    else
27713     break
27714    end
27715   else
27716    break
27717   end
27718  end
27719  flushcomponents(components)
27720 else
27721  local discprev,discnext=getboth(discfound)
27722  if discprev and discnext then
27723   local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true)
27724   if not replace then
27725    local prev=getprev(base)
27726    local copied=copyonlyglyphs(comp)
27727    if pre then
27728     setlink(discprev,pre)
27729    else
27730     setnext(discprev) 
27731    end
27732    pre=comp 
27733    if post then
27734     setlink(posttail,discnext)
27735     setprev(post) 
27736    else
27737     post=discnext
27738     setprev(discnext) 
27739    end
27740    setlink(prev,discfound,next)
27741    setboth(base)
27742    setcomponents(base,copied)
27743    replace=base
27744    if forcediscretionaries then
27745     setdisc(discfound,pre,post,replace,discretionarydisc_code)
27746    else
27747     setdisc(discfound,pre,post,replace)
27748    end
27749    base=prev
27750   end
27751  end
27752 end
27753 return head,base
27754end
27755local function multiple_glyphs(head,start,multiple,skiphash,what,stop) 
27756 local nofmultiples=#multiple
27757 if nofmultiples>0 then
27758  local first=start
27759  resetinjection(start)
27760  setchar(start,multiple[1])
27761  if nofmultiples>1 then
27762   for i=2,nofmultiples do
27763    local n=copynode(start) 
27764    resetinjection(n)
27765    setchar(n,multiple[i])
27766    insertnodeafter(head,start,n)
27767    start=n
27768   end
27769  end
27770  if what~=true and repeatablemultiples then
27771   local kind=type(what)
27772   local m,f,l
27773   if kind=="string" then
27774    local what,n=string.match(what,"^repeat(.-)[:=](%d+)$")
27775    if what=="middle" then
27776     m=tonumber(n)
27777    elseif what=="first" then
27778     f=tonumber(n)
27779    elseif what=="last" then
27780     l=tonumber(n)
27781    end
27782   elseif kind=="table" then
27783      m=what.middle
27784      f=what.first
27785      l=what.last
27786   end
27787   if f or m or l then
27788    if m and m>1 and nofmultiples==3 then
27789     local middle=getnext(first)
27790     for i=2,m do
27791      local n=copynode(middle) 
27792      resetinjection(n)
27793      insertnodeafter(head,first,n)
27794     end
27795    end
27796    if f and f>1 then
27797     for i=2,f do
27798      local n=copynode(first) 
27799      resetinjection(n)
27800      insertnodeafter(head,first,n)
27801     end
27802    end
27803    if l and l>1 then
27804     for i=2,l do
27805      local n=copynode(start) 
27806      resetinjection(n)
27807      insertnodeafter(head,start,n)
27808      start=n
27809     end
27810    end
27811   end
27812  end
27813  return head,start,true
27814 else
27815  if trace_multiples then
27816   logprocess("no multiple for %s",gref(getchar(start)))
27817  end
27818  return head,start,false
27819 end
27820end
27821local function get_alternative_glyph(start,alternatives,value)
27822 local n=#alternatives
27823 if n==1 then
27824  return alternatives[1],trace_alternatives and "1 (only one present)"
27825 elseif value=="random" then
27826  local r=getrandom and getrandom("glyph",1,n) or random(1,n)
27827  return alternatives[r],trace_alternatives and formatters["value %a, taking %a"](value,r)
27828 elseif value=="first" then
27829  return alternatives[1],trace_alternatives and formatters["value %a, taking %a"](value,1)
27830 elseif value=="last" then
27831  return alternatives[n],trace_alternatives and formatters["value %a, taking %a"](value,n)
27832 end
27833 value=value==true and 1 or tonumber(value)
27834 if type(value)~="number" then
27835  return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
27836 end
27837 if value>n then
27838  local defaultalt=otf.defaultnodealternate
27839  if defaultalt=="first" then
27840   return alternatives[n],trace_alternatives and formatters["invalid value %s, taking %a"](value,1)
27841  elseif defaultalt=="last" then
27842   return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,n)
27843  else
27844   return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
27845  end
27846 elseif value==0 then
27847  return getchar(start),trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
27848 elseif value<1 then
27849  return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
27850 else
27851  return alternatives[value],trace_alternatives and formatters["value %a, taking %a"](value,value)
27852 end
27853end
27854function handlers.gsub_single(head,start,dataset,sequence,replacement)
27855 if trace_singles then
27856  logprocess("%s: replacing %s by single %s",pref(dataset,sequence),gref(getchar(start)),gref(replacement))
27857 end
27858 resetinjection(start)
27859 setchar(start,replacement)
27860 return head,start,true
27861end
27862function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
27863 local kind=dataset[4]
27864 local what=dataset[1]
27865 local value=what==true and tfmdata.shared.features[kind] or what
27866 local choice,comment=get_alternative_glyph(start,alternative,value)
27867 if choice then
27868  if trace_alternatives then
27869   logprocess("%s: replacing %s by alternative %a to %s, %s",pref(dataset,sequence),gref(getchar(start)),gref(choice),comment)
27870  end
27871  resetinjection(start)
27872  setchar(start,choice)
27873 else
27874  if trace_alternatives then
27875   logwarning("%s: no variant %a for %s, %s",pref(dataset,sequence),value,gref(getchar(start)),comment)
27876  end
27877 end
27878 return head,start,true
27879end
27880function handlers.gsub_multiple(head,start,dataset,sequence,multiple,rlmode,skiphash)
27881 if trace_multiples then
27882  logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
27883 end
27884 return multiple_glyphs(head,start,multiple,skiphash,dataset[1])
27885end
27886function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skiphash)
27887 local current=getnext(start)
27888 if not current then
27889  return head,start,false,nil
27890 end
27891 local stop=nil
27892 local startchar=getchar(start)
27893 if skiphash and skiphash[startchar] then
27894  while current do
27895   local char=ischar(current,currentfont)
27896   if char then
27897    local lg=not tonumber(ligature) and ligature[char]
27898    if lg then
27899     stop=current
27900     ligature=lg
27901     current=getnext(current)
27902    else
27903     break
27904    end
27905   else
27906    break
27907   end
27908  end
27909  if stop then
27910   local ligature=tonumber(ligature) or ligature.ligature
27911   if ligature then
27912    if trace_ligatures then
27913     local stopchar=getchar(stop)
27914     head,start=markstoligature(head,start,stop,ligature)
27915     logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start)))
27916    else
27917     head,start=markstoligature(head,start,stop,ligature)
27918    end
27919    return head,start,true,false
27920   else
27921   end
27922  end
27923 else
27924  local discfound=false
27925  local hasmarks=marks[startchar]
27926  while current do
27927   local char,id=ischar(current,currentfont)
27928   if char then
27929    if skiphash and skiphash[char] then
27930     current=getnext(current)
27931    else
27932     local lg=not tonumber(ligature) and ligature[char]
27933     if lg then
27934      if marks[char] then
27935       hasmarks=true
27936      end
27937      stop=current 
27938      ligature=lg
27939      current=getnext(current)
27940     else
27941      break
27942     end
27943    end
27944   elseif char==false then
27945    break
27946   elseif id==disc_code then
27947    discfound=current
27948    break
27949   else
27950    break
27951   end
27952  end
27953  if discfound then
27954   local pre,post,replace=getdisc(discfound)
27955   local match
27956   if replace then
27957    local char=ischar(replace,currentfont)
27958    if char and (not tonumber(ligature) and ligature[char]) then
27959     match=true
27960    end
27961   end
27962   if not match and pre then
27963    local char=ischar(pre,currentfont)
27964    if char and (not tonumber(ligature) and ligature[char]) then
27965     match=true
27966    end
27967   end
27968   if not match and not pre or not replace then
27969    local n=getnext(discfound)
27970    local char=ischar(n,currentfont)
27971    if char and (not tonumber(ligature) and ligature[char]) then
27972     match=true
27973    end
27974   end
27975   if match then
27976    local ishead=head==start
27977    local prev=getprev(start)
27978    if stop then
27979     setnext(stop)
27980     local copy=copynodelist(start)
27981     local tail=stop 
27982     local liat=findnodetail(copy)
27983     if pre then
27984      setlink(liat,pre)
27985     end
27986     if replace then
27987      setlink(tail,replace)
27988     end
27989     pre=copy
27990     replace=start
27991    else
27992     setnext(start)
27993     local copy=copynode(start)
27994     if pre then
27995      setlink(copy,pre)
27996     end
27997     if replace then
27998      setlink(start,replace)
27999     end
28000     pre=copy
28001     replace=start
28002    end
28003    setdisc(discfound,pre,post,replace)
28004    if prev then
28005     setlink(prev,discfound)
28006    else
28007     setprev(discfound)
28008     head=discfound
28009    end
28010    start=discfound
28011    return head,start,true,true
28012   end
28013  end
28014  local ligature=tonumber(ligature) or ligature.ligature
28015  if ligature then
28016   if stop then
28017    if trace_ligatures then
28018     local stopchar=getchar(stop)
28019     head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
28020     logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(ligature))
28021    else
28022     head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,false,hasmarks)
28023    end
28024   else
28025    resetinjection(start)
28026    setchar(start,ligature)
28027    if trace_ligatures then
28028     logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(ligature))
28029    end
28030   end
28031   return head,start,true,false
28032  else
28033  end
28034 end
28035 return head,start,false,false
28036end
28037function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
28038 if hasglyphoption(start,no_right_kern_code) then
28039  return head,start,false
28040 else
28041  local startchar=getchar(start)
28042  local format=step.format
28043  if format=="single" or type(kerns)=="table" then 
28044   local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection)
28045   if trace_kerns then
28046    logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
28047   end
28048  else
28049   local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
28050   if trace_kerns then
28051    logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k)
28052   end
28053  end
28054  return head,start,true
28055 end
28056end
28057function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
28058 if hasglyphoption(start,no_right_kern_code) then
28059  return head,start,false
28060 else
28061  local snext=getnext(start)
28062  if not snext then
28063   return head,start,false
28064  else
28065   local prev=start
28066   while snext do
28067    local nextchar=ischar(snext,currentfont)
28068    if nextchar then
28069     if skiphash and skiphash[nextchar] then 
28070      prev=snext
28071      snext=getnext(snext)
28072     else
28073      local krn=kerns[nextchar]
28074      if not krn then
28075       break
28076      end
28077      local format=step.format
28078      if format=="pair" then
28079       local a=krn[1]
28080       local b=krn[2]
28081       if a==true then
28082       elseif a then 
28083        local x,y,w,h=setposition(1,start,factor,rlmode,a,injection)
28084        if trace_kerns then
28085         local startchar=getchar(start)
28086         logprocess("%s: shifting first of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
28087        end
28088       end
28089       if b==true then
28090        start=snext 
28091       elseif b then 
28092        local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection)
28093        if trace_kerns then
28094         local startchar=getchar(start)
28095         logprocess("%s: shifting second of pair %s and %s by xy (%p,%p) and wh (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
28096        end
28097        start=snext 
28098       elseif forcepairadvance then
28099        start=snext 
28100       end
28101       return head,start,true
28102      elseif krn~=0 then
28103       local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection)
28104       if trace_kerns then
28105        logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections")
28106       end
28107       return head,start,true
28108      else 
28109       break
28110      end
28111     end
28112    else
28113     break
28114    end
28115   end
28116   return head,start,false
28117  end
28118 end
28119end
28120function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash)
28121 local markchar=getchar(start)
28122 if marks[markchar] then
28123  local base=getprev(start) 
28124  if base then
28125   local basechar=ischar(base,currentfont)
28126   if basechar then
28127    if marks[basechar] then
28128     while base do
28129      base=getprev(base)
28130      if base then
28131       basechar=ischar(base,currentfont)
28132       if basechar then
28133        if not marks[basechar] then
28134         break
28135        end
28136       else
28137        if trace_bugs then
28138         logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
28139        end
28140        return head,start,false
28141       end
28142      else
28143       if trace_bugs then
28144        logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
28145       end
28146       return head,start,false
28147      end
28148     end
28149    end
28150    local ba=markanchors[1][basechar]
28151    if ba then
28152     local ma=markanchors[2]
28153     local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
28154     if trace_marks then
28155      logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
28156       pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
28157     end
28158     return head,start,true
28159    elseif trace_bugs then
28160     logwarning("%s: mark %s is not anchored to %s",pref(dataset,sequence),gref(markchar),gref(basechar))
28161    end
28162   elseif trace_bugs then
28163    logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),1)
28164   end
28165  elseif trace_bugs then
28166   logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),2)
28167  end
28168 elseif trace_bugs then
28169  logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar))
28170 end
28171 return head,start,false
28172end
28173function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode,skiphash)
28174 local markchar=getchar(start)
28175 if marks[markchar] then
28176  local base=getprev(start) 
28177  if base then
28178   local basechar=ischar(base,currentfont)
28179   if basechar then
28180    if marks[basechar] then
28181     while base do
28182      base=getprev(base)
28183      if base then
28184       basechar=ischar(base,currentfont)
28185       if basechar then
28186        if not marks[basechar] then
28187         break
28188        end
28189       else
28190        if trace_bugs then
28191         logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
28192        end
28193        return head,start,false
28194       end
28195      else
28196       if trace_bugs then
28197        logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
28198       end
28199       return head,start,false
28200      end
28201     end
28202    end
28203    local ba=markanchors[1][basechar]
28204    if ba then
28205     local ma=markanchors[2]
28206     if ma then
28207      local index=getligaindex(start)
28208      ba=ba[index]
28209      if ba then
28210       local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
28211       if trace_marks then
28212        logprocess("%s, index %s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
28213         pref(dataset,sequence),index,bound,gref(markchar),gref(basechar),index,dx,dy)
28214       end
28215       return head,start,true
28216      else
28217       if trace_bugs then
28218        logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(dataset,sequence),gref(markchar),gref(basechar),index)
28219       end
28220      end
28221     end
28222    elseif trace_bugs then
28223     onetimemessage(currentfont,basechar,"no base anchors")
28224    end
28225   elseif trace_bugs then
28226    logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1)
28227   end
28228  elseif trace_bugs then
28229   logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),2)
28230  end
28231 elseif trace_bugs then
28232  logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar))
28233 end
28234 return head,start,false
28235end
28236function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode,skiphash)
28237 local markchar=getchar(start)
28238 if marks[markchar] then
28239  local base=getprev(start) 
28240  local slc=getligaindex(start)
28241  if slc then 
28242   while base do
28243    local blc=getligaindex(base)
28244    if blc and blc~=slc then
28245     base=getprev(base)
28246    else
28247     break
28248    end
28249   end
28250  end
28251  if base then
28252   local basechar=ischar(base,currentfont)
28253   if basechar then 
28254    local ba=markanchors[1][basechar] 
28255    if ba then
28256     local ma=markanchors[2]
28257     local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
28258     if trace_marks then
28259      logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
28260       pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
28261     end
28262     return head,start,true
28263    end
28264   end
28265  end
28266 elseif trace_bugs then
28267  logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar))
28268 end
28269 return head,start,false
28270end
28271function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,skiphash,step) 
28272 local startchar=getchar(start)
28273 if marks[startchar] then
28274  if trace_cursive then
28275   logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
28276  end
28277 else
28278  local nxt=getnext(start)
28279  while nxt do
28280   local nextchar=ischar(nxt,currentfont)
28281   if not nextchar then
28282    break
28283   elseif marks[nextchar] then 
28284    nxt=getnext(nxt)
28285   else
28286    local exit=exitanchors[3]
28287    if exit then
28288     local entry=exitanchors[1][nextchar]
28289     if entry then
28290      entry=entry[2]
28291      if entry then
28292       local r2lflag=sequence.flags[4] 
28293       local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
28294       if trace_cursive then
28295        logprocess("%s: moving %s to %s cursive (%p,%p) using bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,bound,mref(rlmode))
28296       end
28297       return head,start,true
28298      end
28299     end
28300    end
28301    break
28302   end
28303  end
28304 end
28305 return head,start,false
28306end
28307local chainprocs={}
28308local function logprocess(...)
28309 if trace_steps then
28310  registermessage(...)
28311  if trace_steps=="silent" then
28312   return
28313  end
28314 end
28315 report_subchain(...)
28316end
28317local logwarning=report_subchain
28318local function logprocess(...)
28319 if trace_steps then
28320  registermessage(...)
28321  if trace_steps=="silent" then
28322   return
28323  end
28324 end
28325 report_chain(...)
28326end
28327local logwarning=report_chain
28328local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode,skiphash)
28329 local char=getchar(start)
28330 local replacement=replacements[char]
28331 if replacement then
28332  if trace_singles then
28333   logprocess("%s: single reverse replacement of %s by %s",cref(dataset,sequence),gref(char),gref(replacement))
28334  end
28335  resetinjection(start)
28336  setchar(start,replacement)
28337  return head,start,true
28338 else
28339  return head,start,false
28340 end
28341end
28342chainprocs.reversesub=reversesub
28343local function reportzerosteps(dataset,sequence)
28344 logwarning("%s: no steps",cref(dataset,sequence))
28345end
28346local function reportmoresteps(dataset,sequence)
28347 logwarning("%s: more than 1 step",cref(dataset,sequence))
28348end
28349local function getmapping(dataset,sequence,currentlookup)
28350 local steps=currentlookup.steps
28351 local nofsteps=currentlookup.nofsteps
28352 if nofsteps==0 then
28353  reportzerosteps(dataset,sequence)
28354  currentlookup.mapping=false
28355  return false
28356 else
28357  if nofsteps>1 then
28358   reportmoresteps(dataset,sequence)
28359  end
28360  local mapping=steps[1].coverage
28361  currentlookup.mapping=mapping
28362  currentlookup.format=steps[1].format
28363  return mapping
28364 end
28365end
28366function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28367 if trace_chains then
28368  logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start)))
28369 end
28370 head,start=removenode(head,start,true)
28371 return head,getprev(start),true
28372end
28373function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28374 local mapping=currentlookup.mapping
28375 if mapping==nil then
28376  mapping=getmapping(dataset,sequence,currentlookup)
28377 end
28378 if mapping then
28379  local current=start
28380  while current do
28381   local currentchar=ischar(current)
28382   if currentchar then
28383    local replacement=mapping[currentchar]
28384    if not replacement or replacement=="" then
28385     if trace_bugs then
28386      logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
28387     end
28388    else
28389     if trace_singles then
28390      logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
28391     end
28392     resetinjection(current)
28393     setchar(current,replacement)
28394    end
28395    return head,start,true
28396   elseif currentchar==false then
28397    break
28398   elseif current==stop then
28399    break
28400   else
28401    current=getnext(current)
28402   end
28403  end
28404 end
28405 return head,start,false
28406end
28407function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28408 local mapping=currentlookup.mapping
28409 if mapping==nil then
28410  mapping=getmapping(dataset,sequence,currentlookup)
28411 end
28412 if mapping then
28413  local kind=dataset[4]
28414  local what=dataset[1]
28415  local value=what==true and tfmdata.shared.features[kind] or what 
28416  local current=start
28417  while current do
28418   local currentchar=ischar(current)
28419   if currentchar then
28420    local alternatives=mapping[currentchar]
28421    if alternatives then
28422     local choice,comment=get_alternative_glyph(current,alternatives,value)
28423     if choice then
28424      if trace_alternatives then
28425       logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(currentchar),choice,gref(choice),comment)
28426      end
28427      resetinjection(start)
28428      setchar(start,choice)
28429     else
28430      if trace_alternatives then
28431       logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(currentchar),comment)
28432      end
28433     end
28434    end
28435    return head,start,true
28436   elseif currentchar==false then
28437    break
28438   elseif current==stop then
28439    break
28440   else
28441    current=getnext(current)
28442   end
28443  end
28444 end
28445 return head,start,false
28446end
28447function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28448 local mapping=currentlookup.mapping
28449 if mapping==nil then
28450  mapping=getmapping(dataset,sequence,currentlookup)
28451 end
28452 if mapping then
28453  local startchar=getchar(start)
28454  local replacement=mapping[startchar]
28455  if not replacement or replacement=="" then
28456   if trace_bugs then
28457    logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
28458   end
28459  else
28460   if trace_multiples then
28461    logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
28462   end
28463   return multiple_glyphs(head,start,replacement,skiphash,dataset[1],stop)
28464  end
28465 end
28466 return head,start,false
28467end
28468function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28469 local mapping=currentlookup.mapping
28470 if mapping==nil then
28471  mapping=getmapping(dataset,sequence,currentlookup)
28472 end
28473 if mapping then
28474  local startchar=getchar(start)
28475  local ligatures=mapping[startchar]
28476  if not ligatures then
28477   if trace_bugs then
28478    logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
28479   end
28480  else
28481   local hasmarks=marks[startchar]
28482   local current=getnext(start)
28483   local discfound=false
28484   local last=stop
28485   local nofreplacements=1
28486   while current do
28487    local id=getid(current)
28488    if id==disc_code then
28489     if not discfound then
28490      discfound=current
28491     end
28492     if current==stop then
28493      break 
28494     else
28495      current=getnext(current)
28496     end
28497    else
28498     local schar=getchar(current)
28499     if skiphash and skiphash[schar] then
28500       current=getnext(current)
28501     else
28502      local lg=not tonumber(ligatures) and ligatures[schar]
28503      if lg then
28504       ligatures=lg
28505       last=current
28506       nofreplacements=nofreplacements+1
28507       if marks[char] then
28508        hasmarks=true
28509       end
28510       if current==stop then
28511        break
28512       else
28513        current=getnext(current)
28514       end
28515      else
28516       break
28517      end
28518     end
28519    end
28520   end
28521   local ligature=tonumber(ligatures) or ligatures.ligature
28522   if ligature then
28523    if chainindex then
28524     stop=last
28525    end
28526    if trace_ligatures then
28527     if start==stop then
28528      logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
28529     else
28530      logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
28531     end
28532    end
28533    head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound,hasmarks)
28534    return head,start,true,nofreplacements,discfound
28535   elseif trace_bugs then
28536    if start==stop then
28537     logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
28538    else
28539     logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
28540    end
28541   end
28542  end
28543 end
28544 return head,start,false,0,false
28545end
28546function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28547 if not hasglyphoption(start,no_right_kern_code) then
28548  local mapping=currentlookup.mapping
28549  if mapping==nil then
28550   mapping=getmapping(dataset,sequence,currentlookup)
28551  end
28552  if mapping then
28553   local startchar=getchar(start)
28554   local kerns=mapping[startchar]
28555   if kerns then
28556    local format=currentlookup.format
28557    if format=="single" then
28558     local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns) 
28559     if trace_kerns then
28560      logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
28561     end
28562    else 
28563     local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
28564     if trace_kerns then
28565      logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k)
28566     end
28567    end
28568    return head,start,true
28569   end
28570  end
28571 end
28572 return head,start,false
28573end
28574function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28575 if not hasglyphoption(start,no_right_kern_code) then
28576  local mapping=currentlookup.mapping
28577  if mapping==nil then
28578   mapping=getmapping(dataset,sequence,currentlookup)
28579  end
28580  if mapping then
28581   local snext=getnext(start)
28582   if snext then
28583    local startchar=getchar(start)
28584    local kerns=mapping[startchar] 
28585    if kerns then
28586     local prev=start
28587     while snext do
28588      local nextchar=ischar(snext,currentfont)
28589      if not nextchar then
28590       break
28591      end
28592      if skiphash and skiphash[nextchar] then
28593       prev=snext
28594       snext=getnext(snext)
28595      else
28596       local krn=kerns[nextchar]
28597       if not krn then
28598        break
28599       end
28600       local format=currentlookup.format
28601       if format=="pair" then
28602        local a=krn[1]
28603        local b=krn[2]
28604        if a==true then
28605        elseif a then
28606         local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") 
28607         if trace_kerns then
28608          local startchar=getchar(start)
28609          logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
28610         end
28611        end
28612        if b==true then
28613         start=snext 
28614        elseif b then 
28615         local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections")
28616         if trace_kerns then
28617          local startchar=getchar(start)
28618          logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
28619         end
28620         start=snext 
28621        elseif forcepairadvance then
28622         start=snext 
28623        end
28624        return head,start,true
28625       elseif krn~=0 then
28626        local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn)
28627        if trace_kerns then
28628         logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar))
28629        end
28630        return head,start,true
28631       else
28632        break
28633       end
28634      end
28635     end
28636    end
28637   end
28638  end
28639 end
28640 return head,start,false
28641end
28642function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28643 local mapping=currentlookup.mapping
28644 if mapping==nil then
28645  mapping=getmapping(dataset,sequence,currentlookup)
28646 end
28647 if mapping then
28648  local markchar=getchar(start)
28649  if marks[markchar] then
28650   local markanchors=mapping[markchar] 
28651   if markanchors then
28652    local base=getprev(start) 
28653    if base then
28654     local basechar=ischar(base,currentfont)
28655     if basechar then
28656      if marks[basechar] then
28657       while base do
28658        base=getprev(base)
28659        if base then
28660         local basechar=ischar(base,currentfont)
28661         if basechar then
28662          if not marks[basechar] then
28663           break
28664          end
28665         else
28666          if trace_bugs then
28667           logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
28668          end
28669          return head,start,false
28670         end
28671        else
28672         if trace_bugs then
28673          logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
28674         end
28675         return head,start,false
28676        end
28677       end
28678      end
28679      local ba=markanchors[1][basechar]
28680      if ba then
28681       local ma=markanchors[2]
28682       if ma then
28683        local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
28684        if trace_marks then
28685         logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
28686          cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
28687        end
28688        return head,start,true
28689       end
28690      end
28691     elseif trace_bugs then
28692      logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
28693     end
28694    elseif trace_bugs then
28695     logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
28696    end
28697   elseif trace_bugs then
28698    logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
28699   end
28700  elseif trace_bugs then
28701   logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
28702  end
28703 end
28704 return head,start,false
28705end
28706function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28707 local mapping=currentlookup.mapping
28708 if mapping==nil then
28709  mapping=getmapping(dataset,sequence,currentlookup)
28710 end
28711 if mapping then
28712  local markchar=getchar(start)
28713  if marks[markchar] then
28714   local markanchors=mapping[markchar] 
28715   if markanchors then
28716    local base=getprev(start) 
28717    if base then
28718     local basechar=ischar(base,currentfont)
28719     if basechar then
28720      if marks[basechar] then
28721       while base do
28722        base=getprev(base)
28723        if base then
28724         local basechar=ischar(base,currentfont)
28725         if basechar then
28726          if not marks[basechar] then
28727           break
28728          end
28729         else
28730          if trace_bugs then
28731           logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
28732          end
28733          return head,start,false
28734         end
28735        else
28736         if trace_bugs then
28737          logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
28738         end
28739         return head,start,false
28740        end
28741       end
28742      end
28743      local ba=markanchors[1][basechar]
28744      if ba then
28745       local ma=markanchors[2]
28746       if ma then
28747        local index=getligaindex(start)
28748        ba=ba[index]
28749        if ba then
28750         local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
28751         if trace_marks then
28752          logprocess("%s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
28753           cref(dataset,sequence),a or bound,gref(markchar),gref(basechar),index,dx,dy)
28754         end
28755         return head,start,true
28756        end
28757       end
28758      end
28759     elseif trace_bugs then
28760      logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
28761     end
28762    elseif trace_bugs then
28763     logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
28764    end
28765   elseif trace_bugs then
28766    logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
28767   end
28768  elseif trace_bugs then
28769   logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
28770  end
28771 end
28772 return head,start,false
28773end
28774function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28775 local mapping=currentlookup.mapping
28776 if mapping==nil then
28777  mapping=getmapping(dataset,sequence,currentlookup)
28778 end
28779 if mapping then
28780  local markchar=getchar(start)
28781  if marks[markchar] then
28782   local markanchors=mapping[markchar] 
28783   if markanchors then
28784    local base=getprev(start) 
28785    local slc=getligaindex(start)
28786    if slc then 
28787     while base do
28788      local blc=getligaindex(base)
28789      if blc and blc~=slc then
28790       base=getprev(base)
28791      else
28792       break
28793      end
28794     end
28795    end
28796    if base then 
28797     local basechar=ischar(base,currentfont)
28798     if basechar then
28799      local ba=markanchors[1][basechar]
28800      if ba then
28801       local ma=markanchors[2]
28802       if ma then
28803        local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
28804        if trace_marks then
28805         logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
28806          cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
28807        end
28808        return head,start,true
28809       end
28810      end
28811     elseif trace_bugs then
28812      logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
28813     end
28814    elseif trace_bugs then
28815     logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
28816    end
28817   elseif trace_bugs then
28818    logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
28819   end
28820  elseif trace_bugs then
28821   logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
28822  end
28823 end
28824 return head,start,false
28825end
28826function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
28827 local mapping=currentlookup.mapping
28828 if mapping==nil then
28829  mapping=getmapping(dataset,sequence,currentlookup)
28830 end
28831 if mapping then
28832  local startchar=getchar(start)
28833  local exitanchors=mapping[startchar] 
28834  if exitanchors then
28835   if marks[startchar] then
28836    if trace_cursive then
28837     logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
28838    end
28839   else
28840    local nxt=getnext(start)
28841    while nxt do
28842     local nextchar=ischar(nxt,currentfont)
28843     if not nextchar then
28844      break
28845     elseif marks[nextchar] then
28846      nxt=getnext(nxt)
28847     else
28848      local exit=exitanchors[3]
28849      if exit then
28850       local entry=exitanchors[1][nextchar]
28851       if entry then
28852        entry=entry[2]
28853        if entry then
28854         local r2lflag=sequence.flags[4] 
28855         local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
28856         if trace_cursive then
28857          logprocess("%s: moving %s to %s cursive (%p,%p) using bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,bound,mref(rlmode))
28858         end
28859         return head,start,true
28860        end
28861       end
28862      elseif trace_bugs then
28863       onetimemessage(currentfont,startchar,"no entry anchors")
28864      end
28865      break
28866     end
28867    end
28868   end
28869  elseif trace_cursive and trace_details then
28870   logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone)
28871  end
28872 end
28873 return head,start,false
28874end
28875local function show_skip(dataset,sequence,char,ck,class)
28876 logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8] or ck[2])
28877end
28878local userkern=nuts.pool and nuts.pool.newkern 
28879do if not userkern then 
28880 local thekern=nuts.new("kern",1) 
28881 local setkern=nuts.setkern    
28882 userkern=function(k)
28883  local n=copynode(thekern)
28884  setkern(n,k)
28885  return n
28886 end
28887end end
28888local function checked(head)
28889 local current=head
28890 while current do
28891  if getid(current)==glue_code then
28892   local kern=userkern(getwidth(current))
28893   if head==current then
28894    local next=getnext(current)
28895    if next then
28896     setlink(kern,next)
28897    end
28898    flushnode(current)
28899    head=kern
28900    current=next
28901   else
28902    local prev,next=getboth(current)
28903    setlink(prev,kern,next)
28904    flushnode(current)
28905    current=next
28906   end
28907  else
28908   current=getnext(current)
28909  end
28910 end
28911 return head
28912end
28913local function setdiscchecked(d,pre,post,replace)
28914 if pre  then pre=checked(pre)  end
28915 if post then post=checked(post) end
28916 if replace then replace=checked(replace) end
28917 setdisc(d,pre,post,replace)
28918end
28919local noflags={ false,false,false,false }
28920local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,where)
28921 local size=ck[5]-ck[4]+1
28922 local chainlookups=ck[6]
28923 local done=false
28924 if chainlookups then
28925  if size==1 then
28926   local chainlookup=chainlookups[1]
28927   if chainlookup then
28928    for j=1,#chainlookup do
28929     local chainstep=chainlookup[j]
28930     if chainstep then
28931      local chainkind=chainstep.type
28932      local chainproc=chainprocs[chainkind]
28933      if chainproc then
28934       local ok
28935       head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,1)
28936       if ok then
28937        done=true
28938       end
28939      else
28940       logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
28941      end
28942     else
28943      logprocess("%s: has an issue (1)",cref(dataset,sequence))
28944     end
28945    end
28946   else
28947   end
28948   else
28949   local i=1
28950   local laststart=start
28951   local nofchainlookups=#chainlookups 
28952   while start do
28953    if skiphash then 
28954     while start do
28955      local char=ischar(start,currentfont)
28956      if char then
28957       if skiphash and skiphash[char] then
28958        start=getnext(start)
28959       else
28960        break
28961       end
28962      else
28963       break
28964      end
28965     end
28966    end
28967    local chainlookup=chainlookups[i]
28968    if chainlookup then
28969     for j=1,#chainlookup do
28970      local chainstep=chainlookup[j]
28971      if chainstep then
28972       local chainkind=chainstep.type
28973       local chainproc=chainprocs[chainkind]
28974       if chainproc then
28975        local ok,n
28976        head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i)
28977        if ok then
28978         done=true
28979         if n and n>1 and i+n>nofchainlookups then
28980          i=size 
28981          break
28982         end
28983        end
28984       else
28985        logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
28986       end
28987      else
28988       logprocess("%s: has an issue (2)",cref(dataset,sequence))
28989      end
28990     end
28991    else
28992    end
28993    i=i+1
28994    if i>size or not start then
28995     break
28996    elseif start then
28997     laststart=start
28998     start=getnext(start)
28999    end
29000   end
29001   if not start then
29002    start=laststart
29003   end
29004  end
29005 else
29006  local replacements=ck[7]
29007  if replacements then
29008   head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode,skiphash)
29009  else
29010   done=true
29011   if trace_contexts then
29012    logprocess("%s: skipping match @ %i",cref(dataset,sequence),where)
29013   end
29014  end
29015 end
29016 return head,start,done
29017end
29018local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
29019 if not start then
29020  return head,start,false
29021 end
29022 local startishead=start==head
29023 local seq=ck[3]
29024 local f=ck[4]
29025 local l=ck[5]
29026 local s=#seq
29027 local done=false
29028 local sweepnode=sweepnode
29029 local sweeptype=sweeptype
29030 local sweepoverflow=false
29031 local checkdisc=getprev(head)
29032 local keepdisc=not sweepnode
29033 local lookaheaddisc=nil
29034 local backtrackdisc=nil
29035 local current=start
29036 local last=start
29037 local prev=getprev(start)
29038 local hasglue=false
29039 local useddisc=nil   
29040 local usedstart=start
29041 local i=f
29042 while i<=l do
29043  local id=getid(current)
29044  if id==glyph_code then
29045   i=i+1
29046   last=current
29047   current=getnext(current)
29048  elseif id==glue_code then
29049   i=i+1
29050   last=current
29051   current=getnext(current)
29052   hasglue=true
29053  elseif id==disc_code then
29054   if keepdisc then
29055    keepdisc=false
29056    lookaheaddisc=current
29057    local replace=getreplace(current)
29058    if not replace then
29059     sweepoverflow=true
29060     sweepnode=current
29061     current=getnext(current)
29062    else
29063     while replace and i<=l do
29064      if getid(replace)==glyph_code then
29065       i=i+1
29066      end
29067      replace=getnext(replace)
29068     end
29069     current=getnext(replace)
29070    end
29071    last=current
29072   else
29073    head,current=flattendisk(head,current)
29074   end
29075  else
29076   last=current
29077   current=getnext(current)
29078  end
29079  if current then
29080  elseif sweepoverflow then
29081   break
29082  elseif sweeptype=="post" or sweeptype=="replace" then
29083   current=getnext(sweepnode)
29084   if current then
29085    sweeptype=nil
29086    sweepoverflow=true
29087   else
29088    break
29089   end
29090  else
29091   break 
29092  end
29093 end
29094 if sweepoverflow then
29095  local prev=current and getprev(current)
29096  if not current or prev~=sweepnode then
29097   local head=getnext(sweepnode)
29098   local tail=nil
29099   if prev then
29100    tail=prev
29101    setprev(current,sweepnode)
29102   else
29103    tail=findnodetail(head)
29104   end
29105   setnext(sweepnode,current)
29106   setprev(head)
29107   setnext(tail)
29108   appenddisc(sweepnode,head)
29109  end
29110 end
29111 if l<s then
29112  local i=l
29113  local t=sweeptype=="post" or sweeptype=="replace"
29114  while current and i<s do
29115   local id=getid(current)
29116   if id==glyph_code then
29117    i=i+1
29118    current=getnext(current)
29119   elseif id==glue_code then
29120    i=i+1
29121    current=getnext(current)
29122    hasglue=true
29123   elseif id==disc_code then
29124    if keepdisc then
29125     keepdisc=false
29126     if notmatchpre[current]~=notmatchreplace[current] then
29127      lookaheaddisc=current
29128     end
29129     local replace=getreplace(current)
29130     while replace and i<s do
29131      if getid(replace)==glyph_code then
29132       i=i+1
29133      end
29134      replace=getnext(replace)
29135     end
29136     current=getnext(current)
29137    elseif notmatchpre[current]~=notmatchreplace[current] then
29138     head,current=flattendisk(head,current)
29139    else
29140     current=getnext(current) 
29141    end
29142   else
29143    current=getnext(current)
29144   end
29145   if not current and t then
29146    current=getnext(sweepnode)
29147    if current then
29148     sweeptype=nil
29149    end
29150   end
29151  end
29152 end
29153 if f>1 then
29154  local current=prev
29155  local i=f
29156  local t=sweeptype=="pre" or sweeptype=="replace"
29157  if not current and t and current==checkdisc then
29158   current=getprev(sweepnode)
29159  end
29160  while current and i>1 do 
29161   local id=getid(current)
29162   if id==glyph_code then
29163    i=i-1
29164   elseif id==glue_code then
29165    i=i-1
29166    hasglue=true
29167   elseif id==disc_code then
29168    if keepdisc then
29169     keepdisc=false
29170     if notmatchpost[current]~=notmatchreplace[current] then
29171      backtrackdisc=current
29172     end
29173     local replace=getreplace(current)
29174     while replace and i>1 do
29175      if getid(replace)==glyph_code then
29176       i=i-1
29177      end
29178      replace=getnext(replace)
29179     end
29180    elseif notmatchpost[current]~=notmatchreplace[current] then
29181     head,current=flattendisk(head,current)
29182    end
29183   end
29184   current=getprev(current)
29185   if t and current==checkdisc then
29186    current=getprev(sweepnode)
29187   end
29188  end
29189 end
29190 local done=false
29191 if lookaheaddisc then
29192  local cf=start
29193  local cl=getprev(lookaheaddisc)
29194  local cprev=getprev(start)
29195  local insertedmarks=0
29196  while cprev do
29197   local char=ischar(cf,currentfont)
29198   if char and marks[char] then
29199    insertedmarks=insertedmarks+1
29200    cf=cprev
29201    startishead=cf==head
29202    cprev=getprev(cprev)
29203   else
29204    break
29205   end
29206  end
29207  setlink(cprev,lookaheaddisc)
29208  setprev(cf)
29209  setnext(cl)
29210  if startishead then
29211   head=lookaheaddisc
29212  end
29213  local pre,post,replace=getdisc(lookaheaddisc)
29214  local new=copynodelist(cf) 
29215  local cnew=new
29216  if pre then
29217   setlink(findnodetail(cf),pre)
29218  end
29219  if replace then
29220   local tail=findnodetail(new)
29221   setlink(tail,replace)
29222  end
29223  for i=1,insertedmarks do
29224   cnew=getnext(cnew)
29225  end
29226  cl=start
29227  local clast=cnew
29228  for i=f,l do
29229   cl=getnext(cl)
29230   clast=getnext(clast)
29231  end
29232  if not notmatchpre[lookaheaddisc] then
29233   local ok=false
29234   cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck,1)
29235   if ok then
29236    done=true
29237   end
29238  end
29239  if not notmatchreplace[lookaheaddisc] then
29240   local ok=false
29241   new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,2)
29242   if ok then
29243    done=true
29244   end
29245  end
29246  if hasglue then
29247   setdiscchecked(lookaheaddisc,cf,post,new)
29248  else
29249   setdisc(lookaheaddisc,cf,post,new)
29250  end
29251  start=getprev(lookaheaddisc)
29252  useddisc=lookaheaddisc 
29253  sweephead[cf]=getnext(clast) or false
29254  sweephead[new]=getnext(cl) or false
29255 elseif backtrackdisc then
29256  local cf=getnext(backtrackdisc)
29257  local cl=start
29258  local cnext=getnext(start)
29259  local insertedmarks=0
29260  while cnext do
29261   local char=ischar(cnext,currentfont)
29262   if char and marks[char] then
29263    insertedmarks=insertedmarks+1
29264    cl=cnext
29265    cnext=getnext(cnext)
29266   else
29267    break
29268   end
29269  end
29270  setlink(backtrackdisc,cnext)
29271  setprev(cf)
29272  setnext(cl)
29273  local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true)
29274  local new=copynodelist(cf)
29275  local cnew=findnodetail(new)
29276  for i=1,insertedmarks do
29277   cnew=getprev(cnew)
29278  end
29279  local clast=cnew
29280  for i=f,l do
29281   clast=getnext(clast)
29282  end
29283  if not notmatchpost[backtrackdisc] then
29284   local ok=false
29285   cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck,3)
29286   if ok then
29287    done=true
29288   end
29289  end
29290  if not notmatchreplace[backtrackdisc] then
29291   local ok=false
29292   new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck,4)
29293   if ok then
29294    done=true
29295   end
29296  end
29297  if post then
29298   setlink(posttail,cf)
29299  else
29300   post=cf
29301  end
29302  if replace then
29303   setlink(replacetail,new)
29304  else
29305   replace=new
29306  end
29307  if hasglue then
29308   setdiscchecked(backtrackdisc,pre,post,replace)
29309  else
29310   setdisc(backtrackdisc,pre,post,replace)
29311  end
29312  start=getprev(backtrackdisc)
29313  useddisc=backtrackdisc 
29314  sweephead[post]=getnext(clast) or false
29315  sweephead[replace]=getnext(last) or false
29316 else
29317  local ok=false
29318  head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck,5)
29319  if ok then
29320   done=true
29321  end
29322 end
29323 if useddisc and start~=usedstart then 
29324    start=getnext(start)           
29325 end                  
29326 return head,start,done,useddisc           
29327end
29328local chaintrac do
29329 local level=0
29330 local last={}
29331 chaintrac=function(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode)
29332  if dataset then
29333   level=level+1
29334   last[level]=start
29335   local rule=ck[1]
29336   local lookuptype=ck[8] or ck[2]
29337   local nofseq=#ck[3] 
29338   local first=ck[4]
29339   local last=ck[5]
29340   local char=getchar(start)
29341   logwarning("+ %i : %s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping",
29342    level,cref(dataset,sequence),rule,match and "matches" or "nomatch",
29343    gref(char),first-1,last-first+1,nofseq-last,lookuptype,
29344    discseen and "" or "no ",sweepnode and "" or "not ")
29345  else
29346   local what=start and "done" or "continue"
29347   local where=head==last[level] and "same" or "different"
29348   local char=getchar(head)
29349   if char then
29350    logwarning("- %i : %s at char %s, %s node",level,what,gref(char),where)
29351   else
29352    logwarning("- %i : %s, %s node",level,what,where)
29353   end
29354   level=level-1
29355  end
29356 end
29357end
29358local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
29359 if not contexts then
29360  return head,start,false
29361 end
29362 local sweepnode=sweepnode
29363 local sweeptype=sweeptype
29364 local postreplace
29365 local prereplace
29366 local checkdisc
29367 local discseen  
29368 if sweeptype then
29369  if sweeptype=="replace" then
29370   postreplace=true
29371   prereplace=true
29372  else
29373   postreplace=sweeptype=="post"
29374   prereplace=sweeptype=="pre"
29375  end
29376  checkdisc=getprev(head)
29377 end
29378 local currentfont=currentfont
29379 local skipped   
29380 local startprev,
29381    startnext=getboth(start)
29382 local done
29383 local nofcontexts=contexts.n 
29384 local startchar=nofcontext==1 or ischar(start,currentfont) 
29385 for k=1,nofcontexts do 
29386  local ck=contexts[k]
29387  local seq=ck[3]
29388  local f=ck[4] 
29389  local last=start
29390  if not startchar or not seq[f][startchar] then
29391   goto next
29392  end
29393  local s=seq.n 
29394  if s==1 then
29395  else
29396   local l=ck[5] 
29397   local current=start
29398   if l>f then
29399    local discfound 
29400    local n=f+1
29401    last=startnext 
29402    while n<=l do
29403     if postreplace and not last then
29404      last=getnext(sweepnode)
29405      sweeptype=nil
29406     end
29407     if last then
29408      local char,id=ischar(last,currentfont)
29409      if char then
29410       if seq[n][char] then
29411        if n<l then
29412         last=getnext(last)
29413        end
29414        n=n+1
29415       elseif skiphash and skiphash[char] then
29416        skipped=true
29417        if trace_skips then
29418         show_skip(dataset,sequence,char,ck,classes[char])
29419        end
29420        last=getnext(last)
29421       elseif discfound then
29422        notmatchreplace[discfound]=true
29423        if notmatchpre[discfound] then
29424         goto next
29425        else
29426         break
29427        end
29428       else
29429        goto next
29430       end
29431      elseif char==false then
29432       if discfound then
29433        notmatchreplace[discfound]=true
29434        if notmatchpre[discfound] then
29435         goto next
29436        else
29437         break
29438        end
29439       else
29440        goto next
29441       end
29442      elseif id==disc_code then
29443       discseen=true
29444       discfound=last
29445       notmatchpre[last]=nil
29446       notmatchpost[last]=true
29447       notmatchreplace[last]=nil
29448       local pre,post,replace=getdisc(last)
29449       if pre then
29450        local n=n
29451        while pre do
29452         if seq[n][getchar(pre)] then
29453          n=n+1
29454          if n>l then
29455           break
29456          end
29457          pre=getnext(pre)
29458         else
29459          notmatchpre[last]=true
29460          break
29461         end
29462        end
29463        if n<=l then
29464         notmatchpre[last]=true
29465        end
29466       else
29467        notmatchpre[last]=true
29468       end
29469       if replace then
29470        while replace do
29471         if seq[n][getchar(replace)] then
29472          n=n+1
29473          if n>l then
29474           break
29475          end
29476          replace=getnext(replace)
29477         else
29478          notmatchreplace[last]=true
29479          if notmatchpre[last] then
29480           goto next
29481          else
29482           break
29483          end
29484         end
29485        end
29486        if notmatchpre[last] then
29487         goto next
29488        end
29489       end
29490       last=getnext(last)
29491      else
29492       goto next
29493      end
29494     else
29495      goto next
29496     end
29497    end
29498   end
29499   if f>1 then
29500     local prev=startprev
29501     if prereplace and prev==checkdisc then
29502      prev=getprev(sweepnode)
29503     end
29504     if prev then
29505      local discfound 
29506      local n=f-1
29507      while n>=1 do
29508       if prev then
29509        local char,id=ischar(prev,currentfont)
29510        if char then
29511         if seq[n][char] then
29512          if n>1 then
29513           prev=getprev(prev)
29514          end
29515          n=n-1
29516         elseif skiphash and skiphash[char] then
29517          skipped=true
29518          if trace_skips then
29519           show_skip(dataset,sequence,char,ck,classes[char])
29520          end
29521          prev=getprev(prev)
29522         elseif discfound then
29523          notmatchreplace[discfound]=true
29524          if notmatchpost[discfound] then
29525           goto next
29526          else
29527           break
29528          end
29529         else
29530          goto next
29531         end
29532        elseif char==false then
29533         if discfound then
29534          notmatchreplace[discfound]=true
29535          if notmatchpost[discfound] then
29536           goto next
29537          end
29538         else
29539          goto next
29540         end
29541         break
29542        elseif id==disc_code then
29543         discseen=true
29544         discfound=prev
29545         notmatchpre[prev]=true
29546         notmatchpost[prev]=nil
29547         notmatchreplace[prev]=nil
29548         local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
29549         if pre~=start and post~=start and replace~=start then
29550          if post then
29551           local n=n
29552           while posttail do
29553            if seq[n][getchar(posttail)] then
29554             n=n-1
29555             if posttail==post or n<1 then
29556              break
29557             else
29558              posttail=getprev(posttail)
29559             end
29560            else
29561             notmatchpost[prev]=true
29562             break
29563            end
29564           end
29565           if n>=1 then
29566            notmatchpost[prev]=true
29567           end
29568          else
29569           notmatchpost[prev]=true
29570          end
29571          if replace then
29572           while replacetail do
29573            if seq[n][getchar(replacetail)] then
29574             n=n-1
29575             if replacetail==replace or n<1 then
29576              break
29577             else
29578              replacetail=getprev(replacetail)
29579             end
29580            else
29581             notmatchreplace[prev]=true
29582             if notmatchpost[prev] then
29583              goto next
29584             else
29585              break
29586             end
29587            end
29588           end
29589          else
29590          end
29591         end
29592         prev=getprev(prev)
29593        elseif id==glue_code then
29594         local sn=seq[n]
29595         if (sn[32] and spaces[prev]) or sn[0xFFFC] then
29596          n=n-1
29597          prev=getprev(prev)
29598         else
29599          goto next
29600         end
29601        elseif seq[n][0xFFFC] then
29602         n=n-1
29603         prev=getprev(prev)
29604        else
29605         goto next
29606        end
29607       else
29608        goto next
29609       end
29610      end
29611     else
29612      goto next
29613     end
29614   end
29615   if s>l then
29616    local current=last and getnext(last)
29617    if not current and postreplace then
29618     current=getnext(sweepnode)
29619    end
29620    if current then
29621     local discfound 
29622     local n=l+1
29623     while n<=s do
29624      if current then
29625       local char,id=ischar(current,currentfont)
29626       if char then
29627        if seq[n][char] then
29628         if n<s then
29629          current=getnext(current)
29630         end
29631         n=n+1
29632        elseif skiphash and skiphash[char] then
29633         skipped=true
29634         if trace_skips then
29635          show_skip(dataset,sequence,char,ck,classes[char])
29636         end
29637         current=getnext(current)
29638        elseif discfound then
29639         notmatchreplace[discfound]=true
29640         if notmatchpre[discfound] then
29641          goto next
29642         else
29643          break
29644         end
29645        else
29646         goto next
29647        end
29648       elseif char==false then
29649        if discfound then
29650         notmatchreplace[discfound]=true
29651         if notmatchpre[discfound] then
29652          goto next
29653         else
29654          break
29655         end
29656        else
29657         goto next
29658        end
29659       elseif id==disc_code then
29660        discseen=true
29661        discfound=current
29662        notmatchpre[current]=nil
29663        notmatchpost[current]=true
29664        notmatchreplace[current]=nil
29665        local pre,post,replace=getdisc(current)
29666        if pre then
29667         local n=n
29668         while pre do
29669          if seq[n][getchar(pre)] then
29670           n=n+1
29671           if n>s then
29672            break
29673           else
29674            pre=getnext(pre)
29675           end
29676          else
29677           notmatchpre[current]=true
29678           break
29679          end
29680         end
29681         if n<=s then
29682          notmatchpre[current]=true
29683         end
29684        else
29685         notmatchpre[current]=true
29686        end
29687        if replace then
29688         while replace do
29689          if seq[n][getchar(replace)] then
29690           n=n+1
29691           if n>s then
29692            break
29693           else
29694            replace=getnext(replace)
29695           end
29696          else
29697           notmatchreplace[current]=true
29698           if notmatchpre[current] then
29699            goto next
29700           else
29701            break
29702           end
29703          end
29704         end
29705        else
29706        end
29707        current=getnext(current)
29708       elseif id==glue_code then
29709        local sn=seq[n]
29710        if (sn[32] and spaces[current]) or sn[0xFFFC] then
29711         n=n+1
29712         current=getnext(current)
29713        else
29714         goto next
29715        end
29716       elseif seq[n][0xFFFC] then
29717        n=n+1
29718        current=getnext(current)
29719       else
29720        goto next
29721       end
29722      else
29723       goto next
29724      end
29725     end
29726    else
29727     goto next
29728    end
29729   end
29730  end
29731  if trace_contexts then
29732   chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true,discseen,sweepnode)
29733  end
29734  if discseen or sweepnode then
29735   head,start,done=chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck)
29736  else
29737   head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck,6)
29738  end
29739  if trace_contexts then
29740   chaintrac(start,done)
29741  end
29742  if done then
29743   break
29744  end
29745   ::next::
29746 end
29747 if discseen then
29748  notmatchpre={}
29749  notmatchpost={}
29750  notmatchreplace={}
29751 end
29752 return head,start,done
29753end
29754handlers.gsub_context=handle_contextchain
29755handlers.gsub_contextchain=handle_contextchain
29756handlers.gsub_reversecontextchain=handle_contextchain
29757handlers.gpos_contextchain=handle_contextchain
29758handlers.gpos_context=handle_contextchain
29759local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
29760 local steps=currentlookup.steps
29761 local nofsteps=currentlookup.nofsteps
29762 local char=getchar(start)
29763 if nofsteps==1 then
29764  local s=steps[1]
29765  local l=s.coverage[char]
29766  if l then
29767   return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash)
29768  end
29769 else
29770  for i=1,nofsteps do
29771   local s=steps[i]
29772   local l=s.coverage[char]
29773   if l then
29774    local h,s,d=handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash)
29775    if d then
29776     return h,s,d
29777    end
29778   end
29779  end
29780 end
29781 return head,start,false
29782end
29783chainprocs.gsub_context=chained_contextchain
29784chainprocs.gsub_contextchain=chained_contextchain
29785chainprocs.gsub_reversecontextchain=chained_contextchain
29786chainprocs.gpos_contextchain=chained_contextchain
29787chainprocs.gpos_context=chained_contextchain
29788local missing=setmetatableindex("table")
29789local logwarning=report_process
29790local resolved={} 
29791local function logprocess(...)
29792 if trace_steps then
29793  registermessage(...)
29794  if trace_steps=="silent" then
29795   return
29796  end
29797 end
29798 report_process(...)
29799end
29800local sequencelists=setmetatableindex(function(t,font)
29801 local sequences=fontdata[font].resources.sequences
29802 if not sequences or not next(sequences) then
29803  sequences=false
29804 end
29805 t[font]=sequences
29806 return sequences
29807end)
29808do 
29809 local autofeatures=fonts.analyzers.features
29810 local featuretypes=otf.tables.featuretypes
29811 local defaultscript=otf.features.checkeddefaultscript
29812 local defaultlanguage=otf.features.checkeddefaultlanguage
29813 local wildcard="*"
29814 local default="dflt"
29815 local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
29816  local features=sequence.features
29817  if features then
29818   local order=sequence.order
29819   if order then
29820    local featuretype=featuretypes[sequence.type or "unknown"]
29821    for i=1,#order do
29822     local kind=order[i]
29823     local valid=enabled[kind]
29824     if valid then
29825      local scripts=features[kind]
29826      local languages=scripts and (
29827       scripts[script] or
29828       scripts[wildcard] or
29829       (autoscript and defaultscript(featuretype,autoscript,scripts))
29830      )
29831      local enabled=languages and (
29832       languages[language] or
29833       languages[wildcard] or
29834       (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
29835      )
29836      if enabled then
29837       return { valid,autofeatures[kind] or false,sequence,kind }
29838      end
29839     end
29840    end
29841   else
29842   end
29843  end
29844  return false
29845 end
29846 function otf.dataset(tfmdata,font) 
29847  local shared=tfmdata.shared
29848  local properties=tfmdata.properties
29849  local language=properties.language or "dflt"
29850  local script=properties.script   or "dflt"
29851  local enabled=shared.features
29852  local autoscript=enabled and enabled.autoscript
29853  local autolanguage=enabled and enabled.autolanguage
29854  local res=resolved[font]
29855  if not res then
29856   res={}
29857   resolved[font]=res
29858  end
29859  local rs=res[script]
29860  if not rs then
29861   rs={}
29862   res[script]=rs
29863  end
29864  local rl=rs[language]
29865  if not rl then
29866   rl={
29867   }
29868   rs[language]=rl
29869   local sequences=tfmdata.resources.sequences
29870   if sequences then
29871    for s=1,#sequences do
29872     local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
29873     if v then
29874      rl[#rl+1]=v
29875     end
29876    end
29877   end
29878  end
29879  return rl
29880 end
29881end
29882local function report_disc(what,n)
29883 report_run("%s: %s > %s",what,n,languages.serializediscretionary(n))
29884end
29885local function kernrun(disc,k_run,font,attr,...)
29886 if trace_kernruns then
29887  report_disc("kern",disc)
29888 end
29889 local prev,next=getboth(disc)
29890 local nextstart=next
29891 local done=false
29892 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
29893 local prevmarks=prev
29894 while prevmarks do
29895  local char=ischar(prevmarks,font)
29896  if char and marks[char] then
29897   prevmarks=getprev(prevmarks)
29898  else
29899   break
29900  end
29901 end
29902 if prev and not ischar(prev,font) then  
29903  prev=false
29904 end
29905 if next and not ischar(next,font) then  
29906  next=false
29907 end
29908 if pre then
29909  if k_run(pre,"injections",nil,font,attr,...) then
29910   done=true
29911  end
29912  if prev then
29913   setlink(prev,pre)
29914   if k_run(prevmarks,"preinjections",pre,font,attr,...) then 
29915    done=true
29916   end
29917   setprev(pre)
29918   setlink(prev,disc)
29919  end
29920 end
29921 if post then
29922  if k_run(post,"injections",nil,font,attr,...) then
29923   done=true
29924  end
29925  if next then
29926   setlink(posttail,next)
29927   if k_run(posttail,"postinjections",next,font,attr,...) then
29928    done=true
29929   end
29930   setnext(posttail)
29931   setlink(disc,next)
29932  end
29933 end
29934 if replace then
29935  if k_run(replace,"injections",nil,font,attr,...) then
29936   done=true
29937  end
29938  if prev then
29939   setlink(prev,replace)
29940   if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then 
29941    done=true
29942   end
29943   setprev(replace)
29944   setlink(prev,disc)
29945  end
29946  if next then
29947   setlink(replacetail,next)
29948   if k_run(replacetail,"replaceinjections",next,font,attr,...) then
29949    done=true
29950   end
29951   setnext(replacetail)
29952   setlink(disc,next)
29953  end
29954 elseif prev and next then
29955  setlink(prev,next)
29956  if k_run(prevmarks,"emptyinjections",next,font,attr,...) then
29957   done=true
29958  end
29959  setlink(prev,disc,next)
29960 end
29961 if done and trace_testruns then
29962  report_disc("done",disc)
29963 end
29964 return nextstart
29965end
29966local function comprun(disc,c_run,...) 
29967 if trace_compruns then
29968  report_disc("comp",disc)
29969 end
29970 local pre,post,replace=getdisc(disc)
29971 local renewed=false
29972 if pre then
29973  sweepnode=disc
29974  sweeptype="pre" 
29975  local new,done=c_run(pre,...)
29976  if done then
29977   pre=new
29978   renewed=true
29979  end
29980 end
29981 if post then
29982  sweepnode=disc
29983  sweeptype="post"
29984  local new,done=c_run(post,...)
29985  if done then
29986   post=new
29987   renewed=true
29988  end
29989 end
29990 if replace then
29991  sweepnode=disc
29992  sweeptype="replace"
29993  local new,done=c_run(replace,...)
29994  if done then
29995   replace=new
29996   renewed=true
29997  end
29998 end
29999 sweepnode=nil
30000 sweeptype=nil
30001 if renewed then
30002  if trace_testruns then
30003   report_disc("done",disc)
30004  end
30005  setdisc(disc,pre,post,replace)
30006 end
30007 return getnext(disc)
30008end
30009local test_flatten_start=2 
30010directives.register("otf.testrun.forceflatten",function(v)
30011 test_flatten_start=v and 1 or 2
30012end)
30013local function testrun(disc,t_run,c_run,...)
30014 if trace_testruns then
30015  report_disc("test",disc)
30016 end
30017 local prev,next=getboth(disc)
30018 if not next then
30019  return
30020 end
30021 local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
30022 local renewed=false
30023 if post or replace then 
30024  if post then
30025   setlink(posttail,next)
30026  else
30027   post=next
30028  end
30029  if replace then
30030   setlink(replacetail,next)
30031  else
30032   replace=next
30033  end
30034  local d_post=t_run(post,next,...)
30035  local d_replace=t_run(replace,next,...)
30036  if d_post>0 or d_replace>0 then
30037   local d=d_replace>d_post and d_replace or d_post
30038   local head=getnext(disc) 
30039   local tail=head
30040   for i=test_flatten_start,d do
30041    local nx=getnext(tail)
30042    local id=getid(nx)
30043    if id==disc_code then
30044     head,tail=flattendisk(head,nx)
30045    elseif id==glyph_code then
30046     tail=nx
30047    else
30048     break
30049    end
30050   end
30051   next=getnext(tail)
30052   setnext(tail)
30053   setprev(head)
30054   local new=copynodelist(head)
30055   if posttail then
30056    setlink(posttail,head)
30057   else
30058    post=head
30059   end
30060   if replacetail then
30061    setlink(replacetail,new)
30062   else
30063    replace=new
30064   end
30065  else
30066   if posttail then
30067    setnext(posttail)
30068   else
30069    post=nil
30070   end
30071   if replacetail then
30072    setnext(replacetail)
30073   else
30074    replace=nil
30075   end
30076  end
30077  setlink(disc,next)
30078 end
30079 if trace_testruns then
30080  report_disc("more",disc)
30081 end
30082 if pre then
30083  sweepnode=disc
30084  sweeptype="pre"
30085  local new,ok=c_run(pre,...)
30086  if ok then
30087   pre=new
30088   renewed=true
30089  end
30090 end
30091 if post then
30092  sweepnode=disc
30093  sweeptype="post"
30094  local new,ok=c_run(post,...)
30095  if ok then
30096   post=new
30097   renewed=true
30098  end
30099 end
30100 if replace then
30101  sweepnode=disc
30102  sweeptype="replace"
30103  local new,ok=c_run(replace,...)
30104  if ok then
30105   replace=new
30106   renewed=true
30107  end
30108 end
30109 sweepnode=nil
30110 sweeptype=nil
30111 if renewed then
30112  setdisc(disc,pre,post,replace)
30113  if trace_testruns then
30114   report_disc("done",disc)
30115  end
30116 end
30117 return getnext(disc)
30118end
30119local nesting=0
30120local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
30121 local done=false
30122 local sweep=sweephead[head]
30123 local start
30124 if sweep then
30125  start=sweep
30126  sweephead[head]=false
30127 else
30128  start=head
30129 end
30130 while start do
30131  local char,id=ischar(start,font)
30132  if char then
30133   local a 
30134   if attr then
30135    a=getglyphdata(start)
30136   end
30137   if not a or (a==attr) then
30138    local lookupmatch=lookupcache[char]
30139    if lookupmatch then
30140     local ok
30141     head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
30142     if ok then
30143      done=true
30144     end
30145    end
30146    if start then
30147     start=getnext(start)
30148    end
30149   else
30150    start=getnext(start)
30151   end
30152  elseif char==false then
30153   return head,done
30154  elseif sweep then
30155   return head,done
30156  else
30157   start=getnext(start)
30158  end
30159 end
30160 return head,done
30161end
30162local function t_run_single(start,stop,font,attr,lookupcache)
30163 local lastd=nil
30164 while start~=stop do
30165  local char=ischar(start,font)
30166  if char then
30167   local a 
30168   if attr then
30169    a=getglyphdata(start)
30170   end
30171   local startnext=getnext(start)
30172   if not a or (a==attr) then
30173    local lookupmatch=lookupcache[char]
30174    if lookupmatch then
30175     local s=startnext
30176     local ss=nil
30177     local sstop=s==stop
30178     if not s then
30179      s=ss
30180      ss=nil
30181     end
30182     while getid(s)==disc_code do
30183      ss=getnext(s)
30184      s=getreplace(s)
30185      if not s then
30186       s=ss
30187       ss=nil
30188      end
30189     end
30190     local l=nil
30191     local d=0
30192     while s do
30193      local char=ischar(s,font)
30194      if char then
30195       local lg=not tonumber(lookupmatch) and lookupmatch[char]
30196       if lg then
30197        if sstop then
30198         d=1
30199        elseif d>0 then
30200         d=d+1
30201        end
30202        l=lg
30203        s=getnext(s)
30204        sstop=s==stop
30205        if not s then
30206         s=ss
30207         ss=nil
30208        end
30209        while getid(s)==disc_code do
30210         ss=getnext(s)
30211         s=getreplace(s)
30212         if not s then
30213          s=ss
30214          ss=nil
30215         end
30216        end
30217        lookupmatch=lg
30218       else
30219        break
30220       end
30221      else
30222       break
30223      end
30224     end
30225     if l and (tonumber(l) or l.ligature) then 
30226      lastd=d
30227     end
30228    else
30229    end
30230   else
30231   end
30232   if lastd then
30233    return lastd
30234   end
30235   start=startnext
30236  else
30237   break
30238  end
30239 end
30240 return 0
30241end
30242local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
30243 local a 
30244 if attr then
30245  a=getglyphdata(sub)
30246 end
30247 if not a or (a==attr) then
30248  for n in nextnode,sub do 
30249   if n==last then
30250    break
30251   end
30252   local char=ischar(n,font)
30253   if char then
30254    local lookupmatch=lookupcache[char]
30255    if lookupmatch then
30256     local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection)
30257     if ok then
30258      return true
30259     end
30260    end
30261   end
30262  end
30263 end
30264end
30265local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
30266 local done=false
30267 local sweep=sweephead[head]
30268 local start
30269 if sweep then
30270  start=sweep
30271  sweephead[head]=false
30272 else
30273  start=head
30274 end
30275 while start do
30276  local char=ischar(start,font)
30277  if char then
30278   local a 
30279   if attr then
30280    a=getglyphdata(start)
30281   end
30282   if not a or (a==attr) then
30283    for i=1,nofsteps do
30284     local step=steps[i]
30285     local lookupcache=step.coverage
30286     local lookupmatch=lookupcache[char]
30287     if lookupmatch then
30288      local ok
30289      head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
30290      if ok then
30291       done=true
30292       break
30293      elseif not start then
30294       break
30295      end
30296     end
30297    end
30298    if start then
30299     start=getnext(start)
30300    end
30301   else
30302    start=getnext(start)
30303   end
30304  elseif char==false then
30305   return head,done
30306  elseif sweep then
30307   return head,done
30308  else
30309   start=getnext(start)
30310  end
30311 end
30312 return head,done
30313end
30314local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
30315 local lastd=nil
30316 while start~=stop do
30317  local char=ischar(start,font)
30318  if char then
30319   local a 
30320   if attr then
30321    a=getglyphdata(start)
30322   end
30323   local startnext=getnext(start)
30324   if not a or (a==attr) then
30325    for i=1,nofsteps do
30326     local step=steps[i]
30327     local lookupcache=step.coverage
30328     local lookupmatch=lookupcache[char]
30329     if lookupmatch then
30330      local s=startnext
30331      local ss=nil
30332      local sstop=s==stop
30333      if not s then
30334       s=ss
30335       ss=nil
30336      end
30337      while getid(s)==disc_code do
30338       ss=getnext(s)
30339       s=getreplace(s)
30340       if not s then
30341        s=ss
30342        ss=nil
30343       end
30344      end
30345      local l=nil
30346      local d=0
30347      while s do
30348       local char=ischar(s)
30349       if char then
30350        local lg=not tonumber(lookupmatch) and lookupmatch[char]
30351        if lg then
30352         if sstop then
30353          d=1
30354         elseif d>0 then
30355          d=d+1
30356         end
30357         l=lg
30358         s=getnext(s)
30359         sstop=s==stop
30360         if not s then
30361          s=ss
30362          ss=nil
30363         end
30364         while getid(s)==disc_code do
30365          ss=getnext(s)
30366          s=getreplace(s)
30367          if not s then
30368           s=ss
30369           ss=nil
30370          end
30371         end
30372         lookupmatch=lg
30373        else
30374         break
30375        end
30376       else
30377        break
30378       end
30379      end
30380      if l and (tonumber(l) or l.ligature) then
30381       lastd=d
30382      end
30383     end
30384    end
30385   else
30386   end
30387   if lastd then
30388    return lastd
30389   end
30390   start=startnext
30391  else
30392   break
30393  end
30394 end
30395 return 0
30396end
30397local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
30398 local a 
30399 if attr then
30400  a=getglyphdata(sub)
30401 end
30402 if not a or (a==attr) then
30403  for n in nextnode,sub do 
30404   if n==last then
30405    break
30406   end
30407   local char=ischar(n)
30408   if char then
30409    for i=1,nofsteps do
30410     local step=steps[i]
30411     local lookupcache=step.coverage
30412     local lookupmatch=lookupcache[char]
30413     if lookupmatch then
30414      local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection) 
30415      if ok then
30416       return true
30417      end
30418     end
30419    end
30420   end
30421  end
30422 end
30423end
30424local txtdirstate,pardirstate  do 
30425 local getdirection=nuts.getdirection
30426 txtdirstate=function(start,stack,top,rlparmode)
30427  local dir,pop=getdirection(start)
30428  if pop then
30429   if top==1 then
30430    return 0,rlparmode
30431   else
30432    top=top-1
30433    if stack[top]==righttoleft_code then
30434     return top,-1
30435    else
30436     return top,1
30437    end
30438   end
30439  elseif dir==lefttoright_code then
30440   top=top+1
30441   stack[top]=lefttoright_code
30442   return top,1
30443  elseif dir==righttoleft_code then
30444   top=top+1
30445   stack[top]=righttoleft_code
30446   return top,-1
30447  else
30448   return top,rlparmode
30449  end
30450 end
30451 pardirstate=function(start)
30452  local dir=getdirection(start)
30453  if dir==lefttoright_code then
30454   return 1,1
30455  elseif dir==righttoleft_code then
30456   return -1,-1
30457  else
30458   return 0,0
30459  end
30460 end
30461end
30462otf.helpers=otf.helpers or {}
30463otf.helpers.txtdirstate=txtdirstate
30464otf.helpers.pardirstate=pardirstate
30465do
30466 local fastdisc=true
30467 local testdics=false
30468 directives.register("otf.fastdisc",function(v) fastdisc=v end)
30469 local otfdataset=nil 
30470 local getfastdisc={ __index=function(t,k)
30471  local v=usesfont(k,currentfont)
30472  t[k]=v
30473  return v
30474 end }
30475 local getfastspace={ __index=function(t,k)
30476  local v=isspace(k,threshold) or false
30477  t[k]=v
30478  return v
30479 end }
30480 function otf.featuresprocessor(head,font,attr,direction,n)
30481  local sequences=sequencelists[font] 
30482  nesting=nesting+1
30483  if nesting==1 then
30484   currentfont=font
30485   tfmdata=fontdata[font]
30486   descriptions=tfmdata.descriptions 
30487   characters=tfmdata.characters   
30488   local resources=tfmdata.resources
30489   marks=resources.marks
30490   classes=resources.classes
30491   threshold,
30492   factor=getthreshold(font)
30493   checkmarks=tfmdata.properties.checkmarks
30494   if not otfdataset then
30495    otfdataset=otf.dataset
30496   end
30497   discs=fastdisc and n and n>1 and setmetatable({},getfastdisc) 
30498   spaces=setmetatable({},getfastspace)
30499  elseif currentfont~=font then
30500   report_warning("nested call with a different font, level %s, quitting",nesting)
30501   nesting=nesting-1
30502   return head,false
30503  end
30504  if trace_steps then
30505   checkstep(head)
30506  end
30507  local initialrl=0
30508  if getid(head)==par_code and startofpar(head) then
30509   initialrl=pardirstate(head)
30510  elseif direction==righttoleft_code then
30511   initialrl=-1
30512  end
30513  local datasets=otfdataset(tfmdata,font,attr)
30514  local dirstack={ nil } 
30515  sweephead={}
30516  for s=1,#datasets do
30517   local dataset=datasets[s]
30518   local attribute=dataset[2]
30519   local sequence=dataset[3] 
30520   local rlparmode=initialrl
30521   local topstack=0
30522   local typ=sequence.type
30523   local gpossing=typ=="gpos_single" or typ=="gpos_pair" 
30524   local forcetestrun=typ=="gsub_ligature" 
30525   local handler=handlers[typ] 
30526   local steps=sequence.steps
30527   local nofsteps=sequence.nofsteps
30528   local skiphash=sequence.skiphash
30529   if not steps then
30530    local h,ok=handler(head,dataset,sequence,initialrl,font,attr)
30531    if h and h~=head then
30532     head=h
30533    end
30534   elseif typ=="gsub_reversecontextchain" then
30535    local start=findnodetail(head)
30536    local rlmode=0 
30537    local merged=steps.merged
30538    while start do
30539     local char=ischar(start,font)
30540     if char then
30541      local m=merged[char]
30542      if m then
30543       local a 
30544       if attr then
30545        a=getglyphdata(start)
30546       end
30547       if not a or (a==attr) then
30548        for i=m[1],m[2] do
30549         local step=steps[i]
30550         local lookupcache=step.coverage
30551         local lookupmatch=lookupcache[char]
30552         if lookupmatch then
30553          local ok
30554          head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
30555          if ok then
30556           break
30557          end
30558         end
30559        end
30560        if start then
30561         start=getprev(start)
30562        end
30563       else
30564        start=getprev(start)
30565       end
30566      else
30567       start=getprev(start)
30568      end
30569     else
30570      start=getprev(start)
30571     end
30572    end
30573   else
30574    local start=head
30575    local rlmode=initialrl
30576    if nofsteps==1 then 
30577     local step=steps[1]
30578     local lookupcache=step.coverage
30579     while start do
30580      local char,id=ischar(start,font)
30581      if char then
30582       local lookupmatch=lookupcache[char]
30583       if lookupmatch then
30584        local a 
30585        if attr then
30586         if getglyphdata(start)==attr and (not attribute or getstate(start,attribute)) then
30587          a=true
30588         end
30589        elseif not attribute or getstate(start,attribute) then
30590         a=true
30591        end
30592        if a then
30593         local ok,df
30594         head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
30595         if df then
30596         elseif start then
30597          start=getnext(start)
30598         end
30599        else
30600         start=getnext(start)
30601        end
30602       else
30603          start=getnext(start)
30604       end
30605      elseif char==false or id==glue_code then
30606       start=getnext(start)
30607      elseif id==disc_code then
30608       if not discs or discs[start]==true then
30609        if gpossing then
30610         start=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
30611        elseif forcetestrun then
30612         start=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
30613        else
30614         start=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
30615        end
30616       else
30617        start=getnext(start)
30618       end
30619      elseif id==math_code then
30620       start=getnext(endofmath(start))
30621      elseif id==dir_code then
30622       topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
30623       start=getnext(start)
30624      else
30625       start=getnext(start)
30626      end
30627     end
30628    else
30629     local merged=steps.merged
30630     while start do
30631      local char,id=ischar(start,font)
30632      if char then
30633       local m=merged[char]
30634       if m then
30635        local a 
30636        if attr then
30637         if getglyphdata(start)==attr and (not attribute or getstate(start,attribute)) then
30638          a=true
30639         end
30640        elseif not attribute or getstate(start,attribute) then
30641         a=true
30642        end
30643        if a then
30644         local ok,df
30645         for i=m[1],m[2] do
30646          local step=steps[i]
30647          local lookupcache=step.coverage
30648          local lookupmatch=lookupcache[char]
30649          if lookupmatch then
30650           head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
30651           if df then
30652            break
30653           elseif ok then
30654            break
30655           elseif not start then
30656            break
30657           end
30658          end
30659         end
30660         if df then
30661         elseif start then
30662          start=getnext(start)
30663         end
30664        else
30665         start=getnext(start)
30666        end
30667       else
30668        start=getnext(start)
30669       end
30670      elseif char==false or id==glue_code then
30671       start=getnext(start)
30672      elseif id==disc_code then
30673       if not discs or discs[start]==true then
30674        if gpossing then
30675         start=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
30676        elseif forcetestrun then
30677         start=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
30678        else
30679         start=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
30680        end
30681       else
30682        start=getnext(start)
30683       end
30684      elseif id==math_code then
30685       start=getnext(endofmath(start))
30686      elseif id==dir_code then
30687       topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
30688       start=getnext(start)
30689      else
30690       start=getnext(start)
30691      end
30692     end
30693    end
30694   end
30695   if trace_steps then 
30696    registerstep(head)
30697   end
30698  end
30699  nesting=nesting-1
30700  return head
30701 end
30702 function otf.datasetpositionprocessor(head,font,direction,dataset)
30703  currentfont=font
30704  tfmdata=fontdata[font]
30705  descriptions=tfmdata.descriptions 
30706  characters=tfmdata.characters   
30707  local resources=tfmdata.resources
30708  marks=resources.marks
30709  classes=resources.classes
30710  threshold,
30711  factor=getthreshold(font)
30712  checkmarks=tfmdata.properties.checkmarks
30713  if type(dataset)=="number" then
30714   dataset=otfdataset(tfmdata,font,0)[dataset]
30715  end
30716  local sequence=dataset[3] 
30717  local typ=sequence.type
30718  local handler=handlers[typ] 
30719  local steps=sequence.steps
30720  local nofsteps=sequence.nofsteps
30721  local done=false
30722  local dirstack={ nil } 
30723  local start=head
30724  local initialrl=(direction==righttoleft_code) and -1 or 0
30725  local rlmode=initialrl
30726  local rlparmode=initialrl
30727  local topstack=0
30728  local merged=steps.merged
30729  local position=0
30730  while start do
30731   local char,id=ischar(start,font)
30732   if char then
30733    position=position+1
30734    local m=merged[char]
30735    if m then
30736     for i=m[1],m[2] do
30737      local step=steps[i]
30738      local lookupcache=step.coverage
30739      local lookupmatch=lookupcache[char]
30740      if lookupmatch then
30741       local ok
30742       head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
30743       if ok then
30744        break
30745       elseif not start then
30746        break
30747       end
30748      end
30749     end
30750     if start then
30751      start=getnext(start)
30752     end
30753    else
30754     start=getnext(start)
30755    end
30756   elseif char==false or id==glue_code then
30757    start=getnext(start)
30758   elseif id==math_code then
30759    start=getnext(endofmath(start))
30760   elseif id==dir_code then
30761    topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
30762    start=getnext(start)
30763   else
30764    start=getnext(start)
30765   end
30766  end
30767  return head
30768 end
30769end
30770do
30771 local plugins={}
30772 otf.plugins=plugins
30773 local report=logs.reporter("fonts")
30774 local warned=false
30775 local okay={ text=true }
30776 function otf.registerplugin(name,f)
30777  if type(name)=="string" and type(f)=="function" then
30778   plugins[name]={ name,f }
30779   if okay[name] then
30780   else
30781    report("plugin %a has been loaded, please be aware of possible side effects",name)
30782    if not warned then
30783     if logs.pushtarget then
30784      logs.pushtarget("log")
30785     end
30786     report("Plugins are not officially supported unless stated otherwise. This is because")
30787     report("they bypass the regular font handling and therefore some features in ConTeXt")
30788     report("(especially those related to fonts) might not work as expected or might not work")
30789     report("at all. Some plugins are for testing and development only and might change")
30790     report("whenever we feel the need for it.")
30791     report()
30792     if logs.poptarget then
30793      logs.poptarget()
30794     end
30795     warned=true
30796    end
30797   end
30798  end
30799 end
30800 function otf.plugininitializer(tfmdata,value)
30801  if type(value)=="string" then
30802   tfmdata.shared.plugin=plugins[value]
30803  end
30804 end
30805 function otf.pluginprocessor(head,font,dynamic,direction) 
30806  local s=fontdata[font].shared
30807  local p=s and s.plugin
30808  if p then
30809   if trace_plugins then
30810    report_process("applying plugin %a",p[1])
30811   end
30812   return p[2](head,font,dynamic,direction)
30813  else
30814   return head,false
30815  end
30816 end
30817end
30818function otf.featuresinitializer(tfmdata,value)
30819end
30820registerotffeature {
30821 name="features",
30822 description="features",
30823 default=true,
30824 initializers={
30825  position=1,
30826  node=otf.featuresinitializer,
30827  plug=otf.plugininitializer,
30828 },
30829 processors={
30830  node=otf.featuresprocessor,
30831  plug=otf.pluginprocessor,
30832 }
30833}
30834local function markinitializer(tfmdata,value)
30835 local properties=tfmdata.properties
30836 properties.checkmarks=value
30837end
30838registerotffeature {
30839 name="checkmarks",
30840 description="check mark widths",
30841 default=true,
30842 initializers={
30843  node=markinitializer,
30844 },
30845}
30846otf.handlers=handlers
30847if context then
30848
30849--removed
30850
30851else
30852end
30853local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end
30854local tag="kern"
30855 function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
30856  local shared=fontdata[font].shared
30857  local features=shared and shared.features
30858  local enabled=features and features.spacekern and features[tag]
30859  if enabled then
30860   setspacekerns(font,sequence)
30861  end
30862  return head,enabled
30863 end
30864local function hasspacekerns(data)
30865 local resources=data.resources
30866 local sequences=resources.sequences
30867 local validgpos=resources.features.gpos
30868 if validgpos and sequences then
30869  for i=1,#sequences do
30870   local sequence=sequences[i]
30871   local steps=sequence.steps
30872   if steps and sequence.features[tag] then
30873    local kind=sequence.type
30874    if kind=="gpos_pair" or kind=="gpos_single" then
30875     for i=1,#steps do
30876      local step=steps[i]
30877      local coverage=step.coverage
30878      local rules=step.rules
30879      if rules then
30880      elseif not coverage then
30881      elseif kind=="gpos_single" then
30882      elseif kind=="gpos_pair" then
30883       local format=step.format
30884       if format=="move" or format=="kern" then
30885        local kerns=coverage[32]
30886        if kerns then
30887         return true
30888        end
30889        for k,v in next,coverage do
30890         if v[32] then
30891          return true
30892         end
30893        end
30894       elseif format=="pair" then
30895        local kerns=coverage[32]
30896        if kerns then
30897         for k,v in next,kerns do
30898          local one=v[1]
30899          if one and one~=true then
30900           return true
30901          end
30902         end
30903        end
30904        for k,v in next,coverage do
30905         local kern=v[32]
30906         if kern then
30907          local one=kern[1]
30908          if one and one~=true then
30909           return true
30910          end
30911         end
30912        end
30913       end
30914      end
30915     end
30916    end
30917   end
30918  end
30919 end
30920 return false
30921end
30922otf.readers.registerextender {
30923 name="spacekerns",
30924 action=function(data)
30925  data.properties.hasspacekerns=hasspacekerns(data)
30926 end
30927}
30928local function spaceinitializer(tfmdata,value) 
30929 local resources=tfmdata.resources
30930 local spacekerns=resources and resources.spacekerns
30931 if value and spacekerns==nil then
30932  local rawdata=tfmdata.shared and tfmdata.shared.rawdata
30933  local properties=rawdata.properties
30934  if properties and properties.hasspacekerns then
30935   local sequences=resources.sequences
30936   local validgpos=resources.features.gpos
30937   if validgpos and sequences then
30938    local left={}
30939    local right={}
30940    local last=0
30941    local feat=nil
30942    for i=1,#sequences do
30943     local sequence=sequences[i]
30944     local steps=sequence.steps
30945     if steps then
30946      local kern=sequence.features[tag]
30947      if kern then
30948       local kind=sequence.type
30949       if kind=="gpos_pair" or kind=="gpos_single" then
30950        if feat then
30951         for script,languages in next,kern do
30952          local f=feat[script]
30953          if f then
30954           for l in next,languages do
30955            f[l]=true
30956           end
30957          else
30958           feat[script]=languages
30959          end
30960         end
30961        else
30962         feat=kern
30963        end
30964        for i=1,#steps do
30965         local step=steps[i]
30966         local coverage=step.coverage
30967         local rules=step.rules
30968         if rules then
30969         elseif not coverage then
30970         elseif kind=="gpos_single" then
30971         elseif kind=="gpos_pair" then
30972          local format=step.format
30973          if format=="move" or format=="kern" then
30974           local kerns=coverage[32]
30975           if kerns then
30976            for k,v in next,kerns do
30977             right[k]=v
30978            end
30979           end
30980           for k,v in next,coverage do
30981            local kern=v[32]
30982            if kern then
30983             left[k]=kern
30984            end
30985           end
30986          elseif format=="pair" then
30987           local kerns=coverage[32]
30988           if kerns then
30989            for k,v in next,kerns do
30990             local one=v[1]
30991             if one and one~=true then
30992              right[k]=one[3]
30993             end
30994            end
30995           end
30996           for k,v in next,coverage do
30997            local kern=v[32]
30998            if kern then
30999             local one=kern[1]
31000             if one and one~=true then
31001              left[k]=one[3]
31002             end
31003            end
31004           end
31005          end
31006         end
31007        end
31008        last=i
31009       end
31010      else
31011      end
31012     end
31013    end
31014    left=next(left)  and left  or false
31015    right=next(right) and right or false
31016    if left or right then
31017     spacekerns={
31018      left=left,
31019      right=right,
31020     }
31021     if last>0 then
31022      local triggersequence={
31023       features={ [tag]=feat or { dflt={ dflt=true,} } },
31024       flags=noflags,
31025       name="trigger_space_kerns",
31026       order={ tag },
31027       type="trigger_space_kerns",
31028       left=left,
31029       right=right,
31030      }
31031      insert(sequences,last,triggersequence)
31032     end
31033    end
31034   end
31035  end
31036  resources.spacekerns=spacekerns
31037 end
31038 return spacekerns
31039end
31040registerotffeature {
31041 name="spacekern",
31042 description="space kern injection",
31043 default=true,
31044 initializers={
31045  node=spaceinitializer,
31046 },
31047}
31048
31049end -- closure
31050
31051do -- begin closure to overcome local limits and interference
31052
31053if not modules then modules={} end modules ['font-otc']={
31054 version=1.001,
31055 comment="companion to font-ini.mkiv",
31056 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
31057 copyright="PRAGMA ADE / ConTeXt Development Team",
31058 license="see context related readme files"
31059}
31060local insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash
31061local type,next,tonumber=type,next,tonumber
31062local lpegmatch=lpeg.match
31063local utfbyte,utflen=utf.byte,utf.len
31064local sortedhash=table.sortedhash
31065local trace_loading=false  trackers.register("otf.loading",function(v) trace_loading=v end)
31066local report_otf=logs.reporter("fonts","otf loading")
31067local fonts=fonts
31068local otf=fonts.handlers.otf
31069local registerotffeature=otf.features.register
31070local setmetatableindex=table.setmetatableindex
31071local fonthelpers=fonts.helpers
31072local checkmerge=fonthelpers.checkmerge
31073local checkflags=fonthelpers.checkflags
31074local checksteps=fonthelpers.checksteps
31075local normalized={
31076 substitution="substitution",
31077 single="substitution",
31078 ligature="ligature",
31079 alternate="alternate",
31080 multiple="multiple",
31081 kern="kern",
31082 pair="pair",
31083 single="single",
31084 chainsubstitution="chainsubstitution",
31085 chainposition="chainposition",
31086}
31087local types={
31088 substitution="gsub_single",
31089 ligature="gsub_ligature",
31090 alternate="gsub_alternate",
31091 multiple="gsub_multiple",
31092 kern="gpos_pair",
31093 pair="gpos_pair",
31094 single="gpos_single",
31095 chainsubstitution="gsub_contextchain",
31096 chainposition="gpos_contextchain",
31097}
31098local names={
31099 gsub_single="gsub",
31100 gsub_multiple="gsub",
31101 gsub_alternate="gsub",
31102 gsub_ligature="gsub",
31103 gsub_context="gsub",
31104 gsub_contextchain="gsub",
31105 gsub_reversecontextchain="gsub",
31106 gpos_single="gpos",
31107 gpos_pair="gpos",
31108 gpos_cursive="gpos",
31109 gpos_mark2base="gpos",
31110 gpos_mark2ligature="gpos",
31111 gpos_mark2mark="gpos",
31112 gpos_context="gpos",
31113 gpos_contextchain="gpos",
31114}
31115setmetatableindex(types,function(t,k) t[k]=k return k end) 
31116local everywhere={ ["*"]={ ["*"]=true } } 
31117local noflags={ false,false,false,false }
31118local function getrange(sequences,category)
31119 local count=#sequences
31120 local first=nil
31121 local last=nil
31122 for i=1,count do
31123  local t=sequences[i].type
31124  if t and names[t]==category then
31125   if not first then
31126    first=i
31127   end
31128   last=i
31129  end
31130 end
31131 return first or 1,last or count
31132end
31133local function validspecification(specification,name)
31134 local dataset=specification.dataset
31135 if dataset then
31136 elseif specification[1] then
31137  dataset=specification
31138  specification={ dataset=dataset }
31139 else
31140  dataset={ { data=specification.data } }
31141  specification.data=nil
31142  specification.coverage=dataset
31143  specification.dataset=dataset
31144 end
31145 local first=dataset[1]
31146 if first then
31147  first=first.data
31148 end
31149 if not first then
31150  report_otf("invalid feature specification, no dataset")
31151  return
31152 end
31153 if type(name)~="string" then
31154  name=specification.name or first.name
31155 end
31156 if type(name)~="string" then
31157  report_otf("invalid feature specification, no name")
31158  return
31159 end
31160 local n=#dataset
31161 if n>0 then
31162  for i=1,n do
31163   setmetatableindex(dataset[i],specification)
31164  end
31165  return specification,name
31166 end
31167end
31168local function addfeature(data,feature,specifications,prepareonly)
31169 if not specifications then
31170  report_otf("missing specification")
31171  return
31172 end
31173 local descriptions=data.descriptions
31174 local resources=data.resources
31175 if not descriptions or not resources then
31176  report_otf("missing specification")
31177  return
31178 end
31179 local features=resources.features
31180 local sequences=resources.sequences
31181 if not features or not sequences then
31182  report_otf("missing specification")
31183  return
31184 end
31185 local alreadydone=resources.alreadydone
31186 if not alreadydone then
31187  alreadydone={}
31188  resources.alreadydone=alreadydone
31189 end
31190 if alreadydone[specifications] then
31191  return
31192 else
31193  alreadydone[specifications]=true
31194 end
31195 local fontfeatures=resources.features or everywhere
31196 local unicodes=resources.unicodes
31197 local splitter=lpeg.splitter(" ",unicodes)
31198 local done=0
31199 local skip=0
31200 local aglunicodes=false
31201 local privateslot=fonthelpers.privateslot
31202 local specifications=validspecification(specifications,feature)
31203 if not specifications then
31204  return
31205 end
31206 local p=lpeg.P("P")*(lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)*lpeg.P(-1)
31207 local function tounicode(code)
31208  if not code then
31209   return
31210  end
31211  if type(code)=="number" then
31212   return code
31213  end
31214  local u=unicodes[code]
31215  if u then
31216   return u
31217  end
31218  if utflen(code)==1 then
31219   u=utfbyte(code)
31220   if u then
31221    return u
31222   end
31223  end
31224  if privateslot then
31225   u=privateslot(code) 
31226   if u then
31227    return u
31228   end
31229  end
31230  local u=lpegmatch(p,code)
31231  if u then
31232   return u
31233  end
31234  if not aglunicodes then
31235   aglunicodes=fonts.encodings.agl.unicodes 
31236  end
31237  local u=aglunicodes[code]
31238  if u then
31239   return u
31240  end
31241 end
31242 local coverup=otf.coverup
31243 local coveractions=coverup.actions
31244 local stepkey=coverup.stepkey
31245 local register=coverup.register
31246 local function prepare_substitution(list,featuretype,nocheck)
31247  local coverage={}
31248  local cover=coveractions[featuretype]
31249  for code,replacement in next,list do
31250   local unicode=tounicode(code)
31251   local description=descriptions[unicode]
31252   if not nocheck and not description then
31253    skip=skip+1
31254   else
31255    if type(replacement)=="table" then
31256     replacement=replacement[1]
31257    end
31258    replacement=tounicode(replacement)
31259    if replacement and (nocheck or descriptions[replacement]) then
31260     cover(coverage,unicode,replacement)
31261     done=done+1
31262    else
31263     skip=skip+1
31264    end
31265   end
31266  end
31267  return coverage
31268 end
31269 local function prepare_alternate(list,featuretype,nocheck)
31270  local coverage={}
31271  local cover=coveractions[featuretype]
31272  for code,replacement in next,list do
31273   local unicode=tounicode(code)
31274   local description=descriptions[unicode]
31275   if not nocheck and not description then
31276    skip=skip+1
31277   elseif type(replacement)=="table" then
31278    local r={}
31279    for i=1,#replacement do
31280     local u=tounicode(replacement[i])
31281     r[i]=(nocheck or descriptions[u]) and u or unicode
31282    end
31283    cover(coverage,unicode,r)
31284    done=done+1
31285   else
31286    local u=tounicode(replacement)
31287    if u then
31288     cover(coverage,unicode,{ u })
31289     done=done+1
31290    else
31291     skip=skip+1
31292    end
31293   end
31294  end
31295  return coverage
31296 end
31297 local function prepare_multiple(list,featuretype,nocheck)
31298  local coverage={}
31299  local cover=coveractions[featuretype]
31300  for code,replacement in next,list do
31301   local unicode=tounicode(code)
31302   local description=descriptions[unicode]
31303   if not nocheck and not description then
31304    skip=skip+1
31305   elseif type(replacement)=="table" then
31306    local r={}
31307    local n=0
31308    for i=1,#replacement do
31309     local u=tounicode(replacement[i])
31310     if nocheck or descriptions[u] then
31311      n=n+1
31312      r[n]=u
31313     end
31314    end
31315    if n>0 then
31316     cover(coverage,unicode,r)
31317     done=done+1
31318    else
31319     skip=skip+1
31320    end
31321   else
31322    local u=tounicode(replacement)
31323    if u then
31324     cover(coverage,unicode,{ u })
31325     done=done+1
31326    else
31327     skip=skip+1
31328    end
31329   end
31330  end
31331  return coverage
31332 end
31333 local function prepare_ligature(list,featuretype,nocheck)
31334  local coverage={}
31335  local cover=coveractions[featuretype]
31336  for code,ligature in next,list do
31337   local unicode=tounicode(code)
31338   local description=descriptions[unicode]
31339   if not nocheck and not description then
31340    skip=skip+1
31341   else
31342    if type(ligature)=="string" then
31343     ligature={ lpegmatch(splitter,ligature) }
31344    end
31345    local present=true
31346    for i=1,#ligature do
31347     local l=ligature[i]
31348     local u=tounicode(l)
31349     if nocheck or descriptions[u] then
31350      ligature[i]=u
31351     else
31352      present=false
31353      break
31354     end
31355    end
31356    if present then
31357     cover(coverage,unicode,ligature)
31358     done=done+1
31359    else
31360     skip=skip+1
31361    end
31362   end
31363  end
31364  return coverage
31365 end
31366 local function resetspacekerns()
31367  data.properties.hasspacekerns=true
31368  data.resources .spacekerns=nil
31369 end
31370 local function prepare_kern(list,featuretype)
31371  local coverage={}
31372  local cover=coveractions[featuretype]
31373  local isspace=false
31374  for code,replacement in next,list do
31375   local unicode=tounicode(code)
31376   local description=descriptions[unicode]
31377   if description and type(replacement)=="table" then
31378    local r={}
31379    for k,v in next,replacement do
31380     local u=tounicode(k)
31381     if u then
31382      r[u]=v
31383      if u==32 then
31384       isspace=true
31385      end
31386     end
31387    end
31388    if next(r) then
31389     cover(coverage,unicode,r)
31390     done=done+1
31391     if unicode==32 then
31392      isspace=true
31393     end
31394    else
31395     skip=skip+1
31396    end
31397   else
31398    skip=skip+1
31399   end
31400  end
31401  if isspace then
31402   resetspacekerns()
31403  end
31404  return coverage
31405 end
31406 local function prepare_pair(list,featuretype)
31407  local coverage={}
31408  local cover=coveractions[featuretype]
31409  if cover then
31410   for code,replacement in next,list do
31411    local unicode=tounicode(code)
31412    local description=descriptions[unicode]
31413    if description and type(replacement)=="table" then
31414     local r={}
31415     for k,v in next,replacement do
31416      local u=tounicode(k)
31417      if u then
31418       r[u]=v
31419       if u==32 then
31420        isspace=true
31421       end
31422      end
31423     end
31424     if next(r) then
31425      cover(coverage,unicode,r)
31426      done=done+1
31427      if unicode==32 then
31428       isspace=true
31429      end
31430     else
31431      skip=skip+1
31432     end
31433    else
31434     skip=skip+1
31435    end
31436   end
31437   if isspace then
31438    resetspacekerns()
31439   end
31440  else
31441   report_otf("unknown cover type %a",featuretype)
31442  end
31443  return coverage
31444 end
31445 local prepare_single=prepare_pair 
31446 local function hassteps(lookups)
31447  if lookups then
31448   for i=1,#lookups do
31449    local l=lookups[i]
31450    if l then
31451     for j=1,#l do
31452      local l=l[j]
31453      if l then
31454       local n=l.nofsteps
31455       if not n then
31456        return true
31457       elseif n>0 then
31458        return true
31459       end
31460      end
31461     end
31462    end
31463   end
31464  end
31465  return false
31466 end
31467 local function prepare_chain(list,featuretype,sublookups,nocheck)
31468  local rules=list.rules
31469  local coverage={}
31470  if rules then
31471   local lookuptype=types[featuretype]
31472   for nofrules=1,#rules do
31473    local rule=rules[nofrules]
31474    local current=rule.current
31475    local before=rule.before
31476    local after=rule.after
31477    local replacements=rule.replacements or false
31478    local sequence={}
31479    local nofsequences=0
31480    if before then
31481     for n=1,#before do
31482      nofsequences=nofsequences+1
31483      sequence[nofsequences]=before[n]
31484     end
31485    end
31486    local start=nofsequences+1
31487    for n=1,#current do
31488     nofsequences=nofsequences+1
31489     sequence[nofsequences]=current[n]
31490    end
31491    local stop=nofsequences
31492    if after then
31493     for n=1,#after do
31494      nofsequences=nofsequences+1
31495      sequence[nofsequences]=after[n]
31496     end
31497    end
31498    local lookups=rule.lookups or false
31499    local subtype=nil
31500    if lookups and sublookups then
31501     if #lookups>0 then
31502      local ns=stop-start+1
31503      for i=1,ns do
31504       if lookups[i]==nil then
31505        lookups[i]=0
31506       end
31507      end
31508     end
31509     local l={}
31510     for k,v in sortedhash(lookups) do
31511      local t=type(v)
31512      if t=="table" then
31513       for i=1,#v do
31514        local vi=v[i]
31515        if type(vi)~="table" then
31516         v[i]={ vi }
31517        end
31518       end
31519       l[k]=v
31520      elseif t=="number" then
31521       local lookup=sublookups[v]
31522       if lookup then
31523        l[k]={ lookup }
31524        if not subtype then
31525         subtype=lookup.type
31526        end
31527       elseif v==0 then
31528        l[k]={ { type="gsub_remove",nosteps=true } }
31529       else
31530        l[k]=false 
31531       end
31532      else
31533       l[k]=false 
31534      end
31535     end
31536     if nocheck then
31537      rule.lookups=l 
31538     end
31539     lookups=l
31540    end
31541    if nofsequences>0 then
31542     if hassteps(lookups) then
31543      local hashed={}
31544      for i=1,nofsequences do
31545       local t={}
31546       local s=sequence[i]
31547       for i=1,#s do
31548        local u=tounicode(s[i])
31549        if u then
31550         t[u]=true
31551        end
31552       end
31553       hashed[i]=t
31554      end
31555      sequence=hashed
31556      local ruleset={
31557       nofrules,
31558       lookuptype,
31559       sequence,
31560       start,
31561       stop,
31562       lookups,
31563       replacements,
31564       subtype,
31565      }
31566      for unic in sortedhash(sequence[start]) do
31567       local cu=coverage[unic]
31568       if cu then
31569        local n=cu.n+1
31570        cu[n]=ruleset
31571        cu.n=n
31572       else
31573        coverage[unic]={
31574         ruleset,
31575         n=1,
31576        }
31577       end
31578      end
31579      sequence.n=nofsequences
31580     else
31581     end
31582    end
31583   end
31584  end
31585  return coverage
31586 end
31587 local dataset=specifications.dataset
31588 local function report(name,category,position,first,last,sequences)
31589  report_otf("injecting name %a of category %a at position %i in [%i,%i] of [%i,%i]",
31590   name,category,position,first,last,1,#sequences)
31591 end
31592 local function inject(specification,sequences,sequence,first,last,category,name)
31593  local position=specification.position or false
31594  if not position then
31595   position=specification.prepend
31596   if position==true then
31597    if trace_loading then
31598     report(name,category,first,first,last,sequences)
31599    end
31600    insert(sequences,first,sequence)
31601    return
31602   end
31603  end
31604  if not position then
31605   position=specification.append
31606   if position==true then
31607    if trace_loading then
31608     report(name,category,last+1,first,last,sequences)
31609    end
31610    insert(sequences,last+1,sequence)
31611    return
31612   end
31613  end
31614  local kind=type(position)
31615  if kind=="string" then
31616   local index=false
31617   for i=first,last do
31618    local s=sequences[i]
31619    local f=s.features
31620    if f then
31621     for k in sortedhash(f) do 
31622      if k==position then
31623       index=i
31624       break
31625      end
31626     end
31627     if index then
31628      break
31629     end
31630    end
31631   end
31632   if index then
31633    position=index
31634   else
31635    position=last+1
31636   end
31637  elseif kind=="number" then
31638   if position<0 then
31639    position=last-position+1
31640   end
31641   if position>last then
31642    position=last+1
31643   elseif position<first then
31644    position=first
31645   end
31646  else
31647   position=last+1
31648  end
31649  if trace_loading then
31650   report(name,category,position,first,last,sequences)
31651  end
31652  insert(sequences,position,sequence)
31653 end
31654 for s=1,#dataset do
31655  local specification=dataset[s]
31656  local valid=specification.valid 
31657  local feature=specification.name or feature
31658  if not feature or feature=="" then
31659   report_otf("no valid name given for extra feature")
31660  elseif not valid or valid(data,specification,feature) then 
31661   local initialize=specification.initialize
31662   if initialize then
31663    specification.initialize=initialize(specification,data) and initialize or nil
31664   end
31665   local askedfeatures=specification.features or everywhere
31666   local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
31667   local featuretype=specification.type or "substitution"
31668   local featureaction=false
31669   local featureflags=specification.flags or noflags
31670   local nocheck=specification.nocheck
31671   local mapping=specification.mapping
31672   local featureorder=specification.order or { feature }
31673   local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0
31674   local nofsteps=0
31675   local steps={}
31676   local sublookups=specification.lookups
31677   local category=nil
31678   local steptype=nil
31679   local sequence=nil
31680   if fonts.handlers.otf.handlers[featuretype] then
31681    featureaction=true 
31682   else
31683    featuretype=normalized[specification.type or "substitution"] or "substitution"
31684   end
31685   checkflags(specification,resources)
31686   for k,v in next,askedfeatures do
31687    if v[1] then
31688     askedfeatures[k]=tohash(v)
31689    end
31690   end
31691   if featureflags[1] then featureflags[1]="mark" end
31692   if featureflags[2] then featureflags[2]="ligature" end
31693   if featureflags[3] then featureflags[3]="base" end
31694   if featureaction then
31695    category="gsub"
31696    sequence={
31697     features={ [feature]=askedfeatures },
31698     flags=featureflags,
31699     name=feature,
31700     order=featureorder,
31701     type=featuretype,
31702     nofsteps=0,
31703    }
31704   else
31705    if sublookups then
31706     local s={}
31707     for i=1,#sublookups do
31708      local specification=sublookups[i]
31709      local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
31710      local featuretype=normalized[specification.type or "substitution"] or "substitution"
31711      local featureflags=specification.flags or noflags
31712      local nofsteps=0
31713      local steps={}
31714      for i=1,#askedsteps do
31715       local list=askedsteps[i]
31716       local coverage=nil
31717       local format=nil
31718       if featuretype=="substitution" then
31719        coverage=prepare_substitution(list,featuretype,nocheck)
31720       elseif featuretype=="ligature" then
31721        coverage=prepare_ligature(list,featuretype,nocheck)
31722       elseif featuretype=="alternate" then
31723        coverage=prepare_alternate(list,featuretype,nocheck)
31724       elseif featuretype=="multiple" then
31725        coverage=prepare_multiple(list,featuretype,nocheck)
31726       elseif featuretype=="kern" or featuretype=="move" then
31727        format=featuretype
31728        coverage=prepare_kern(list,featuretype)
31729       elseif featuretype=="pair" then
31730        format="pair"
31731        coverage=prepare_pair(list,featuretype)
31732       elseif featuretype=="single" then
31733        format="single"
31734        coverage=prepare_single(list,featuretype)
31735       end
31736       if coverage and next(coverage) then
31737        nofsteps=nofsteps+1
31738        steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
31739       end
31740      end
31741      checkmerge(specification)
31742      checksteps(specification)
31743      s[i]={
31744       [stepkey]=steps,
31745       nofsteps=nofsteps,
31746       flags=featureflags,
31747       type=types[featuretype],
31748      }
31749     end
31750     sublookups=s
31751    end
31752    for i=1,#askedsteps do
31753     local list=askedsteps[i]
31754     local coverage=nil
31755     local format=nil
31756if type(list)=="function" then
31757 list=list(data,specification,list,i)
31758end
31759     if not list then
31760     elseif featuretype=="substitution" then
31761      category="gsub"
31762      coverage=(mapping and list) or prepare_substitution(list,featuretype,nocheck)
31763     elseif featuretype=="ligature" then
31764      category="gsub"
31765      coverage=prepare_ligature(list,featuretype,nocheck)
31766     elseif featuretype=="alternate" then
31767      category="gsub"
31768      coverage=prepare_alternate(list,featuretype,nocheck)
31769     elseif featuretype=="multiple" then
31770      category="gsub"
31771      coverage=prepare_multiple(list,featuretype,nocheck)
31772     elseif featuretype=="kern" or featuretype=="move" then
31773      category="gpos"
31774      format=featuretype
31775      coverage=prepare_kern(list,featuretype)
31776     elseif featuretype=="pair" then
31777      category="gpos"
31778      format="pair"
31779      coverage=prepare_pair(list,featuretype)
31780     elseif featuretype=="single" then
31781      category="gpos"
31782      format="single"
31783      coverage=prepare_single(list,featuretype)
31784     elseif featuretype=="chainsubstitution" then
31785      category="gsub"
31786      coverage=prepare_chain(list,featuretype,sublookups,nocheck)
31787     elseif featuretype=="chainposition" then
31788      category="gpos"
31789      coverage=prepare_chain(list,featuretype,sublookups,nocheck)
31790     else
31791      report_otf("not registering feature %a, unknown category",feature)
31792      return
31793     end
31794     if coverage and next(coverage) then
31795      nofsteps=nofsteps+1
31796      steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
31797     end
31798    end
31799    if nofsteps>0 then
31800     sequence={
31801      chain=featurechain,
31802      features={ [feature]=askedfeatures },
31803      flags=featureflags,
31804      name=feature,
31805      order=featureorder,
31806      [stepkey]=steps,
31807      nofsteps=nofsteps,
31808      type=specification.handler or types[featuretype],
31809     }
31810     if prepareonly then
31811      return sequence
31812     end
31813    end
31814   end
31815   if sequence then
31816    checkflags(sequence,resources)
31817    checkmerge(sequence)
31818    checksteps(sequence)
31819    local first,last=getrange(sequences,category)
31820    inject(specification,sequences,sequence,first,last,category,feature)
31821    local features=fontfeatures[category]
31822    if not features then
31823     features={}
31824     fontfeatures[category]=features
31825    end
31826    local k=features[feature]
31827    if not k then
31828     k={}
31829     features[feature]=k
31830    end
31831    for script,languages in next,askedfeatures do
31832     local kk=k[script]
31833     if not kk then
31834      kk={}
31835      k[script]=kk
31836     end
31837     for language,value in next,languages do
31838      kk[language]=value
31839     end
31840    end
31841   end
31842  end
31843 end
31844 if trace_loading then
31845  report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip)
31846 end
31847end
31848otf.enhancers.addfeature=addfeature
31849local extrafeatures={}
31850local knownfeatures={}
31851function otf.addfeature(name,specification)
31852 if type(name)=="table" then
31853  specification=name
31854 end
31855 if type(specification)~="table" then
31856  report_otf("invalid feature specification, no valid table")
31857  return
31858 end
31859 specification,name=validspecification(specification,name)
31860 if name and specification then
31861  local slot=knownfeatures[name]
31862  if not slot then
31863   slot=#extrafeatures+1
31864   knownfeatures[name]=slot
31865  elseif specification.overload==false then
31866   slot=#extrafeatures+1
31867   knownfeatures[name]=slot
31868  else
31869  end
31870  specification.name=name 
31871  extrafeatures[slot]=specification
31872 end
31873end
31874local function enhance(data,filename,raw)
31875 for slot=1,#extrafeatures do
31876  local specification=extrafeatures[slot]
31877  addfeature(data,specification.name,specification)
31878 end
31879end
31880otf.enhancers.enhance=enhance
31881otf.enhancers.register("check extra features",enhance)
31882
31883end -- closure
31884
31885do -- begin closure to overcome local limits and interference
31886
31887if not modules then modules={} end modules ['font-osd']={ 
31888 version=1.001,
31889 comment="companion to font-ini.mkiv",
31890 author="Kai Eigner, TAT Zetwerk / Hans Hagen, PRAGMA ADE",
31891 copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team",
31892 license="see context related readme files"
31893}
31894local insert,remove,imerge,copy,tohash=table.insert,table.remove,table.imerge,table.copy,table.tohash
31895local next,type,rawget=next,type,rawget
31896local formatters=string.formatters
31897local settings_to_hash=utilities.parsers.settings_to_hash
31898local report=logs.reporter("otf","devanagari")
31899fonts=fonts       or {}
31900fonts.analyzers=fonts.analyzers   or {}
31901fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } }
31902local otf=fonts.handlers.otf
31903local handlers=otf.handlers
31904local methods=fonts.analyzers.methods
31905local otffeatures=fonts.constructors.features.otf
31906local registerotffeature=otffeatures.register
31907local trace_steps=false
31908local nuts=nodes.nuts
31909local getnext=nuts.getnext
31910local getprev=nuts.getprev
31911local getboth=nuts.getboth
31912local getid=nuts.getid
31913local getchar=nuts.getchar
31914local getfont=nuts.getfont
31915local getsubtype=nuts.getsubtype
31916local setlink=nuts.setlink
31917local setnext=nuts.setnext
31918local setprev=nuts.setprev
31919local setchar=nuts.setchar
31920local getprop=nuts.getprop
31921local setprop=nuts.setprop
31922local getstate=nuts.getstate
31923local setstate=nuts.setstate
31924local ischar=nuts.ischar
31925local insertnodeafter=nuts.insertafter
31926local copy_node=nuts.copy
31927local remove_node=nuts.remove
31928local flushlist=nuts.flushlist
31929local flushnode=nuts.flushnode
31930local copyinjection=nodes.injections.copy 
31931local unsetvalue=attributes.unsetvalue
31932local fontdata=fonts.hashes.identifiers
31933local a_syllabe="syllable"  
31934local a_reordered="reordered" 
31935local dotted_circle=0x25CC
31936local c_nbsp=0x00A0
31937local c_zwnj=0x200C
31938local c_zwj=0x200D
31939local states=fonts.analyzers.states 
31940local s_rphf=states.rphf
31941local s_half=states.half
31942local s_pref=states.pref
31943local s_blwf=states.blwf
31944local s_pstf=states.pstf
31945local s_init=states.init
31946local replace_all_nbsp=nil
31947replace_all_nbsp=function(head) 
31948 replace_all_nbsp=typesetters and typesetters.characters and typesetters.characters.replacenbspaces or function(head)
31949  return head
31950 end
31951 return replace_all_nbsp(head)
31952end
31953local processcharacters=nil
31954local logprocess=nil
31955if context then
31956
31957--removed
31958
31959else
31960 function processcharacters(head,font)
31961  local processors=fontdata[font].shared.processes
31962  for i=1,#processors do
31963   head=processors[i](head,font,0)
31964  end
31965  return head
31966 end
31967 logprocess=function(str)
31968 end
31969end
31970local indicgroups=characters and characters.indicgroups
31971if not indicgroups and characters then
31972 local indic={
31973  c={},
31974  i={},
31975  d={},
31976  m={},
31977  s={},
31978  o={},
31979 }
31980 local indicmarks={
31981  l={},
31982  t={},
31983  b={},
31984  r={},
31985  s={},
31986 }
31987 local indicclasses={
31988  nukta={},
31989  halant={},
31990  ra={},
31991  anudatta={},
31992 }
31993 local indicorders={
31994  bp={},
31995  ap={},
31996  bs={},
31997  as={},
31998  bh={},
31999  ah={},
32000  bm={},
32001  am={},
32002 }
32003 for k,v in next,characters.data do
32004  local i=v.indic
32005  if i then
32006   indic[i][k]=true
32007   i=v.indicmark
32008   if i then
32009    if i=="s" then
32010     local s=v.specials
32011     indicmarks[i][k]={ s[2],s[3] }
32012    else
32013     indicmarks[i][k]=true
32014    end
32015   end
32016   i=v.indicclass
32017   if i then
32018    indicclasses[i][k]=true
32019   end
32020   i=v.indicorder
32021   if i then
32022    indicorders[i][k]=true
32023   end
32024  end
32025 end
32026 indicgroups={
32027  consonant=indic.c,
32028  independent_vowel=indic.i,
32029  dependent_vowel=indic.d,
32030  vowel_modifier=indic.m,
32031  stress_tone_mark=indic.s,
32032  pre_mark=indicmarks.l,
32033  above_mark=indicmarks.t,
32034  below_mark=indicmarks.b,
32035  post_mark=indicmarks.r,
32036  twopart_mark=indicmarks.s,
32037  nukta=indicclasses.nukta,
32038  halant=indicclasses.halant,
32039  ra=indicclasses.ra,
32040  anudatta=indicclasses.anudatta,
32041  before_postscript=indicorders.bp,
32042  after_postscript=indicorders.ap,
32043  before_half=indicorders.bh,
32044  after_half=indicorders.ah,
32045  before_subscript=indicorders.bs,
32046  after_subscript=indicorders.as,
32047  before_main=indicorders.bm,
32048  after_main=indicorders.am,
32049 }
32050 indic=nil
32051 indicmarks=nil
32052 indicclasses=nil
32053 indicorders=nil
32054 characters.indicgroups=indicgroups
32055end
32056local consonant=indicgroups.consonant
32057local independent_vowel=indicgroups.independent_vowel
32058local dependent_vowel=indicgroups.dependent_vowel
32059local vowel_modifier=indicgroups.vowel_modifier
32060local stress_tone_mark=indicgroups.stress_tone_mark
32061local pre_mark=indicgroups.pre_mark
32062local above_mark=indicgroups.above_mark
32063local below_mark=indicgroups.below_mark
32064local post_mark=indicgroups.post_mark
32065local twopart_mark=indicgroups.twopart_mark
32066local nukta=indicgroups.nukta
32067local halant=indicgroups.halant
32068local ra=indicgroups.ra
32069local anudatta=indicgroups.anudatta
32070local before_postscript=indicgroups.before_postscript
32071local after_postscript=indicgroups.after_postscript
32072local before_half=indicgroups.before_half
32073local after_half=indicgroups.after_half
32074local before_subscript=indicgroups.before_subscript
32075local after_subscript=indicgroups.after_subscript
32076local before_main=indicgroups.before_main
32077local after_main=indicgroups.after_main
32078local mark_pre_above_below_post=table.merged (
32079 pre_mark,
32080 above_mark,
32081 below_mark,
32082 post_mark
32083)
32084local mark_above_below_post=table.merged (
32085 above_mark,
32086 below_mark,
32087 post_mark
32088)
32089local devanagarihash=table.setmetatableindex(function(t,k)
32090 local v=fontdata[k].resources.devanagari or false
32091 t[k]=v
32092 return v
32093end)
32094local zw_char={ 
32095 [c_zwnj]=true,
32096 [c_zwj ]=true,
32097}
32098local dflt_true={
32099 dflt=true,
32100}
32101local two_defaults={}
32102local one_defaults={}
32103local false_flags={ false,false,false,false }
32104local sequence_reorder_matras={
32105 features={ dv01=two_defaults },
32106 flags=false_flags,
32107 name="dv01_reorder_matras",
32108 order={ "dv01" },
32109 type="devanagari_reorder_matras",
32110 nofsteps=1,
32111 steps={
32112  {
32113   coverage=pre_mark,
32114  }
32115 }
32116}
32117local sequence_reorder_reph={
32118 features={ dv02=two_defaults },
32119 flags=false_flags,
32120 name="dv02_reorder_reph",
32121 order={ "dv02" },
32122 type="devanagari_reorder_reph",
32123 nofsteps=1,
32124 steps={
32125  {
32126   coverage={},
32127  }
32128 }
32129}
32130local sequence_reorder_pre_base_reordering_consonants={
32131 features={ dv03=one_defaults },
32132 flags=false_flags,
32133 name="dv03_reorder_pre_base_reordering_consonants",
32134 order={ "dv03" },
32135 type="devanagari_reorder_pre_base_reordering_consonants",
32136 nofsteps=1,
32137 steps={
32138  {
32139   coverage={},
32140  }
32141 }
32142}
32143local sequence_remove_joiners={
32144 features={ dv04=one_defaults },
32145 flags=false_flags,
32146 name="dv04_remove_joiners",
32147 order={ "dv04" },
32148 type="devanagari_remove_joiners",
32149 nofsteps=1,
32150 steps={
32151  {
32152     coverage=zw_char,
32153  },
32154 }
32155}
32156local basic_shaping_forms={
32157 akhn=true,
32158 blwf=true,
32159 cjct=true,
32160 half=true,
32161 nukt=true,
32162 pref=true,
32163 pstf=true,
32164 rkrf=true,
32165 rphf=true,
32166 vatu=true,
32167 locl=true,
32168}
32169local valid={
32170 abvs=true,
32171 akhn=true,
32172 blwf=true,
32173 calt=true,
32174 cjct=true,
32175 half=true,
32176 haln=true,
32177 nukt=true,
32178 pref=true,
32179 pres=true,
32180 pstf=true,
32181 psts=true,
32182 rkrf=true,
32183 rphf=true,
32184 vatu=true,
32185 pres=true,
32186 abvs=true,
32187 blws=true,
32188 psts=true,
32189 haln=true,
32190 calt=true,
32191 locl=true,
32192}
32193local scripts={}
32194local scripts_one={ "deva","mlym","beng","gujr","guru","knda","orya","taml","telu" }
32195local scripts_two={ "dev2","mlm2","bng2","gjr2","gur2","knd2","ory2","tml2","tel2" }
32196local nofscripts=#scripts_one
32197for i=1,nofscripts do
32198 local one=scripts_one[i]
32199 local two=scripts_two[i]
32200 scripts[one]=true
32201 scripts[two]=true
32202 two_defaults[two]=dflt_true
32203 one_defaults[one]=dflt_true
32204 one_defaults[two]=dflt_true
32205end
32206local function valid_one(s) for i=1,nofscripts do if s[scripts_one[i]] then return true end end end
32207local function valid_two(s) for i=1,nofscripts do if s[scripts_two[i]] then return true end end end
32208local function initializedevanagi(tfmdata)
32209 local script,language=otf.scriptandlanguage(tfmdata,attr) 
32210 if scripts[script] then
32211  local resources=tfmdata.resources
32212  local devanagari=resources.devanagari
32213  if not devanagari then
32214   report("adding features to font")
32215   local gsubfeatures=resources.features.gsub
32216   local sequences=resources.sequences
32217   local sharedfeatures=tfmdata.shared.features
32218   gsubfeatures["dv01"]=two_defaults 
32219   gsubfeatures["dv02"]=two_defaults 
32220   gsubfeatures["dv03"]=one_defaults 
32221   gsubfeatures["dv04"]=one_defaults
32222   local reorder_pre_base_reordering_consonants=copy(sequence_reorder_pre_base_reordering_consonants)
32223   local reorder_reph=copy(sequence_reorder_reph)
32224   local reorder_matras=copy(sequence_reorder_matras)
32225   local remove_joiners=copy(sequence_remove_joiners)
32226   local lastmatch=0
32227   for s=1,#sequences do 
32228    local features=sequences[s].features
32229    if features then
32230     for k,v in next,features do
32231      if k=="locl" then
32232       local steps=sequences[s].steps
32233       local nofsteps=sequences[s].nofsteps
32234       for i=1,nofsteps do
32235        local step=steps[i]
32236        local coverage=step.coverage
32237        if coverage then
32238         for k,v in next,pre_mark do
32239          local locl=coverage[k]
32240          if locl then
32241           if #locl>0 then
32242            for j=1,#locl do
32243             local ck=locl[j]
32244             local f=ck[4]
32245             local chainlookups=ck[6]
32246             if chainlookups then
32247              local chainlookup=chainlookups[f]
32248              for j=1,#chainlookup do
32249               local chainstep=chainlookup[j]
32250               local steps=chainstep.steps
32251               local nofsteps=chainstep.nofsteps
32252               for i=1,nofsteps do
32253                local step=steps[i]
32254                local coverage=step.coverage
32255                if coverage then
32256                 locl=coverage[k]
32257                end
32258               end
32259              end
32260             end
32261            end
32262           else
32263           end
32264           if locl then
32265            reorder_matras.steps[1].coverage[locl]=true
32266           end
32267          end
32268         end
32269        end
32270       end
32271      end
32272      if basic_shaping_forms[k] then
32273       lastmatch=lastmatch+1
32274       if s~=lastmatch then
32275        insert(sequences,lastmatch,remove(sequences,s))
32276       end
32277      end
32278     end
32279    end
32280   end
32281   local insertindex=lastmatch+1
32282   if tfmdata.properties.language then
32283    dflt_true[tfmdata.properties.language]=true
32284   end
32285   insert(sequences,insertindex,reorder_pre_base_reordering_consonants)
32286   insert(sequences,insertindex,reorder_reph)
32287   insert(sequences,insertindex,reorder_matras)
32288   insert(sequences,insertindex,remove_joiners)
32289   local blwfcache={}
32290   local vatucache={}
32291   local pstfcache={}
32292   local seqsubset={}
32293   local rephstep={ coverage={} } 
32294   local devanagari={
32295    reph=false,
32296    vattu=false,
32297    blwfcache=blwfcache,
32298    vatucache=vatucache,
32299    pstfcache=pstfcache,
32300    seqsubset=seqsubset,
32301    reorderreph=rephstep,
32302   }
32303   reorder_reph.steps={ rephstep }
32304   local pre_base_reordering_consonants={}
32305   reorder_pre_base_reordering_consonants.steps[1].coverage=pre_base_reordering_consonants
32306   resources.devanagari=devanagari
32307   for s=1,#sequences do
32308    local sequence=sequences[s]
32309    local steps=sequence.steps
32310    local nofsteps=sequence.nofsteps
32311    local features=sequence.features
32312    local has_rphf=features.rphf
32313    local has_blwf=features.blwf
32314    local has_vatu=features.vatu
32315    local has_pstf=features.pstf
32316    if has_rphf and has_rphf[script] then
32317     devanagari.reph=true
32318    elseif (has_blwf and has_blwf[script]) or (has_vatu and has_vatu[script]) then
32319     devanagari.vattu=true
32320     for i=1,nofsteps do
32321      local step=steps[i]
32322      local coverage=step.coverage
32323      if coverage then
32324       for k,v in next,coverage do
32325        for h,w in next,halant do
32326         if v[h] and not blwfcache[k] then
32327          blwfcache[k]=v
32328         end
32329         if has_vatu and has_vatu[script] and not vatucache[k] then
32330          vatucache[k]=v
32331         end
32332        end
32333       end
32334      end
32335     end
32336    elseif has_pstf and has_pstf[script] then
32337     for i=1,nofsteps do
32338      local step=steps[i]
32339      local coverage=step.coverage
32340      if coverage then
32341       for k,v in next,coverage do
32342        if not pstfcache[k] then
32343         pstfcache[k]=v
32344        end
32345       end
32346       for k,v in next,ra do
32347        local r=coverage[k]
32348        if r then
32349         local found=false
32350         if #r>0 then
32351          for j=1,#r do
32352           local ck=r[j]
32353           local f=ck[4]
32354           local chainlookups=ck[6]
32355           if chainlookups then
32356            local chainlookup=chainlookups[f]
32357            if chainlookup then
32358             for j=1,#chainlookup do
32359              local chainstep=chainlookup[j]
32360              local steps=chainstep.steps
32361              local nofsteps=chainstep.nofsteps
32362              for i=1,nofsteps do
32363               local step=steps[i]
32364               local coverage=step.coverage
32365               if coverage then
32366                local h=coverage[k]
32367                if h then
32368                 for k,v in next,h do
32369                  if v then
32370                   found=tonumber(v) or v.ligature
32371                   if found then
32372                    pre_base_reordering_consonants[found]=true
32373                    break
32374                   end
32375                  end
32376                 end
32377                 if found then
32378                  break
32379                 end
32380                end
32381               end
32382              end
32383             end
32384            end
32385           end
32386          end
32387         else
32388          for k,v in next,r do
32389           if v then
32390            found=tonumber(v) or v.ligature
32391            if found then
32392             pre_base_reordering_consonants[found]=true
32393             break
32394            end
32395           end
32396          end
32397         end
32398         if found then
32399          break
32400         end
32401        end
32402       end
32403      end
32404     end
32405    end
32406    for kind,spec in next,features do
32407     if valid[kind] and valid_two(spec)then
32408      for i=1,nofsteps do
32409       local step=steps[i]
32410       local coverage=step.coverage
32411       if coverage then
32412        local reph=false
32413        local base=false
32414        if kind=="rphf" then
32415         for k,v in next,ra do
32416          local r=coverage[k]
32417          if r then
32418           base=k
32419           local h=false
32420           if #r>0 then
32421            for j=1,#r do
32422             local ck=r[j]
32423             local f=ck[4]
32424             local chainlookups=ck[6]
32425             if chainlookups then
32426              local chainlookup=chainlookups[f]
32427              for j=1,#chainlookup do
32428               local chainstep=chainlookup[j]
32429               local steps=chainstep.steps
32430               local nofsteps=chainstep.nofsteps
32431               for i=1,nofsteps do
32432                local step=steps[i]
32433                local coverage=step.coverage
32434                if coverage then
32435                 local r=coverage[k]
32436                 if r then
32437                  for k,v in next,halant do
32438                   local h=r[k]
32439                   if h then
32440                    reph=tonumber(h) or h.ligature or false
32441                    break
32442                   end
32443                  end
32444                  if h then
32445                   break
32446                  end
32447                 end
32448                end
32449               end
32450              end
32451             end
32452            end
32453           else
32454            for k,v in next,halant do
32455             local h=r[k]
32456             if h then
32457              reph=tonumber(h) or h.ligature or false
32458              break
32459             end
32460            end
32461           end
32462           if reph then
32463            break
32464           end
32465          end
32466         end
32467        end
32468         seqsubset[#seqsubset+1]={ kind,coverage,reph,base }
32469       end
32470      end
32471     end
32472     if kind=="pref" then
32473      local steps=sequence.steps
32474      local nofsteps=sequence.nofsteps
32475      for i=1,nofsteps do
32476       local step=steps[i]
32477       local coverage=step.coverage
32478       if coverage then
32479        for k,v in next,halant do
32480         local h=coverage[k]
32481         if h then
32482          local found=false
32483          if #h>0 then
32484           for j=1,#h do
32485            local ck=h[j]
32486            local f=ck[4]
32487            local chainlookups=ck[6]
32488            if chainlookups then
32489             local chainlookup=chainlookups[f]
32490             for j=1,#chainlookup do
32491              local chainstep=chainlookup[j]
32492              local steps=chainstep.steps
32493              local nofsteps=chainstep.nofsteps
32494              for i=1,nofsteps do
32495               local step=steps[i]
32496               local coverage=step.coverage
32497               if coverage then
32498                local h=coverage[k]
32499                if h then
32500                 for k,v in next,h do
32501                  if v then
32502                   found=tonumber(v) or v.ligature
32503                   if found then
32504                    pre_base_reordering_consonants[found]=true
32505                    break
32506                   end
32507                  end
32508                 end
32509                 if found then
32510                  break
32511                 end
32512                end
32513               end
32514              end
32515             end
32516            end
32517           end
32518          else
32519           for k,v in next,h do
32520            found=v and (tonumber(v) or v.ligature)
32521            if found then
32522             pre_base_reordering_consonants[found]=true
32523             break
32524            end
32525           end
32526          end
32527          if found then
32528           break
32529          end
32530         end
32531        end
32532       end
32533      end
32534     end
32535    end
32536   end
32537   if two_defaults[script] then
32538    sharedfeatures["dv01"]=true 
32539    sharedfeatures["dv02"]=true 
32540    sharedfeatures["dv03"]=true 
32541    sharedfeatures["dv04"]=true 
32542   elseif one_defaults[script] then
32543    sharedfeatures["dv03"]=true 
32544    sharedfeatures["dv04"]=true 
32545   end
32546  end
32547 end
32548end
32549registerotffeature {
32550 name="devanagari",
32551 description="inject additional features",
32552 default=true,
32553 initializers={
32554  node=initializedevanagi,
32555 },
32556}
32557local function initializeconjuncts(tfmdata,value)
32558 if value then
32559  local resources=tfmdata.resources
32560  local devanagari=resources.devanagari
32561  if devanagari then
32562   local conjuncts="auto" 
32563   local movematra="auto" 
32564   if type(value)=="string" and value~="auto" then
32565    value=settings_to_hash(value)
32566    conjuncts=rawget(value,"conjuncts") or conjuncts
32567    movematra=rawget(value,"movematra") or movematra
32568   end
32569   if conjuncts=="auto" then
32570    conjuncts="mixed" 
32571   end
32572   if movematra=="auto" and
32573      script=="mlym" or
32574      script=="taml" then
32575    movematra="leftbeforebase"
32576   else
32577    movematra="default"
32578   end
32579   devanagari.conjuncts=conjuncts
32580   devanagari.movematra=movematra
32581   if trace_steps then
32582    report("conjuncts %a, movematra %a",conjuncts,movematra)
32583   end
32584  end
32585 end
32586end
32587registerotffeature {
32588 name="indic",
32589 description="control indic",
32590 default="auto",
32591 initializers={
32592  node=initializeconjuncts,
32593 },
32594}
32595local show_syntax_errors=false
32596local function inject_syntax_error(head,current,char)
32597 local signal=copy_node(current)
32598 copyinjection(signal,current)
32599 if pre_mark[char] then
32600  setchar(signal,dotted_circle)
32601 else
32602  setchar(current,dotted_circle)
32603 end
32604 return insertnodeafter(head,current,signal)
32605end
32606local function initialize_one(font,attr) 
32607 local tfmdata=fontdata[font]
32608 local datasets=otf.dataset(tfmdata,font,attr) 
32609 local devanagaridata=datasets.devanagari
32610 if not devanagaridata then
32611  devanagaridata={
32612   reph=false,
32613   vattu=false,
32614   blwfcache={},
32615   vatucache={},
32616   pstfcache={},
32617  }
32618  datasets.devanagari=devanagaridata
32619  local resources=tfmdata.resources
32620  local devanagari=resources.devanagari
32621  for s=1,#datasets do
32622   local dataset=datasets[s]
32623   if dataset and dataset[1] then 
32624    local kind=dataset[4]
32625    if kind=="rphf" then
32626     devanagaridata.reph=true
32627    elseif kind=="blwf" or kind=="vatu" then
32628     devanagaridata.vattu=true
32629     devanagaridata.blwfcache=devanagari.blwfcache
32630     devanagaridata.vatucache=devanagari.vatucache
32631     devanagaridata.pstfcache=devanagari.pstfcache
32632    end
32633   end
32634  end
32635 end
32636 return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache,devanagaridata.vatucache,devanagaridata.pstfcache
32637end
32638local function contextchain(contexts,n)
32639 local char=getchar(n)
32640 if not contexts.n then
32641  return contexts[char]
32642 else
32643  for k=1,#contexts do
32644   local ck=contexts[k]
32645   local seq=ck[3]
32646   local f=ck[4]
32647   local l=ck[5]
32648   if (l-f)==1 and seq[f+1][char] then
32649    local ok=true
32650    local c=n
32651    for i=l+1,#seq do
32652     c=getnext(c)
32653     if not c or not seq[i][ischar(c)] then
32654      ok=false
32655      break
32656     end
32657    end
32658    if ok then
32659     c=getprev(n)
32660     for i=1,f-1 do
32661      c=getprev(c)
32662      if not c or not seq[f-i][ischar(c)] then
32663       ok=false
32664      end
32665     end
32666    end
32667    if ok then
32668     return true
32669    end
32670   end
32671  end
32672  return false
32673 end
32674end
32675local function order_matras(c)
32676 local cn=getnext(c)
32677 local char=getchar(cn)
32678 while dependent_vowel[char] do
32679  local next=getnext(cn)
32680  local cc=c
32681  local cchar=getchar(cc)
32682  while cc~=cn do
32683   if (above_mark[char] and (below_mark[cchar] or post_mark[cchar])) or (below_mark[char] and (post_mark[cchar])) then
32684    local prev,next=getboth(cn)
32685    if next then
32686     setprev(next,prev)
32687    end
32688    setnext(prev,next)
32689    setnext(getprev(cc),cn)
32690    setprev(cn,getprev(cc))
32691    setnext(cn,cc)
32692    setprev(cc,cn)
32693    break
32694   end
32695   cc=getnext(cc)
32696   cchar=getchar(cc)
32697  end
32698  cn=next
32699  char=getchar(cn)
32700 end
32701end
32702local swapped=table.swapped(states)
32703local function reorder_one(head,start,stop,font,attr,nbspaces)
32704 local reph,vattu,blwfcache,vatucache,pstfcache=initialize_one(font,attr)
32705 local current=start
32706 local n=getnext(start)
32707 local base=nil
32708 local firstcons=nil
32709 local lastcons=nil
32710 local basefound=false
32711 if reph and ra[getchar(start)] and halant[getchar(n)] then
32712  if n==stop then
32713   return head,stop,nbspaces
32714  end
32715  if getchar(getnext(n))==c_zwj then
32716   current=start
32717  else
32718   current=getnext(n)
32719   setstate(start,s_rphf)
32720  end
32721 end
32722 if getchar(current)==c_nbsp then
32723  if current==stop then
32724   stop=getprev(stop)
32725   head=remove_node(head,current)
32726   flushnode(current)
32727   if trace_steps then
32728    logprocess("reorder one, remove nbsp")
32729   end
32730   return head,stop,nbspaces
32731  else
32732   nbspaces=nbspaces+1
32733   base=current
32734   firstcons=current
32735   lastcons=current
32736   current=getnext(current)
32737   if current~=stop then
32738    local char=getchar(current)
32739    if nukta[char] then
32740     current=getnext(current)
32741     char=getchar(current)
32742    end
32743    if char==c_zwj and current~=stop then
32744     local next=getnext(current)
32745     if next~=stop and halant[getchar(next)] then
32746      current=next
32747      next=getnext(current)
32748      local tmp=next and getnext(next) or nil 
32749      local changestop=next==stop
32750      local tempcurrent=copy_node(next)
32751      copyinjection(tempcurrent,next)
32752      local nextcurrent=copy_node(current)
32753      copyinjection(nextcurrent,current) 
32754      setlink(tempcurrent,nextcurrent)
32755      setstate(tempcurrent,s_blwf)
32756      tempcurrent=processcharacters(tempcurrent,font)
32757      setstate(tempcurrent,unsetvalue)
32758      if getchar(next)==getchar(tempcurrent) then
32759       flushlist(tempcurrent)
32760       if show_syntax_errors then
32761        head,current=inject_syntax_error(head,current,char)
32762       end
32763      else
32764       setchar(current,getchar(tempcurrent)) 
32765       local freenode=getnext(current)
32766       setlink(current,tmp)
32767       flushnode(freenode)
32768       flushlist(tempcurrent)
32769       if changestop then
32770        stop=current
32771       end
32772      end
32773      if trace_steps then
32774       logprocess("reorder one, handle nbsp")
32775      end
32776     end
32777    end
32778   end
32779  end
32780 end
32781 while not basefound do
32782  local char=getchar(current)
32783  if consonant[char] then
32784   setstate(current,s_half)
32785   if not firstcons then
32786    firstcons=current
32787   end
32788   lastcons=current
32789   if not base then
32790    base=current
32791   elseif blwfcache[char] then
32792    setstate(current,s_blwf)
32793   elseif pstfcache[char] then
32794    setstate(current,s_pstf)
32795   else
32796    base=current
32797   end
32798  end
32799  basefound=current==stop
32800  current=getnext(current)
32801 end
32802 if base~=lastcons then
32803  local np=base
32804  local n=getnext(base)
32805  local ch=getchar(n)
32806  if nukta[ch] then
32807   np=n
32808   n=getnext(n)
32809   ch=getchar(n)
32810  end
32811  if halant[ch] then
32812   if lastcons~=stop then
32813    local ln=getnext(lastcons)
32814    if nukta[getchar(ln)] then
32815     lastcons=ln
32816    end
32817   end
32818   local nn=getnext(n)
32819   local ln=getnext(lastcons) 
32820   setlink(np,nn)
32821   setnext(lastcons,n)
32822   if ln then
32823    setprev(ln,n)
32824   end
32825   setnext(n,ln)
32826   setprev(n,lastcons)
32827   if lastcons==stop then
32828    stop=n
32829   end
32830   if trace_steps then
32831    logprocess("reorder one, handle halant")
32832   end
32833  end
32834 end
32835 n=getnext(start)
32836 if n~=stop and ra[getchar(start)] and halant[getchar(n)] and not zw_char[getchar(getnext(n))] then
32837  local matra=base
32838  if base~=stop then
32839   local next=getnext(base)
32840   if dependent_vowel[getchar(next)] then
32841    matra=next
32842   end
32843  end
32844  local sp=getprev(start)
32845  local nn=getnext(n)
32846  local mn=getnext(matra)
32847  setlink(sp,nn)
32848  setlink(matra,start)
32849  setlink(n,mn)
32850  if head==start then
32851   head=nn
32852  end
32853  start=nn
32854  if matra==stop then
32855   stop=n
32856  end
32857  if trace_steps then
32858   logprocess("reorder one, handle matra")
32859  end
32860 end
32861 local current=start
32862 while current~=stop do
32863  local next=getnext(current)
32864  if next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwnj then
32865   setstate(current,unsetvalue)
32866  end
32867  current=next
32868 end
32869 if base~=stop and getstate(base) then 
32870  local next=getnext(base)
32871  if halant[getchar(next)] and not (next~=stop and getchar(getnext(next))==c_zwj) then
32872   setstate(base,unsetvalue)
32873  end
32874 end
32875 local current,allreordered,moved=start,false,{ [base]=true }
32876 local a,b,p,bn=base,base,base,getnext(base)
32877 if base~=stop and nukta[getchar(bn)] then
32878  a,b,p=bn,bn,bn
32879 end
32880 while not allreordered do
32881  local c=current
32882  local n=getnext(current)
32883  local l=nil 
32884  if c~=stop then
32885   local ch=getchar(n)
32886   if nukta[ch] then
32887    c=n
32888    n=getnext(n)
32889    ch=getchar(n)
32890   end
32891   if c~=stop then
32892    if halant[ch] then
32893     c=n
32894     n=getnext(n)
32895     ch=getchar(n)
32896    end
32897    local tpm=twopart_mark[ch]
32898    if tpm then
32899     while tpm do
32900      local extra=copy_node(n)
32901      copyinjection(extra,n)
32902      ch=tpm[1]
32903      setchar(n,ch)
32904      setchar(extra,tpm[2])
32905      head=insertnodeafter(head,current,extra)
32906      tpm=twopart_mark[ch]
32907     end
32908     if trace_steps then
32909      logprocess("reorder one, handle mark")
32910     end
32911    end
32912    while c~=stop and dependent_vowel[ch] do
32913     c=n
32914     n=getnext(n)
32915     ch=getchar(n)
32916    end
32917    if c~=stop then
32918     if vowel_modifier[ch] then
32919      c=n
32920      n=getnext(n)
32921      ch=getchar(n)
32922     end
32923     if c~=stop and stress_tone_mark[ch] then
32924      c=n
32925      n=getnext(n)
32926     end
32927    end
32928   end
32929  end
32930  local bp=getprev(firstcons)
32931  local cn=getnext(current)
32932  local last=getnext(c)
32933  local done=false
32934  while cn~=last do
32935   if pre_mark[getchar(cn)] then
32936    if devanagarihash[font].movematra=="leftbeforebase" then
32937     local prev,next=getboth(cn)
32938     setlink(prev,next)
32939     if cn==stop then
32940      stop=getprev(cn)
32941     end
32942     if base==start then
32943        if head==start then
32944         head=cn
32945        end
32946        start=cn
32947     end
32948     setlink(getprev(base),cn)
32949     setlink(cn,base)
32950     cn=next
32951    else
32952     if bp then
32953      setnext(bp,cn)
32954     end
32955     local prev,next=getboth(cn)
32956     if next then
32957      setprev(next,prev)
32958     end
32959     setnext(prev,next)
32960     if cn==stop then
32961      stop=prev
32962     end
32963     setprev(cn,bp)
32964     setlink(cn,firstcons)
32965     if firstcons==start then
32966      if head==start then
32967       head=cn
32968      end
32969      start=cn
32970     end
32971     cn=next
32972    end
32973    done=true
32974   elseif current~=base and dependent_vowel[getchar(cn)] then
32975    local prev,next=getboth(cn)
32976    if next then
32977     setprev(next,prev)
32978    end
32979    setnext(prev,next)
32980    if cn==stop then
32981     stop=prev
32982    end
32983    setlink(b,cn,getnext(b))
32984    order_matras(cn)
32985    cn=next
32986    done=true
32987   elseif current==base and dependent_vowel[getchar(cn)] then
32988    local cnn=getnext(cn)
32989    order_matras(cn)
32990    cn=cnn
32991    while cn~=last and dependent_vowel[getchar(cn)] do
32992     cn=getnext(cn)
32993    end
32994   else
32995    cn=getnext(cn)
32996   end
32997  end
32998  allreordered=c==stop
32999  current=getnext(c)
33000  if done and trace_steps then
33001   logprocess("reorder one, matra")
33002  end
33003 end
33004 if reph or vattu then
33005  local current=start
33006  local cns=nil
33007  local done=false
33008  while current~=stop do
33009   local c=current
33010   local n=getnext(current)
33011   if ra[getchar(current)] and halant[getchar(n)] then
33012    c=n
33013    n=getnext(n)
33014    local b,bn=base,base
33015    while bn~=stop  do
33016     local next=getnext(bn)
33017     if dependent_vowel[getchar(next)] then
33018      b=next
33019     end
33020     bn=next
33021    end
33022    if getstate(current,s_rphf) then
33023     if b~=current then
33024      if current==start then
33025       if head==start then
33026        head=n
33027       end
33028       start=n
33029      end
33030      if b==stop then
33031       stop=c
33032      end
33033      local prev=getprev(current)
33034      setlink(prev,n)
33035      local next=getnext(b)
33036      setlink(c,next)
33037      setlink(b,current)
33038      done=true
33039     end
33040    elseif cns and getnext(cns)~=current then
33041     local cp=getprev(current)
33042     local cnsn=getnext(cns)
33043     setlink(cp,n)
33044     setlink(cns,current) 
33045     setlink(c,cnsn)
33046     done=true
33047     if c==stop then
33048      stop=cp
33049      break
33050     end
33051     current=getprev(n)
33052    end
33053   else
33054    local char=getchar(current)
33055    if consonant[char] then
33056     cns=current
33057     local next=getnext(cns)
33058     if halant[getchar(next)] then
33059      cns=next
33060     end
33061     if not vatucache[char] then
33062      next=getnext(cns)
33063      while dependent_vowel[getchar(next)] do
33064       cns=next
33065       next=getnext(cns)
33066      end
33067     end
33068    elseif char==c_nbsp then
33069     nbspaces=nbspaces+1
33070     cns=current
33071     local next=getnext(cns)
33072     if halant[getchar(next)] then
33073      cns=next
33074     end
33075     if not vatucache[char] then
33076      next=getnext(cns)
33077      while dependent_vowel[getchar(next)] do
33078       cns=next
33079       next=getnext(cns)
33080      end
33081     end
33082    end
33083   end
33084   current=getnext(current)
33085  end
33086  if done and trace_steps then
33087   logprocess("reorder one, handle reph and vata") 
33088  end
33089 end
33090 if getchar(base)==c_nbsp then
33091  nbspaces=nbspaces-1
33092  if base==stop then
33093   stop=getprev(stop)
33094  end
33095  head=remove_node(head,base)
33096  flushnode(base)
33097 end
33098 return head,stop,nbspaces
33099end
33100function handlers.devanagari_reorder_matras(head,start) 
33101 local current=start 
33102 local startfont=getfont(start)
33103 local startattr=getprop(start,a_syllabe)
33104 while current do
33105  local char=ischar(current,startfont)
33106  local next=getnext(current)
33107  if char and getprop(current,a_syllabe)==startattr then
33108   if halant[char] then 
33109    if next then
33110     local char=ischar(next,startfont)
33111     if char and zw_char[char] and getprop(next,a_syllabe)==startattr then
33112      current=next
33113      next=getnext(current)
33114     end
33115    end
33116    local startnext=getnext(start)
33117    head=remove_node(head,start)
33118    setlink(start,next)
33119    setlink(current,start)
33120    start=startnext
33121    if trace_steps then
33122     logprocess("reorder matra")
33123    end
33124    break
33125   end
33126  else
33127   break
33128  end
33129  current=next
33130 end
33131 return head,start,true
33132end
33133local rephbase={}
33134function handlers.devanagari_reorder_reph(head,start)
33135 local current=getnext(start)
33136 local startnext=nil
33137 local startprev=nil
33138 local startfont=getfont(start)
33139 local startattr=getprop(start,a_syllabe)
33140 ::step_1::
33141 local char=ischar(start,startfont)
33142 local rephbase=rephbase[startfont][char]
33143 if char and after_subscript[rephbase] then
33144  goto step_5
33145 end
33146 ::step_2::
33147 if char and not after_postscript[rephbase] then
33148  while current do
33149   local char=ischar(current,startfont)
33150   if char and getprop(current,a_syllabe)==startattr then
33151    if halant[char] then
33152     if trace_steps then
33153      logprocess("reorder reph, handling halant")
33154     end
33155     local next=getnext(current)
33156     if next then
33157      local nextchar=ischar(next,startfont)
33158      if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then
33159       current=next
33160       next=getnext(current)
33161      end
33162     end
33163     startnext=getnext(start)
33164     head=remove_node(head,start)
33165     setlink(start,next)
33166     setlink(current,start)
33167     start=startnext
33168     startattr=getprop(start,a_syllabe)
33169     break
33170    end
33171    current=getnext(current)
33172   else
33173    break
33174   end
33175  end
33176 end
33177 ::step_3::
33178 if not startnext then
33179  if char and after_main[rephbase] then
33180   current=getnext(start)
33181   while current do
33182    local char=ischar(current,startfont)
33183    if char and getprop(current,a_syllabe)==startattr then
33184     if consonant[char] and not getstate(current,s_pref) then
33185      if trace_steps then
33186       logprocess("reorder reph, handling consonant")
33187      end
33188      startnext=getnext(start)
33189      head=remove_node(head,start)
33190      setlink(current,start)
33191      setlink(start,getnext(current))
33192      start=startnext
33193      startattr=getprop(start,a_syllabe)
33194      break
33195     end
33196     current=getnext(current)
33197    else
33198     break
33199    end
33200   end
33201  end
33202 end
33203 ::step_4::
33204 if not startnext then
33205  if char and before_postscript[rephbase] then
33206   current=getnext(start)
33207   local c=nil
33208   while current do
33209    local char=ischar(current,startfont)
33210    if char and getprop(current,a_syllabe)==startattr then
33211     if getstate(current,s_pstf) then 
33212      if trace_steps then
33213       logprocess("reorder reph, before postscript, post base")
33214      end
33215      startnext=getnext(start)
33216      head=remove_node(head,start)
33217      setlink(getprev(current),start)
33218      setlink(start,current)
33219      start=startnext
33220      startattr=getprop(start,a_syllabe)
33221      break
33222     elseif not c and (vowel_modifier[char] or stress_tone_mark[char]) then
33223      c=current
33224     end
33225     current=getnext(current)
33226    else
33227     if c then
33228      if trace_steps then
33229       logprocess("reorder reph, before postscript")
33230      end
33231      startnext=getnext(start)
33232      head=remove_node(head,start)
33233      setlink(getprev(c),start)
33234      setlink(start,c)
33235      start=startnext
33236      startattr=getprop(start,a_syllabe)
33237     end
33238     break
33239    end
33240   end
33241  end
33242 end
33243 ::step_5::
33244 if not startnext then
33245  current=getnext(start)
33246  local c=nil
33247  while current do
33248   local char=ischar(current,startfont)
33249   if char and getprop(current,a_syllabe)==startattr then
33250    local state=getstate(current)
33251    if before_subscript[rephbase] and (state==s_blwf or state==s_pstf) then
33252     c=current
33253     if trace_steps then
33254      logprocess("reorder reph, before subscript")
33255     end
33256    elseif after_subscript[rephbase] and (state==s_pstf) then
33257     if trace_steps then
33258      logprocess("reorder reph, after subscript")
33259     end
33260     c=current
33261    end
33262    current=getnext(current)
33263   else
33264    break
33265   end
33266  end
33267  if c then
33268   startnext=getnext(start)
33269   head=remove_node(head,start)
33270   setlink(getprev(c),start)
33271   setlink(start,c)
33272   start=startnext
33273   startattr=getprop(start,a_syllabe)
33274  end
33275 end
33276 ::step_6::
33277 if not startnext then
33278  current=start
33279  local next=getnext(current)
33280  while next do
33281   local nextchar=ischar(next,startfont)
33282   if nextchar and getprop(next,a_syllabe)==startattr then
33283    current=next
33284    next=getnext(current)
33285   else
33286    break
33287   end
33288  end
33289  if start~=current then
33290   if trace_steps then
33291    logprocess("reorder reph, to end")
33292   end
33293   startnext=getnext(start)
33294   head=remove_node(head,start)
33295   setlink(start,getnext(current))
33296   setlink(current,start)
33297   start=startnext
33298  end
33299 end
33300 return head,start,true
33301end
33302function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
33303 if getprop(start,a_reordered) then
33304  return head,start,true
33305 end
33306 local current=start 
33307 local startfont=getfont(start)
33308 local startattr=getprop(start,a_syllabe)
33309 while current do
33310  local char=ischar(current,startfont)
33311  local next=getnext(current)
33312  if char and getprop(current,a_syllabe)==startattr then
33313   if halant[char] then 
33314    if trace_steps then
33315     logprocess("reorder pre base consonants, handle halant")
33316    end
33317    if next then
33318     local char=ischar(next,startfont)
33319     if char and zw_char[char] and getprop(next,a_syllabe)==startattr then
33320      current=next
33321      next=getnext(current)
33322     end
33323    end
33324    local startnext=getnext(start)
33325    head=remove_node(head,start)
33326    setlink(start,next)
33327    setlink(current,start)
33328    setprop(start,"reordered",true)
33329    start=startnext
33330    return head,start,true
33331   end
33332  else
33333   break
33334  end
33335  current=next
33336 end
33337 local startattr=getprop(start,a_syllabe)
33338 local current=getprev(start)
33339 while current and getprop(current,a_syllabe)==startattr do
33340  local char=ischar(current)
33341  if (not dependent_vowel[char] and (not getstate(current) or getstate(current,s_init))) then
33342   if trace_steps then
33343    logprocess("reorder pre base consonants, handle vowel or initial")
33344   end
33345   startnext=getnext(start)
33346   head=remove_node(head,start)
33347   if current==head then
33348    setlink(start,current)
33349    head=start
33350   else
33351    setlink(getprev(current),start)
33352    setlink(start,current)
33353   end
33354   setprop(start,"reordered",true)
33355   start=startnext
33356   break
33357  end
33358  current=getprev(current)
33359 end
33360 return head,start,true
33361end
33362function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement)
33363 local stop=getnext(start)
33364 local font=getfont(start)
33365 local last=start
33366 while stop do
33367  local char=ischar(stop,font)
33368  if char and (char==c_zwnj or char==c_zwj) then
33369   last=stop
33370   stop=getnext(stop)
33371  else
33372   break
33373  end
33374 end
33375 local prev=getprev(start)
33376 if stop then
33377  setnext(last)
33378  setlink(prev,stop)
33379 elseif prev then
33380  setnext(prev)
33381 end
33382 if head==start then
33383  head=stop
33384 end
33385 flushlist(start)
33386 if trace_steps then
33387  logprocess("remove joiners")
33388 end
33389 return head,stop,true
33390end
33391local function initialize_two(font,attr)
33392 local devanagari=fontdata[font].resources.devanagari
33393 if devanagari then
33394  return devanagari.seqsubset or {},devanagari.reorderreph or {}
33395 else
33396  return {},{}
33397 end
33398end
33399local function reorder_two(head,start,stop,font,attr,nbspaces) 
33400 local seqsubset,reorderreph=initialize_two(font,attr)
33401 local halfpos=nil
33402 local basepos=nil
33403 local subpos=nil
33404 local postpos=nil
33405 reorderreph.coverage={} 
33406 rephbase[font]={} 
33407 for i=1,#seqsubset do
33408  local subset=seqsubset[i]
33409  local kind=subset[1]
33410  local lookupcache=subset[2]
33411  if kind=="rphf" then
33412   local reph=subset[3]
33413   local base=subset[4]
33414   reorderreph.coverage[reph]=true 
33415   rephbase[font][reph]=base
33416   local current=start
33417   local last=getnext(stop)
33418   while current~=last do
33419    if current~=stop then
33420     local c=getchar(current)
33421     local found=lookupcache[c]
33422     if found then
33423      local next=getnext(current)
33424      if contextchain(found,next) then 
33425       local afternext=next~=stop and getnext(next)
33426       if afternext and zw_char[getchar(afternext)] then 
33427        current=afternext 
33428       elseif current==start then
33429        setstate(current,s_rphf)
33430        current=next 
33431       else
33432        current=next 
33433       end
33434      end
33435     end
33436    end
33437    current=getnext(current)
33438   end
33439  elseif kind=="pref" then
33440   local current=start
33441   local last=getnext(stop)
33442   while current~=last do
33443    if current~=stop then
33444     local c=getchar(current)
33445     local found=lookupcache[c]
33446     if found then 
33447      local next=getnext(current)
33448      if contextchain(found,next) then
33449       if not getstate(current) and not getstate(next) then 
33450        setstate(current,s_pref)
33451        setstate(next,s_pref)
33452        current=next
33453       end
33454      end
33455     end
33456    end
33457    current=getnext(current)
33458   end
33459  elseif kind=="half" then 
33460   local current=start
33461   local last=getnext(stop)
33462   while current~=last do
33463    if current~=stop then
33464     local c=getchar(current)
33465     local found=lookupcache[c]
33466     if found then
33467      local next=getnext(current)
33468      if contextchain(found,next) then
33469       if next~=stop and getchar(getnext(next))==c_zwnj then 
33470        current=next
33471       elseif not getstate(current) then 
33472        setstate(current,s_half)
33473        if not halfpos then
33474         halfpos=current
33475        end
33476       end
33477       current=getnext(current)
33478      end
33479     end
33480    end
33481    current=getnext(current)
33482   end
33483  elseif kind=="blwf" or kind=="vatu" then 
33484   local current=start
33485   local last=getnext(stop)
33486   while current~=last do
33487    if current~=stop then
33488     local c=getchar(current)
33489     local found=lookupcache[c]
33490     if found then
33491      local next=getnext(current)
33492      if contextchain(found,next) then
33493       if not getstate(current) and not getstate(next) then 
33494        setstate(current,s_blwf)
33495        setstate(next,s_blwf)
33496        current=next
33497        subpos=current
33498       end
33499      end
33500     end
33501    end
33502    current=getnext(current)
33503   end
33504  elseif kind=="pstf" then 
33505   local current=start
33506   local last=getnext(stop)
33507   while current~=last do
33508    if current~=stop then
33509     local c=getchar(current)
33510     local found=lookupcache[c]
33511     if found then
33512      local next=getnext(current)
33513      if contextchain(found,next) then
33514       if not getstate(current) and not getstate(next) then 
33515        setstate(current,s_pstf)
33516        setstate(next,s_pstf)
33517        current=next
33518        postpos=current
33519       end
33520      end
33521     end
33522    end
33523    current=getnext(current)
33524   end
33525  end
33526 end
33527 local current,base,firstcons,subnotafterbase,postnotafterbase=start,nil,nil,nil,nil
33528 if getstate(start,s_rphf) then
33529  current=getnext(getnext(start))
33530 end
33531 if current~=getnext(stop) and getchar(current)==c_nbsp then
33532  if current==stop then
33533   stop=getprev(stop)
33534   head=remove_node(head,current)
33535   flushnode(current)
33536   if trace_steps then
33537    logprocess("reorder two, remove nbsp")
33538   end
33539   return head,stop,nbspaces
33540  else
33541   nbspaces=nbspaces+1
33542   base=current
33543   current=getnext(current)
33544   if current~=stop then
33545    local char=getchar(current)
33546    if nukta[char] then
33547     current=getnext(current)
33548     char=getchar(current)
33549    end
33550    if char==c_zwj then
33551     local next=getnext(current)
33552     if current~=stop and next~=stop and halant[getchar(next)] then
33553      current=next
33554      next=getnext(current)
33555      local tmp=getnext(next)
33556      local changestop=next==stop
33557      setnext(next)
33558      setstate(current,s_pref)
33559      current=processcharacters(current,font)
33560      setstate(current,s_blwf)
33561      current=processcharacters(current,font)
33562      setstate(current,s_pstf)
33563      current=processcharacters(current,font)
33564      setstate(current,unsetvalue)
33565      if halant[getchar(current)] then
33566       setnext(getnext(current),tmp)
33567       if show_syntax_errors then
33568        head,current=inject_syntax_error(head,current,char)
33569       end
33570      else
33571       setnext(current,tmp) 
33572       if changestop then
33573        stop=current
33574       end
33575      end
33576     end
33577    end
33578   end
33579   if trace_steps then
33580    logprocess("reorder two, handle nbsp")
33581   end
33582  end
33583 else 
33584  local last=getnext(stop)
33585  while current~=last do 
33586   local next=getnext(current)
33587   if current==subpos then
33588    subnotafterbase=current
33589   end
33590   if current==postpos then
33591    postnotafterbase=current
33592   end
33593   if consonant[getchar(current)] then
33594    if not (current~=stop and next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwj) then
33595     if not firstcons then
33596      firstcons=current
33597     end
33598     local a=getstate(current)
33599     if not (a==s_blwf or a==s_pstf or (a~=s_rphf and a~=s_blwf and ra[getchar(current)])) then
33600      base=current
33601      if subnotafterbase then
33602       subpos=base
33603      end
33604      if postnotafterbase then
33605       postpos=base
33606      end
33607     end
33608    end
33609   end
33610   current=next
33611  end
33612  if not base then
33613   base=firstcons
33614  end
33615 end
33616 if not base then
33617  if getstate(start,s_rphf) then
33618   setstate(start,unsetvalue)
33619  end
33620  return head,stop,nbspaces
33621 else
33622  if getstate(base) then 
33623   setstate(base,unsetvalue)  
33624  end
33625  basepos=base
33626 end
33627 if not halfpos then
33628  halfpos=base
33629 end
33630 if not subpos then
33631  subpos=base
33632 end
33633 if not postpos then
33634  postpos=subpos or base
33635 end
33636 local moved={}
33637 local current=start
33638 local last=getnext(stop)
33639 while current~=last do
33640  local char=getchar(current)
33641  local target=nil
33642  local cn=getnext(current)
33643  local tpm=twopart_mark[char]
33644  if tpm then
33645   while tpm do
33646    local extra=copy_node(current)
33647    copyinjection(extra,current)
33648    char=tpm[1]
33649    setchar(current,char)
33650    setchar(extra,tpm[2])
33651    head=insertnodeafter(head,current,extra)
33652    tpm=twopart_mark[char]
33653   end
33654   if tpm and trace_steps then
33655    logprocess("reorder two, handle matra")
33656   end
33657  end
33658   if not moved[current] and dependent_vowel[char] then
33659   if pre_mark[char] then 
33660    moved[current]=true
33661    local prev,next=getboth(current)
33662    setlink(prev,next)
33663    if current==stop then
33664     stop=getprev(current)
33665    end
33666    local pos
33667    if before_main[char] then
33668     pos=basepos
33669    else
33670     pos=halfpos
33671    end
33672    local ppos=getprev(pos) 
33673    while ppos and getprop(ppos,a_syllabe)==getprop(pos,a_syllabe) do
33674     if getstate(ppos,s_pref) then
33675      pos=ppos
33676     end
33677     ppos=getprev(ppos)
33678    end
33679    local ppos=getprev(pos) 
33680    while ppos and getprop(ppos,a_syllabe)==getprop(pos,a_syllabe) and halant[ischar(ppos)] do
33681     ppos=getprev(ppos)
33682     if ppos and getprop(ppos,a_syllabe)==getprop(pos,a_syllabe) and consonant[ischar(ppos)] then
33683      pos=ppos
33684      ppos=getprev(ppos)
33685     else
33686      break
33687     end
33688    end
33689    if pos==start then
33690     if head==start then
33691      head=current
33692     end
33693     start=current
33694    end
33695    setlink(getprev(pos),current)
33696    setlink(current,pos)
33697    if trace_steps then
33698     logprocess("reorder two, handle pre mark")
33699    end
33700   elseif above_mark[char] then
33701    target=subpos
33702    if postpos==subpos then
33703     postpos=current
33704    end
33705    subpos=current
33706   elseif below_mark[char] then
33707    target=subpos
33708    if postpos==subpos then
33709     postpos=current
33710    end
33711    subpos=current
33712   elseif post_mark[char] then
33713    local n=getnext(postpos) 
33714    while n do
33715     local v=ischar(n,font)
33716     if nukta[v] or stress_tone_mark[v] or vowel_modifier[v] then
33717      postpos=n
33718     else
33719      break
33720     end
33721     n=getnext(n)
33722    end
33723    target=postpos
33724    postpos=current
33725   end
33726   if mark_above_below_post[char] then
33727    local prev=getprev(current)
33728    if prev~=target then
33729     local next=getnext(current)
33730     setlink(prev,next)
33731     if current==stop then
33732      stop=prev
33733     end
33734     setlink(current,getnext(target))
33735     setlink(target,current)
33736     if trace_steps then
33737      logprocess("reorder two, handle mark")
33738     end
33739    end
33740   end
33741  end
33742  current=cn
33743 end
33744 local current=getnext(start)
33745 local last=getnext(stop)
33746 while current~=last do
33747  local char=getchar(current)
33748  local cn=getnext(current)
33749  if halant[char] and ra[ischar(cn)] and (not getstate(cn,s_rphf)) and (not getstate(cn,s_blwf)) then
33750   if after_main[ischar(cn)] then
33751    local prev=getprev(current)
33752    local next=getnext(cn)
33753    local bpn=getnext(basepos)
33754    while bpn and dependent_vowel[ischar(bpn)] do
33755     basepos=bpn
33756     bpn=getnext(bpn)
33757    end
33758    if basepos~=prev then
33759     setlink(prev,next)
33760     setlink(cn,getnext(basepos))
33761     setlink(basepos,current)
33762     if cn==stop then
33763      stop=prev
33764     end
33765     cn=next
33766     if trace_steps then
33767      logprocess("reorder two, handle halant and ra")
33768     end
33769    end
33770   end
33771  end
33772  current=cn
33773 end
33774 local current=start
33775 local c=nil
33776 while current~=stop do
33777  local char=getchar(current)
33778  if halant[char] or stress_tone_mark[char] then
33779   if not c then
33780    c=current
33781   end
33782  else
33783   c=nil
33784  end
33785  local next=getnext(current)
33786  if c and nukta[getchar(next)] then
33787   if head==c then
33788    head=next
33789   end
33790   if stop==next then
33791    stop=current
33792   end
33793   setlink(getprev(c),next)
33794   local nextnext=getnext(next)
33795   setnext(current,nextnext)
33796   local nextnextnext=getnext(nextnext)
33797   if nextnextnext then
33798    setprev(nextnextnext,current)
33799   end
33800   setlink(nextnext,c)
33801   if trace_steps then
33802    logprocess("reorder two, handle nukta")
33803   end
33804  end
33805  if stop==current then break end
33806  current=getnext(current)
33807 end
33808 if getchar(base)==c_nbsp then
33809  if base==stop then
33810   stop=getprev(stop)
33811  end
33812  nbspaces=nbspaces-1
33813  head=remove_node(head,base)
33814  flushnode(base)
33815  if trace_steps then
33816   logprocess("reorder two, handle nbsp")
33817  end
33818 end
33819 return head,stop,nbspaces
33820end
33821local separator={}
33822imerge(separator,consonant)
33823imerge(separator,independent_vowel)
33824imerge(separator,dependent_vowel)
33825imerge(separator,vowel_modifier)
33826imerge(separator,stress_tone_mark)
33827for k,v in next,nukta  do separator[k]=true end
33828for k,v in next,halant do separator[k]=true end
33829local function analyze_next_chars_one(c,font,variant)
33830 local n=getnext(c)
33831 if not n then
33832  return c
33833 end
33834 local v=ischar(n,font)
33835 if variant==1 then
33836  if v and nukta[v] then
33837   n=getnext(n)
33838   if n then
33839    v=ischar(n,font)
33840   end
33841  end
33842  if n and v then
33843   local nn=getnext(n)
33844   if nn then
33845    local vv=ischar(nn,font)
33846    if vv then
33847     local nnn=getnext(nn)
33848     if nnn then
33849      local vvv=ischar(nnn,font)
33850      if vvv then
33851       if vv==c_zwj and consonant[vvv] then
33852        c=nnn
33853       elseif (vv==c_zwnj or vv==c_zwj) and halant[vvv] then
33854        local nnnn=getnext(nnn)
33855        if nnnn then
33856         local vvvv=ischar(nnnn,font)
33857         if vvvv and consonant[vvvv] then
33858          c=nnnn
33859         end
33860        end
33861       end
33862      end
33863     end
33864    end
33865   end
33866  end
33867 elseif variant==2 then
33868  if v and nukta[v] then
33869   c=n
33870  end
33871  n=getnext(c)
33872  if n then
33873   v=ischar(n,font)
33874   if v then
33875    local nn=getnext(n)
33876    if nn then
33877     local vv=ischar(nn,font)
33878     if vv and zw_char[v] then
33879      n=nn
33880      v=vv
33881      nn=getnext(nn)
33882      vv=nn and ischar(nn,font)
33883     end
33884     if vv and halant[v] and consonant[vv] then
33885      c=nn
33886     end
33887    end
33888   end
33889  end
33890 end
33891 n=getnext(c)
33892 if not n then
33893  return c
33894 end
33895 v=ischar(n,font)
33896 if not v then
33897  return c
33898 end
33899 local already_pre_mark   
33900 local already_above_mark 
33901 local already_below_mark 
33902 local already_post_mark  
33903 while dependent_vowel[v] do
33904  local vowels=twopart_mark[v]
33905  if vowels then
33906   for k=1,#vowels do
33907    local v=vowels[k]
33908    if pre_mark[v] and not already_pre_mark then
33909     already_pre_mark=true
33910    elseif above_mark[v] and not already_above_mark then
33911     already_above_mark=true
33912    elseif below_mark[v] and not already_below_mark then
33913     already_below_mark=true
33914    elseif post_mark[v] and not already_post_mark then
33915     already_post_mark=true
33916    elseif devanagarihash[font].conjuncts=="continue" then
33917    else
33918     return c
33919    end
33920   end
33921  else
33922   if pre_mark[v] and not already_pre_mark then
33923    already_pre_mark=true
33924   elseif post_mark[v] and not already_post_mark then
33925     already_post_mark=true
33926   elseif below_mark[v] and not already_below_mark then
33927    already_below_mark=true
33928   elseif above_mark[v] and not already_above_mark then
33929    already_above_mark=true
33930   elseif devanagarihash[font].conjuncts=="continue" then
33931   else
33932    return c
33933   end
33934  end
33935  c=n
33936  n=getnext(c)
33937  if not n then
33938   return c
33939  end
33940  v=ischar(n,font)
33941  if not v then
33942   return c
33943  end
33944 end
33945 if nukta[v] then
33946  c=n
33947  n=getnext(c)
33948  if not n then
33949   return c
33950  end
33951  v=ischar(n,font)
33952  if not v then
33953   return c
33954  end
33955 end
33956 if halant[v] then
33957  c=n
33958  n=getnext(c)
33959  if not n then
33960   return c
33961  end
33962  v=ischar(n,font)
33963  if not v then
33964   return c
33965  end
33966 end
33967 if vowel_modifier[v] then
33968  c=n
33969  n=getnext(c)
33970  if not n then
33971   return c
33972  end
33973  v=ischar(n,font)
33974  if not v then
33975   return c
33976  end
33977 end
33978 if stress_tone_mark[v] then
33979  c=n
33980  n=getnext(c)
33981  if not n then
33982   return c
33983  end
33984  v=ischar(n,font)
33985  if not v then
33986   return c
33987  end
33988 end
33989 if stress_tone_mark[v] then
33990  return n
33991 else
33992  return c
33993 end
33994end
33995local function analyze_next_chars_two(c,font)
33996 local n=getnext(c)
33997 if not n then
33998  return c
33999 end
34000 local v=ischar(n,font)
34001 if v and nukta[v] then
34002  c=n
34003 end
34004 n=c
34005 while true do
34006  local nn=getnext(n)
34007  if nn then
34008   local vv=ischar(nn,font)
34009   if vv then
34010    if halant[vv] then
34011     n=nn
34012     local nnn=getnext(nn)
34013     if nnn then
34014      local vvv=ischar(nnn,font)
34015      if vvv and zw_char[vvv] then
34016       n=nnn
34017      end
34018     end
34019    elseif vv==c_zwnj or vv==c_zwj then
34020     local nnn=getnext(nn)
34021     if nnn then
34022      local vvv=ischar(nnn,font)
34023      if vvv and halant[vvv] then
34024       n=nnn
34025      end
34026     end
34027    else
34028     break
34029    end
34030    local nn=getnext(n)
34031    if nn then
34032     local vv=ischar(nn,font)
34033     if vv and consonant[vv] then
34034      n=nn
34035      local nnn=getnext(nn)
34036      if nnn then
34037       local vvv=ischar(nnn,font)
34038       if vvv and nukta[vvv] then
34039        n=nnn
34040       end
34041      end
34042      c=n
34043     else
34044      break
34045     end
34046    else
34047     break
34048    end
34049   else
34050    break
34051   end
34052  else
34053   break
34054  end
34055 end
34056 if not c then
34057  return
34058 end
34059 n=getnext(c)
34060 if not n then
34061  return c
34062 end
34063 v=ischar(n,font)
34064 if not v then
34065  return c
34066 end
34067 if anudatta[v] then
34068  c=n
34069  n=getnext(c)
34070  if not n then
34071   return c
34072  end
34073  v=ischar(n,font)
34074  if not v then
34075   return c
34076  end
34077 end
34078 if halant[v] then
34079  c=n
34080  n=getnext(c)
34081  if not n then
34082   return c
34083  end
34084  v=ischar(n,font)
34085  if not v then
34086   return c
34087  end
34088  if v==c_zwnj or v==c_zwj then
34089   c=n
34090   n=getnext(c)
34091   if not n then
34092    return c
34093   end
34094   v=ischar(n,font)
34095   if not v then
34096    return c
34097   end
34098  end
34099 else
34100  local already_pre_mark   
34101  local already_above_mark 
34102  local already_below_mark 
34103  local already_post_mark
34104  while dependent_vowel[v] do
34105   local vowels=twopart_mark[v]
34106   if vowels then
34107    for k=1,#vowels do
34108     local v=vowels[k]
34109     if pre_mark[v] and not already_pre_mark then
34110      already_pre_mark=true
34111     elseif above_mark[v] and not already_above_mark then
34112      already_above_mark=true
34113     elseif below_mark[v] and not already_below_mark then
34114      already_below_mark=true
34115     elseif post_mark[v] and not already_post_mark then
34116      already_post_mark=true
34117     elseif devanagarihash[font].conjuncts=="continue" then
34118     else
34119      return c
34120     end
34121    end
34122   else
34123    if pre_mark[v] and not already_pre_mark then
34124     already_pre_mark=true
34125    elseif post_mark[v] and not already_post_mark then
34126        already_post_mark=true
34127    elseif below_mark[v] and not already_below_mark then
34128     already_below_mark=true
34129    elseif above_mark[v] and not already_above_mark then
34130     already_above_mark=true
34131    elseif devanagarihash[font].conjuncts=="continue" then
34132    else
34133     return c
34134    end
34135   end
34136   c=n
34137   n=getnext(c)
34138   if not n then
34139    return c
34140   end
34141   v=ischar(n,font)
34142   if not v then
34143    return c
34144   end
34145  end
34146  if nukta[v] then
34147   c=n
34148   n=getnext(c)
34149   if not n then
34150    return c
34151   end
34152   v=ischar(n,font)
34153   if not v then
34154    return c
34155   end
34156  end
34157  if halant[v] then
34158   c=n
34159   n=getnext(c)
34160   if not n then
34161    return c
34162   end
34163   v=ischar(n,font)
34164   if not v then
34165    return c
34166   end
34167  end
34168 end
34169 if vowel_modifier[v] then
34170  c=n
34171  n=getnext(c)
34172  if not n then
34173   return c
34174  end
34175  v=ischar(n,font)
34176  if not v then
34177   return c
34178  end
34179 end
34180 if stress_tone_mark[v] then
34181  c=n
34182  n=getnext(c)
34183  if not n then
34184   return c
34185  end
34186  v=ischar(n,font)
34187  if not v then
34188   return c
34189  end
34190 end
34191 if stress_tone_mark[v] then
34192  return n
34193 else
34194  return c
34195 end
34196end
34197local function method_one(head,font,attr)
34198 local current=head
34199 local start=true
34200 local done=false
34201 local nbspaces=0
34202 local syllabe=0
34203 while current do
34204  local char=ischar(current,font)
34205  if char then
34206   done=true
34207   local syllablestart=current
34208   local syllableend=nil
34209   local c=current
34210   local n=getnext(c)
34211   local first=char
34212   if n and ra[first] then
34213    local second=ischar(n,font)
34214    if second and halant[second] then
34215     local n=getnext(n)
34216     if n then
34217      local third=ischar(n,font)
34218      if third then
34219       c=n
34220       first=third
34221      end
34222     end
34223    end
34224   end
34225   local standalone=first==c_nbsp
34226   if standalone then
34227    local prev=getprev(current)
34228    if prev then
34229     local prevchar=ischar(prev,font)
34230     if not prevchar then
34231     elseif not separator[prevchar] then
34232     else
34233      standalone=false
34234     end
34235    else
34236    end
34237   end
34238   if standalone then
34239    local syllableend=analyze_next_chars_one(c,font,2)
34240    current=getnext(syllableend)
34241    if syllablestart~=syllableend then
34242     head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
34243     current=getnext(current)
34244    end
34245   else
34246    if consonant[char] then
34247     local prevc=true
34248     while prevc do
34249      prevc=false
34250      local n=getnext(current)
34251      if not n then
34252       break
34253      end
34254      local v=ischar(n,font)
34255      if not v then
34256       break
34257      end
34258      if nukta[v] then
34259       n=getnext(n)
34260       if not n then
34261        break
34262       end
34263       v=ischar(n,font)
34264       if not v then
34265        break
34266       end
34267      end
34268      if halant[v] then
34269       n=getnext(n)
34270       if not n then
34271        break
34272       end
34273       v=ischar(n,font)
34274       if not v then
34275        break
34276       end
34277       if v==c_zwnj or v==c_zwj then
34278        n=getnext(n)
34279        if not n then
34280         break
34281        end
34282        v=ischar(n,font)
34283        if not v then
34284         break
34285        end
34286       end
34287       if consonant[v] then
34288        prevc=true
34289        current=n
34290       end
34291      end
34292     end
34293     local n=getnext(current)
34294     if n then
34295      local v=ischar(n,font)
34296      if v and nukta[v] then
34297       current=n
34298       n=getnext(current)
34299      end
34300     end
34301     syllableend=current
34302     current=n
34303     if current then
34304      local v=ischar(current,font)
34305      if not v then
34306      elseif halant[v] then
34307       local n=getnext(current)
34308       if n then
34309        local v=ischar(n,font)
34310        if v and zw_char[v] then
34311         syllableend=n
34312         current=getnext(n)
34313        else
34314         syllableend=current
34315         current=n
34316        end
34317       else
34318        syllableend=current
34319        current=n
34320       end
34321      else
34322       if dependent_vowel[v] then
34323        syllableend=current
34324        current=getnext(current)
34325        v=ischar(current,font)
34326       end
34327       if v and vowel_modifier[v] then
34328        syllableend=current
34329        current=getnext(current)
34330        v=ischar(current,font)
34331       end
34332       if v and stress_tone_mark[v] then
34333        syllableend=current
34334        current=getnext(current)
34335       end
34336      end
34337     end
34338     if syllablestart~=syllableend then
34339      if syllableend then
34340       syllabe=syllabe+1
34341       local c=syllablestart
34342       local n=getnext(syllableend)
34343       while c~=n do
34344        setprop(c,a_syllabe,syllabe)
34345        c=getnext(c)
34346       end
34347      end
34348      head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
34349      current=getnext(current)
34350     end
34351    elseif independent_vowel[char] then
34352     syllableend=current
34353     current=getnext(current)
34354     if current then
34355      local v=ischar(current,font)
34356      if v then
34357       if vowel_modifier[v] then
34358        syllableend=current
34359        current=getnext(current)
34360        v=ischar(current,font)
34361       end
34362       if v and stress_tone_mark[v] then
34363        syllableend=current
34364        current=getnext(current)
34365       end
34366      end
34367     end
34368    else
34369     if show_syntax_errors then
34370      local mark=mark_pre_above_below_post[char]
34371      if mark then
34372       head,current=inject_syntax_error(head,current,char)
34373      end
34374     end
34375     current=getnext(current)
34376    end
34377   end
34378  else
34379   current=getnext(current)
34380  end
34381  start=false
34382 end
34383 if nbspaces>0 then
34384  head=replace_all_nbsp(head)
34385 end
34386 current=head
34387 local n=0
34388 while current do
34389  local char=ischar(current,font)
34390  if char then
34391   if n==0 and not getstate(current) then
34392    setstate(current,s_init)
34393   end
34394   n=n+1
34395  else
34396   n=0
34397  end
34398  current=getnext(current)
34399 end
34400 return head,done
34401end
34402local function method_two(head,font,attr)
34403 local current=head
34404 local start=true
34405 local done=false
34406 local syllabe=0
34407 local nbspaces=0
34408 while current do
34409  local syllablestart=nil
34410  local syllableend=nil
34411  local char=ischar(current,font)
34412  if char then
34413   done=true
34414   syllablestart=current
34415   local c=current
34416   local n=getnext(current)
34417   if n and ra[char] then
34418    local nextchar=ischar(n,font)
34419    if nextchar and halant[nextchar] then
34420     local n=getnext(n)
34421     if n then
34422      local nextnextchar=ischar(n,font)
34423      if nextnextchar then
34424       c=n
34425       char=nextnextchar
34426      end
34427     end
34428    end
34429   end
34430   if independent_vowel[char] then
34431    current=analyze_next_chars_one(c,font,1)
34432    syllableend=current
34433   else
34434    local standalone=char==c_nbsp
34435    if standalone then
34436     nbspaces=nbspaces+1
34437     local p=getprev(current)
34438     if not p then
34439     elseif ischar(p,font) then
34440     elseif not separator[getchar(p)] then
34441     else
34442      standalone=false
34443     end
34444    end
34445    if standalone then
34446     current=analyze_next_chars_one(c,font,2)
34447     syllableend=current
34448    elseif consonant[getchar(current)] then
34449     current=analyze_next_chars_two(current,font) 
34450     syllableend=current
34451    end
34452   end
34453  end
34454  if syllableend then
34455   syllabe=syllabe+1
34456   local c=syllablestart
34457   local n=getnext(syllableend)
34458   while c~=n do
34459    setprop(c,a_syllabe,syllabe)
34460    c=getnext(c)
34461   end
34462  end
34463  if syllableend and syllablestart~=syllableend then
34464   head,current,nbspaces=reorder_two(head,syllablestart,syllableend,font,attr,nbspaces)
34465  end
34466  if not syllableend and show_syntax_errors then
34467   local char=ischar(current,font)
34468   if char and not getstate(current) then 
34469    local mark=mark_pre_above_below_post[char]
34470    if mark then
34471     head,current=inject_syntax_error(head,current,char)
34472    end
34473   end
34474  end
34475  start=false
34476  current=getnext(current)
34477 end
34478 if nbspaces>0 then
34479  head=replace_all_nbsp(head)
34480 end
34481 current=head
34482 local n=0
34483 while current do
34484  local char=ischar(current,font)
34485  if char then
34486   if n==0 and not getstate(current) then 
34487    setstate(current,s_init)
34488   end
34489   n=n+1
34490  else
34491   n=0
34492  end
34493  current=getnext(current)
34494 end
34495 return head,done
34496end
34497for i=1,nofscripts do
34498 methods[scripts_one[i]]=method_one
34499 methods[scripts_two[i]]=method_two
34500end
34501
34502end -- closure
34503
34504do -- begin closure to overcome local limits and interference
34505
34506if not modules then modules={} end modules ['font-ocl']={
34507 version=1.001,
34508 comment="companion to font-ini.mkiv",
34509 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
34510 copyright="PRAGMA ADE / ConTeXt Development Team",
34511 license="see context related readme files"
34512}
34513local tostring,tonumber,next=tostring,tonumber,next
34514local round,max=math.round,math.round
34515local gsub,find=string.gsub,string.find
34516local sortedkeys,sortedhash,concat=table.sortedkeys,table.sortedhash,table.concat
34517local setmetatableindex=table.setmetatableindex
34518local formatters=string.formatters
34519local tounicode=fonts.mappings.tounicode
34520local helpers=fonts.helpers
34521local charcommand=helpers.commands.char
34522local rightcommand=helpers.commands.right
34523local leftcommand=helpers.commands.left
34524local downcommand=helpers.commands.down
34525local otf=fonts.handlers.otf
34526local otfregister=otf.features.register
34527local f_color=formatters["%.3f %.3f %.3f rg"]
34528local f_gray=formatters["%.3f g"]
34529if context then
34530
34531--removed
34532
34533else
34534 local tounicode=fonts.mappings.tounicode16
34535 function otf.getactualtext(s)
34536  return
34537   "/Span << /ActualText <feff"..s.."> >> BDC",
34538   "EMC"
34539 end
34540end
34541local sharedpalettes={}
34542local hash=setmetatableindex(function(t,k)
34543 local v={ "pdf","direct",k }
34544 t[k]=v
34545 return v
34546end)
34547if context then
34548
34549--removed
34550
34551else 
34552 function otf.registerpalette(name,values)
34553  sharedpalettes[name]=values
34554  for i=1,#values do
34555   local v=values[i]
34556   if v then
34557    values[i]=hash[f_color(
34558     max(round((v.r or 0)*255),255)/255,
34559     max(round((v.g or 0)*255),255)/255,
34560     max(round((v.b or 0)*255),255)/255
34561    )]
34562   end
34563  end
34564 end
34565end
34566local function convert(t,k)
34567 local v={}
34568 for i=1,#k do
34569  local p=k[i]
34570  local r,g,b=p[1],p[2],p[3]
34571  if r==g and g==b then
34572   v[i]=hash[f_gray(r/255)]
34573  else
34574   v[i]=hash[f_color(r/255,g/255,b/255)]
34575  end
34576 end
34577 t[k]=v
34578 return v
34579end
34580local mode={ "pdf","mode","font" }
34581local push={ "pdf","page","q" }
34582local pop={ "pdf","page","Q" }
34583local function initializeoverlay(tfmdata,kind,value)
34584 if value then
34585  local resources=tfmdata.resources
34586  local palettes=resources.colorpalettes
34587  if palettes then
34588   local converted=resources.converted
34589   if not converted then
34590    converted=setmetatableindex(convert)
34591    resources.converted=converted
34592   end
34593   local colorvalues=sharedpalettes[value]
34594   local default=false 
34595   if colorvalues then
34596    default=colorvalues[#colorvalues]
34597   else
34598    colorvalues=converted[palettes[tonumber(value) or 1] or palettes[1]] or {}
34599   end
34600   local classes=#colorvalues
34601   if classes==0 then
34602    return
34603   end
34604   local characters=tfmdata.characters
34605   local descriptions=tfmdata.descriptions
34606   local properties=tfmdata.properties
34607   properties.virtualized=true
34608   tfmdata.fonts={
34609    { id=0 }
34610   }
34611   local getactualtext=otf.getactualtext
34612   local b,e=getactualtext(tounicode(0xFFFD))
34613   local actualb={ "pdf","page",b } 
34614   local actuale={ "pdf","page",e }
34615   for unicode,character in next,characters do
34616    local description=descriptions[unicode]
34617    if description then
34618     local colorlist=description.colors
34619     if colorlist then
34620      local u=description.unicode or characters[unicode].unicode
34621      local w=character.width or 0
34622      local s=#colorlist
34623      local goback=w~=0 and leftcommand[w] or nil 
34624      local t={
34625       mode,
34626       not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) },
34627       push,
34628      }
34629      local n=3
34630      local l=nil
34631      for i=1,s do
34632       local entry=colorlist[i]
34633       local v=colorvalues[entry.class] or default
34634       if v and l~=v then
34635        n=n+1 t[n]=v
34636        l=v
34637       end
34638       n=n+1 t[n]=charcommand[entry.slot]
34639       if s>1 and i<s and goback then
34640        n=n+1 t[n]=goback
34641       end
34642      end
34643      n=n+1 t[n]=pop
34644      n=n+1 t[n]=actuale
34645      character.commands=t
34646     end
34647    end
34648   end
34649   return true
34650  end
34651 end
34652end
34653otfregister {
34654 name="colr",
34655 description="color glyphs",
34656 manipulators={
34657  base=initializeoverlay,
34658  node=initializeoverlay,
34659 }
34660}
34661do
34662 local nofstreams=0
34663 local f_name=formatters[ [[pdf-glyph-%05i]] ]
34664 local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
34665 local hashed={}
34666 local cache={}
34667 local openpdf=pdfe.new
34668 function otf.storepdfdata(pdf)
34669  local done=hashed[pdf]
34670  if not done then
34671   nofstreams=nofstreams+1
34672   local f=f_name(nofstreams)
34673   local n=openpdf(pdf,#pdf,f)
34674   done=f_used(n)
34675   hashed[pdf]=done
34676  end
34677  return done
34678 end
34679end
34680local function pdftovirtual(tfmdata,pdfshapes,kind) 
34681 if not tfmdata or not pdfshapes or not kind then
34682  return
34683 end
34684 local characters=tfmdata.characters
34685 local properties=tfmdata.properties
34686 local parameters=tfmdata.parameters
34687 local hfactor=parameters.hfactor
34688 properties.virtualized=true
34689 tfmdata.fonts={
34690  { id=0 } 
34691 }
34692 local getactualtext=otf.getactualtext
34693 local storepdfdata=otf.storepdfdata
34694 local b,e=getactualtext(tounicode(0xFFFD))
34695 local actualb={ "pdf","page",b } 
34696 local actuale={ "pdf","page",e }
34697 local vfimage=lpdf and lpdf.vfimage or function(wd,ht,dp,data,name)
34698  local name=storepdfdata(data)
34699  return { "image",{ filename=name,width=wd,height=ht,depth=dp } }
34700 end
34701 for unicode,character in sortedhash(characters) do  
34702  local index=character.index
34703  if index then
34704   local pdf=pdfshapes[index]
34705   local typ=type(pdf)
34706   local data=nil
34707   local dx=nil
34708   local dy=nil
34709   local scale=1
34710   if typ=="table" then
34711    data=pdf.data
34712    dx=pdf.x or pdf.dx or 0
34713    dy=pdf.y or pdf.dy or 0
34714    scale=pdf.scale or 1
34715   elseif typ=="string" then
34716    data=pdf
34717    dx=0
34718    dy=0
34719   elseif typ=="number" then
34720    data=pdf
34721    dx=0
34722    dy=0
34723   end
34724   if data then
34725    local bt=unicode and getactualtext(unicode)
34726    local wd=character.width  or 0
34727    local ht=character.height or 0
34728    local dp=character.depth  or 0
34729    character.commands={
34730     not unicode and actualb or { "pdf","page",(getactualtext(unicode)) },
34731     downcommand [dp+dy*hfactor],
34732     rightcommand[  dx*hfactor],
34733     vfimage(scale*wd,ht,dp,data,pdfshapes.filename or ""),
34734     actuale,
34735    }
34736    character[kind]=true
34737   end
34738  end
34739 end
34740end
34741local otfsvg=otf.svg or {}
34742otf.svg=otfsvg
34743otf.svgenabled=true
34744do
34745 local report_svg=logs.reporter("fonts","svg conversion")
34746 local loaddata=io.loaddata
34747 local savedata=io.savedata
34748 local remove=os.remove
34749if context then
34750
34751--removed
34752
34753else
34754  function otfsvg.filterglyph(entry,index) 
34755   return entry.data
34756  end
34757end
34758 local runner=sandbox and sandbox.registerrunner {
34759  name="otfsvg",
34760  program="inkscape",
34761  method="pipeto",
34762  template="--export-area-drawing --shell > temp-otf-svg-shape.log",
34763  reporter=report_svg,
34764 }
34765 if not runner then
34766  runner=function()
34767   return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w")
34768  end
34769 end
34770 local new=nil
34771 local function inkscapeformat(suffix)
34772  if new==nil then
34773   new=os.resultof("inkscape --version") or ""
34774   new=new=="" or not find(new,"Inkscape%s*0")
34775  end
34776  return new and "filename" or suffix
34777 end
34778 function otfsvg.topdf(svgshapes,tfmdata)
34779  local pdfshapes={}
34780  local inkscape=runner()
34781  if inkscape then
34782   local descriptions=tfmdata.descriptions
34783   local nofshapes=#svgshapes
34784   local s_format=inkscapeformat("pdf") 
34785   local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
34786   local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
34787   local f_convert=formatters[new and "file-open:%s; export-%s:%s; export-do\n" or "%s --export-%s=%s\n"]
34788   local filterglyph=otfsvg.filterglyph
34789   local nofdone=0
34790   local processed={}
34791   report_svg("processing %i svg containers",nofshapes)
34792   statistics.starttiming()
34793   for i=1,nofshapes do
34794    local entry=svgshapes[i]
34795    for index=entry.first,entry.last do
34796     local data=filterglyph(entry,index)
34797     if data and data~="" then
34798      local svgfile=f_svgfile(index)
34799      local pdffile=f_pdffile(index)
34800      savedata(svgfile,data)
34801      inkscape:write(f_convert(svgfile,s_format,pdffile))
34802      processed[index]=true
34803      nofdone=nofdone+1
34804      if nofdone%25==0 then
34805       report_svg("%i shapes submitted",nofdone)
34806      end
34807     end
34808    end
34809   end
34810   if nofdone%25~=0 then
34811    report_svg("%i shapes submitted",nofdone)
34812   end
34813   report_svg("processing can be going on for a while")
34814   inkscape:write("quit\n")
34815   inkscape:close()
34816   report_svg("processing %i pdf results",nofshapes)
34817   for index in next,processed do
34818    local svgfile=f_svgfile(index)
34819    local pdffile=f_pdffile(index)
34820    local pdfdata=loaddata(pdffile)
34821    if pdfdata and pdfdata~="" then
34822     pdfshapes[index]={
34823      data=pdfdata,
34824     }
34825    end
34826    remove(svgfile)
34827    remove(pdffile)
34828   end
34829   local characters=tfmdata.characters
34830   for k,v in next,characters do
34831    local d=descriptions[k]
34832    local i=d.index
34833    if i then
34834     local p=pdfshapes[i]
34835     if p then
34836      local w=d.width
34837      local l=d.boundingbox[1]
34838      local r=d.boundingbox[3]
34839      p.scale=(r-l)/w
34840      p.x=l
34841     end
34842    end
34843   end
34844   if not next(pdfshapes) then
34845    report_svg("there are no converted shapes, fix your setup")
34846   end
34847   statistics.stoptiming()
34848   if statistics.elapsedseconds then
34849    report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
34850   end
34851  end
34852  return pdfshapes
34853 end
34854end
34855local function initializesvg(tfmdata,kind,value) 
34856 if value and otf.svgenabled then
34857  local svg=tfmdata.properties.svg
34858  local hash=svg and svg.hash
34859  local timestamp=svg and svg.timestamp
34860  if not hash then
34861   return
34862  end
34863  local pdffile=containers.read(otf.pdfcache,hash)
34864  local pdfshapes=pdffile and pdffile.pdfshapes
34865  if not pdfshapes or pdffile.timestamp~=timestamp or not next(pdfshapes) then
34866   local svgfile=containers.read(otf.svgcache,hash)
34867   local svgshapes=svgfile and svgfile.svgshapes
34868   pdfshapes=svgshapes and otfsvg.topdf(svgshapes,tfmdata,otf.pdfcache.writable,hash) or {}
34869   containers.write(otf.pdfcache,hash,{
34870    pdfshapes=pdfshapes,
34871    timestamp=timestamp,
34872   })
34873  end
34874  pdftovirtual(tfmdata,pdfshapes,"svg")
34875  return true
34876 end
34877end
34878otfregister {
34879 name="svg",
34880 description="svg glyphs",
34881 manipulators={
34882  base=initializesvg,
34883  node=initializesvg,
34884 }
34885}
34886local otfpng=otf.png or {}
34887otf.png=otfpng
34888otf.pngenabled=true
34889do
34890 local report_png=logs.reporter("fonts","png conversion")
34891 local loaddata=io.loaddata
34892 local savedata=io.savedata
34893 local remove=os.remove
34894 local runner=sandbox and sandbox.registerrunner {
34895  name="otfpng",
34896  program="gm",
34897  template="convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log",
34898 }
34899 if not runner then
34900  runner=function()
34901   return os.execute("gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log")
34902  end
34903 end
34904 function otfpng.topdf(pngshapes)
34905  local pdfshapes={}
34906  local pngfile="temp-otf-png-shape.png"
34907  local pdffile="temp-otf-png-shape.pdf"
34908  local nofdone=0
34909  local indices=sortedkeys(pngshapes) 
34910  local nofindices=#indices
34911  report_png("processing %i png containers",nofindices)
34912  statistics.starttiming()
34913  for i=1,nofindices do
34914   local index=indices[i]
34915   local entry=pngshapes[index]
34916   local data=entry.data 
34917   local x=entry.x
34918   local y=entry.y
34919   savedata(pngfile,data)
34920   runner()
34921   pdfshapes[index]={
34922    x=x~=0 and x or nil,
34923    y=y~=0 and y or nil,
34924    data=loaddata(pdffile),
34925   }
34926   nofdone=nofdone+1
34927   if nofdone%100==0 then
34928    report_png("%i shapes processed",nofdone)
34929   end
34930  end
34931  report_png("processing %i pdf results",nofindices)
34932  remove(pngfile)
34933  remove(pdffile)
34934  statistics.stoptiming()
34935  if statistics.elapsedseconds then
34936   report_png("png conversion time %s",statistics.elapsedseconds() or "-")
34937  end
34938  return pdfshapes
34939 end
34940end
34941local function initializepng(tfmdata,kind,value) 
34942 if value and otf.pngenabled then
34943  local png=tfmdata.properties.png
34944  local hash=png and png.hash
34945  local timestamp=png and png.timestamp
34946  if not hash then
34947   return
34948  end
34949  local pdffile=containers.read(otf.pdfcache,hash)
34950  local pdfshapes=pdffile and pdffile.pdfshapes
34951  if not pdfshapes or pdffile.timestamp~=timestamp then
34952   local pngfile=containers.read(otf.pngcache,hash)
34953   local pngshapes=pngfile and pngfile.pngshapes
34954   pdfshapes=pngshapes and otfpng.topdf(pngshapes) or {}
34955   containers.write(otf.pdfcache,hash,{
34956    pdfshapes=pdfshapes,
34957    timestamp=timestamp,
34958   })
34959  end
34960  pdftovirtual(tfmdata,pdfshapes,"png")
34961  return true
34962 end
34963end
34964otfregister {
34965 name="sbix",
34966 description="sbix glyphs",
34967 manipulators={
34968  base=initializepng,
34969  node=initializepng,
34970 }
34971}
34972otfregister {
34973 name="cblc",
34974 description="cblc glyphs",
34975 manipulators={
34976  base=initializepng,
34977  node=initializepng,
34978 }
34979}
34980if context then
34981
34982--removed
34983
34984end
34985
34986end -- closure
34987
34988do -- begin closure to overcome local limits and interference
34989
34990if not modules then modules={} end modules ['font-onr']={
34991 version=1.001,
34992 optimize=true,
34993 comment="companion to font-ini.mkiv",
34994 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
34995 copyright="PRAGMA ADE / ConTeXt Development Team",
34996 license="see context related readme files"
34997}
34998local fonts,logs,trackers,resolvers=fonts,logs,trackers,resolvers
34999local next,type,tonumber,rawset=next,type,tonumber,rawset
35000local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find
35001local char,byte,sub=string.char,string.byte,string.sub
35002local abs=math.abs
35003local bxor,rshift=bit32.bxor,bit32.rshift
35004local P,S,R,V,Cmt,C,Ct,Cs,Carg,Cf,Cg,Cc=lpeg.P,lpeg.S,lpeg.R,lpeg.V,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg,lpeg.Cc
35005local lpegmatch,patterns=lpeg.match,lpeg.patterns
35006local trace_indexing=false  trackers.register("afm.indexing",function(v) trace_indexing=v end)
35007local trace_loading=false  trackers.register("afm.loading",function(v) trace_loading=v end)
35008local report_afm=logs.reporter("fonts","afm loading")
35009local report_pfb=logs.reporter("fonts","pfb loading")
35010local handlers=fonts.handlers
35011local afm=handlers.afm or {}
35012handlers.afm=afm
35013local readers=afm.readers or {}
35014afm.readers=readers
35015afm.version=1.513
35016local get_indexes,get_shapes
35017do
35018 local decrypt
35019 do
35020  local r,c1,c2,n=0,0,0,0
35021  local function step(c)
35022   local cipher=byte(c)
35023   local plain=bxor(cipher,rshift(r,8))
35024   r=((cipher+r)*c1+c2)%65536
35025   return char(plain)
35026  end
35027  decrypt=function(binary,initial,seed)
35028   r,c1,c2,n=initial,52845,22719,seed
35029   binary=gsub(binary,".",step)
35030   return sub(binary,n+1)
35031  end
35032 end
35033 local charstrings=P("/CharStrings")
35034 local subroutines=P("/Subrs")
35035 local encoding=P("/Encoding")
35036 local dup=P("dup")
35037 local put=P("put")
35038 local array=P("array")
35039 local name=P("/")*C((R("az","AZ","09")+S("-_."))^1)
35040 local digits=R("09")^1
35041 local cardinal=digits/tonumber
35042 local spaces=P(" ")^1
35043 local spacing=patterns.whitespace^0
35044 local routines,vector,chars,n,m
35045 local initialize=function(str,position,size)
35046  n=0
35047  m=size
35048  return position+1
35049 end
35050 local setroutine=function(str,position,index,size,filename)
35051  if routines[index] then
35052   return false
35053  end
35054  local forward=position+size
35055  local stream=decrypt(sub(str,position+1,forward),4330,4)
35056  routines[index]={ byte(stream,1,#stream) }
35057  n=n+1
35058  if n>=m then
35059   return #str
35060  end
35061  return forward+1
35062 end
35063 local setvector=function(str,position,name,size,filename)
35064  local forward=position+tonumber(size)
35065  if n>=m then
35066   return #str
35067  elseif forward<#str then
35068   if n==0 and name~=".notdef" then
35069    report_pfb("reserving .notdef at index 0 in %a",filename) 
35070    n=n+1
35071   end
35072   vector[n]=name
35073   n=n+1
35074   return forward
35075  else
35076   return #str
35077  end
35078 end
35079 local setshapes=function(str,position,name,size,filename)
35080  local forward=position+tonumber(size)
35081  local stream=sub(str,position+1,forward)
35082  if n>m then
35083   return #str
35084  elseif forward<#str then
35085   if n==0 and name~=".notdef" then
35086    report_pfb("reserving .notdef at index 0 in %a",filename) 
35087    n=n+1
35088   end
35089   vector[n]=name
35090   n=n+1
35091   chars [n]=decrypt(stream,4330,4)
35092   return forward
35093  else
35094   return #str
35095  end
35096 end
35097 local p_rd=spacing*(P("RD")+P("-|"))
35098 local p_np=spacing*(P("NP")+P("|"))
35099 local p_nd=spacing*(P("ND")+P("|"))
35100 local p_filterroutines=
35101  (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd*Carg(1),setroutine)*p_np+(1-p_nd))^1
35102 local p_filtershapes=
35103  (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd*Carg(1),setshapes)*p_nd+P(1))^1
35104 local p_filternames=Ct (
35105  (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*Carg(1),setvector)+P(1))^1
35106 )
35107 local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf(
35108   Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1
35109,rawset)
35110 local key=spacing*P("/")*R("az","AZ")
35111 local str=spacing*Cs { (P("(")/"")*((1-P("\\(")-P("\\)")-S("()"))+V(1))^0*(P(")")/"") }
35112 local num=spacing*(R("09")+S("+-."))^1/tonumber
35113 local arr=spacing*Ct (S("[{")*(num)^0*spacing*S("]}"))
35114 local boo=spacing*(P("true")*Cc(true)+P("false")*Cc(false))
35115 local nam=spacing*P("/")*Cs(R("az","AZ")^1)
35116 local p_filtermetadata=(
35117  P("/")*Carg(1)*((
35118   C("version")*str+C("Copyright")*str+C("Notice")*str+C("FullName")*str+C("FamilyName")*str+C("Weight")*str+C("ItalicAngle")*num+C("isFixedPitch")*boo+C("UnderlinePosition")*num+C("UnderlineThickness")*num+C("FontName")*nam+C("FontMatrix")*arr+C("FontBBox")*arr
35119  ) )/function(t,k,v) t[lower(k)]=v end+P(1)
35120 )^0*Carg(1)
35121 local function loadpfbvector(filename,shapestoo,streams)
35122  local data=io.loaddata(resolvers.findfile(filename))
35123  if not data then
35124   report_pfb("no data in %a",filename)
35125   return
35126  end
35127  if not (find(data,"!PS-AdobeFont-",1,true) or find(data,"%!FontType1",1,true)) then
35128   report_pfb("no font in %a",filename)
35129   return
35130  end
35131  local ascii,binary=match(data,"(.*)eexec%s+......(.*)")
35132  if not binary then
35133   report_pfb("no binary data in %a",filename)
35134   return
35135  end
35136  binary=decrypt(binary,55665,4)
35137  local names={}
35138  local encoding=lpegmatch(p_filterencoding,ascii)
35139  local metadata=lpegmatch(p_filtermetadata,ascii,1,{})
35140  local glyphs={}
35141  routines,vector,chars={},{},{}
35142  if shapestoo or streams then
35143   lpegmatch(p_filterroutines,binary,1,filename)
35144   lpegmatch(p_filtershapes,binary,1,filename)
35145   local data={
35146    dictionaries={
35147     {
35148      charstrings=chars,
35149      charset=vector,
35150      subroutines=routines,
35151     }
35152    },
35153   }
35154   fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams,true)
35155  else
35156   lpegmatch(p_filternames,binary,1,filename)
35157  end
35158  names=vector
35159  routines,vector,chars=nil,nil,nil
35160  return names,encoding,glyphs,metadata
35161 end
35162 local pfb=handlers.pfb or {}
35163 handlers.pfb=pfb
35164 pfb.loadvector=loadpfbvector
35165 get_indexes=function(data,pfbname)
35166  local vector=loadpfbvector(pfbname)
35167  if vector then
35168   local characters=data.characters
35169   if trace_loading then
35170    report_afm("getting index data from %a",pfbname)
35171   end
35172   for index=0,#vector do 
35173    local name=vector[index]
35174    local char=characters[name]
35175    if char then
35176     if trace_indexing then
35177      report_afm("glyph %a has index %a",name,index)
35178     end
35179     char.index=index
35180    else
35181     if trace_indexing then
35182      report_afm("glyph %a has index %a but no data",name,index)
35183     end
35184    end
35185   end
35186  end
35187 end
35188 get_shapes=function(pfbname)
35189  local vector,encoding,glyphs=loadpfbvector(pfbname,true)
35190  return glyphs
35191 end
35192end
35193local spacer=patterns.spacer
35194local whitespace=patterns.whitespace
35195local lineend=patterns.newline
35196local spacing=spacer^0
35197local number=spacing*S("+-")^-1*(R("09")+S("."))^1/tonumber
35198local name=spacing*C((1-whitespace)^1)
35199local words=spacing*((1-lineend)^1/strip)
35200local rest=(1-lineend)^0
35201local fontdata=Carg(1)
35202local semicolon=spacing*P(";")
35203local plus=spacing*P("plus")*number
35204local minus=spacing*P("minus")*number
35205local function addkernpair(data,one,two,value)
35206 local chr=data.characters[one]
35207 if chr then
35208  local kerns=chr.kerns
35209  if kerns then
35210   kerns[two]=tonumber(value)
35211  else
35212   chr.kerns={ [two]=tonumber(value) }
35213  end
35214 end
35215end
35216local p_kernpair=(fontdata*P("KPX")*name*name*number)/addkernpair
35217local chr=false
35218local ind=0
35219local function start(data,version)
35220 data.metadata.afmversion=version
35221 ind=0
35222 chr={}
35223end
35224local function stop()
35225 ind=0
35226 chr=false
35227end
35228local function setindex(i)
35229 if i<0 then
35230  ind=ind+1 
35231 else
35232  ind=i
35233 end
35234 chr={
35235  index=ind
35236 }
35237end
35238local function setwidth(width)
35239 chr.width=width
35240end
35241local function setname(data,name)
35242 data.characters[name]=chr
35243end
35244local function setboundingbox(boundingbox)
35245 chr.boundingbox=boundingbox
35246end
35247local function setligature(plus,becomes)
35248 local ligatures=chr.ligatures
35249 if ligatures then
35250  ligatures[plus]=becomes
35251 else
35252  chr.ligatures={ [plus]=becomes }
35253 end
35254end
35255local p_charmetric=((
35256 P("C")*number/setindex+P("WX")*number/setwidth+P("N")*fontdata*name/setname+P("B")*Ct((number)^4)/setboundingbox+P("L")*(name)^2/setligature
35257  )*semicolon )^1
35258local p_charmetrics=P("StartCharMetrics")*number*(p_charmetric+(1-P("EndCharMetrics")))^0*P("EndCharMetrics")
35259local p_kernpairs=P("StartKernPairs")*number*(p_kernpair+(1-P("EndKernPairs"  )))^0*P("EndKernPairs"  )
35260local function set_1(data,key,a)  data.metadata[lower(key)]=a     end
35261local function set_2(data,key,a,b)   data.metadata[lower(key)]={ a,b } end
35262local function set_3(data,key,a,b,c) data.metadata[lower(key)]={ a,b,c } end
35263local p_parameters=P(false)+fontdata*((P("FontName")+P("FullName")+P("FamilyName"))/lower)*words/function(data,key,value)
35264  data.metadata[key]=value
35265 end+fontdata*((P("Weight")+P("Version"))/lower)*name/function(data,key,value)
35266  data.metadata[key]=value
35267 end+fontdata*P("IsFixedPitch")*name/function(data,pitch)
35268  data.metadata.monospaced=toboolean(pitch,true)
35269 end+fontdata*P("FontBBox")*Ct(number^4)/function(data,boundingbox)
35270  data.metadata.boundingbox=boundingbox
35271  end+fontdata*((P("CharWidth")+P("CapHeight")+P("XHeight")+P("Descender")+P("Ascender")+P("ItalicAngle"))/lower)*number/function(data,key,value)
35272  data.metadata[key]=value
35273 end+P("Comment")*spacing*(P(false)+(fontdata*C("DESIGNSIZE")*number*rest)/set_1 
35274+(fontdata*C("TFM designsize")*number*rest)/set_1+(fontdata*C("DesignSize")*number*rest)/set_1+(fontdata*C("CODINGSCHEME")*words*rest)/set_1 
35275+(fontdata*C("CHECKSUM")*number*words*rest)/set_1 
35276+(fontdata*C("SPACE")*number*plus*minus*rest)/set_3 
35277+(fontdata*C("QUAD")*number*rest)/set_1 
35278+(fontdata*C("EXTRASPACE")*number*rest)/set_1 
35279+(fontdata*C("NUM")*number*number*number*rest)/set_3 
35280+(fontdata*C("DENOM")*number*number*rest)/set_2 
35281+(fontdata*C("SUP")*number*number*number*rest)/set_3 
35282+(fontdata*C("SUB")*number*number*rest)/set_2 
35283+(fontdata*C("SUPDROP")*number*rest)/set_1 
35284+(fontdata*C("SUBDROP")*number*rest)/set_1 
35285+(fontdata*C("DELIM")*number*number*rest)/set_2 
35286+(fontdata*C("AXISHEIGHT")*number*rest)/set_1 
35287 )
35288local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
35289local infoparser=(P("StartFontMetrics")*fontdata*name/start )*(p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
35290local function read(filename,parser)
35291 local afmblob=io.loaddata(filename)
35292 if afmblob then
35293  local data={
35294   resources={
35295    filename=resolvers.unresolve(filename),
35296    version=afm.version,
35297    creator="context mkiv",
35298   },
35299   properties={
35300    hasitalics=false,
35301   },
35302   goodies={},
35303   metadata={
35304    filename=file.removesuffix(file.basename(filename))
35305   },
35306   characters={
35307   },
35308   descriptions={
35309   },
35310  }
35311  if trace_loading then
35312   report_afm("parsing afm file %a",filename)
35313  end
35314  lpegmatch(parser,afmblob,1,data)
35315  return data
35316 else
35317  if trace_loading then
35318   report_afm("no valid afm file %a",filename)
35319  end
35320  return nil
35321 end
35322end
35323function readers.loadfont(afmname,pfbname)
35324 local data=read(resolvers.findfile(afmname),fullparser)
35325 if data then
35326  if not pfbname or pfbname=="" then
35327   pfbname=resolvers.findfile(file.replacesuffix(file.nameonly(afmname),"pfb"))
35328  end
35329  if pfbname and pfbname~="" then
35330   data.resources.filename=resolvers.unresolve(pfbname)
35331   get_indexes(data,pfbname)
35332   return data
35333  else 
35334   report_afm("no pfb file for %a",afmname)
35335  end
35336 end
35337end
35338function readers.loadshapes(filename)
35339 local fullname=resolvers.findfile(filename) or ""
35340 if fullname=="" then
35341  return {
35342   filename="not found: "..filename,
35343   glyphs={}
35344  }
35345 else
35346  return {
35347   filename=fullname,
35348   format="opentype",
35349   glyphs=get_shapes(fullname) or {},
35350   units=1000,
35351  }
35352 end
35353end
35354function readers.getinfo(filename)
35355 local data=read(resolvers.findfile(filename),infoparser)
35356 if data then
35357  return data.metadata
35358 end
35359end
35360
35361end -- closure
35362
35363do -- begin closure to overcome local limits and interference
35364
35365if not modules then modules={} end modules ['font-one']={
35366 version=1.001,
35367 optimize=true,
35368 comment="companion to font-ini.mkiv",
35369 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
35370 copyright="PRAGMA ADE / ConTeXt Development Team",
35371 license="see context related readme files"
35372}
35373local fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers
35374local next,type,tonumber,rawget=next,type,tonumber,rawget
35375local match,gsub=string.match,string.gsub
35376local abs=math.abs
35377local P,S,R,Cmt,C,Ct,Cs,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg
35378local lpegmatch,patterns=lpeg.match,lpeg.patterns
35379local sortedhash=table.sortedhash
35380local trace_features=false  trackers.register("afm.features",function(v) trace_features=v end)
35381local trace_indexing=false  trackers.register("afm.indexing",function(v) trace_indexing=v end)
35382local trace_loading=false  trackers.register("afm.loading",function(v) trace_loading=v end)
35383local trace_defining=false  trackers.register("fonts.defining",function(v) trace_defining=v end)
35384local report_afm=logs.reporter("fonts","afm loading")
35385local setmetatableindex=table.setmetatableindex
35386local derivetable=table.derive
35387local findbinfile=resolvers.findbinfile
35388local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 
35389local definers=fonts.definers
35390local readers=fonts.readers
35391local constructors=fonts.constructors
35392local afm=constructors.handlers.afm
35393local pfb=constructors.handlers.pfb
35394local otf=fonts.handlers.otf
35395local otfreaders=otf.readers
35396local otfenhancers=otf.enhancers
35397local afmfeatures=constructors.features.afm
35398local registerafmfeature=afmfeatures.register
35399local afmenhancers=constructors.enhancers.afm
35400local registerafmenhancer=afmenhancers.register
35401afm.version=1.513 
35402afm.cache=containers.define("fonts","one",afm.version,true)
35403afm.autoprefixed=true 
35404afm.helpdata={}  
35405afm.syncspace=true 
35406local overloads=fonts.mappings.overloads
35407local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
35408function afm.load(filename)
35409 filename=resolvers.findfile(filename,'afm') or ""
35410 if filename~="" and not fonts.names.ignoredfile(filename) then
35411  local name=file.removesuffix(file.basename(filename))
35412  local data=containers.read(afm.cache,name)
35413  local attr=lfs.attributes(filename)
35414  local size=attr and attr.size or 0
35415  local time=attr and attr.modification or 0
35416  local pfbfile=file.replacesuffix(name,"pfb")
35417  local pfbname=resolvers.findfile(pfbfile,"pfb") or ""
35418  if pfbname=="" then
35419   pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or ""
35420  end
35421  local pfbsize=0
35422  local pfbtime=0
35423  if pfbname~="" then
35424   local attr=lfs.attributes(pfbname)
35425   pfbsize=attr.size or 0
35426   pfbtime=attr.modification or 0
35427  end
35428  if not data or data.size~=size or data.time~=time or data.pfbsize~=pfbsize or data.pfbtime~=pfbtime then
35429   report_afm("reading %a",filename)
35430   data=afm.readers.loadfont(filename,pfbname)
35431   if data then
35432    afmenhancers.apply(data,filename)
35433    fonts.mappings.addtounicode(data,filename)
35434    otfreaders.stripredundant(data)
35435    otfreaders.pack(data)
35436    data.size=size
35437    data.time=time
35438    data.pfbsize=pfbsize
35439    data.pfbtime=pfbtime
35440    report_afm("saving %a in cache",name)
35441    data=containers.write(afm.cache,name,data)
35442    data=containers.read(afm.cache,name)
35443   end
35444  end
35445  if data then
35446   otfreaders.unpack(data)
35447   otfreaders.expand(data) 
35448   otfreaders.addunicodetable(data) 
35449   otfenhancers.apply(data,filename,data)
35450   if applyruntimefixes then
35451    applyruntimefixes(filename,data)
35452   end
35453  end
35454  return data
35455 end
35456end
35457local uparser=fonts.mappings.makenameparser() 
35458local function enhance_unify_names(data,filename)
35459 local unicodevector=fonts.encodings.agl.unicodes 
35460 local unicodes={}
35461 local names={}
35462 local private=data.private or privateoffset
35463 local descriptions=data.descriptions
35464 for name,blob in sortedhash(data.characters) do 
35465  local code=unicodevector[name] 
35466  if not code then
35467   code=lpegmatch(uparser,name)
35468   if type(code)~="number" then
35469    code=private
35470    private=private+1
35471    report_afm("assigning private slot %U for unknown glyph name %a",code,name)
35472   end
35473  end
35474  local index=blob.index
35475  unicodes[name]=code
35476  names[name]=index
35477  blob.name=name
35478  descriptions[code]={
35479   boundingbox=blob.boundingbox,
35480   width=blob.width,
35481   kerns=blob.kerns,
35482   index=index,
35483   name=name,
35484  }
35485 end
35486 for unicode,description in next,descriptions do
35487  local kerns=description.kerns
35488  if kerns then
35489   local krn={}
35490   for name,kern in next,kerns do
35491    local unicode=unicodes[name]
35492    if unicode then
35493     krn[unicode]=kern
35494    else
35495    end
35496   end
35497   description.kerns=krn
35498  end
35499 end
35500 data.characters=nil
35501 data.private=private
35502 local resources=data.resources
35503 local filename=resources.filename or file.removesuffix(file.basename(filename))
35504 resources.filename=resolvers.unresolve(filename) 
35505 resources.unicodes=unicodes 
35506 resources.marks={}
35507end
35508local everywhere={ ["*"]={ ["*"]=true } } 
35509local noflags={ false,false,false,false }
35510local function enhance_normalize_features(data)
35511 local ligatures=setmetatableindex("table")
35512 local kerns=setmetatableindex("table")
35513 local extrakerns=setmetatableindex("table")
35514 for u,c in next,data.descriptions do
35515  local l=c.ligatures
35516  local k=c.kerns
35517  local e=c.extrakerns
35518  if l then
35519   ligatures[u]=l
35520   for u,v in next,l do
35521    l[u]={ ligature=v }
35522   end
35523   c.ligatures=nil
35524  end
35525  if k then
35526   kerns[u]=k
35527   for u,v in next,k do
35528    k[u]=v 
35529   end
35530   c.kerns=nil
35531  end
35532  if e then
35533   extrakerns[u]=e
35534   for u,v in next,e do
35535    e[u]=v 
35536   end
35537   c.extrakerns=nil
35538  end
35539 end
35540 local features={
35541  gpos={},
35542  gsub={},
35543 }
35544 local sequences={
35545 }
35546 if next(ligatures) then
35547  features.gsub.liga=everywhere
35548  data.properties.hasligatures=true
35549  sequences[#sequences+1]={
35550   features={
35551    liga=everywhere,
35552   },
35553   flags=noflags,
35554   name="s_s_0",
35555   nofsteps=1,
35556   order={ "liga" },
35557   type="gsub_ligature",
35558   steps={
35559    {
35560     coverage=ligatures,
35561    },
35562   },
35563  }
35564 end
35565 if next(kerns) then
35566  features.gpos.kern=everywhere
35567  data.properties.haskerns=true
35568  sequences[#sequences+1]={
35569   features={
35570    kern=everywhere,
35571   },
35572   flags=noflags,
35573   name="p_s_0",
35574   nofsteps=1,
35575   order={ "kern" },
35576   type="gpos_pair",
35577   steps={
35578    {
35579     format="kern",
35580     coverage=kerns,
35581    },
35582   },
35583  }
35584 end
35585 if next(extrakerns) then
35586  features.gpos.extrakerns=everywhere
35587  data.properties.haskerns=true
35588  sequences[#sequences+1]={
35589   features={
35590    extrakerns=everywhere,
35591   },
35592   flags=noflags,
35593   name="p_s_1",
35594   nofsteps=1,
35595   order={ "extrakerns" },
35596   type="gpos_pair",
35597   steps={
35598    {
35599     format="kern",
35600     coverage=extrakerns,
35601    },
35602   },
35603  }
35604 end
35605 data.resources.features=features
35606 data.resources.sequences=sequences
35607end
35608local function enhance_fix_names(data)
35609 for k,v in next,data.descriptions do
35610  local n=v.name
35611  local r=overloads[n]
35612  if r then
35613   local name=r.name
35614   if trace_indexing then
35615    report_afm("renaming characters %a to %a",n,name)
35616   end
35617   v.name=name
35618   v.unicode=r.unicode
35619  end
35620 end
35621end
35622local addthem=function(rawdata,ligatures)
35623 if ligatures then
35624  local descriptions=rawdata.descriptions
35625  local resources=rawdata.resources
35626  local unicodes=resources.unicodes
35627  for ligname,ligdata in next,ligatures do
35628   local one=descriptions[unicodes[ligname]]
35629   if one then
35630    for _,pair in next,ligdata do
35631     local two=unicodes[pair[1]]
35632     local three=unicodes[pair[2]]
35633     if two and three then
35634      local ol=one.ligatures
35635      if ol then
35636       if not ol[two] then
35637        ol[two]=three
35638       end
35639      else
35640       one.ligatures={ [two]=three }
35641      end
35642     end
35643    end
35644   end
35645  end
35646 end
35647end
35648local function enhance_add_ligatures(rawdata)
35649 addthem(rawdata,afm.helpdata.ligatures)
35650end
35651local function enhance_add_extra_kerns(rawdata) 
35652 local descriptions=rawdata.descriptions
35653 local resources=rawdata.resources
35654 local unicodes=resources.unicodes
35655 local function do_it_left(what)
35656  if what then
35657   for unicode,description in next,descriptions do
35658    local kerns=description.kerns
35659    if kerns then
35660     local extrakerns
35661     for complex,simple in next,what do
35662      complex=unicodes[complex]
35663      simple=unicodes[simple]
35664      if complex and simple then
35665       local ks=kerns[simple]
35666       if ks and not kerns[complex] then
35667        if extrakerns then
35668         extrakerns[complex]=ks
35669        else
35670         extrakerns={ [complex]=ks }
35671        end
35672       end
35673      end
35674     end
35675     if extrakerns then
35676      description.extrakerns=extrakerns
35677     end
35678    end
35679   end
35680  end
35681 end
35682 local function do_it_copy(what)
35683  if what then
35684   for complex,simple in next,what do
35685    complex=unicodes[complex]
35686    simple=unicodes[simple]
35687    if complex and simple then
35688     local complexdescription=descriptions[complex]
35689     if complexdescription then 
35690      local simpledescription=descriptions[complex]
35691      if simpledescription then
35692       local extrakerns
35693       local kerns=simpledescription.kerns
35694       if kerns then
35695        for unicode,kern in next,kerns do
35696         if extrakerns then
35697          extrakerns[unicode]=kern
35698         else
35699          extrakerns={ [unicode]=kern }
35700         end
35701        end
35702       end
35703       local extrakerns=simpledescription.extrakerns
35704       if extrakerns then
35705        for unicode,kern in next,extrakerns do
35706         if extrakerns then
35707          extrakerns[unicode]=kern
35708         else
35709          extrakerns={ [unicode]=kern }
35710         end
35711        end
35712       end
35713       if extrakerns then
35714        complexdescription.extrakerns=extrakerns
35715       end
35716      end
35717     end
35718    end
35719   end
35720  end
35721 end
35722 do_it_left(afm.helpdata.leftkerned)
35723 do_it_left(afm.helpdata.bothkerned)
35724 do_it_copy(afm.helpdata.bothkerned)
35725 do_it_copy(afm.helpdata.rightkerned)
35726end
35727local function adddimensions(data) 
35728 if data then
35729  for unicode,description in next,data.descriptions do
35730   local bb=description.boundingbox
35731   if bb then
35732    local ht=bb[4]
35733    local dp=-bb[2]
35734    if ht==0 or ht<0 then
35735    else
35736     description.height=ht
35737    end
35738    if dp==0 or dp<0 then
35739    else
35740     description.depth=dp
35741    end
35742   end
35743  end
35744 end
35745end
35746local function copytotfm(data)
35747 if data and data.descriptions then
35748  local metadata=data.metadata
35749  local resources=data.resources
35750  local properties=derivetable(data.properties)
35751  local descriptions=derivetable(data.descriptions)
35752  local goodies=derivetable(data.goodies)
35753  local characters={}
35754  local parameters={}
35755  local unicodes=resources.unicodes
35756  for unicode,description in next,data.descriptions do 
35757   characters[unicode]={}
35758  end
35759  local filename=constructors.checkedfilename(resources)
35760  local fontname=metadata.fontname or metadata.fullname
35761  local fullname=metadata.fullname or metadata.fontname
35762  local endash=0x2013
35763  local emdash=0x2014
35764  local space=0x0020 
35765  local spacer="space"
35766  local spaceunits=500
35767  local monospaced=metadata.monospaced
35768  local charwidth=metadata.charwidth
35769  local italicangle=metadata.italicangle
35770  local charxheight=metadata.xheight and metadata.xheight>0 and metadata.xheight
35771  properties.monospaced=monospaced
35772  parameters.italicangle=italicangle
35773  parameters.charwidth=charwidth
35774  parameters.charxheight=charxheight
35775  local d_endash=descriptions[endash]
35776  local d_emdash=descriptions[emdash]
35777  local d_space=descriptions[space]
35778  if not d_space or d_space==0 then
35779   d_space=d_endash
35780  end
35781  if d_space then
35782   spaceunits,spacer=d_space.width or 0,"space"
35783  end
35784  if properties.monospaced then
35785   if spaceunits==0 and d_emdash then
35786    spaceunits,spacer=d_emdash.width or 0,"emdash"
35787   end
35788  else
35789   if spaceunits==0 and d_endash then
35790    spaceunits,spacer=d_emdash.width or 0,"endash"
35791   end
35792  end
35793  if spaceunits==0 and charwidth then
35794   spaceunits,spacer=charwidth or 0,"charwidth"
35795  end
35796  if spaceunits==0 then
35797   spaceunits=tonumber(spaceunits) or 500
35798  end
35799  if spaceunits==0 then
35800   spaceunits=500
35801  end
35802  parameters.slant=0
35803  parameters.space=spaceunits
35804  parameters.space_stretch=500
35805  parameters.space_shrink=333
35806  parameters.x_height=400
35807  parameters.quad=1000
35808  if italicangle and italicangle~=0 then
35809   parameters.italicangle=italicangle
35810   parameters.italicfactor=math.cos(math.rad(90+italicangle))
35811   parameters.slant=- math.tan(italicangle*math.pi/180)
35812  end
35813  if monospaced then
35814   parameters.space_stretch=0
35815   parameters.space_shrink=0
35816  elseif afm.syncspace then
35817   parameters.space_stretch=spaceunits/2
35818   parameters.space_shrink=spaceunits/3
35819  end
35820  parameters.extra_space=parameters.space_shrink
35821  if charxheight then
35822   parameters.x_height=charxheight
35823  else
35824   local x=0x0078 
35825   if x then
35826    local x=descriptions[x]
35827    if x then
35828     parameters.x_height=x.height
35829    end
35830   end
35831  end
35832  if metadata.sup then
35833   local dummy={ 0,0,0 }
35834   parameters[ 1]=metadata.designsize  or 0
35835   parameters[ 2]=metadata.checksum    or 0
35836   parameters[ 3],
35837   parameters[ 4],
35838   parameters[ 5]=unpack(metadata.space   or dummy)
35839   parameters[ 6]=metadata.quad    or 0
35840   parameters[ 7]=metadata.extraspace or 0
35841   parameters[ 8],
35842   parameters[ 9],
35843   parameters[10]=unpack(metadata.num  or dummy)
35844   parameters[11],
35845   parameters[12]=unpack(metadata.denom   or dummy)
35846   parameters[13],
35847   parameters[14],
35848   parameters[15]=unpack(metadata.sup  or dummy)
35849   parameters[16],
35850   parameters[17]=unpack(metadata.sub  or dummy)
35851   parameters[18]=metadata.supdrop or 0
35852   parameters[19]=metadata.subdrop or 0
35853   parameters[20],
35854   parameters[21]=unpack(metadata.delim   or dummy)
35855   parameters[22]=metadata.axisheight or 0
35856  end
35857  parameters.designsize=(metadata.designsize or 10)*65536
35858  parameters.ascender=abs(metadata.ascender  or 0)
35859  parameters.descender=abs(metadata.descender or 0)
35860  parameters.units=1000
35861  properties.spacer=spacer
35862  properties.format=fonts.formats[filename] or "type1"
35863  properties.filename=filename
35864  properties.fontname=fontname
35865  properties.fullname=fullname
35866  properties.psname=fullname
35867  properties.name=filename or fullname or fontname
35868  properties.private=properties.private or data.private or privateoffset
35869if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
35870  properties.encodingbytes=2
35871end
35872  if next(characters) then
35873   return {
35874    characters=characters,
35875    descriptions=descriptions,
35876    parameters=parameters,
35877    resources=resources,
35878    properties=properties,
35879    goodies=goodies,
35880   }
35881  end
35882 end
35883 return nil
35884end
35885function afm.setfeatures(tfmdata,features)
35886 local okay=constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm)
35887 if okay then
35888  return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm)
35889 else
35890  return {} 
35891 end
35892end
35893local function addtables(data)
35894 local resources=data.resources
35895 local lookuptags=resources.lookuptags
35896 local unicodes=resources.unicodes
35897 if not lookuptags then
35898  lookuptags={}
35899  resources.lookuptags=lookuptags
35900 end
35901 setmetatableindex(lookuptags,function(t,k)
35902  local v=type(k)=="number" and ("lookup "..k) or k
35903  t[k]=v
35904  return v
35905 end)
35906 if not unicodes then
35907  unicodes={}
35908  resources.unicodes=unicodes
35909  setmetatableindex(unicodes,function(t,k)
35910   setmetatableindex(unicodes,nil)
35911   for u,d in next,data.descriptions do
35912    local n=d.name
35913    if n then
35914     t[n]=u
35915    end
35916   end
35917   return rawget(t,k)
35918  end)
35919 end
35920 constructors.addcoreunicodes(unicodes) 
35921end
35922local function afmtotfm(specification)
35923 local afmname=specification.filename or specification.name
35924 if specification.forced=="afm" or specification.format=="afm" then 
35925  if trace_loading then
35926   report_afm("forcing afm format for %a",afmname)
35927  end
35928 else
35929  local tfmname=findbinfile(afmname,"ofm") or ""
35930  if tfmname~="" then
35931   if trace_loading then
35932    report_afm("fallback from afm to tfm for %a",afmname)
35933   end
35934   return 
35935  end
35936 end
35937 if afmname~="" then
35938  local features=constructors.checkedfeatures("afm",specification.features.normal)
35939  specification.features.normal=features
35940  constructors.hashinstance(specification,true)
35941  specification=definers.resolve(specification) 
35942  local cache_id=specification.hash
35943  local tfmdata=containers.read(constructors.cache,cache_id) 
35944  if not tfmdata then
35945   local rawdata=afm.load(afmname)
35946   if rawdata and next(rawdata) then
35947    addtables(rawdata)
35948    adddimensions(rawdata)
35949    tfmdata=copytotfm(rawdata)
35950    if tfmdata and next(tfmdata) then
35951     local shared=tfmdata.shared
35952     if not shared then
35953      shared={}
35954      tfmdata.shared=shared
35955     end
35956     shared.rawdata=rawdata
35957     shared.dynamics={}
35958     tfmdata.changed={}
35959     shared.features=features
35960     shared.processes=afm.setfeatures(tfmdata,features)
35961    end
35962   elseif trace_loading then
35963    report_afm("no (valid) afm file found with name %a",afmname)
35964   end
35965   tfmdata=containers.write(constructors.cache,cache_id,tfmdata)
35966  end
35967  return tfmdata
35968 end
35969end
35970local function read_from_afm(specification)
35971 local tfmdata=afmtotfm(specification)
35972 if tfmdata then
35973  tfmdata.properties.name=specification.name
35974  tfmdata.properties.id=specification.id
35975  tfmdata=constructors.scale(tfmdata,specification)
35976  local allfeatures=tfmdata.shared.features or specification.features.normal
35977  constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm)
35978  fonts.loggers.register(tfmdata,'afm',specification)
35979 end
35980 return tfmdata
35981end
35982registerafmfeature {
35983 name="mode",
35984 description="mode",
35985 initializers={
35986  base=otf.modeinitializer,
35987  node=otf.modeinitializer,
35988 }
35989}
35990registerafmfeature {
35991 name="features",
35992 description="features",
35993 default=true,
35994 initializers={
35995  node=otf.nodemodeinitializer,
35996  base=otf.basemodeinitializer,
35997 },
35998 processors={
35999  node=otf.featuresprocessor,
36000 }
36001}
36002fonts.formats.afm="type1"
36003fonts.formats.pfb="type1"
36004local function check_afm(specification,fullname)
36005 local foundname=findbinfile(fullname,'afm') or "" 
36006 if foundname=="" then
36007  foundname=fonts.names.getfilename(fullname,"afm") or ""
36008 end
36009 if fullname and foundname=="" and afm.autoprefixed then
36010  local encoding,shortname=match(fullname,"^(.-)%-(.*)$") 
36011  if encoding and shortname and fonts.encodings.known[encoding] then
36012   shortname=findbinfile(shortname,'afm') or "" 
36013   if shortname~="" then
36014    foundname=shortname
36015    if trace_defining then
36016     report_afm("stripping encoding prefix from filename %a",afmname)
36017    end
36018   end
36019  end
36020 end
36021 if foundname~="" then
36022  specification.filename=foundname
36023  specification.format="afm"
36024  return read_from_afm(specification)
36025 end
36026end
36027function readers.afm(specification,method)
36028 local fullname=specification.filename or ""
36029 local tfmdata=nil
36030 if fullname=="" then
36031  local forced=specification.forced or ""
36032  if forced~="" then
36033   tfmdata=check_afm(specification,specification.name.."."..forced)
36034  end
36035  if not tfmdata then
36036   local check_tfm=readers.check_tfm
36037   method=(check_tfm and (method or definers.method or "afm or tfm")) or "afm"
36038   if method=="tfm" then
36039    tfmdata=check_tfm(specification,specification.name)
36040   elseif method=="afm" then
36041    tfmdata=check_afm(specification,specification.name)
36042   elseif method=="tfm or afm" then
36043    tfmdata=check_tfm(specification,specification.name) or check_afm(specification,specification.name)
36044   else 
36045    tfmdata=check_afm(specification,specification.name) or check_tfm(specification,specification.name)
36046   end
36047  end
36048 else
36049  tfmdata=check_afm(specification,fullname)
36050 end
36051 return tfmdata
36052end
36053function readers.pfb(specification,method) 
36054 local original=specification.specification
36055 if trace_defining then
36056  report_afm("using afm reader for %a",original)
36057 end
36058 specification.forced="afm"
36059 local function swap(name)
36060  local value=specification[swap]
36061  if value then
36062   specification[swap]=gsub("%.pfb",".afm",1)
36063  end
36064 end
36065 swap("filename")
36066 swap("fullname")
36067 swap("forcedname")
36068 swap("specification")
36069 return readers.afm(specification,method)
36070end
36071registerafmenhancer("unify names",enhance_unify_names)
36072registerafmenhancer("add ligatures",enhance_add_ligatures)
36073registerafmenhancer("add extra kerns",enhance_add_extra_kerns)
36074registerafmenhancer("normalize features",enhance_normalize_features)
36075registerafmenhancer("check extra features",otfenhancers.enhance)
36076registerafmenhancer("fix names",enhance_fix_names)
36077
36078end -- closure
36079
36080do -- begin closure to overcome local limits and interference
36081
36082if not modules then modules={} end modules ['font-afk']={
36083 version=1.001,
36084 comment="companion to font-lib.mkiv",
36085 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
36086 copyright="PRAGMA ADE / ConTeXt Development Team",
36087 license="see context related readme files",
36088 dataonly=true,
36089}
36090local allocate=utilities.storage.allocate
36091fonts.handlers.afm.helpdata={
36092 ligatures=allocate { 
36093  ['f']={ 
36094   { 'f','ff' },
36095   { 'i','fi' },
36096   { 'l','fl' },
36097  },
36098  ['ff']={
36099   { 'i','ffi' }
36100  },
36101  ['fi']={
36102   { 'i','fii' }
36103  },
36104  ['fl']={
36105   { 'i','fli' }
36106  },
36107  ['s']={
36108   { 't','st' }
36109  },
36110  ['i']={
36111   { 'j','ij' }
36112  },
36113 },
36114 texligatures=allocate {
36115  ['quoteleft']={
36116   { 'quoteleft','quotedblleft' }
36117  },
36118  ['quoteright']={
36119   { 'quoteright','quotedblright' }
36120  },
36121  ['hyphen']={
36122   { 'hyphen','endash' }
36123  },
36124  ['endash']={
36125   { 'hyphen','emdash' }
36126  }
36127 },
36128 leftkerned=allocate {
36129  AEligature="A",aeligature="a",
36130  OEligature="O",oeligature="o",
36131  IJligature="I",ijligature="i",
36132  AE="A",ae="a",
36133  OE="O",oe="o",
36134  IJ="I",ij="i",
36135  Ssharp="S",ssharp="s",
36136 },
36137 rightkerned=allocate {
36138  AEligature="E",aeligature="e",
36139  OEligature="E",oeligature="e",
36140  IJligature="J",ijligature="j",
36141  AE="E",ae="e",
36142  OE="E",oe="e",
36143  IJ="J",ij="j",
36144  Ssharp="S",ssharp="s",
36145 },
36146 bothkerned=allocate {
36147  Acircumflex="A",acircumflex="a",
36148  Ccircumflex="C",ccircumflex="c",
36149  Ecircumflex="E",ecircumflex="e",
36150  Gcircumflex="G",gcircumflex="g",
36151  Hcircumflex="H",hcircumflex="h",
36152  Icircumflex="I",icircumflex="i",
36153  Jcircumflex="J",jcircumflex="j",
36154  Ocircumflex="O",ocircumflex="o",
36155  Scircumflex="S",scircumflex="s",
36156  Ucircumflex="U",ucircumflex="u",
36157  Wcircumflex="W",wcircumflex="w",
36158  Ycircumflex="Y",ycircumflex="y",
36159  Agrave="A",agrave="a",
36160  Egrave="E",egrave="e",
36161  Igrave="I",igrave="i",
36162  Ograve="O",ograve="o",
36163  Ugrave="U",ugrave="u",
36164  Ygrave="Y",ygrave="y",
36165  Atilde="A",atilde="a",
36166  Itilde="I",itilde="i",
36167  Otilde="O",otilde="o",
36168  Utilde="U",utilde="u",
36169  Ntilde="N",ntilde="n",
36170  Adiaeresis="A",adiaeresis="a",Adieresis="A",adieresis="a",
36171  Ediaeresis="E",ediaeresis="e",Edieresis="E",edieresis="e",
36172  Idiaeresis="I",idiaeresis="i",Idieresis="I",idieresis="i",
36173  Odiaeresis="O",odiaeresis="o",Odieresis="O",odieresis="o",
36174  Udiaeresis="U",udiaeresis="u",Udieresis="U",udieresis="u",
36175  Ydiaeresis="Y",ydiaeresis="y",Ydieresis="Y",ydieresis="y",
36176  Aacute="A",aacute="a",
36177  Cacute="C",cacute="c",
36178  Eacute="E",eacute="e",
36179  Iacute="I",iacute="i",
36180  Lacute="L",lacute="l",
36181  Nacute="N",nacute="n",
36182  Oacute="O",oacute="o",
36183  Racute="R",racute="r",
36184  Sacute="S",sacute="s",
36185  Uacute="U",uacute="u",
36186  Yacute="Y",yacute="y",
36187  Zacute="Z",zacute="z",
36188  Dstroke="D",dstroke="d",
36189  Hstroke="H",hstroke="h",
36190  Tstroke="T",tstroke="t",
36191  Cdotaccent="C",cdotaccent="c",
36192  Edotaccent="E",edotaccent="e",
36193  Gdotaccent="G",gdotaccent="g",
36194  Idotaccent="I",idotaccent="i",
36195  Zdotaccent="Z",zdotaccent="z",
36196  Amacron="A",amacron="a",
36197  Emacron="E",emacron="e",
36198  Imacron="I",imacron="i",
36199  Omacron="O",omacron="o",
36200  Umacron="U",umacron="u",
36201  Ccedilla="C",ccedilla="c",
36202  Kcedilla="K",kcedilla="k",
36203  Lcedilla="L",lcedilla="l",
36204  Ncedilla="N",ncedilla="n",
36205  Rcedilla="R",rcedilla="r",
36206  Scedilla="S",scedilla="s",
36207  Tcedilla="T",tcedilla="t",
36208  Ohungarumlaut="O",ohungarumlaut="o",
36209  Uhungarumlaut="U",uhungarumlaut="u",
36210  Aogonek="A",aogonek="a",
36211  Eogonek="E",eogonek="e",
36212  Iogonek="I",iogonek="i",
36213  Uogonek="U",uogonek="u",
36214  Aring="A",aring="a",
36215  Uring="U",uring="u",
36216  Abreve="A",abreve="a",
36217  Ebreve="E",ebreve="e",
36218  Gbreve="G",gbreve="g",
36219  Ibreve="I",ibreve="i",
36220  Obreve="O",obreve="o",
36221  Ubreve="U",ubreve="u",
36222  Ccaron="C",ccaron="c",
36223  Dcaron="D",dcaron="d",
36224  Ecaron="E",ecaron="e",
36225  Lcaron="L",lcaron="l",
36226  Ncaron="N",ncaron="n",
36227  Rcaron="R",rcaron="r",
36228  Scaron="S",scaron="s",
36229  Tcaron="T",tcaron="t",
36230  Zcaron="Z",zcaron="z",
36231  dotlessI="I",dotlessi="i",
36232  dotlessJ="J",dotlessj="j",
36233  AEligature="AE",aeligature="ae",AE="AE",ae="ae",
36234  OEligature="OE",oeligature="oe",OE="OE",oe="oe",
36235  IJligature="IJ",ijligature="ij",IJ="IJ",ij="ij",
36236  Lstroke="L",lstroke="l",Lslash="L",lslash="l",
36237  Ostroke="O",ostroke="o",Oslash="O",oslash="o",
36238  Ssharp="SS",ssharp="ss",
36239  Aumlaut="A",aumlaut="a",
36240  Eumlaut="E",eumlaut="e",
36241  Iumlaut="I",iumlaut="i",
36242  Oumlaut="O",oumlaut="o",
36243  Uumlaut="U",uumlaut="u",
36244 }
36245}
36246
36247end -- closure
36248
36249do -- begin closure to overcome local limits and interference
36250
36251if not modules then modules={} end modules ['luatex-fonts-tfm']={
36252 version=1.001,
36253 comment="companion to font-ini.mkiv",
36254 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
36255 copyright="PRAGMA ADE / ConTeXt Development Team",
36256 license="see context related readme files"
36257}
36258local next,type=next,type
36259local match,format=string.match,string.format
36260local concat,sortedhash=table.concat,table.sortedhash
36261local idiv=number.idiv
36262local trace_defining=false  trackers.register("fonts.defining",function(v) trace_defining=v end)
36263local trace_features=false  trackers.register("tfm.features",function(v) trace_features=v end)
36264local report_defining=logs.reporter("fonts","defining")
36265local report_tfm=logs.reporter("fonts","tfm loading")
36266local findbinfile=resolvers.findbinfile
36267local setmetatableindex=table.setmetatableindex
36268local fonts=fonts
36269local handlers=fonts.handlers
36270local helpers=fonts.helpers
36271local readers=fonts.readers
36272local constructors=fonts.constructors
36273local encodings=fonts.encodings
36274local tfm=constructors.handlers.tfm
36275tfm.version=1.000
36276tfm.maxnestingdepth=5
36277tfm.maxnestingsize=65536*1024
36278local otf=fonts.handlers.otf
36279local otfenhancers=otf.enhancers
36280local tfmfeatures=constructors.features.tfm
36281local registertfmfeature=tfmfeatures.register
36282local tfmenhancers=constructors.enhancers.tfm
36283local registertfmenhancer=tfmenhancers.register
36284local charcommand=helpers.commands.char
36285constructors.resolvevirtualtoo=false 
36286fonts.formats.tfm="type1" 
36287fonts.formats.ofm="type1" 
36288function tfm.setfeatures(tfmdata,features)
36289 local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
36290 if okay then
36291  return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
36292 else
36293  return {} 
36294 end
36295end
36296local depth={} 
36297local loadtfm=font.read_tfm
36298local loadvf=font.read_vf
36299local function read_from_tfm(specification)
36300 local filename=specification.filename
36301 local size=specification.size
36302 depth[filename]=(depth[filename] or 0)+1
36303 if trace_defining then
36304  report_defining("loading tfm file %a at size %s",filename,size)
36305 end
36306 local tfmdata=loadtfm(filename,size)
36307 if tfmdata then
36308  local features=specification.features and specification.features.normal or {}
36309  local features=constructors.checkedfeatures("tfm",features)
36310  specification.features.normal=features
36311  local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification)
36312  if newtfmdata then
36313    tfmdata=newtfmdata
36314  end
36315  local resources=tfmdata.resources  or {}
36316  local properties=tfmdata.properties or {}
36317  local parameters=tfmdata.parameters or {}
36318  local shared=tfmdata.shared  or {}
36319  shared.features=features
36320  shared.resources=resources
36321  properties.name=tfmdata.name     
36322  properties.fontname=tfmdata.fontname    
36323  properties.psname=tfmdata.psname   
36324  properties.fullname=tfmdata.fullname    
36325  properties.filename=specification.filename 
36326  properties.format=tfmdata.format or fonts.formats.tfm 
36327  properties.usedbitmap=tfmdata.usedbitmap
36328  tfmdata.properties=properties
36329  tfmdata.resources=resources
36330  tfmdata.parameters=parameters
36331  tfmdata.shared=shared
36332  shared.rawdata={ resources=resources }
36333  shared.features=features
36334  if newtfmdata then
36335   if not resources.marks then
36336    resources.marks={}
36337   end
36338   if not resources.sequences then
36339    resources.sequences={}
36340   end
36341   if not resources.features then
36342    resources.features={
36343     gsub={},
36344     gpos={},
36345    }
36346   end
36347   if not tfmdata.changed then
36348    tfmdata.changed={}
36349   end
36350   if not tfmdata.descriptions then
36351    tfmdata.descriptions=tfmdata.characters
36352   end
36353   otf.readers.addunicodetable(tfmdata)
36354   tfmenhancers.apply(tfmdata,filename)
36355   constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
36356   otf.readers.unifymissing(tfmdata)
36357   fonts.mappings.addtounicode(tfmdata,filename)
36358   tfmdata.tounicode=1
36359   local tounicode=fonts.mappings.tounicode
36360   for unicode,v in next,tfmdata.characters do
36361    local u=v.unicode
36362    if u then
36363     v.tounicode=tounicode(u)
36364    end
36365   end
36366   if tfmdata.usedbitmap then
36367    tfm.addtounicode(tfmdata)
36368   end
36369  end
36370  shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil
36371  if size<0 then
36372   size=idiv(65536*-size,100)
36373  end
36374  parameters.factor=1  
36375  parameters.units=1000  
36376  parameters.size=size
36377  parameters.slant=parameters.slant    or parameters[1] or 0
36378  parameters.space=parameters.space    or parameters[2] or 0
36379  parameters.space_stretch=parameters.space_stretch  or parameters[3] or 0
36380  parameters.space_shrink=parameters.space_shrink   or parameters[4] or 0
36381  parameters.x_height=parameters.x_height    or parameters[5] or 0
36382  parameters.quad=parameters.quad     or parameters[6] or 0
36383  parameters.extra_space=parameters.extra_space or parameters[7] or 0
36384  constructors.enhanceparameters(parameters)
36385  properties.private=properties.private or tfmdata.private or privateoffset
36386  if newtfmdata then
36387  elseif constructors.resolvevirtualtoo then
36388   fonts.loggers.register(tfmdata,file.suffix(filename),specification) 
36389   local vfname=findbinfile(specification.name,'ovf')
36390   if vfname and vfname~="" then
36391    local vfdata=loadvf(vfname,size)
36392    if vfdata then
36393     local chars=tfmdata.characters
36394     for k,v in next,vfdata.characters do
36395      chars[k].commands=v.commands
36396     end
36397     properties.virtualized=true
36398     tfmdata.fonts=vfdata.fonts
36399     tfmdata.type="virtual" 
36400     local fontlist=vfdata.fonts
36401     local name=file.nameonly(filename)
36402     for i=1,#fontlist do
36403      local n=fontlist[i].name
36404      local s=fontlist[i].size
36405      local d=depth[filename]
36406      s=constructors.scaled(s,vfdata.designsize)
36407      if d>tfm.maxnestingdepth then
36408       report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth)
36409       fontlist[i]={ id=0 }
36410      elseif (d>1) and (s>tfm.maxnestingsize) then
36411       report_defining("virtual font %a exceeds size %s",n,s)
36412       fontlist[i]={ id=0 }
36413      else
36414       local t,id=constructors.readanddefine(n,s)
36415       fontlist[i]={ id=id }
36416      end
36417     end
36418    end
36419   end
36420  end
36421  properties.haskerns=true
36422  properties.hasligatures=true
36423  properties.hasitalics=true
36424  resources.unicodes={}
36425  resources.lookuptags={}
36426  depth[filename]=depth[filename]-1
36427  return tfmdata
36428 else
36429  depth[filename]=depth[filename]-1
36430 end
36431end
36432local function check_tfm(specification,fullname) 
36433 local foundname=findbinfile(fullname,'tfm') or ""
36434 if foundname=="" then
36435  foundname=findbinfile(fullname,'ofm') or "" 
36436 end
36437 if foundname=="" then
36438  foundname=fonts.names.getfilename(fullname,"tfm") or ""
36439 end
36440 if foundname~="" then
36441  specification.filename=foundname
36442  specification.format="ofm"
36443  return read_from_tfm(specification)
36444 elseif trace_defining then
36445  report_defining("loading tfm with name %a fails",specification.name)
36446 end
36447end
36448readers.check_tfm=check_tfm
36449function readers.tfm(specification)
36450 local fullname=specification.filename or ""
36451 if fullname=="" then
36452  local forced=specification.forced or ""
36453  if forced~="" then
36454   fullname=specification.name.."."..forced
36455  else
36456   fullname=specification.name
36457  end
36458 end
36459 return check_tfm(specification,fullname)
36460end
36461readers.ofm=readers.tfm
36462do
36463 local outfiles={}
36464 local tfmcache=table.setmetatableindex(function(t,tfmdata)
36465  local id=font.define(tfmdata)
36466  t[tfmdata]=id
36467  return id
36468 end)
36469 local encdone=table.setmetatableindex("table")
36470 function tfm.reencode(tfmdata,specification)
36471  local features=specification.features
36472  if not features then
36473   return
36474  end
36475  local features=features.normal
36476  if not features then
36477   return
36478  end
36479  local tfmfile=file.basename(tfmdata.name)
36480  local encfile=features.reencode 
36481  local pfbfile=features.pfbfile  
36482  local bitmap=features.bitmap   
36483  if not encfile then
36484   return
36485  end
36486  local pfbfile=outfiles[tfmfile]
36487  if pfbfile==nil then
36488   if bitmap then
36489    pfbfile=false
36490   elseif type(pfbfile)~="string" then
36491    pfbfile=tfmfile
36492   end
36493   if type(pfbfile)=="string" then
36494    pfbfile=file.addsuffix(pfbfile,"pfb")
36495    report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile)
36496   else
36497    report_tfm("using bitmap shapes for %a",tfmfile)
36498    pfbfile=false 
36499   end
36500   outfiles[tfmfile]=pfbfile
36501  end
36502  local encoding=false
36503  local vector=false
36504  if type(pfbfile)=="string" then
36505   local pfb=constructors.handlers.pfb
36506   if pfb and pfb.loadvector then
36507    local v,e=pfb.loadvector(pfbfile)
36508    if v then
36509     vector=v
36510    end
36511    if e then
36512     encoding=e
36513    end
36514   end
36515  end
36516  if type(encfile)=="string" and encfile~="auto" then
36517   encoding=fonts.encodings.load(file.addsuffix(encfile,"enc"))
36518   if encoding then
36519    encoding=encoding.vector
36520   end
36521  end
36522  if not encoding then
36523   report_tfm("bad encoding for %a, quitting",tfmfile)
36524   return
36525  end
36526  local unicoding=fonts.encodings.agl and fonts.encodings.agl.unicodes
36527  local virtualid=tfmcache[tfmdata]
36528  local tfmdata=table.copy(tfmdata) 
36529  local characters={}
36530  local originals=tfmdata.characters
36531  local indices={}
36532  local parentfont={ "font",1 }
36533  local private=tfmdata.privateoffset or constructors.privateoffset
36534  local reported=encdone[tfmfile][encfile]
36535  local backmap=vector and table.swapped(vector)
36536  local done={} 
36537  for index,name in sortedhash(encoding) do 
36538   local unicode=unicoding[name]
36539   local original=originals[index]
36540   if original then
36541    if unicode then
36542     original.unicode=unicode
36543    else
36544     unicode=private
36545     private=private+1
36546     if not reported then
36547      report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode)
36548     end
36549    end
36550    characters[unicode]=original
36551    indices[index]=unicode
36552    original.name=name 
36553    if backmap then
36554     original.index=backmap[name]
36555    else 
36556     original.commands={ parentfont,charcommand[index] } 
36557     original.oindex=index
36558    end
36559    done[name]=true
36560   elseif not done[name] then
36561    report_tfm("bad index %a in font %a with name %a",index,tfmfile,name)
36562   end
36563  end
36564  encdone[tfmfile][encfile]=true
36565  for k,v in next,characters do
36566   local kerns=v.kerns
36567   if kerns then
36568    local t={}
36569    for k,v in next,kerns do
36570     local i=indices[k]
36571     if i then
36572      t[i]=v
36573     end
36574    end
36575    v.kerns=next(t) and t or nil
36576   end
36577   local ligatures=v.ligatures
36578   if ligatures then
36579    local t={}
36580    for k,v in next,ligatures do
36581     local i=indices[k]
36582     if i then
36583      t[i]=v
36584      v.char=indices[v.char]
36585     end
36586    end
36587    v.ligatures=next(t) and t or nil
36588   end
36589  end
36590  tfmdata.fonts={ { id=virtualid } }
36591  tfmdata.characters=characters
36592  tfmdata.fullname=tfmdata.fullname or tfmdata.name
36593  tfmdata.psname=file.nameonly(pfbfile or tfmdata.name)
36594  tfmdata.filename=pfbfile
36595  tfmdata.encodingbytes=2
36596  tfmdata.format="type1"
36597  tfmdata.tounicode=1
36598  tfmdata.embedding="subset"
36599  tfmdata.usedbitmap=bitmap and virtualid
36600  tfmdata.private=private
36601  return tfmdata
36602 end
36603end
36604do
36605 local template=[[
36606/CIDInit /ProcSet findresource begin
36607  12 dict begin
36608  begincmap
36609    /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def
36610    /CMapName /TeX-bitmap-%s def
36611    /CMapType 2 def
36612    1 begincodespacerange
36613      <00> <FF>
36614    endcodespacerange
36615    %s beginbfchar
36616%s
36617    endbfchar
36618  endcmap
36619CMapName currentdict /CMap defineresource pop end
36620end
36621end
36622]]
36623 local flushstreamobject=lpdf and lpdf.flushstreamobject 
36624 local setfontattributes=lpdf and lpdf.setfontattributes 
36625 if not flushstreamobject then
36626  flushstreamobject=function(data)
36627   return pdf.obj { immediate=true,type="stream",string=data } 
36628  end
36629 end
36630 if not setfontattributes then
36631  setfontattributes=function(id,data)
36632   return pdf.setfontattributes(id,data) 
36633  end
36634 end
36635 function tfm.addtounicode(tfmdata)
36636  local id=tfmdata.usedbitmap
36637  local map={}
36638  local char={} 
36639  for k,v in next,tfmdata.characters do
36640   local index=v.oindex
36641   local tounicode=v.tounicode
36642   if index and tounicode then
36643    map[index]=tounicode
36644   end
36645  end
36646  for k,v in sortedhash(map) do
36647   char[#char+1]=format("<%02X> <%s>",k,v)
36648  end
36649  char=concat(char,"\n")
36650  local stream=format(template,id,id,#char,char)
36651  local reference=flushstreamobject(stream,nil,true)
36652  setfontattributes(id,format("/ToUnicode %i 0 R",reference))
36653 end
36654end
36655do
36656 local everywhere={ ["*"]={ ["*"]=true } } 
36657 local noflags={ false,false,false,false }
36658 local function enhance_normalize_features(data)
36659  local ligatures=setmetatableindex("table")
36660  local kerns=setmetatableindex("table")
36661  local characters=data.characters
36662  for u,c in next,characters do
36663   local l=c.ligatures
36664   local k=c.kerns
36665   if l then
36666    ligatures[u]=l
36667    for u,v in next,l do
36668     l[u]={ ligature=v.char }
36669    end
36670    c.ligatures=nil
36671   end
36672   if k then
36673    kerns[u]=k
36674    for u,v in next,k do
36675     k[u]=v 
36676    end
36677    c.kerns=nil
36678   end
36679  end
36680  for u,l in next,ligatures do
36681   for k,v in next,l do
36682    local vl=v.ligature
36683    local dl=ligatures[vl]
36684    if dl then
36685     for kk,vv in next,dl do
36686      v[kk]=vv 
36687     end
36688    end
36689   end
36690  end
36691  local features={
36692   gpos={},
36693   gsub={},
36694  }
36695  local sequences={
36696  }
36697  if next(ligatures) then
36698   features.gsub.liga=everywhere
36699   data.properties.hasligatures=true
36700   sequences[#sequences+1]={
36701    features={
36702     liga=everywhere,
36703    },
36704    flags=noflags,
36705    name="s_s_0",
36706    nofsteps=1,
36707    order={ "liga" },
36708    type="gsub_ligature",
36709    steps={
36710     {
36711      coverage=ligatures,
36712     },
36713    },
36714   }
36715  end
36716  if next(kerns) then
36717   features.gpos.kern=everywhere
36718   data.properties.haskerns=true
36719   sequences[#sequences+1]={
36720    features={
36721     kern=everywhere,
36722    },
36723    flags=noflags,
36724    name="p_s_0",
36725    nofsteps=1,
36726    order={ "kern" },
36727    type="gpos_pair",
36728    steps={
36729     {
36730      format="kern",
36731      coverage=kerns,
36732     },
36733    },
36734   }
36735  end
36736  data.resources.features=features
36737  data.resources.sequences=sequences
36738  data.shared.resources=data.shared.resources or resources
36739 end
36740 registertfmenhancer("normalize features",enhance_normalize_features)
36741 registertfmenhancer("check extra features",otfenhancers.enhance)
36742end
36743registertfmfeature {
36744 name="mode",
36745 description="mode",
36746 initializers={
36747  base=otf.modeinitializer,
36748  node=otf.modeinitializer,
36749 }
36750}
36751registertfmfeature {
36752 name="features",
36753 description="features",
36754 default=true,
36755 initializers={
36756  base=otf.basemodeinitializer,
36757  node=otf.nodemodeinitializer,
36758 },
36759 processors={
36760  node=otf.featuresprocessor,
36761 }
36762}
36763
36764end -- closure
36765
36766do -- begin closure to overcome local limits and interference
36767
36768if not modules then modules={} end modules ['font-lua']={
36769 version=1.001,
36770 comment="companion to font-ini.mkiv",
36771 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
36772 copyright="PRAGMA ADE / ConTeXt Development Team",
36773 license="see context related readme files"
36774}
36775local trace_defining=false  trackers.register("fonts.defining",function(v) trace_defining=v end)
36776local report_lua=logs.reporter("fonts","lua loading")
36777local fonts=fonts
36778local readers=fonts.readers
36779fonts.formats.lua="lua"
36780local function check_lua(specification,fullname)
36781 local fullname=resolvers.findfile(fullname) or ""
36782 if fullname~="" then
36783  local loader=loadfile(fullname)
36784  loader=loader and loader()
36785  return loader and loader(specification)
36786 end
36787end
36788readers.check_lua=check_lua
36789function readers.lua(specification)
36790 local original=specification.specification
36791 if trace_defining then
36792  report_lua("using lua reader for %a",original)
36793 end
36794 local fullname=specification.filename or ""
36795 if fullname=="" then
36796  local forced=specification.forced or ""
36797  if forced~="" then
36798   fullname=specification.name.."."..forced
36799  else
36800   fullname=specification.name
36801  end
36802 end
36803 return check_lua(specification,fullname)
36804end
36805
36806end -- closure
36807
36808do -- begin closure to overcome local limits and interference
36809
36810if not modules then modules={} end modules ['font-def']={
36811 version=1.001,
36812 comment="companion to font-ini.mkiv",
36813 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
36814 copyright="PRAGMA ADE / ConTeXt Development Team",
36815 license="see context related readme files"
36816}
36817local lower,gsub=string.lower,string.gsub
36818local tostring,next=tostring,next
36819local lpegmatch=lpeg.match
36820local suffixonly,removesuffix,basename=file.suffix,file.removesuffix,file.basename
36821local formatters=string.formatters
36822local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
36823local allocate=utilities.storage.allocate
36824local trace_defining=false  trackers  .register("fonts.defining",function(v) trace_defining=v end)
36825local directive_embedall=false  directives.register("fonts.embedall",function(v) directive_embedall=v end)
36826trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading")
36827local report_defining=logs.reporter("fonts","defining")
36828local fonts=fonts
36829local fontdata=fonts.hashes.identifiers
36830local readers=fonts.readers
36831local definers=fonts.definers
36832local specifiers=fonts.specifiers
36833local constructors=fonts.constructors
36834local fontgoodies=fonts.goodies
36835readers.sequence=allocate { 'otf','ttf','afm','tfm','lua' } 
36836local variants=allocate()
36837specifiers.variants=variants
36838definers.methods=definers.methods or {}
36839local internalized=allocate() 
36840local loadedfonts=constructors.loadedfonts
36841local designsizes=constructors.designsizes
36842local resolvefile=fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end
36843local function makespecification(specification,lookup,name,sub,method,detail,size)
36844 size=size or 655360
36845 if not lookup or lookup=="" then
36846  lookup=definers.defaultlookup
36847 end
36848 if trace_defining then
36849  report_defining("specification %a, lookup %a, name %a, sub %a, method %a, detail %a",
36850   specification,lookup,name,sub,method,detail)
36851 end
36852 local t={
36853  lookup=lookup,
36854  specification=specification,
36855  size=size,
36856  name=name,
36857  sub=sub,
36858  method=method,
36859  detail=detail,
36860  resolved="",
36861  forced="",
36862  features={},
36863 }
36864 return t
36865end
36866definers.makespecification=makespecification
36867if context then
36868
36869--removed
36870
36871end
36872definers.resolvers=definers.resolvers or {}
36873local resolvers=definers.resolvers
36874function resolvers.file(specification)
36875 local name=resolvefile(specification.name) 
36876 local suffix=lower(suffixonly(name))
36877 if fonts.formats[suffix] then
36878  specification.forced=suffix
36879  specification.forcedname=name
36880  specification.name=removesuffix(name)
36881 else
36882  specification.name=name 
36883 end
36884end
36885function resolvers.name(specification)
36886 local resolve=fonts.names.resolve
36887 if resolve then
36888  local resolved,sub,subindex,instance=resolve(specification.name,specification.sub,specification) 
36889  if resolved then
36890   specification.resolved=resolved
36891   specification.sub=sub
36892   specification.subindex=subindex
36893   if instance then
36894    specification.instance=instance
36895    local features=specification.features
36896    if not features then
36897     features={}
36898     specification.features=features
36899    end
36900    local normal=features.normal
36901    if not normal then
36902     normal={}
36903     features.normal=normal
36904    end
36905    normal.instance=instance
36906   end
36907   local suffix=lower(suffixonly(resolved))
36908   if fonts.formats[suffix] then
36909    specification.forced=suffix
36910    specification.forcedname=resolved
36911    specification.name=removesuffix(resolved)
36912   else
36913    specification.name=resolved
36914   end
36915  end
36916 else
36917  resolvers.file(specification)
36918 end
36919end
36920function resolvers.spec(specification)
36921 local resolvespec=fonts.names.resolvespec
36922 if resolvespec then
36923  local resolved,sub,subindex=resolvespec(specification.name,specification.sub,specification) 
36924  if resolved then
36925   specification.resolved=resolved
36926   specification.sub=sub
36927   specification.subindex=subindex
36928   specification.forced=lower(suffixonly(resolved))
36929   specification.forcedname=resolved
36930   specification.name=removesuffix(resolved)
36931  end
36932 else
36933  resolvers.name(specification)
36934 end
36935end
36936function definers.resolve(specification)
36937 if not specification.resolved or specification.resolved=="" then 
36938  local r=resolvers[specification.lookup]
36939  if r then
36940   r(specification)
36941  end
36942 end
36943 if specification.forced=="" then
36944  specification.forced=nil
36945  specification.forcedname=nil
36946 end
36947 specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification))
36948 if specification.sub and specification.sub~="" then
36949  specification.hash=specification.sub..' @ '..specification.hash
36950 end
36951 return specification
36952end
36953function definers.applypostprocessors(tfmdata)
36954 local postprocessors=tfmdata.postprocessors
36955 if postprocessors then
36956  local properties=tfmdata.properties
36957  for i=1,#postprocessors do
36958   local extrahash=postprocessors[i](tfmdata) 
36959   if type(extrahash)=="string" and extrahash~="" then
36960    extrahash=gsub(lower(extrahash),"[^a-z]","-")
36961    properties.fullname=formatters["%s-%s"](properties.fullname,extrahash)
36962   end
36963  end
36964 end
36965 return tfmdata
36966end
36967local function checkembedding(tfmdata)
36968 local properties=tfmdata.properties
36969 local embedding
36970 if directive_embedall then
36971  embedding="full"
36972 elseif properties and properties.filename and constructors.dontembed[properties.filename] then
36973  embedding="no"
36974 else
36975  embedding="subset"
36976 end
36977 if properties then
36978  properties.embedding=embedding
36979 else
36980  tfmdata.properties={ embedding=embedding }
36981 end
36982 tfmdata.embedding=embedding
36983end
36984local function checkfeatures(tfmdata)
36985 local resources=tfmdata.resources
36986 local shared=tfmdata.shared
36987 if resources and shared then
36988  local features=resources.features
36989  local usedfeatures=shared.features
36990  if features and usedfeatures then
36991   local usedlanguage=usedfeatures.language or "dflt"
36992   local usedscript=usedfeatures.script or "dflt"
36993   local function check(what)
36994    if what then
36995     local foundlanguages={}
36996     for feature,scripts in next,what do
36997      if usedscript=="auto" or scripts["*"] then
36998      elseif not scripts[usedscript] then
36999      else
37000       for script,languages in next,scripts do
37001        if languages["*"] then
37002        elseif context and not languages[usedlanguage] then
37003         report_defining("font %!font:name!, feature %a, script %a, no language %a",
37004          tfmdata,feature,script,usedlanguage)
37005        end
37006       end
37007      end
37008      for script,languages in next,scripts do
37009       for language in next,languages do
37010        foundlanguages[language]=true
37011       end
37012      end
37013     end
37014     if false then
37015      foundlanguages["*"]=nil
37016      foundlanguages=sortedkeys(foundlanguages)
37017      for feature,scripts in sortedhash(what) do
37018       for script,languages in next,scripts do
37019        if not languages["*"] then
37020         for i=1,#foundlanguages do
37021          local language=foundlanguages[i]
37022          if context and not languages[language] then
37023           report_defining("font %!font:name!, feature %a, script %a, no language %a",
37024            tfmdata,feature,script,language)
37025          end
37026         end
37027        end
37028       end
37029      end
37030     end
37031    end
37032   end
37033   check(features.gsub)
37034   check(features.gpos)
37035  end
37036 end
37037end
37038function definers.loadfont(specification)
37039 local hash=constructors.hashinstance(specification)
37040 local tfmdata=loadedfonts[hash] 
37041 if not tfmdata then
37042  local forced=specification.forced or ""
37043  if forced~="" then
37044   local reader=readers[lower(forced)] 
37045   tfmdata=reader and reader(specification)
37046   if not tfmdata then
37047    report_defining("forced type %a of %a not found",forced,specification.name)
37048   end
37049  else
37050   local sequence=readers.sequence 
37051   for s=1,#sequence do
37052    local reader=sequence[s]
37053    if readers[reader] then 
37054     if trace_defining then
37055      report_defining("trying (reader sequence driven) type %a for %a with file %a",reader,specification.name,specification.filename)
37056     end
37057     tfmdata=readers[reader](specification)
37058     if tfmdata then
37059      break
37060     else
37061      specification.filename=nil
37062     end
37063    end
37064   end
37065  end
37066  if tfmdata then
37067   tfmdata=definers.applypostprocessors(tfmdata)
37068   checkembedding(tfmdata) 
37069   loadedfonts[hash]=tfmdata
37070   designsizes[specification.hash]=tfmdata.parameters.designsize
37071   checkfeatures(tfmdata)
37072  end
37073 end
37074 if not tfmdata then
37075  report_defining("font with asked name %a is not found using lookup %a",specification.name,specification.lookup)
37076 end
37077 return tfmdata
37078end
37079function constructors.readanddefine(name,size) 
37080 local specification=definers.analyze(name,size)
37081 local method=specification.method
37082 if method and variants[method] then
37083  specification=variants[method](specification)
37084 end
37085 specification=definers.resolve(specification)
37086 local hash=constructors.hashinstance(specification)
37087 local id=definers.registered(hash)
37088 if not id then
37089  local tfmdata=definers.loadfont(specification)
37090  if tfmdata then
37091   tfmdata.properties.hash=hash
37092   id=font.define(tfmdata)
37093   definers.register(tfmdata,id)
37094  else
37095   id=0  
37096  end
37097 end
37098 return fontdata[id],id
37099end
37100function definers.registered(hash)
37101 local id=internalized[hash]
37102 return id,id and fontdata[id]
37103end
37104function definers.register(tfmdata,id)
37105 if tfmdata and id then
37106  local hash=tfmdata.properties.hash
37107  if not hash then
37108   report_defining("registering font, id %a, name %a, invalid hash",id,tfmdata.properties.filename or "?")
37109  elseif not internalized[hash] then
37110   internalized[hash]=id
37111   if trace_defining then
37112    report_defining("registering font, id %s, hash %a",id,hash)
37113   end
37114   fontdata[id]=tfmdata
37115  end
37116 end
37117end
37118function definers.read(specification,size,id) 
37119 statistics.starttiming(fonts)
37120 if type(specification)=="string" then
37121  specification=definers.analyze(specification,size)
37122 end
37123 local method=specification.method
37124 if method and variants[method] then
37125  specification=variants[method](specification)
37126 end
37127 specification=definers.resolve(specification)
37128 local hash=constructors.hashinstance(specification)
37129 local tfmdata=definers.registered(hash) 
37130 if tfmdata then
37131  if trace_defining then
37132   report_defining("already hashed: %s",hash)
37133  end
37134 else
37135  tfmdata=definers.loadfont(specification)
37136  if tfmdata then
37137   tfmdata.original=specification.specification
37138   if trace_defining then
37139    report_defining("loaded and hashed: %s",hash)
37140   end
37141   tfmdata.properties.hash=hash
37142   if id then
37143    definers.register(tfmdata,id)
37144   end
37145  else
37146   if trace_defining then
37147    report_defining("not loaded and hashed: %s",hash)
37148   end
37149  end
37150 end
37151 if not tfmdata then 
37152  report_defining("unknown font %a, loading aborted",specification.name)
37153 elseif trace_defining and type(tfmdata)=="table" then
37154  local properties=tfmdata.properties or {}
37155  local parameters=tfmdata.parameters or {}
37156  report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
37157   properties.format or "unknown",id or "-",properties.name,parameters.size,properties.encodingbytes,
37158   properties.encodingname,properties.fullname,basename(properties.filename))
37159 end
37160 statistics.stoptiming(fonts)
37161 return tfmdata
37162end
37163function font.getfont(id)
37164 return fontdata[id] 
37165end
37166if not context then
37167 callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)")
37168end
37169
37170end -- closure
37171
37172do -- begin closure to overcome local limits and interference
37173
37174if not modules then modules={} end modules ['font-shp']={
37175 version=1.001,
37176 comment="companion to font-ini.mkiv",
37177 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
37178 copyright="PRAGMA ADE / ConTeXt Development Team",
37179 license="see context related readme files"
37180}
37181local tonumber,next=tonumber,next
37182local concat=table.concat
37183local formatters,lower=string.formatters,string.lower
37184local otf=fonts.handlers.otf
37185local afm=fonts.handlers.afm
37186local pfb=fonts.handlers.pfb
37187local hashes=fonts.hashes
37188local identifiers=hashes.identifiers
37189local version=otf.version or 0.015
37190local shapescache=containers.define("fonts","shapes",version,true)
37191local streamscache=containers.define("fonts","streams",version,true)
37192local compact_streams=false
37193directives.register("fonts.streams.compact",function(v) compact_streams=v end)
37194local function packoutlines(data,makesequence)
37195 local subfonts=data.subfonts
37196 if subfonts then
37197  for i=1,#subfonts do
37198   packoutlines(subfonts[i],makesequence)
37199  end
37200  return
37201 end
37202 local common=data.segments
37203 if common then
37204  return
37205 end
37206 local glyphs=data.glyphs
37207 if not glyphs then
37208  return
37209 end
37210 if makesequence then
37211  for index=0,#glyphs do
37212   local glyph=glyphs[index]
37213   if glyph then
37214    local segments=glyph.segments
37215    if segments then
37216     local sequence={}
37217     local nofsequence=0
37218     for i=1,#segments do
37219      local segment=segments[i]
37220      local nofsegment=#segment
37221      nofsequence=nofsequence+1
37222      sequence[nofsequence]=segment[nofsegment]
37223      for i=1,nofsegment-1 do
37224       nofsequence=nofsequence+1
37225       sequence[nofsequence]=segment[i]
37226      end
37227     end
37228     glyph.sequence=sequence
37229     glyph.segments=nil
37230    end
37231   end
37232  end
37233 else
37234  local hash={}
37235  local common={}
37236  local reverse={}
37237  local last=0
37238  for index=0,#glyphs do
37239   local glyph=glyphs[index]
37240   if glyph then
37241    local segments=glyph.segments
37242    if segments then
37243     for i=1,#segments do
37244      local h=concat(segments[i]," ")
37245      hash[h]=(hash[h] or 0)+1
37246     end
37247    end
37248   end
37249  end
37250  for index=0,#glyphs do
37251   local glyph=glyphs[index]
37252   if glyph then
37253    local segments=glyph.segments
37254    if segments then
37255     for i=1,#segments do
37256      local segment=segments[i]
37257      local h=concat(segment," ")
37258      if hash[h]>1 then 
37259       local idx=reverse[h]
37260       if not idx then
37261        last=last+1
37262        reverse[h]=last
37263        common[last]=segment
37264        idx=last
37265       end
37266       segments[i]=idx
37267      end
37268     end
37269    end
37270   end
37271  end
37272  if last>0 then
37273   data.segments=common
37274  end
37275 end
37276end
37277local function unpackoutlines(data)
37278 local subfonts=data.subfonts
37279 if subfonts then
37280  for i=1,#subfonts do
37281   unpackoutlines(subfonts[i])
37282  end
37283  return
37284 end
37285 local common=data.segments
37286 if not common then
37287  return
37288 end
37289 local glyphs=data.glyphs
37290 if not glyphs then
37291  return
37292 end
37293 for index=0,#glyphs do
37294  local glyph=glyphs[index]
37295  if glyph then
37296   local segments=glyph.segments
37297   if segments then
37298    for i=1,#segments do
37299     local c=common[segments[i]]
37300     if c then
37301      segments[i]=c
37302     end
37303    end
37304   end
37305  end
37306 end
37307 data.segments=nil
37308end
37309local readers=otf.readers
37310local cleanname=otf.readers.helpers.cleanname
37311local function makehash(filename,sub,instance)
37312 local name=cleanname(file.basename(filename))
37313 if instance then
37314  return formatters["%s-%s-%s"](name,sub or 0,cleanname(instance))
37315 else
37316  return formatters["%s-%s"]   (name,sub or 0)
37317 end
37318end
37319local function loadoutlines(cache,filename,sub,instance)
37320 local base=file.basename(filename)
37321 local name=file.removesuffix(base)
37322 local kind=file.suffix(filename)
37323 local attr=lfs.attributes(filename)
37324 local size=attr and attr.size or 0
37325 local time=attr and attr.modification or 0
37326 local sub=tonumber(sub)
37327 if size>0 and (kind=="otf" or kind=="ttf" or kind=="tcc") then
37328  local hash=makehash(filename,sub,instance)
37329  data=containers.read(cache,hash)
37330  if not data or data.time~=time or data.size~=size then
37331   data=otf.readers.loadshapes(filename,sub,instance)
37332   if data then
37333    data.size=size
37334    data.format=data.format or (kind=="otf" and "opentype") or "truetype"
37335    data.time=time
37336    packoutlines(data)
37337    containers.write(cache,hash,data)
37338    data=containers.read(cache,hash) 
37339   end
37340  end
37341  unpackoutlines(data)
37342 elseif size>0 and (kind=="pfb") then
37343  local hash=containers.cleanname(base) 
37344  data=containers.read(cache,hash)
37345  if not data or data.time~=time or data.size~=size then
37346   data=afm.readers.loadshapes(filename)
37347   if data then
37348    data.size=size
37349    data.format="type1"
37350    data.time=time
37351    packoutlines(data)
37352    containers.write(cache,hash,data)
37353    data=containers.read(cache,hash) 
37354   end
37355  end
37356  unpackoutlines(data)
37357 else
37358  data={
37359   filename=filename,
37360   size=0,
37361   time=time,
37362   format="unknown",
37363   units=1000,
37364   glyphs={}
37365  }
37366 end
37367 return data
37368end
37369local function cachethem(cache,hash,data)
37370 containers.write(cache,hash,data,compact_streams) 
37371 return containers.read(cache,hash) 
37372end
37373local function loadstreams(cache,filename,sub,instance)
37374 local base=file.basename(filename)
37375 local name=file.removesuffix(base)
37376 local kind=lower(file.suffix(filename))
37377 local attr=lfs.attributes(filename)
37378 local size=attr and attr.size or 0
37379 local time=attr and attr.modification or 0
37380 local sub=tonumber(sub)
37381 if size>0 and (kind=="otf" or kind=="ttf" or kind=="ttc") then
37382  local hash=makehash(filename,sub,instance)
37383  data=containers.read(cache,hash)
37384  if not data or data.time~=time or data.size~=size then
37385   data=otf.readers.loadshapes(filename,sub,instance,true)
37386   if data then
37387    local glyphs=data.glyphs
37388    local streams={}
37389    if glyphs then
37390     for i=0,#glyphs do
37391      local glyph=glyphs[i]
37392      if glyph then
37393       streams[i]=glyph.stream or ""
37394      else
37395       streams[i]=""
37396      end
37397     end
37398    end
37399    data.streams=streams
37400    data.glyphs=nil
37401    data.size=size
37402    data.format=data.format or (kind=="otf" and "opentype") or "truetype"
37403    data.time=time
37404    data=cachethem(cache,hash,data)
37405   end
37406  end
37407 elseif size>0 and (kind=="pfb") then
37408  local hash=makehash(filename,sub,instance)
37409  data=containers.read(cache,hash)
37410  if not data or data.time~=time or data.size~=size then
37411   local names,encoding,streams,metadata=pfb.loadvector(filename,false,true)
37412   if streams then
37413    local fontbbox=metadata.fontbbox or { 0,0,0,0 }
37414    for i=0,#streams do
37415     local s=streams[i]
37416     streams[i]=s.stream or "\14"
37417    end
37418    data={
37419     filename=filename,
37420     size=size,
37421     time=time,
37422     format="type1",
37423     streams=streams,
37424     fontheader={
37425      fontversion=metadata.version,
37426      units=1000,
37427      xmin=fontbbox[1],
37428      ymin=fontbbox[2],
37429      xmax=fontbbox[3],
37430      ymax=fontbbox[4],
37431     },
37432     horizontalheader={
37433      ascender=0,
37434      descender=0,
37435     },
37436     maximumprofile={
37437      nofglyphs=#streams+1,
37438     },
37439     names={
37440      copyright=metadata.copyright,
37441      family=metadata.familyname,
37442      fullname=metadata.fullname,
37443      fontname=metadata.fontname,
37444      subfamily=metadata.subfamilyname,
37445      trademark=metadata.trademark,
37446      notice=metadata.notice,
37447      version=metadata.version,
37448     },
37449     cffinfo={
37450      familyname=metadata.familyname,
37451      fullname=metadata.fullname,
37452      italicangle=metadata.italicangle,
37453      monospaced=metadata.isfixedpitch and true or false,
37454      underlineposition=metadata.underlineposition,
37455      underlinethickness=metadata.underlinethickness,
37456      weight=metadata.weight,
37457     },
37458    }
37459    data=cachethem(cache,hash,data)
37460   end
37461  end
37462 else
37463  data={
37464   filename=filename,
37465   size=0,
37466   time=time,
37467   format="unknown",
37468   streams={}
37469  }
37470 end
37471 return data
37472end
37473local loadedshapes={}
37474local loadedstreams={}
37475local function loadoutlinedata(fontdata,streams)
37476 local properties=fontdata.properties
37477 local filename=properties.filename
37478 local subindex=fontdata.subindex
37479 local instance=properties.instance
37480 local hash=makehash(filename,subindex,instance)
37481 local loaded=loadedshapes[hash]
37482 if not loaded then
37483  loaded=loadoutlines(shapescache,filename,subindex,instance)
37484  loadedshapes[hash]=loaded
37485 end
37486 return loaded
37487end
37488hashes.shapes=table.setmetatableindex(function(t,k)
37489 local f=identifiers[k]
37490 if f then
37491  return loadoutlinedata(f)
37492 end
37493end)
37494local function getstreamhash(fontid)
37495 local fontdata=identifiers[fontid]
37496 if fontdata then
37497  local properties=fontdata.properties
37498  local fonthash=makehash(properties.filename,properties.subfont,properties.instance)
37499  return fonthash,fontdata
37500 end
37501end
37502local function loadstreamdata(fontdata)
37503 local properties=fontdata.properties
37504 local shared=fontdata.shared
37505 local rawdata=shared and shared.rawdata
37506 local metadata=rawdata and rawdata.metadata
37507 local filename=properties.filename
37508 local subindex=metadata and metadata.subfontindex
37509 local instance=properties.instance
37510 local hash=makehash(filename,subindex,instance)
37511 local loaded=loadedstreams[hash]
37512 if not loaded then
37513  loaded=loadstreams(streamscache,filename,subindex,instance)
37514  loadedstreams[hash]=loaded
37515 end
37516 return loaded
37517end
37518hashes.streams=table.setmetatableindex(function(t,k)
37519 local f=identifiers[k]
37520 if f then
37521  return loadstreamdata(f)
37522 end
37523end)
37524otf.loadoutlinedata=loadoutlinedata 
37525otf.loadstreamdata=loadstreamdata  
37526otf.loadshapes=loadshapes
37527otf.getstreamhash=getstreamhash   
37528local streams=fonts.hashes.streams
37529callback.register("glyph_stream_provider",function(id,index,mode)
37530 if id>0 then
37531  local streams=streams[id].streams
37532  if streams then
37533   return streams[index] or ""
37534  end
37535 end
37536 return ""
37537end)
37538
37539end -- closure
37540
37541do -- begin closure to overcome local limits and interference
37542
37543if not modules then modules={} end modules ['luatex-fonts-def']={
37544 version=1.001,
37545 comment="companion to luatex-*.tex",
37546 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
37547 copyright="PRAGMA ADE / ConTeXt Development Team",
37548 license="see context related readme files"
37549}
37550if context then
37551--removed
37552
37553end
37554local fonts=fonts
37555fonts.constructors.namemode="specification"
37556function fonts.definers.getspecification(str)
37557 return "",str,"",":",str
37558end
37559local list={} 
37560local function issome () list.lookup='name'    end 
37561local function isfile () list.lookup='file'    end
37562local function isname () list.lookup='name'    end
37563local function thename(s)   list.name=s      end
37564local function issub  (v)   list.sub=v      end
37565local function iscrap (s)   list.crap=string.lower(s) end
37566local function iskey  (k,v) list[k]=v      end
37567local function istrue (s)   list[s]=true   end
37568local function isfalse(s)   list[s]=false     end
37569local P,S,R,C,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs
37570local spaces=P(" ")^0
37571local namespec=Cs((P("{")/"")*(1-S("}"))^0*(P("}")/"")+(1-S("/:("))^0)
37572local crapspec=spaces*P("/")*(((1-P(":"))^0)/iscrap)*spaces
37573local filename_1=P("file:")/isfile*(namespec/thename)
37574local filename_2=P("[")*P(true)/isfile*(((1-P("]"))^0)/thename)*P("]")
37575local fontname_1=P("name:")/isname*(namespec/thename)
37576local fontname_2=P(true)/issome*(namespec/thename)
37577local sometext=R("az","AZ","09")^1
37578local somekey=R("az","AZ","09")^1
37579local somevalue=(P("{")/"")*(1-P("}"))^0*(P("}")/"")+(1-S(";"))^1
37580local truevalue=P("+")*spaces*(sometext/istrue)
37581local falsevalue=P("-")*spaces*(sometext/isfalse)
37582local keyvalue=(C(somekey)*spaces*P("=")*spaces*C(somevalue))/iskey
37583local somevalue=sometext/istrue
37584local subvalue=P("(")*(C(P(1-S("()"))^1)/issub)*P(")") 
37585local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces
37586local options=P(":")*spaces*(P(";")^0*option)^0
37587local pattern=(filename_1+filename_2+fontname_1+fontname_2)*subvalue^0*crapspec^0*options^0
37588function fonts.definers.analyze(str,size)
37589 local specification=fonts.definers.makespecification(str,nil,nil,nil,":",nil,size)
37590 list={}
37591 lpeg.match(pattern,str)
37592 list.crap=nil
37593 if list.name then
37594  specification.name=list.name
37595  list.name=nil
37596 end
37597 if list.lookup then
37598  specification.lookup=list.lookup
37599  list.lookup=nil
37600 end
37601 if list.sub then
37602  specification.sub=list.sub
37603  list.sub=nil
37604 end
37605 specification.features.normal=fonts.handlers.otf.features.normalize(list)
37606 list=nil
37607 return specification
37608end
37609function fonts.definers.applypostprocessors(tfmdata)
37610 local postprocessors=tfmdata.postprocessors
37611 if postprocessors then
37612  for i=1,#postprocessors do
37613   local extrahash=postprocessors[i](tfmdata) 
37614   if type(extrahash)=="string" and extrahash~="" then
37615    extrahash=string.gsub(lower(extrahash),"[^a-z]","-")
37616    tfmdata.properties.fullname=format("%s-%s",tfmdata.properties.fullname,extrahash)
37617   end
37618  end
37619 end
37620 return tfmdata
37621end
37622
37623end -- closure
37624
37625do -- begin closure to overcome local limits and interference
37626
37627if not modules then modules={} end modules ['luatex-fonts-ext']={
37628 version=1.001,
37629 comment="companion to luatex-*.tex",
37630 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
37631 copyright="PRAGMA ADE / ConTeXt Development Team",
37632 license="see context related readme files"
37633}
37634if context then
37635--removed
37636
37637end
37638local byte=string.byte
37639local fonts=fonts
37640local handlers=fonts.handlers
37641local otf=handlers.otf
37642local afm=handlers.afm
37643local registerotffeature=otf.features.register
37644local registerafmfeature=afm.features.register
37645function fonts.loggers.onetimemessage() end
37646fonts.protrusions=fonts.protrusions  or {}
37647fonts.protrusions.setups=fonts.protrusions.setups or {}
37648local setups=fonts.protrusions.setups
37649setups['default']={ 
37650 factor=1,
37651 left=1,
37652 right=1,
37653 [0x002C]={ 0,1 },
37654 [0x002E]={ 0,1 },
37655 [0x003A]={ 0,1 },
37656 [0x003B]={ 0,1 },
37657 [0x002D]={ 0,1 },
37658 [0x2013]={ 0,0.50 },
37659 [0x2014]={ 0,0.33 },
37660 [0x3001]={ 0,1 },
37661 [0x3002]={ 0,1 },
37662 [0x060C]={ 0,1 },
37663 [0x061B]={ 0,1 },
37664 [0x06D4]={ 0,1 },
37665}
37666local function initializeprotrusion(tfmdata,value)
37667 if value then
37668  local setup=setups[value]
37669  if setup then
37670   local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1
37671   local emwidth=tfmdata.parameters.quad
37672   tfmdata.parameters.protrusion={
37673    auto=true,
37674   }
37675   for i,chr in next,tfmdata.characters do
37676    local v,pl,pr=setup[i],nil,nil
37677    if v then
37678     pl,pr=v[1],v[2]
37679    end
37680    if pl and pl~=0 then chr.left_protruding=left*pl*factor end
37681    if pr and pr~=0 then chr.right_protruding=right*pr*factor end
37682   end
37683  end
37684 end
37685end
37686local specification={
37687 name="protrusion",
37688 description="shift characters into the left and or right margin",
37689 initializers={
37690  base=initializeprotrusion,
37691  node=initializeprotrusion,
37692 }
37693}
37694registerotffeature(specification)
37695registerafmfeature(specification)
37696fonts.expansions=fonts.expansions  or {}
37697fonts.expansions.setups=fonts.expansions.setups or {}
37698local setups=fonts.expansions.setups
37699setups['default']={ 
37700 stretch=2,
37701 shrink=2,
37702 step=.5,
37703 factor=1,
37704 [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
37705 [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
37706 [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
37707 [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
37708 [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
37709 [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
37710 [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
37711 [byte('w')]=0.7,[byte('z')]=0.7,
37712 [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
37713}
37714local function initializeexpansion(tfmdata,value)
37715 if value then
37716  local setup=setups[value]
37717  if setup then
37718   local factor=setup.factor or 1
37719   tfmdata.parameters.expansion={
37720    stretch=10*(setup.stretch or 0),
37721    shrink=10*(setup.shrink  or 0),
37722    step=10*(setup.step or 0),
37723    auto=true,
37724   }
37725   for i,chr in next,tfmdata.characters do
37726    local v=setup[i]
37727    if v and v~=0 then
37728     chr.expansion_factor=v*factor
37729    else 
37730     chr.expansion_factor=factor
37731    end
37732   end
37733  end
37734 end
37735end
37736local specification={
37737 name="expansion",
37738 description="apply hz optimization",
37739 initializers={
37740  base=initializeexpansion,
37741  node=initializeexpansion,
37742 }
37743}
37744registerotffeature(specification)
37745registerafmfeature(specification)
37746if not otf.features.normalize then
37747 otf.features.normalize=function(t)
37748  if t.rand then
37749   t.rand="random"
37750  end
37751  return t
37752 end
37753end
37754function fonts.helpers.nametoslot(name)
37755 local t=type(name)
37756 if t=="string" then
37757  local tfmdata=fonts.hashes.identifiers[currentfont()]
37758  local shared=tfmdata and tfmdata.shared
37759  local fntdata=shared and shared.rawdata
37760  return fntdata and fntdata.resources.unicodes[name]
37761 elseif t=="number" then
37762  return n
37763 end
37764end
37765fonts.encodings=fonts.encodings or {}
37766local reencodings={}
37767fonts.encodings.reencodings=reencodings
37768local function specialreencode(tfmdata,value)
37769 local encoding=value and reencodings[value]
37770 if encoding then
37771  local temp={}
37772  local char=tfmdata.characters
37773  for k,v in next,encoding do
37774   temp[k]=char[v]
37775  end
37776  for k,v in next,temp do
37777   char[k]=temp[k]
37778  end
37779  return string.format("reencoded:%s",value)
37780 end
37781end
37782local function initialize(tfmdata,value)
37783 tfmdata.postprocessors=tfmdata.postprocessors or {}
37784 table.insert(tfmdata.postprocessors,
37785  function(tfmdata)
37786   return specialreencode(tfmdata,value)
37787  end
37788 )
37789end
37790registerotffeature {
37791 name="reencode",
37792 description="reencode characters",
37793 manipulators={
37794  base=initialize,
37795  node=initialize,
37796 }
37797}
37798local function initialize(tfmdata,key,value)
37799 if value then
37800  tfmdata.mathparameters=nil
37801 end
37802end
37803registerotffeature {
37804 name="ignoremathconstants",
37805 description="ignore math constants table",
37806 initializers={
37807  base=initialize,
37808  node=initialize,
37809 }
37810}
37811
37812end -- closure
37813
37814do -- begin closure to overcome local limits and interference
37815
37816if not modules then modules={} end modules ['font-imp-tex']={
37817 version=1.001,
37818 comment="companion to font-ini.mkiv",
37819 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
37820 copyright="PRAGMA ADE / ConTeXt Development Team",
37821 license="see context related readme files"
37822}
37823local next=next
37824local fonts=fonts
37825local otf=fonts.handlers.otf
37826local registerotffeature=otf.features.register
37827local addotffeature=otf.addfeature
37828local tlig={
37829 type="ligature",
37830 order={ "tlig" },
37831 prepend=true,
37832 data={
37833  [0x2013]={ 0x002D,0x002D },
37834  [0x2014]={ 0x002D,0x002D,0x002D },
37835 },
37836}
37837local tquo={
37838 type="ligature",
37839 order={ "tquo" },
37840 prepend=true,
37841 data={
37842  [0x201C]={ 0x0060,0x0060 },
37843  [0x201D]={ 0x0027,0x0027 },
37844  [0x201E]={ 0x002C,0x002C },
37845 },
37846}
37847local trep={
37848 type="substitution",
37849 order={ "trep" },
37850 prepend=true,
37851 data={
37852  [0x0027]=0x2019,
37853 },
37854}
37855addotffeature("trep",trep) 
37856addotffeature("tlig",tlig)
37857addotffeature("tquo",tquo) 
37858registerotffeature { name="tlig",description="tex ligatures" }
37859registerotffeature { name="tquo",description="tex quotes" }
37860registerotffeature { name="trep",description="tex replacements" }
37861local anum_arabic={
37862 [0x0030]=0x0660,
37863 [0x0031]=0x0661,
37864 [0x0032]=0x0662,
37865 [0x0033]=0x0663,
37866 [0x0034]=0x0664,
37867 [0x0035]=0x0665,
37868 [0x0036]=0x0666,
37869 [0x0037]=0x0667,
37870 [0x0038]=0x0668,
37871 [0x0039]=0x0669,
37872}
37873local anum_persian={
37874 [0x0030]=0x06F0,
37875 [0x0031]=0x06F1,
37876 [0x0032]=0x06F2,
37877 [0x0033]=0x06F3,
37878 [0x0034]=0x06F4,
37879 [0x0035]=0x06F5,
37880 [0x0036]=0x06F6,
37881 [0x0037]=0x06F7,
37882 [0x0038]=0x06F8,
37883 [0x0039]=0x06F9,
37884}
37885local function valid(data)
37886 local features=data.resources.features
37887 if features then
37888  for k,v in next,features do
37889   for k,v in next,v do
37890    if v.arab then
37891     return true
37892    end
37893   end
37894  end
37895 end
37896end
37897local specification={
37898 {
37899  type="substitution",
37900  features={ arab={ urd=true,dflt=true } },
37901  order={ "anum" },
37902  data=anum_arabic,
37903  valid=valid,
37904 },
37905 {
37906  type="substitution",
37907  features={ arab={ urd=true } },
37908  order={ "anum" },
37909  data=anum_persian,
37910  valid=valid,
37911 },
37912}
37913addotffeature("anum",specification)
37914registerotffeature {
37915 name="anum",
37916 description="arabic digits",
37917}
37918
37919end -- closure
37920
37921do -- begin closure to overcome local limits and interference
37922
37923if not modules then modules={} end modules ['font-imp-ligatures']={
37924 version=1.001,
37925 comment="companion to font-ini.mkiv",
37926 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
37927 copyright="PRAGMA ADE / ConTeXt Development Team",
37928 license="see context related readme files"
37929}
37930local lpegmatch=lpeg.match
37931local utfsplit=utf.split
37932local settings_to_array=utilities.parsers.settings_to_array
37933local fonts=fonts
37934local otf=fonts.handlers.otf
37935local registerotffeature=otf.features.register
37936local addotffeature=otf.addfeature
37937local lookups={}
37938local protect={}
37939local revert={}
37940local zwjchar=0x200C
37941local zwj={ zwjchar }
37942addotffeature {
37943 name="blockligatures",
37944 type="chainsubstitution",
37945 nocheck=true,
37946 prepend=true,
37947 future=true,
37948 lookups={
37949  {
37950   type="multiple",
37951   data=lookups,
37952  },
37953 },
37954 data={
37955  rules=protect,
37956 }
37957}
37958addotffeature {
37959 name="blockligatures",
37960 type="chainsubstitution",
37961 nocheck=true,
37962 append=true,
37963 overload=false,
37964 lookups={
37965  {
37966   type="ligature",
37967   data=lookups,
37968  },
37969 },
37970 data={
37971  rules=revert,
37972 }
37973}
37974registerotffeature {
37975 name='blockligatures',
37976 description='block certain ligatures',
37977}
37978local splitter=lpeg.splitat(":")
37979local function blockligatures(str)
37980 local t=settings_to_array(str)
37981 for i=1,#t do
37982  local ti=t[i]
37983  local before,current,after=lpegmatch(splitter,ti)
37984  if current and after then
37985   if before then
37986    before=utfsplit(before)
37987    for i=1,#before do
37988     before[i]={ before[i] }
37989    end
37990   end
37991   if current then
37992    current=utfsplit(current)
37993   end
37994   if after then
37995    after=utfsplit(after)
37996    for i=1,#after do
37997     after[i]={ after[i] }
37998    end
37999   end
38000  else
38001   before=nil
38002   current=utfsplit(ti)
38003   after=nil
38004  end
38005  if #current>1 then
38006   local one=current[1]
38007   local two=current[2]
38008   lookups[one]={ one,zwjchar }
38009   local one={ one }
38010   local two={ two }
38011   local new=#protect+1
38012   protect[new]={
38013    before=before,
38014    current={ one,two },
38015    after=after,
38016    lookups={ 1,false },
38017   }
38018   revert[new]={
38019    current={ one,zwj },
38020    after={ two },
38021    lookups={ 1,false },
38022   }
38023  end
38024 end
38025end
38026otf.helpers.blockligatures=blockligatures
38027if context then
38028
38029--removed
38030
38031end
38032
38033end -- closure
38034
38035do -- begin closure to overcome local limits and interference
38036
38037if not modules then modules={} end modules ['font-imp-italics']={
38038 version=1.001,
38039 comment="companion to font-ini.mkiv and hand-ini.mkiv",
38040 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
38041 copyright="PRAGMA ADE / ConTeXt Development Team",
38042 license="see context related readme files"
38043}
38044local next,tonumber=next,tonumber
38045local fonts=fonts
38046local handlers=fonts.handlers
38047local registerotffeature=handlers.otf.features.register
38048local registerafmfeature=handlers.afm.features.register
38049local function initialize(tfmdata,value) 
38050 if value then
38051  local parameters=tfmdata.parameters
38052  local italicangle=parameters.italicangle
38053  if italicangle and italicangle~=0 then
38054   local properties=tfmdata.properties
38055   local factor=tonumber(value) or 1
38056   properties.hasitalics=true
38057   properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
38058  end
38059 end
38060end
38061local specification={
38062 name="itlc",
38063 description="italic correction",
38064 initializers={
38065  base=initialize,
38066  node=initialize,
38067 }
38068}
38069registerotffeature(specification)
38070registerafmfeature(specification)
38071if context then
38072
38073--removed
38074
38075end
38076
38077end -- closure
38078
38079do -- begin closure to overcome local limits and interference
38080
38081if not modules then modules={} end modules ['font-imp-effects']={
38082 version=1.001,
38083 comment="companion to font-ini.mkiv",
38084 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
38085 copyright="PRAGMA ADE / ConTeXt Development Team",
38086 license="see context related readme files"
38087}
38088local next,type,tonumber=next,type,tonumber
38089local is_boolean=string.is_boolean
38090local fonts=fonts
38091local handlers=fonts.handlers
38092local registerotffeature=handlers.otf.features.register
38093local registerafmfeature=handlers.afm.features.register
38094local settings_to_hash=utilities.parsers.settings_to_hash_colon_too
38095local helpers=fonts.helpers
38096local prependcommands=helpers.prependcommands
38097local charcommand=helpers.commands.char
38098local leftcommand=helpers.commands.left
38099local rightcommand=helpers.commands.right
38100local upcommand=helpers.commands.up
38101local downcommand=helpers.commands.down
38102local dummycommand=helpers.commands.dummy
38103local report_effect=logs.reporter("fonts","effect")
38104local report_slant=logs.reporter("fonts","slant")
38105local report_extend=logs.reporter("fonts","extend")
38106local report_squeeze=logs.reporter("fonts","squeeze")
38107local trace=false
38108trackers.register("fonts.effect",function(v) trace=v end)
38109trackers.register("fonts.slant",function(v) trace=v end)
38110trackers.register("fonts.extend",function(v) trace=v end)
38111trackers.register("fonts.squeeze",function(v) trace=v end)
38112local function initializeslant(tfmdata,value)
38113 value=tonumber(value)
38114 if not value then
38115  value=0
38116 elseif value>1 then
38117  value=1
38118 elseif value<-1 then
38119  value=-1
38120 end
38121 if trace then
38122  report_slant("applying %0.3f",value)
38123 end
38124 tfmdata.parameters.slantfactor=value
38125end
38126local specification={
38127 name="slant",
38128 description="slant glyphs",
38129 initializers={
38130  base=initializeslant,
38131  node=initializeslant,
38132 }
38133}
38134registerotffeature(specification)
38135registerafmfeature(specification)
38136local function initializeextend(tfmdata,value)
38137 value=tonumber(value)
38138 if not value then
38139  value=0
38140 elseif value>10 then
38141  value=10
38142 elseif value<-10 then
38143  value=-10
38144 end
38145 if trace then
38146  report_extend("applying %0.3f",value)
38147 end
38148 tfmdata.parameters.extendfactor=value
38149end
38150local specification={
38151 name="extend",
38152 description="scale glyphs horizontally",
38153 initializers={
38154  base=initializeextend,
38155  node=initializeextend,
38156 }
38157}
38158registerotffeature(specification)
38159registerafmfeature(specification)
38160local function initializesqueeze(tfmdata,value)
38161 value=tonumber(value)
38162 if not value then
38163  value=0
38164 elseif value>10 then
38165  value=10
38166 elseif value<-10 then
38167  value=-10
38168 end
38169 if trace then
38170  report_squeeze("applying %0.3f",value)
38171 end
38172 tfmdata.parameters.squeezefactor=value
38173end
38174local specification={
38175 name="squeeze",
38176 description="scale glyphs vertically",
38177 initializers={
38178  base=initializesqueeze,
38179  node=initializesqueeze,
38180 }
38181}
38182registerotffeature(specification)
38183registerafmfeature(specification)
38184local effects={
38185 inner=0,
38186 normal=0,
38187 outer=1,
38188 outline=1,
38189 both=2,
38190 hidden=3,
38191}
38192local function initializeeffect(tfmdata,value)
38193 local spec
38194 if type(value)=="number" then
38195  spec={ width=value }
38196 else
38197  spec=settings_to_hash(value)
38198 end
38199 local effect=spec.effect or "both"
38200 local width=tonumber(spec.width) or 0
38201 local mode=effects[effect]
38202 if not mode then
38203  report_effect("invalid effect %a",effect)
38204 elseif width==0 and mode==0 then
38205  report_effect("invalid width %a for effect %a",width,effect)
38206 else
38207  local parameters=tfmdata.parameters
38208  local properties=tfmdata.properties
38209  parameters.mode=mode
38210  parameters.width=width*1000
38211  if is_boolean(spec.auto)==true then
38212   local squeeze=1-width/20
38213   local average=(1-squeeze)*width*100
38214   spec.squeeze=squeeze
38215   spec.extend=1+width/2
38216   spec.wdelta=average
38217   spec.hdelta=average/2
38218   spec.ddelta=average/2
38219   spec.vshift=average/2
38220  end
38221  local factor=tonumber(spec.factor)  or 0
38222  local hfactor=tonumber(spec.hfactor) or factor
38223  local vfactor=tonumber(spec.vfactor) or factor
38224  local delta=tonumber(spec.delta)   or 1
38225  local wdelta=tonumber(spec.wdelta)  or delta
38226  local hdelta=tonumber(spec.hdelta)  or delta
38227  local ddelta=tonumber(spec.ddelta)  or hdelta
38228  local vshift=tonumber(spec.vshift)  or 0
38229  local slant=spec.slant
38230  local extend=spec.extend
38231  local squeeze=spec.squeeze
38232  if slant then
38233   initializeslant(tfmdata,slant)
38234  end
38235  if extend then
38236   initializeextend(tfmdata,extend)
38237  end
38238  if squeeze then
38239   initializesqueeze(tfmdata,squeeze)
38240  end
38241  properties.effect={
38242   effect=effect,
38243   width=width,
38244   factor=factor,
38245   hfactor=hfactor,
38246   vfactor=vfactor,
38247   wdelta=wdelta,
38248   hdelta=hdelta,
38249   ddelta=ddelta,
38250   vshift=vshift,
38251   slant=tfmdata.parameters.slantfactor,
38252   extend=tfmdata.parameters.extendfactor,
38253   squeeze=tfmdata.parameters.squeezefactor,
38254  }
38255 end
38256end
38257local rules={
38258 "RadicalRuleThickness",
38259 "OverbarRuleThickness",
38260 "FractionRuleThickness",
38261 "UnderbarRuleThickness",
38262}
38263local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier)
38264 if dy~=0 then
38265  for i=1,#rules do
38266   local name=rules[i]
38267   local value=mathparameters[name]
38268   if value then
38269      mathparameters[name]=(squeeze or 1)*(value+dy)
38270   end
38271  end
38272 end
38273end
38274local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
38275 local function wdpatch(char)
38276  if wsnap~=0 then
38277   char.width=char.width+wdelta/2
38278  end
38279 end
38280 local function htpatch(char)
38281  if hsnap~=0 then
38282   local height=char.height
38283   if height then
38284    char.height=char.height+2*dy
38285   end
38286  end
38287 end
38288 local character=characters[0x221A]
38289 if character and character.next then
38290  local char=character
38291  local next=character.next
38292  wdpatch(char)
38293  htpatch(char)
38294  while next do
38295   char=characters[next]
38296   wdpatch(char)
38297   htpatch(char)
38298   next=char.next
38299  end
38300  if char then
38301   local v=char.vert_variants
38302   if v then
38303    local top=v[#v]
38304    if top then
38305     local char=characters[top.glyph]
38306     htpatch(char)
38307    end
38308   end
38309  end
38310 end
38311end
38312local function manipulateeffect(tfmdata)
38313 local effect=tfmdata.properties.effect
38314 if effect then
38315  local characters=tfmdata.characters
38316  local parameters=tfmdata.parameters
38317  local mathparameters=tfmdata.mathparameters
38318  local multiplier=effect.width*100
38319  local factor=parameters.factor
38320  local hfactor=parameters.hfactor
38321  local vfactor=parameters.vfactor
38322  local wdelta=effect.wdelta*hfactor*multiplier
38323  local hdelta=effect.hdelta*vfactor*multiplier
38324  local ddelta=effect.ddelta*vfactor*multiplier
38325  local vshift=effect.vshift*vfactor*multiplier
38326  local squeeze=effect.squeeze
38327  local hshift=wdelta/2
38328  local dx=multiplier*vfactor
38329  local dy=vshift
38330  local factor=(1+effect.factor)*factor
38331  local hfactor=(1+effect.hfactor)*hfactor
38332  local vfactor=(1+effect.vfactor)*vfactor
38333  vshift=vshift~=0 and upcommand[vshift] or false
38334  hshift=rightcommand[hshift]
38335  for unicode,character in next,characters do
38336   local oldwidth=character.width
38337   local oldheight=character.height
38338   local olddepth=character.depth
38339   if oldwidth and oldwidth>0 then
38340    character.width=oldwidth+wdelta
38341    local commands=character.commands
38342    if vshift then
38343     if commands then
38344      prependcommands (commands,
38345       hshift,
38346       vshift
38347      )
38348     else
38349      character.commands={
38350       hshift,
38351       vshift,
38352       charcommand[unicode]
38353      }
38354     end
38355    else
38356     if commands then
38357       prependcommands (commands,
38358        hshift
38359       )
38360     else
38361      character.commands={
38362       hshift,
38363       charcommand[unicode]
38364       }
38365     end
38366    end
38367   end
38368   if oldheight and oldheight>0 then
38369      character.height=oldheight+hdelta
38370   end
38371   if olddepth and olddepth>0 then
38372      character.depth=olddepth+ddelta
38373   end
38374  end
38375  if mathparameters then
38376   setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze,multiplier)
38377   setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
38378  end
38379  parameters.factor=factor
38380  parameters.hfactor=hfactor
38381  parameters.vfactor=vfactor
38382  if trace then
38383   report_effect("applying")
38384   report_effect("  effect  : %s",effect.effect)
38385   report_effect("  width   : %s => %s",effect.width,multiplier)
38386   report_effect("  factor  : %s => %s",effect.factor,factor )
38387   report_effect("  hfactor : %s => %s",effect.hfactor,hfactor)
38388   report_effect("  vfactor : %s => %s",effect.vfactor,vfactor)
38389   report_effect("  wdelta  : %s => %s",effect.wdelta,wdelta)
38390   report_effect("  hdelta  : %s => %s",effect.hdelta,hdelta)
38391   report_effect("  ddelta  : %s => %s",effect.ddelta,ddelta)
38392  end
38393 end
38394end
38395local specification={
38396 name="effect",
38397 description="apply effects to glyphs",
38398 initializers={
38399  base=initializeeffect,
38400  node=initializeeffect,
38401 },
38402 manipulators={
38403  base=manipulateeffect,
38404  node=manipulateeffect,
38405 },
38406}
38407registerotffeature(specification)
38408registerafmfeature(specification)
38409local function initializeoutline(tfmdata,value)
38410 value=tonumber(value)
38411 if not value then
38412  value=0
38413 else
38414  value=tonumber(value) or 0
38415 end
38416 local parameters=tfmdata.parameters
38417 local properties=tfmdata.properties
38418 parameters.mode=effects.outline
38419 parameters.width=value*1000
38420 properties.effect={
38421  effect=effect,
38422  width=width,
38423 }
38424end
38425local specification={
38426 name="outline",
38427 description="outline glyphs",
38428 initializers={
38429  base=initializeoutline,
38430  node=initializeoutline,
38431 }
38432}
38433registerotffeature(specification)
38434registerafmfeature(specification)
38435
38436end -- closure
38437
38438do -- begin closure to overcome local limits and interference
38439
38440
38441fonts.handlers.otf.addfeature {
38442 ["dataset"]={
38443  {
38444   ["data"]={
38445 ["À"]={ "A","̀" },
38446 ["Á"]={ "A","́" },
38447 ["Â"]={ "A","̂" },
38448 ["Ã"]={ "A","̃" },
38449 ["Ä"]={ "A","̈" },
38450 ["Å"]={ "A","̊" },
38451 ["Ç"]={ "C","̧" },
38452 ["È"]={ "E","̀" },
38453 ["É"]={ "E","́" },
38454 ["Ê"]={ "E","̂" },
38455 ["Ë"]={ "E","̈" },
38456 ["Ì"]={ "I","̀" },
38457 ["Í"]={ "I","́" },
38458 ["Î"]={ "I","̂" },
38459 ["Ï"]={ "I","̈" },
38460 ["Ñ"]={ "N","̃" },
38461 ["Ò"]={ "O","̀" },
38462 ["Ó"]={ "O","́" },
38463 ["Ô"]={ "O","̂" },
38464 ["Õ"]={ "O","̃" },
38465 ["Ö"]={ "O","̈" },
38466 ["Ù"]={ "U","̀" },
38467 ["Ú"]={ "U","́" },
38468 ["Û"]={ "U","̂" },
38469 ["Ü"]={ "U","̈" },
38470 ["Ý"]={ "Y","́" },
38471 ["à"]={ "a","̀" },
38472 ["á"]={ "a","́" },
38473 ["â"]={ "a","̂" },
38474 ["ã"]={ "a","̃" },
38475 ["ä"]={ "a","̈" },
38476 ["å"]={ "a","̊" },
38477 ["ç"]={ "c","̧" },
38478 ["è"]={ "e","̀" },
38479 ["é"]={ "e","́" },
38480 ["ê"]={ "e","̂" },
38481 ["ë"]={ "e","̈" },
38482 ["ì"]={ "i","̀" },
38483 ["í"]={ "i","́" },
38484 ["î"]={ "i","̂" },
38485 ["ï"]={ "i","̈" },
38486 ["ñ"]={ "n","̃" },
38487 ["ò"]={ "o","̀" },
38488 ["ó"]={ "o","́" },
38489 ["ô"]={ "o","̂" },
38490 ["õ"]={ "o","̃" },
38491 ["ö"]={ "o","̈" },
38492 ["ù"]={ "u","̀" },
38493 ["ú"]={ "u","́" },
38494 ["û"]={ "u","̂" },
38495 ["ü"]={ "u","̈" },
38496 ["ý"]={ "y","́" },
38497 ["ÿ"]={ "y","̈" },
38498 ["Ā"]={ "A","̄" },
38499 ["ā"]={ "a","̄" },
38500 ["Ă"]={ "A","̆" },
38501 ["ă"]={ "a","̆" },
38502 ["Ą"]={ "A","̨" },
38503 ["ą"]={ "a","̨" },
38504 ["Ć"]={ "C","́" },
38505 ["ć"]={ "c","́" },
38506 ["Ĉ"]={ "C","̂" },
38507 ["ĉ"]={ "c","̂" },
38508 ["Ċ"]={ "C","̇" },
38509 ["ċ"]={ "c","̇" },
38510 ["Č"]={ "C","̌" },
38511 ["č"]={ "c","̌" },
38512 ["Ď"]={ "D","̌" },
38513 ["ď"]={ "d","̌" },
38514 ["Ē"]={ "E","̄" },
38515 ["ē"]={ "e","̄" },
38516 ["Ĕ"]={ "E","̆" },
38517 ["ĕ"]={ "e","̆" },
38518 ["Ė"]={ "E","̇" },
38519 ["ė"]={ "e","̇" },
38520 ["Ę"]={ "E","̨" },
38521 ["ę"]={ "e","̨" },
38522 ["Ě"]={ "E","̌" },
38523 ["ě"]={ "e","̌" },
38524 ["Ĝ"]={ "G","̂" },
38525 ["ĝ"]={ "g","̂" },
38526 ["Ğ"]={ "G","̆" },
38527 ["ğ"]={ "g","̆" },
38528 ["Ġ"]={ "G","̇" },
38529 ["ġ"]={ "g","̇" },
38530 ["Ģ"]={ "G","̧" },
38531 ["ģ"]={ "g","̧" },
38532 ["Ĥ"]={ "H","̂" },
38533 ["ĥ"]={ "h","̂" },
38534 ["Ĩ"]={ "I","̃" },
38535 ["ĩ"]={ "i","̃" },
38536 ["Ī"]={ "I","̄" },
38537 ["ī"]={ "i","̄" },
38538 ["Ĭ"]={ "I","̆" },
38539 ["ĭ"]={ "i","̆" },
38540 ["Į"]={ "I","̨" },
38541 ["į"]={ "i","̨" },
38542 ["İ"]={ "I","̇" },
38543 ["Ĵ"]={ "J","̂" },
38544 ["ĵ"]={ "j","̂" },
38545 ["Ķ"]={ "K","̧" },
38546 ["ķ"]={ "k","̧" },
38547 ["Ĺ"]={ "L","́" },
38548 ["ĺ"]={ "l","́" },
38549 ["Ļ"]={ "L","̧" },
38550 ["ļ"]={ "l","̧" },
38551 ["Ľ"]={ "L","̌" },
38552 ["ľ"]={ "l","̌" },
38553 ["Ń"]={ "N","́" },
38554 ["ń"]={ "n","́" },
38555 ["Ņ"]={ "N","̧" },
38556 ["ņ"]={ "n","̧" },
38557 ["Ň"]={ "N","̌" },
38558 ["ň"]={ "n","̌" },
38559 ["Ō"]={ "O","̄" },
38560 ["ō"]={ "o","̄" },
38561 ["Ŏ"]={ "O","̆" },
38562 ["ŏ"]={ "o","̆" },
38563 ["Ő"]={ "O","̋" },
38564 ["ő"]={ "o","̋" },
38565 ["Ŕ"]={ "R","́" },
38566 ["ŕ"]={ "r","́" },
38567 ["Ŗ"]={ "R","̧" },
38568 ["ŗ"]={ "r","̧" },
38569 ["Ř"]={ "R","̌" },
38570 ["ř"]={ "r","̌" },
38571 ["Ś"]={ "S","́" },
38572 ["ś"]={ "s","́" },
38573 ["Ŝ"]={ "S","̂" },
38574 ["ŝ"]={ "s","̂" },
38575 ["Ş"]={ "S","̧" },
38576 ["ş"]={ "s","̧" },
38577 ["Š"]={ "S","̌" },
38578 ["š"]={ "s","̌" },
38579 ["Ţ"]={ "T","̧" },
38580 ["ţ"]={ "t","̧" },
38581 ["Ť"]={ "T","̌" },
38582 ["ť"]={ "t","̌" },
38583 ["Ũ"]={ "U","̃" },
38584 ["ũ"]={ "u","̃" },
38585 ["Ū"]={ "U","̄" },
38586 ["ū"]={ "u","̄" },
38587 ["Ŭ"]={ "U","̆" },
38588 ["ŭ"]={ "u","̆" },
38589 ["Ů"]={ "U","̊" },
38590 ["ů"]={ "u","̊" },
38591 ["Ű"]={ "U","̋" },
38592 ["ű"]={ "u","̋" },
38593 ["Ų"]={ "U","̨" },
38594 ["ų"]={ "u","̨" },
38595 ["Ŵ"]={ "W","̂" },
38596 ["ŵ"]={ "w","̂" },
38597 ["Ŷ"]={ "Y","̂" },
38598 ["ŷ"]={ "y","̂" },
38599 ["Ÿ"]={ "Y","̈" },
38600 ["Ź"]={ "Z","́" },
38601 ["ź"]={ "z","́" },
38602 ["Ż"]={ "Z","̇" },
38603 ["ż"]={ "z","̇" },
38604 ["Ž"]={ "Z","̌" },
38605 ["ž"]={ "z","̌" },
38606 ["Ơ"]={ "O","̛" },
38607 ["ơ"]={ "o","̛" },
38608 ["Ư"]={ "U","̛" },
38609 ["ư"]={ "u","̛" },
38610 ["Ǎ"]={ "A","̌" },
38611 ["ǎ"]={ "a","̌" },
38612 ["Ǐ"]={ "I","̌" },
38613 ["ǐ"]={ "i","̌" },
38614 ["Ǒ"]={ "O","̌" },
38615 ["ǒ"]={ "o","̌" },
38616 ["Ǔ"]={ "U","̌" },
38617 ["ǔ"]={ "u","̌" },
38618 ["Ǖ"]={ "Ü","̄" },
38619 ["ǖ"]={ "ü","̄" },
38620 ["Ǘ"]={ "Ü","́" },
38621 ["ǘ"]={ "ü","́" },
38622 ["Ǚ"]={ "Ü","̌" },
38623 ["ǚ"]={ "ü","̌" },
38624 ["Ǜ"]={ "Ü","̀" },
38625 ["ǜ"]={ "ü","̀" },
38626 ["Ǟ"]={ "Ä","̄" },
38627 ["ǟ"]={ "ä","̄" },
38628 ["Ǡ"]={ "Ȧ","̄" },
38629 ["ǡ"]={ "ȧ","̄" },
38630 ["Ǣ"]={ "Æ","̄" },
38631 ["ǣ"]={ "æ","̄" },
38632 ["Ǧ"]={ "G","̌" },
38633 ["ǧ"]={ "g","̌" },
38634 ["Ǩ"]={ "K","̌" },
38635 ["ǩ"]={ "k","̌" },
38636 ["Ǫ"]={ "O","̨" },
38637 ["ǫ"]={ "o","̨" },
38638 ["Ǭ"]={ "Ǫ","̄" },
38639 ["ǭ"]={ "ǫ","̄" },
38640 ["Ǯ"]={ "Ʒ","̌" },
38641 ["ǯ"]={ "ʒ","̌" },
38642 ["ǰ"]={ "j","̌" },
38643 ["Ǵ"]={ "G","́" },
38644 ["ǵ"]={ "g","́" },
38645 ["Ǹ"]={ "N","̀" },
38646 ["ǹ"]={ "n","̀" },
38647 ["Ǻ"]={ "Å","́" },
38648 ["ǻ"]={ "å","́" },
38649 ["Ǽ"]={ "Æ","́" },
38650 ["ǽ"]={ "æ","́" },
38651 ["Ǿ"]={ "Ø","́" },
38652 ["ǿ"]={ "ø","́" },
38653 ["Ȁ"]={ "A","̏" },
38654 ["ȁ"]={ "a","̏" },
38655 ["Ȃ"]={ "A","̑" },
38656 ["ȃ"]={ "a","̑" },
38657 ["Ȅ"]={ "E","̏" },
38658 ["ȅ"]={ "e","̏" },
38659 ["Ȇ"]={ "E","̑" },
38660 ["ȇ"]={ "e","̑" },
38661 ["Ȉ"]={ "I","̏" },
38662 ["ȉ"]={ "i","̏" },
38663 ["Ȋ"]={ "I","̑" },
38664 ["ȋ"]={ "i","̑" },
38665 ["Ȍ"]={ "O","̏" },
38666 ["ȍ"]={ "o","̏" },
38667 ["Ȏ"]={ "O","̑" },
38668 ["ȏ"]={ "o","̑" },
38669 ["Ȑ"]={ "R","̏" },
38670 ["ȑ"]={ "r","̏" },
38671 ["Ȓ"]={ "R","̑" },
38672 ["ȓ"]={ "r","̑" },
38673 ["Ȕ"]={ "U","̏" },
38674 ["ȕ"]={ "u","̏" },
38675 ["Ȗ"]={ "U","̑" },
38676 ["ȗ"]={ "u","̑" },
38677 ["Ș"]={ "S","̦" },
38678 ["ș"]={ "s","̦" },
38679 ["Ț"]={ "T","̦" },
38680 ["ț"]={ "t","̦" },
38681 ["Ȟ"]={ "H","̌" },
38682 ["ȟ"]={ "h","̌" },
38683 ["Ȧ"]={ "A","̇" },
38684 ["ȧ"]={ "a","̇" },
38685 ["Ȩ"]={ "E","̧" },
38686 ["ȩ"]={ "e","̧" },
38687 ["Ȫ"]={ "Ö","̄" },
38688 ["ȫ"]={ "ö","̄" },
38689 ["Ȭ"]={ "Õ","̄" },
38690 ["ȭ"]={ "õ","̄" },
38691 ["Ȯ"]={ "O","̇" },
38692 ["ȯ"]={ "o","̇" },
38693 ["Ȱ"]={ "Ȯ","̄" },
38694 ["ȱ"]={ "ȯ","̄" },
38695 ["Ȳ"]={ "Y","̄" },
38696 ["ȳ"]={ "y","̄" },
38697 ["̈́"]={ "̈","́" },
38698 ["΅"]={ "¨","́" },
38699 ["Ά"]={ "Α","́" },
38700 ["Έ"]={ "Ε","́" },
38701 ["Ή"]={ "Η","́" },
38702 ["Ί"]={ "Ι","́" },
38703 ["Ό"]={ "Ο","́" },
38704 ["Ύ"]={ "Υ","́" },
38705 ["Ώ"]={ "Ω","́" },
38706 ["ΐ"]={ "ϊ","́" },
38707 ["Ϊ"]={ "Ι","̈" },
38708 ["Ϋ"]={ "Υ","̈" },
38709 ["ά"]={ "α","́" },
38710 ["έ"]={ "ε","́" },
38711 ["ή"]={ "η","́" },
38712 ["ί"]={ "ι","́" },
38713 ["ΰ"]={ "ϋ","́" },
38714 ["ϊ"]={ "ι","̈" },
38715 ["ϋ"]={ "υ","̈" },
38716 ["ό"]={ "ο","́" },
38717 ["ύ"]={ "υ","́" },
38718 ["ώ"]={ "ω","́" },
38719 ["ϓ"]={ "ϒ","́" },
38720 ["ϔ"]={ "ϒ","̈" },
38721 ["Ѐ"]={ "Е","̀" },
38722 ["Ё"]={ "Е","̈" },
38723 ["Ѓ"]={ "Г","́" },
38724 ["Ї"]={ "І","̈" },
38725 ["Ќ"]={ "К","́" },
38726 ["Ѝ"]={ "И","̀" },
38727 ["Ў"]={ "У","̆" },
38728 ["Й"]={ "И","̆" },
38729 ["й"]={ "и","̆" },
38730 ["ѐ"]={ "е","̀" },
38731 ["ё"]={ "е","̈" },
38732 ["ѓ"]={ "г","́" },
38733 ["ї"]={ "і","̈" },
38734 ["ќ"]={ "к","́" },
38735 ["ѝ"]={ "и","̀" },
38736 ["ў"]={ "у","̆" },
38737 ["Ѷ"]={ "Ѵ","̏" },
38738 ["ѷ"]={ "ѵ","̏" },
38739 ["Ӂ"]={ "Ж","̆" },
38740 ["ӂ"]={ "ж","̆" },
38741 ["Ӑ"]={ "А","̆" },
38742 ["ӑ"]={ "а","̆" },
38743 ["Ӓ"]={ "А","̈" },
38744 ["ӓ"]={ "а","̈" },
38745 ["Ӗ"]={ "Е","̆" },
38746 ["ӗ"]={ "е","̆" },
38747 ["Ӛ"]={ "Ә","̈" },
38748 ["ӛ"]={ "ә","̈" },
38749 ["Ӝ"]={ "Ж","̈" },
38750 ["ӝ"]={ "ж","̈" },
38751 ["Ӟ"]={ "З","̈" },
38752 ["ӟ"]={ "з","̈" },
38753 ["Ӣ"]={ "И","̄" },
38754 ["ӣ"]={ "и","̄" },
38755 ["Ӥ"]={ "И","̈" },
38756 ["ӥ"]={ "и","̈" },
38757 ["Ӧ"]={ "О","̈" },
38758 ["ӧ"]={ "о","̈" },
38759 ["Ӫ"]={ "Ө","̈" },
38760 ["ӫ"]={ "ө","̈" },
38761 ["Ӭ"]={ "Э","̈" },
38762 ["ӭ"]={ "э","̈" },
38763 ["Ӯ"]={ "У","̄" },
38764 ["ӯ"]={ "у","̄" },
38765 ["Ӱ"]={ "У","̈" },
38766 ["ӱ"]={ "у","̈" },
38767 ["Ӳ"]={ "У","̋" },
38768 ["ӳ"]={ "у","̋" },
38769 ["Ӵ"]={ "Ч","̈" },
38770 ["ӵ"]={ "ч","̈" },
38771 ["Ӹ"]={ "Ы","̈" },
38772 ["ӹ"]={ "ы","̈" },
38773 ["آ"]={ "ا","ٓ" },
38774 ["أ"]={ "ا","ٔ" },
38775 ["ؤ"]={ "و","ٔ" },
38776 ["إ"]={ "ا","ٕ" },
38777 ["ئ"]={ "ي","ٔ" },
38778 ["ۀ"]={ "ە","ٔ" },
38779 ["ۂ"]={ "ہ","ٔ" },
38780 ["ۓ"]={ "ے","ٔ" },
38781 [""]={ "","" },
38782 [""]={ "","" },
38783 [""]={ "","" },
38784 [""]={ "","" },
38785 [""]={ "","" },
38786 [""]={ "","" },
38787 [""]={ "","" },
38788 [""]={ "","" },
38789 [""]={ "","" },
38790 [""]={ "","" },
38791 [""]={ "","" },
38792 [""]={ "","" },
38793 [""]={ "","" },
38794 [""]={ "","" },
38795 [""]={ "","" },
38796 [""]={ "","" },
38797 [""]={ "","" },
38798 [""]={ "","" },
38799 [""]={ "","" },
38800 [""]={ "","" },
38801 [""]={ "","" },
38802 [""]={ "","" },
38803 [""]={ "","" },
38804 [""]={ "","" },
38805 [""]={ "","" },
38806 [""]={ "","" },
38807 [""]={ "","" },
38808 [""]={ "","" },
38809 [""]={ "","" },
38810 [""]={ "","" },
38811 [""]={ "","" },
38812 [""]={ "","" },
38813 [""]={ "ಿ","" },
38814 [""]={ "","" },
38815 [""]={ "","" },
38816 [""]={ "","" },
38817 [""]={ "","" },
38818 [""]={ "","" },
38819 [""]={ "","" },
38820 [""]={ "","" },
38821 [""]={ "","" },
38822 [""]={ "","" },
38823 [""]={ "","" },
38824 [""]={ "","" },
38825 [""]={ "","" },
38826 [""]={ "","" },
38827 [""]={ "","" },
38828 [""]={ "","" },
38829 [""]={ "","" },
38830 [""]={ "","" },
38831 [""]={ "","" },
38832 [""]={ "","" },
38833 [""]={ "","" },
38834 [""]={ "","" },
38835 [""]={ "","" },
38836 [""]={ "","" },
38837 [""]={ "","" },
38838 [""]={ "","" },
38839 [""]={ "","" },
38840 [""]={ "","" },
38841 [""]={ "","" },
38842 [""]={ "","" },
38843 [""]={ "","" },
38844 [""]={ "","" },
38845 [""]={ "","" },
38846 [""]={ "","" },
38847 [""]={ "","" },
38848 [""]={ "","" },
38849 [""]={ "","" },
38850 [""]={ "","" },
38851 [""]={ "","" },
38852 [""]={ "ᬿ","" },
38853 [""]={ "","" },
38854 [""]={ "A","̥" },
38855 [""]={ "a","̥" },
38856 [""]={ "B","̇" },
38857 [""]={ "b","̇" },
38858 [""]={ "B","̣" },
38859 [""]={ "b","̣" },
38860 [""]={ "B","̱" },
38861 [""]={ "b","̱" },
38862 [""]={ "Ç","́" },
38863 [""]={ "ç","́" },
38864 [""]={ "D","̇" },
38865 [""]={ "d","̇" },
38866 [""]={ "D","̣" },
38867 [""]={ "d","̣" },
38868 [""]={ "D","̱" },
38869 [""]={ "d","̱" },
38870 [""]={ "D","̧" },
38871 [""]={ "d","̧" },
38872 [""]={ "D","̭" },
38873 [""]={ "d","̭" },
38874 [""]={ "Ē","̀" },
38875 [""]={ "ē","̀" },
38876 [""]={ "Ē","́" },
38877 [""]={ "ē","́" },
38878 [""]={ "E","̭" },
38879 [""]={ "e","̭" },
38880 [""]={ "E","̰" },
38881 [""]={ "e","̰" },
38882 [""]={ "Ȩ","̆" },
38883 [""]={ "ȩ","̆" },
38884 [""]={ "F","̇" },
38885 [""]={ "f","̇" },
38886 [""]={ "G","̄" },
38887 [""]={ "g","̄" },
38888 [""]={ "H","̇" },
38889 [""]={ "h","̇" },
38890 [""]={ "H","̣" },
38891 [""]={ "h","̣" },
38892 [""]={ "H","̈" },
38893 [""]={ "h","̈" },
38894 [""]={ "H","̧" },
38895 [""]={ "h","̧" },
38896 [""]={ "H","̮" },
38897 [""]={ "h","̮" },
38898 [""]={ "I","̰" },
38899 [""]={ "i","̰" },
38900 [""]={ "Ï","́" },
38901 [""]={ "ï","́" },
38902 [""]={ "K","́" },
38903 [""]={ "k","́" },
38904 [""]={ "K","̣" },
38905 [""]={ "k","̣" },
38906 [""]={ "K","̱" },
38907 [""]={ "k","̱" },
38908 [""]={ "L","̣" },
38909 [""]={ "l","̣" },
38910 [""]={ "","̄" },
38911 [""]={ "","̄" },
38912 [""]={ "L","̱" },
38913 [""]={ "l","̱" },
38914 [""]={ "L","̭" },
38915 [""]={ "l","̭" },
38916 [""]={ "M","́" },
38917 ["ḿ"]={ "m","́" },
38918 [""]={ "M","̇" },
38919 [""]={ "m","̇" },
38920 [""]={ "M","̣" },
38921 [""]={ "m","̣" },
38922 [""]={ "N","̇" },
38923 [""]={ "n","̇" },
38924 [""]={ "N","̣" },
38925 [""]={ "n","̣" },
38926 [""]={ "N","̱" },
38927 [""]={ "n","̱" },
38928 [""]={ "N","̭" },
38929 [""]={ "n","̭" },
38930 [""]={ "Õ","́" },
38931 [""]={ "õ","́" },
38932 [""]={ "Õ","̈" },
38933 [""]={ "õ","̈" },
38934 [""]={ "Ō","̀" },
38935 [""]={ "ō","̀" },
38936 [""]={ "Ō","́" },
38937 [""]={ "ō","́" },
38938 [""]={ "P","́" },
38939 [""]={ "p","́" },
38940 [""]={ "P","̇" },
38941 [""]={ "p","̇" },
38942 [""]={ "R","̇" },
38943 [""]={ "r","̇" },
38944 [""]={ "R","̣" },
38945 [""]={ "r","̣" },
38946 [""]={ "","̄" },
38947 [""]={ "","̄" },
38948 [""]={ "R","̱" },
38949 [""]={ "r","̱" },
38950 [""]={ "S","̇" },
38951 [""]={ "s","̇" },
38952 [""]={ "S","̣" },
38953 [""]={ "s","̣" },
38954 [""]={ "Ś","̇" },
38955 [""]={ "ś","̇" },
38956 [""]={ "Š","̇" },
38957 [""]={ "š","̇" },
38958 [""]={ "","̇" },
38959 [""]={ "","̇" },
38960 [""]={ "T","̇" },
38961 [""]={ "t","̇" },
38962 [""]={ "T","̣" },
38963 [""]={ "t","̣" },
38964 [""]={ "T","̱" },
38965 [""]={ "t","̱" },
38966 [""]={ "T","̭" },
38967 [""]={ "t","̭" },
38968 [""]={ "U","̤" },
38969 [""]={ "u","̤" },
38970 [""]={ "U","̰" },
38971 [""]={ "u","̰" },
38972 [""]={ "U","̭" },
38973 [""]={ "u","̭" },
38974 [""]={ "Ũ","́" },
38975 [""]={ "ũ","́" },
38976 [""]={ "Ū","̈" },
38977 [""]={ "ū","̈" },
38978 [""]={ "V","̃" },
38979 [""]={ "v","̃" },
38980 [""]={ "V","̣" },
38981 ["ṿ"]={ "v","̣" },
38982 [""]={ "W","̀" },
38983 [""]={ "w","̀" },
38984 [""]={ "W","́" },
38985 [""]={ "w","́" },
38986 [""]={ "W","̈" },
38987 [""]={ "w","̈" },
38988 [""]={ "W","̇" },
38989 [""]={ "w","̇" },
38990 [""]={ "W","̣" },
38991 [""]={ "w","̣" },
38992 [""]={ "X","̇" },
38993 [""]={ "x","̇" },
38994 [""]={ "X","̈" },
38995 [""]={ "x","̈" },
38996 [""]={ "Y","̇" },
38997 [""]={ "y","̇" },
38998 [""]={ "Z","̂" },
38999 [""]={ "z","̂" },
39000 [""]={ "Z","̣" },
39001 [""]={ "z","̣" },
39002 [""]={ "Z","̱" },
39003 [""]={ "z","̱" },
39004 [""]={ "h","̱" },
39005 [""]={ "t","̈" },
39006 [""]={ "w","̊" },
39007 [""]={ "y","̊" },
39008 [""]={ "ſ","̇" },
39009 [""]={ "A","̣" },
39010 [""]={ "a","̣" },
39011 [""]={ "A","̉" },
39012 [""]={ "a","̉" },
39013 [""]={ "Â","́" },
39014 [""]={ "â","́" },
39015 [""]={ "Â","̀" },
39016 [""]={ "â","̀" },
39017 [""]={ "Â","̉" },
39018 [""]={ "â","̉" },
39019 [""]={ "Â","̃" },
39020 [""]={ "â","̃" },
39021 [""]={ "","̂" },
39022 [""]={ "","̂" },
39023 [""]={ "Ă","́" },
39024 [""]={ "ă","́" },
39025 [""]={ "Ă","̀" },
39026 [""]={ "ă","̀" },
39027 [""]={ "Ă","̉" },
39028 [""]={ "ă","̉" },
39029 [""]={ "Ă","̃" },
39030 [""]={ "ă","̃" },
39031 [""]={ "","̆" },
39032 [""]={ "","̆" },
39033 [""]={ "E","̣" },
39034 [""]={ "e","̣" },
39035 [""]={ "E","̉" },
39036 [""]={ "e","̉" },
39037 [""]={ "E","̃" },
39038 [""]={ "e","̃" },
39039 [""]={ "Ê","́" },
39040 ["ế"]={ "ê","́" },
39041 [""]={ "Ê","̀" },
39042 [""]={ "ê","̀" },
39043 [""]={ "Ê","̉" },
39044 [""]={ "ê","̉" },
39045 [""]={ "Ê","̃" },
39046 [""]={ "ê","̃" },
39047 [""]={ "","̂" },
39048 [""]={ "","̂" },
39049 [""]={ "I","̉" },
39050 [""]={ "i","̉" },
39051 [""]={ "I","̣" },
39052 [""]={ "i","̣" },
39053 [""]={ "O","̣" },
39054 [""]={ "o","̣" },
39055 [""]={ "O","̉" },
39056 [""]={ "o","̉" },
39057 [""]={ "Ô","́" },
39058 [""]={ "ô","́" },
39059 [""]={ "Ô","̀" },
39060 [""]={ "ô","̀" },
39061 [""]={ "Ô","̉" },
39062 [""]={ "ô","̉" },
39063 [""]={ "Ô","̃" },
39064 [""]={ "ô","̃" },
39065 [""]={ "","̂" },
39066 [""]={ "","̂" },
39067 [""]={ "Ơ","́" },
39068 [""]={ "ơ","́" },
39069 [""]={ "Ơ","̀" },
39070 [""]={ "ơ","̀" },
39071 [""]={ "Ơ","̉" },
39072 [""]={ "ơ","̉" },
39073 [""]={ "Ơ","̃" },
39074 [""]={ "ơ","̃" },
39075 [""]={ "Ơ","̣" },
39076 [""]={ "ơ","̣" },
39077 [""]={ "U","̣" },
39078 [""]={ "u","̣" },
39079 [""]={ "U","̉" },
39080 [""]={ "u","̉" },
39081 [""]={ "Ư","́" },
39082 [""]={ "ư","́" },
39083 [""]={ "Ư","̀" },
39084 [""]={ "ư","̀" },
39085 [""]={ "Ư","̉" },
39086 [""]={ "ư","̉" },
39087 [""]={ "Ư","̃" },
39088 [""]={ "ư","̃" },
39089 [""]={ "Ư","̣" },
39090 [""]={ "ư","̣" },
39091 [""]={ "Y","̀" },
39092 [""]={ "y","̀" },
39093 [""]={ "Y","̣" },
39094 [""]={ "y","̣" },
39095 [""]={ "Y","̉" },
39096 [""]={ "y","̉" },
39097 [""]={ "Y","̃" },
39098 [""]={ "y","̃" },
39099 [""]={ "α","̓" },
39100 [""]={ "α","̔" },
39101 [""]={ "","̀" },
39102 [""]={ "","̀" },
39103 [""]={ "","́" },
39104 [""]={ "","́" },
39105 [""]={ "","͂" },
39106 [""]={ "","͂" },
39107 [""]={ "Α","̓" },
39108 [""]={ "Α","̔" },
39109 [""]={ "","̀" },
39110 [""]={ "","̀" },
39111 [""]={ "","́" },
39112 [""]={ "","́" },
39113 [""]={ "","͂" },
39114 [""]={ "","͂" },
39115 [""]={ "ε","̓" },
39116 [""]={ "ε","̔" },
39117 [""]={ "","̀" },
39118 [""]={ "","̀" },
39119 [""]={ "","́" },
39120 [""]={ "","́" },
39121 [""]={ "Ε","̓" },
39122 [""]={ "Ε","̔" },
39123 [""]={ "","̀" },
39124 [""]={ "","̀" },
39125 [""]={ "","́" },
39126 [""]={ "","́" },
39127 [""]={ "η","̓" },
39128 [""]={ "η","̔" },
39129 [""]={ "","̀" },
39130 [""]={ "","̀" },
39131 [""]={ "","́" },
39132 [""]={ "","́" },
39133 [""]={ "","͂" },
39134 [""]={ "","͂" },
39135 [""]={ "Η","̓" },
39136 [""]={ "Η","̔" },
39137 [""]={ "","̀" },
39138 [""]={ "","̀" },
39139 [""]={ "","́" },
39140 [""]={ "","́" },
39141 [""]={ "","͂" },
39142 [""]={ "","͂" },
39143 [""]={ "ι","̓" },
39144 [""]={ "ι","̔" },
39145 [""]={ "","̀" },
39146 [""]={ "","̀" },
39147 [""]={ "","́" },
39148 [""]={ "","́" },
39149 [""]={ "","͂" },
39150 [""]={ "","͂" },
39151 [""]={ "Ι","̓" },
39152 [""]={ "Ι","̔" },
39153 [""]={ "","̀" },
39154 [""]={ "","̀" },
39155 [""]={ "","́" },
39156 [""]={ "","́" },
39157 [""]={ "","͂" },
39158 ["Ἷ"]={ "","͂" },
39159 [""]={ "ο","̓" },
39160 [""]={ "ο","̔" },
39161 [""]={ "","̀" },
39162 [""]={ "","̀" },
39163 [""]={ "","́" },
39164 [""]={ "","́" },
39165 [""]={ "Ο","̓" },
39166 [""]={ "Ο","̔" },
39167 [""]={ "","̀" },
39168 [""]={ "","̀" },
39169 [""]={ "","́" },
39170 [""]={ "","́" },
39171 [""]={ "υ","̓" },
39172 [""]={ "υ","̔" },
39173 [""]={ "","̀" },
39174 [""]={ "","̀" },
39175 [""]={ "","́" },
39176 [""]={ "","́" },
39177 [""]={ "","͂" },
39178 [""]={ "","͂" },
39179 [""]={ "Υ","̔" },
39180 [""]={ "","̀" },
39181 [""]={ "","́" },
39182 [""]={ "","͂" },
39183 [""]={ "ω","̓" },
39184 [""]={ "ω","̔" },
39185 [""]={ "","̀" },
39186 [""]={ "","̀" },
39187 [""]={ "","́" },
39188 [""]={ "","́" },
39189 [""]={ "","͂" },
39190 [""]={ "","͂" },
39191 [""]={ "Ω","̓" },
39192 [""]={ "Ω","̔" },
39193 [""]={ "","̀" },
39194 [""]={ "","̀" },
39195 [""]={ "","́" },
39196 [""]={ "","́" },
39197 [""]={ "","͂" },
39198 [""]={ "","͂" },
39199 [""]={ "α","̀" },
39200 [""]={ "ε","̀" },
39201 [""]={ "η","̀" },
39202 [""]={ "ι","̀" },
39203 [""]={ "ο","̀" },
39204 [""]={ "υ","̀" },
39205 [""]={ "ω","̀" },
39206 [""]={ "","ͅ" },
39207 [""]={ "","ͅ" },
39208 [""]={ "","ͅ" },
39209 [""]={ "","ͅ" },
39210 [""]={ "","ͅ" },
39211 [""]={ "","ͅ" },
39212 [""]={ "","ͅ" },
39213 [""]={ "","ͅ" },
39214 [""]={ "","ͅ" },
39215 [""]={ "","ͅ" },
39216 [""]={ "","ͅ" },
39217 [""]={ "","ͅ" },
39218 [""]={ "","ͅ" },
39219 [""]={ "","ͅ" },
39220 [""]={ "","ͅ" },
39221 [""]={ "","ͅ" },
39222 [""]={ "","ͅ" },
39223 [""]={ "","ͅ" },
39224 [""]={ "","ͅ" },
39225 [""]={ "","ͅ" },
39226 [""]={ "","ͅ" },
39227 [""]={ "","ͅ" },
39228 [""]={ "","ͅ" },
39229 [""]={ "","ͅ" },
39230 [""]={ "","ͅ" },
39231 [""]={ "","ͅ" },
39232 [""]={ "","ͅ" },
39233 [""]={ "","ͅ" },
39234 [""]={ "","ͅ" },
39235 [""]={ "","ͅ" },
39236 [""]={ "","ͅ" },
39237 [""]={ "","ͅ" },
39238 [""]={ "","ͅ" },
39239 [""]={ "","ͅ" },
39240 [""]={ "","ͅ" },
39241 [""]={ "","ͅ" },
39242 [""]={ "","ͅ" },
39243 [""]={ "","ͅ" },
39244 [""]={ "","ͅ" },
39245 [""]={ "","ͅ" },
39246 [""]={ "","ͅ" },
39247 [""]={ "","ͅ" },
39248 [""]={ "","ͅ" },
39249 [""]={ "","ͅ" },
39250 [""]={ "","ͅ" },
39251 [""]={ "","ͅ" },
39252 [""]={ "","ͅ" },
39253 [""]={ "","ͅ" },
39254 [""]={ "α","̆" },
39255 [""]={ "α","̄" },
39256 [""]={ "","ͅ" },
39257 [""]={ "α","ͅ" },
39258 [""]={ "ά","ͅ" },
39259 [""]={ "α","͂" },
39260 [""]={ "","ͅ" },
39261 [""]={ "Α","̆" },
39262 [""]={ "Α","̄" },
39263 [""]={ "Α","̀" },
39264 [""]={ "Α","ͅ" },
39265 [""]={ "¨","͂" },
39266 [""]={ "","ͅ" },
39267 [""]={ "η","ͅ" },
39268 [""]={ "ή","ͅ" },
39269 [""]={ "η","͂" },
39270 [""]={ "","ͅ" },
39271 [""]={ "Ε","̀" },
39272 [""]={ "Η","̀" },
39273 [""]={ "Η","ͅ" },
39274 [""]={ "᾿","̀" },
39275 [""]={ "᾿","́" },
39276 [""]={ "᾿","͂" },
39277 [""]={ "ι","̆" },
39278 [""]={ "ι","̄" },
39279 [""]={ "ϊ","̀" },
39280 [""]={ "ι","͂" },
39281 [""]={ "ϊ","͂" },
39282 [""]={ "Ι","̆" },
39283 [""]={ "Ι","̄" },
39284 [""]={ "Ι","̀" },
39285 [""]={ "","̀" },
39286 [""]={ "","́" },
39287 [""]={ "","͂" },
39288 [""]={ "υ","̆" },
39289 [""]={ "υ","̄" },
39290 [""]={ "ϋ","̀" },
39291 [""]={ "ρ","̓" },
39292 [""]={ "ρ","̔" },
39293 [""]={ "υ","͂" },
39294 [""]={ "ϋ","͂" },
39295 [""]={ "Υ","̆" },
39296 [""]={ "Υ","̄" },
39297 [""]={ "Υ","̀" },
39298 [""]={ "Ρ","̔" },
39299 [""]={ "¨","̀" },
39300 [""]={ "","ͅ" },
39301 [""]={ "ω","ͅ" },
39302 [""]={ "ώ","ͅ" },
39303 [""]={ "ω","͂" },
39304 [""]={ "","ͅ" },
39305 [""]={ "Ο","̀" },
39306 [""]={ "Ω","̀" },
39307 [""]={ "Ω","ͅ" },
39308 [""]={ "","̸" },
39309 [""]={ "","̸" },
39310 [""]={ "","̸" },
39311 [""]={ "","̸" },
39312 [""]={ "","̸" },
39313 [""]={ "","̸" },
39314 [""]={ "","̸" },
39315 [""]={ "","̸" },
39316 [""]={ "","̸" },
39317 [""]={ "","̸" },
39318 [""]={ "","̸" },
39319 [""]={ "","̸" },
39320 [""]={ "","̸" },
39321 [""]={ "","̸" },
39322 [""]={ "","̸" },
39323 [""]={ "=","̸" },
39324 [""]={ "","̸" },
39325 [""]={ "","̸" },
39326 [""]={ "<","̸" },
39327 [""]={ ">","̸" },
39328 [""]={ "","̸" },
39329 [""]={ "","̸" },
39330 [""]={ "","̸" },
39331 [""]={ "","̸" },
39332 [""]={ "","̸" },
39333 [""]={ "","̸" },
39334 [""]={ "","̸" },
39335 [""]={ "","̸" },
39336 [""]={ "","̸" },
39337 [""]={ "","̸" },
39338 [""]={ "","̸" },
39339 [""]={ "","̸" },
39340 [""]={ "","̸" },
39341 [""]={ "","̸" },
39342 [""]={ "","̸" },
39343 [""]={ "","̸" },
39344 [""]={ "","̸" },
39345 [""]={ "","̸" },
39346 [""]={ "","̸" },
39347 [""]={ "","̸" },
39348 [""]={ "","̸" },
39349 [""]={ "","̸" },
39350 [""]={ "","̸" },
39351 [""]={ "","̸" },
39352 [""]={ "","̸" },
39353 [""]={ "","" },
39354 [""]={ "","" },
39355 [""]={ "","" },
39356 [""]={ "","" },
39357 [""]={ "","" },
39358 [""]={ "","" },
39359 [""]={ "","" },
39360 [""]={ "","" },
39361 [""]={ "","" },
39362 [""]={ "","" },
39363 [""]={ "","" },
39364 [""]={ "","" },
39365 [""]={ "","" },
39366 [""]={ "","" },
39367 [""]={ "","" },
39368 [""]={ "","" },
39369 [""]={ "","" },
39370 [""]={ "","" },
39371 [""]={ "","" },
39372 [""]={ "","" },
39373 [""]={ "","" },
39374 [""]={ "","" },
39375 [""]={ "","" },
39376 [""]={ "","" },
39377 [""]={ "","" },
39378 [""]={ "","" },
39379 [""]={ "","" },
39380 [""]={ "","" },
39381 [""]={ "","" },
39382 [""]={ "","" },
39383 [""]={ "","" },
39384 [""]={ "","" },
39385 [""]={ "","" },
39386 [""]={ "","" },
39387 [""]={ "","" },
39388 [""]={ "","" },
39389 [""]={ "","" },
39390 [""]={ "","" },
39391 [""]={ "","" },
39392 [""]={ "","" },
39393 [""]={ "","" },
39394 [""]={ "","" },
39395 [""]={ "","" },
39396 [""]={ "","" },
39397 [""]={ "","" },
39398 [""]={ "","" },
39399 [""]={ "","" },
39400 [""]={ "","" },
39401 [""]={ "","" },
39402 [""]={ "","" },
39403 [""]={ "","" },
39404 [""]={ "","" },
39405 [""]={ "","" },
39406 [""]={ "","" },
39407 [""]={ "","" },
39408 [""]={ "","" },
39409 [""]={ "","" },
39410 [""]={ "","" },
39411 [""]={ "י","ִ" },
39412 [""]={ "ײ","ַ" },
39413 [""]={ "ש","ׁ" },
39414 [""]={ "ש","ׂ" },
39415 [""]={ "","ׁ" },
39416 [""]={ "","ׂ" },
39417 [""]={ "א","ַ" },
39418 [""]={ "א","ָ" },
39419 [""]={ "א","ּ" },
39420 [""]={ "ב","ּ" },
39421 [""]={ "ג","ּ" },
39422 [""]={ "ד","ּ" },
39423 [""]={ "ה","ּ" },
39424 [""]={ "ו","ּ" },
39425 [""]={ "ז","ּ" },
39426 [""]={ "ט","ּ" },
39427 [""]={ "י","ּ" },
39428 [""]={ "ך","ּ" },
39429 [""]={ "כ","ּ" },
39430 [""]={ "ל","ּ" },
39431 [""]={ "מ","ּ" },
39432 [""]={ "נ","ּ" },
39433 [""]={ "ס","ּ" },
39434 [""]={ "ף","ּ" },
39435 [""]={ "פ","ּ" },
39436 [""]={ "צ","ּ" },
39437 [""]={ "ק","ּ" },
39438 [""]={ "ר","ּ" },
39439 [""]={ "ש","ּ" },
39440 [""]={ "ת","ּ" },
39441 [""]={ "ו","ֹ" },
39442 [""]={ "ב","ֿ" },
39443 [""]={ "כ","ֿ" },
39444 [""]={ "פ","ֿ" },
39445 ["𑂚"]={ "𑂙","𑂺" },
39446 ["𑂜"]={ "𑂛","𑂺" },
39447 ["𑂫"]={ "𑂥","𑂺" },
39448 ["𑄮"]={ "𑄱","𑄧" },
39449 ["𑄯"]={ "𑄲","𑄧" },
39450 ["𑍋"]={ "𑍇","𑌾" },
39451 ["𑍌"]={ "𑍇","𑍗" },
39452 ["𑒻"]={ "𑒹","𑒺" },
39453 ["𑒼"]={ "𑒹","𑒰" },
39454 ["𑒾"]={ "𑒹","𑒽" },
39455 ["𑖺"]={ "𑖸","𑖯" },
39456 ["𑖻"]={ "𑖹","𑖯" },
39457 ["𝅗𝅥"]={ "𝅗","𝅥" },
39458 ["𝅘𝅥"]={ "𝅘","𝅥" },
39459 ["𝅘𝅥𝅮"]={ "𝅘𝅥","𝅮" },
39460 ["𝅘𝅥𝅯"]={ "𝅘𝅥","𝅯" },
39461 ["𝅘𝅥𝅰"]={ "𝅘𝅥","𝅰" },
39462 ["𝅘𝅥𝅱"]={ "𝅘𝅥","𝅱" },
39463 ["𝅘𝅥𝅲"]={ "𝅘𝅥","𝅲" },
39464 ["𝆹𝅥"]={ "𝆹","𝅥" },
39465 ["𝆺𝅥"]={ "𝆺","𝅥" },
39466 ["𝆹𝅥𝅮"]={ "𝆹𝅥","𝅮" },
39467 ["𝆺𝅥𝅮"]={ "𝆺𝅥","𝅮" },
39468 ["𝆹𝅥𝅯"]={ "𝆹𝅥","𝅯" },
39469 ["𝆺𝅥𝅯"]={ "𝆺𝅥","𝅯" },
39470   },
39471  },
39472  {
39473   ["data"]={
39474 ["À"]={ "A","̀" },
39475 ["Á"]={ "A","́" },
39476 ["Â"]={ "A","̂" },
39477 ["Ã"]={ "A","̃" },
39478 ["Ä"]={ "A","̈" },
39479 ["Å"]={ "A","̊" },
39480 ["Ç"]={ "C","̧" },
39481 ["È"]={ "E","̀" },
39482 ["É"]={ "E","́" },
39483 ["Ê"]={ "E","̂" },
39484 ["Ë"]={ "E","̈" },
39485 ["Ì"]={ "I","̀" },
39486 ["Í"]={ "I","́" },
39487 ["Î"]={ "I","̂" },
39488 ["Ï"]={ "I","̈" },
39489 ["Ñ"]={ "N","̃" },
39490 ["Ò"]={ "O","̀" },
39491 ["Ó"]={ "O","́" },
39492 ["Ô"]={ "O","̂" },
39493 ["Õ"]={ "O","̃" },
39494 ["Ö"]={ "O","̈" },
39495 ["Ù"]={ "U","̀" },
39496 ["Ú"]={ "U","́" },
39497 ["Û"]={ "U","̂" },
39498 ["Ü"]={ "U","̈" },
39499 ["Ý"]={ "Y","́" },
39500 ["à"]={ "a","̀" },
39501 ["á"]={ "a","́" },
39502 ["â"]={ "a","̂" },
39503 ["ã"]={ "a","̃" },
39504 ["ä"]={ "a","̈" },
39505 ["å"]={ "a","̊" },
39506 ["ç"]={ "c","̧" },
39507 ["è"]={ "e","̀" },
39508 ["é"]={ "e","́" },
39509 ["ê"]={ "e","̂" },
39510 ["ë"]={ "e","̈" },
39511 ["ì"]={ "i","̀" },
39512 ["í"]={ "i","́" },
39513 ["î"]={ "i","̂" },
39514 ["ï"]={ "i","̈" },
39515 ["ñ"]={ "n","̃" },
39516 ["ò"]={ "o","̀" },
39517 ["ó"]={ "o","́" },
39518 ["ô"]={ "o","̂" },
39519 ["õ"]={ "o","̃" },
39520 ["ö"]={ "o","̈" },
39521 ["ù"]={ "u","̀" },
39522 ["ú"]={ "u","́" },
39523 ["û"]={ "u","̂" },
39524 ["ü"]={ "u","̈" },
39525 ["ý"]={ "y","́" },
39526 ["ÿ"]={ "y","̈" },
39527 ["Ā"]={ "A","̄" },
39528 ["ā"]={ "a","̄" },
39529 ["Ă"]={ "A","̆" },
39530 ["ă"]={ "a","̆" },
39531 ["Ą"]={ "A","̨" },
39532 ["ą"]={ "a","̨" },
39533 ["Ć"]={ "C","́" },
39534 ["ć"]={ "c","́" },
39535 ["Ĉ"]={ "C","̂" },
39536 ["ĉ"]={ "c","̂" },
39537 ["Ċ"]={ "C","̇" },
39538 ["ċ"]={ "c","̇" },
39539 ["Č"]={ "C","̌" },
39540 ["č"]={ "c","̌" },
39541 ["Ď"]={ "D","̌" },
39542 ["ď"]={ "d","̌" },
39543 ["Ē"]={ "E","̄" },
39544 ["ē"]={ "e","̄" },
39545 ["Ĕ"]={ "E","̆" },
39546 ["ĕ"]={ "e","̆" },
39547 ["Ė"]={ "E","̇" },
39548 ["ė"]={ "e","̇" },
39549 ["Ę"]={ "E","̨" },
39550 ["ę"]={ "e","̨" },
39551 ["Ě"]={ "E","̌" },
39552 ["ě"]={ "e","̌" },
39553 ["Ĝ"]={ "G","̂" },
39554 ["ĝ"]={ "g","̂" },
39555 ["Ğ"]={ "G","̆" },
39556 ["ğ"]={ "g","̆" },
39557 ["Ġ"]={ "G","̇" },
39558 ["ġ"]={ "g","̇" },
39559 ["Ģ"]={ "G","̧" },
39560 ["ģ"]={ "g","̧" },
39561 ["Ĥ"]={ "H","̂" },
39562 ["ĥ"]={ "h","̂" },
39563 ["Ĩ"]={ "I","̃" },
39564 ["ĩ"]={ "i","̃" },
39565 ["Ī"]={ "I","̄" },
39566 ["ī"]={ "i","̄" },
39567 ["Ĭ"]={ "I","̆" },
39568 ["ĭ"]={ "i","̆" },
39569 ["Į"]={ "I","̨" },
39570 ["į"]={ "i","̨" },
39571 ["İ"]={ "I","̇" },
39572 ["Ĵ"]={ "J","̂" },
39573 ["ĵ"]={ "j","̂" },
39574 ["Ķ"]={ "K","̧" },
39575 ["ķ"]={ "k","̧" },
39576 ["Ĺ"]={ "L","́" },
39577 ["ĺ"]={ "l","́" },
39578 ["Ļ"]={ "L","̧" },
39579 ["ļ"]={ "l","̧" },
39580 ["Ľ"]={ "L","̌" },
39581 ["ľ"]={ "l","̌" },
39582 ["Ń"]={ "N","́" },
39583 ["ń"]={ "n","́" },
39584 ["Ņ"]={ "N","̧" },
39585 ["ņ"]={ "n","̧" },
39586 ["Ň"]={ "N","̌" },
39587 ["ň"]={ "n","̌" },
39588 ["Ō"]={ "O","̄" },
39589 ["ō"]={ "o","̄" },
39590 ["Ŏ"]={ "O","̆" },
39591 ["ŏ"]={ "o","̆" },
39592 ["Ő"]={ "O","̋" },
39593 ["ő"]={ "o","̋" },
39594 ["Ŕ"]={ "R","́" },
39595 ["ŕ"]={ "r","́" },
39596 ["Ŗ"]={ "R","̧" },
39597 ["ŗ"]={ "r","̧" },
39598 ["Ř"]={ "R","̌" },
39599 ["ř"]={ "r","̌" },
39600 ["Ś"]={ "S","́" },
39601 ["ś"]={ "s","́" },
39602 ["Ŝ"]={ "S","̂" },
39603 ["ŝ"]={ "s","̂" },
39604 ["Ş"]={ "S","̧" },
39605 ["ş"]={ "s","̧" },
39606 ["Š"]={ "S","̌" },
39607 ["š"]={ "s","̌" },
39608 ["Ţ"]={ "T","̧" },
39609 ["ţ"]={ "t","̧" },
39610 ["Ť"]={ "T","̌" },
39611 ["ť"]={ "t","̌" },
39612 ["Ũ"]={ "U","̃" },
39613 ["ũ"]={ "u","̃" },
39614 ["Ū"]={ "U","̄" },
39615 ["ū"]={ "u","̄" },
39616 ["Ŭ"]={ "U","̆" },
39617 ["ŭ"]={ "u","̆" },
39618 ["Ů"]={ "U","̊" },
39619 ["ů"]={ "u","̊" },
39620 ["Ű"]={ "U","̋" },
39621 ["ű"]={ "u","̋" },
39622 ["Ų"]={ "U","̨" },
39623 ["ų"]={ "u","̨" },
39624 ["Ŵ"]={ "W","̂" },
39625 ["ŵ"]={ "w","̂" },
39626 ["Ŷ"]={ "Y","̂" },
39627 ["ŷ"]={ "y","̂" },
39628 ["Ÿ"]={ "Y","̈" },
39629 ["Ź"]={ "Z","́" },
39630 ["ź"]={ "z","́" },
39631 ["Ż"]={ "Z","̇" },
39632 ["ż"]={ "z","̇" },
39633 ["Ž"]={ "Z","̌" },
39634 ["ž"]={ "z","̌" },
39635 ["Ơ"]={ "O","̛" },
39636 ["ơ"]={ "o","̛" },
39637 ["Ư"]={ "U","̛" },
39638 ["ư"]={ "u","̛" },
39639 ["Ǎ"]={ "A","̌" },
39640 ["ǎ"]={ "a","̌" },
39641 ["Ǐ"]={ "I","̌" },
39642 ["ǐ"]={ "i","̌" },
39643 ["Ǒ"]={ "O","̌" },
39644 ["ǒ"]={ "o","̌" },
39645 ["Ǔ"]={ "U","̌" },
39646 ["ǔ"]={ "u","̌" },
39647 ["Ǖ"]={ "Ü","̄" },
39648 ["ǖ"]={ "ü","̄" },
39649 ["Ǘ"]={ "Ü","́" },
39650 ["ǘ"]={ "ü","́" },
39651 ["Ǚ"]={ "Ü","̌" },
39652 ["ǚ"]={ "ü","̌" },
39653 ["Ǜ"]={ "Ü","̀" },
39654 ["ǜ"]={ "ü","̀" },
39655 ["Ǟ"]={ "Ä","̄" },
39656 ["ǟ"]={ "ä","̄" },
39657 ["Ǡ"]={ "Ȧ","̄" },
39658 ["ǡ"]={ "ȧ","̄" },
39659 ["Ǣ"]={ "Æ","̄" },
39660 ["ǣ"]={ "æ","̄" },
39661 ["Ǧ"]={ "G","̌" },
39662 ["ǧ"]={ "g","̌" },
39663 ["Ǩ"]={ "K","̌" },
39664 ["ǩ"]={ "k","̌" },
39665 ["Ǫ"]={ "O","̨" },
39666 ["ǫ"]={ "o","̨" },
39667 ["Ǭ"]={ "Ǫ","̄" },
39668 ["ǭ"]={ "ǫ","̄" },
39669 ["Ǯ"]={ "Ʒ","̌" },
39670 ["ǯ"]={ "ʒ","̌" },
39671 ["ǰ"]={ "j","̌" },
39672 ["Ǵ"]={ "G","́" },
39673 ["ǵ"]={ "g","́" },
39674 ["Ǹ"]={ "N","̀" },
39675 ["ǹ"]={ "n","̀" },
39676 ["Ǻ"]={ "Å","́" },
39677 ["ǻ"]={ "å","́" },
39678 ["Ǽ"]={ "Æ","́" },
39679 ["ǽ"]={ "æ","́" },
39680 ["Ǿ"]={ "Ø","́" },
39681 ["ǿ"]={ "ø","́" },
39682 ["Ȁ"]={ "A","̏" },
39683 ["ȁ"]={ "a","̏" },
39684 ["Ȃ"]={ "A","̑" },
39685 ["ȃ"]={ "a","̑" },
39686 ["Ȅ"]={ "E","̏" },
39687 ["ȅ"]={ "e","̏" },
39688 ["Ȇ"]={ "E","̑" },
39689 ["ȇ"]={ "e","̑" },
39690 ["Ȉ"]={ "I","̏" },
39691 ["ȉ"]={ "i","̏" },
39692 ["Ȋ"]={ "I","̑" },
39693 ["ȋ"]={ "i","̑" },
39694 ["Ȍ"]={ "O","̏" },
39695 ["ȍ"]={ "o","̏" },
39696 ["Ȏ"]={ "O","̑" },
39697 ["ȏ"]={ "o","̑" },
39698 ["Ȑ"]={ "R","̏" },
39699 ["ȑ"]={ "r","̏" },
39700 ["Ȓ"]={ "R","̑" },
39701 ["ȓ"]={ "r","̑" },
39702 ["Ȕ"]={ "U","̏" },
39703 ["ȕ"]={ "u","̏" },
39704 ["Ȗ"]={ "U","̑" },
39705 ["ȗ"]={ "u","̑" },
39706 ["Ș"]={ "S","̦" },
39707 ["ș"]={ "s","̦" },
39708 ["Ț"]={ "T","̦" },
39709 ["ț"]={ "t","̦" },
39710 ["Ȟ"]={ "H","̌" },
39711 ["ȟ"]={ "h","̌" },
39712 ["Ȧ"]={ "A","̇" },
39713 ["ȧ"]={ "a","̇" },
39714 ["Ȩ"]={ "E","̧" },
39715 ["ȩ"]={ "e","̧" },
39716 ["Ȫ"]={ "Ö","̄" },
39717 ["ȫ"]={ "ö","̄" },
39718 ["Ȭ"]={ "Õ","̄" },
39719 ["ȭ"]={ "õ","̄" },
39720 ["Ȯ"]={ "O","̇" },
39721 ["ȯ"]={ "o","̇" },
39722 ["Ȱ"]={ "Ȯ","̄" },
39723 ["ȱ"]={ "ȯ","̄" },
39724 ["Ȳ"]={ "Y","̄" },
39725 ["ȳ"]={ "y","̄" },
39726 ["̈́"]={ "̈","́" },
39727 ["΅"]={ "¨","́" },
39728 ["Ά"]={ "Α","́" },
39729 ["Έ"]={ "Ε","́" },
39730 ["Ή"]={ "Η","́" },
39731 ["Ί"]={ "Ι","́" },
39732 ["Ό"]={ "Ο","́" },
39733 ["Ύ"]={ "Υ","́" },
39734 ["Ώ"]={ "Ω","́" },
39735 ["ΐ"]={ "ϊ","́" },
39736 ["Ϊ"]={ "Ι","̈" },
39737 ["Ϋ"]={ "Υ","̈" },
39738 ["ά"]={ "α","́" },
39739 ["έ"]={ "ε","́" },
39740 ["ή"]={ "η","́" },
39741 ["ί"]={ "ι","́" },
39742 ["ΰ"]={ "ϋ","́" },
39743 ["ϊ"]={ "ι","̈" },
39744 ["ϋ"]={ "υ","̈" },
39745 ["ό"]={ "ο","́" },
39746 ["ύ"]={ "υ","́" },
39747 ["ώ"]={ "ω","́" },
39748 ["ϓ"]={ "ϒ","́" },
39749 ["ϔ"]={ "ϒ","̈" },
39750 ["Ѐ"]={ "Е","̀" },
39751 ["Ё"]={ "Е","̈" },
39752 ["Ѓ"]={ "Г","́" },
39753 ["Ї"]={ "І","̈" },
39754 ["Ќ"]={ "К","́" },
39755 ["Ѝ"]={ "И","̀" },
39756 ["Ў"]={ "У","̆" },
39757 ["Й"]={ "И","̆" },
39758 ["й"]={ "и","̆" },
39759 ["ѐ"]={ "е","̀" },
39760 ["ё"]={ "е","̈" },
39761 ["ѓ"]={ "г","́" },
39762 ["ї"]={ "і","̈" },
39763 ["ќ"]={ "к","́" },
39764 ["ѝ"]={ "и","̀" },
39765 ["ў"]={ "у","̆" },
39766 ["Ѷ"]={ "Ѵ","̏" },
39767 ["ѷ"]={ "ѵ","̏" },
39768 ["Ӂ"]={ "Ж","̆" },
39769 ["ӂ"]={ "ж","̆" },
39770 ["Ӑ"]={ "А","̆" },
39771 ["ӑ"]={ "а","̆" },
39772 ["Ӓ"]={ "А","̈" },
39773 ["ӓ"]={ "а","̈" },
39774 ["Ӗ"]={ "Е","̆" },
39775 ["ӗ"]={ "е","̆" },
39776 ["Ӛ"]={ "Ә","̈" },
39777 ["ӛ"]={ "ә","̈" },
39778 ["Ӝ"]={ "Ж","̈" },
39779 ["ӝ"]={ "ж","̈" },
39780 ["Ӟ"]={ "З","̈" },
39781 ["ӟ"]={ "з","̈" },
39782 ["Ӣ"]={ "И","̄" },
39783 ["ӣ"]={ "и","̄" },
39784 ["Ӥ"]={ "И","̈" },
39785 ["ӥ"]={ "и","̈" },
39786 ["Ӧ"]={ "О","̈" },
39787 ["ӧ"]={ "о","̈" },
39788 ["Ӫ"]={ "Ө","̈" },
39789 ["ӫ"]={ "ө","̈" },
39790 ["Ӭ"]={ "Э","̈" },
39791 ["ӭ"]={ "э","̈" },
39792 ["Ӯ"]={ "У","̄" },
39793 ["ӯ"]={ "у","̄" },
39794 ["Ӱ"]={ "У","̈" },
39795 ["ӱ"]={ "у","̈" },
39796 ["Ӳ"]={ "У","̋" },
39797 ["ӳ"]={ "у","̋" },
39798 ["Ӵ"]={ "Ч","̈" },
39799 ["ӵ"]={ "ч","̈" },
39800 ["Ӹ"]={ "Ы","̈" },
39801 ["ӹ"]={ "ы","̈" },
39802 ["آ"]={ "ا","ٓ" },
39803 ["أ"]={ "ا","ٔ" },
39804 ["ؤ"]={ "و","ٔ" },
39805 ["إ"]={ "ا","ٕ" },
39806 ["ئ"]={ "ي","ٔ" },
39807 ["ۀ"]={ "ە","ٔ" },
39808 ["ۂ"]={ "ہ","ٔ" },
39809 ["ۓ"]={ "ے","ٔ" },
39810 [""]={ "","" },
39811 [""]={ "","" },
39812 [""]={ "","" },
39813 [""]={ "","" },
39814 [""]={ "","" },
39815 [""]={ "","" },
39816 [""]={ "","" },
39817 [""]={ "","" },
39818 [""]={ "","" },
39819 [""]={ "","" },
39820 [""]={ "","" },
39821 [""]={ "","" },
39822 [""]={ "","" },
39823 [""]={ "","" },
39824 [""]={ "","" },
39825 [""]={ "","" },
39826 [""]={ "","" },
39827 [""]={ "","" },
39828 [""]={ "","" },
39829 [""]={ "","" },
39830 [""]={ "","" },
39831 [""]={ "","" },
39832 [""]={ "","" },
39833 [""]={ "","" },
39834 [""]={ "","" },
39835 [""]={ "","" },
39836 [""]={ "","" },
39837 [""]={ "","" },
39838 [""]={ "","" },
39839 [""]={ "","" },
39840 [""]={ "","" },
39841 [""]={ "","" },
39842 [""]={ "ಿ","" },
39843 [""]={ "","" },
39844 [""]={ "","" },
39845 [""]={ "","" },
39846 [""]={ "","" },
39847 [""]={ "","" },
39848 [""]={ "","" },
39849 [""]={ "","" },
39850 [""]={ "","" },
39851 [""]={ "","" },
39852 [""]={ "","" },
39853 [""]={ "","" },
39854 [""]={ "","" },
39855 [""]={ "","" },
39856 [""]={ "","" },
39857 [""]={ "","" },
39858 [""]={ "","" },
39859 [""]={ "","" },
39860 [""]={ "","" },
39861 [""]={ "","" },
39862 [""]={ "","" },
39863 [""]={ "","" },
39864 [""]={ "","" },
39865 [""]={ "","" },
39866 [""]={ "","" },
39867 [""]={ "","" },
39868 [""]={ "","" },
39869 [""]={ "","" },
39870 [""]={ "","" },
39871 [""]={ "","" },
39872 [""]={ "","" },
39873 [""]={ "","" },
39874 [""]={ "","" },
39875 [""]={ "","" },
39876 [""]={ "","" },
39877 [""]={ "","" },
39878 [""]={ "","" },
39879 [""]={ "","" },
39880 [""]={ "","" },
39881 [""]={ "ᬿ","" },
39882 [""]={ "","" },
39883 [""]={ "A","̥" },
39884 [""]={ "a","̥" },
39885 [""]={ "B","̇" },
39886 [""]={ "b","̇" },
39887 [""]={ "B","̣" },
39888 [""]={ "b","̣" },
39889 [""]={ "B","̱" },
39890 [""]={ "b","̱" },
39891 [""]={ "Ç","́" },
39892 [""]={ "ç","́" },
39893 [""]={ "D","̇" },
39894 [""]={ "d","̇" },
39895 [""]={ "D","̣" },
39896 [""]={ "d","̣" },
39897 [""]={ "D","̱" },
39898 [""]={ "d","̱" },
39899 [""]={ "D","̧" },
39900 [""]={ "d","̧" },
39901 [""]={ "D","̭" },
39902 [""]={ "d","̭" },
39903 [""]={ "Ē","̀" },
39904 [""]={ "ē","̀" },
39905 [""]={ "Ē","́" },
39906 [""]={ "ē","́" },
39907 [""]={ "E","̭" },
39908 [""]={ "e","̭" },
39909 [""]={ "E","̰" },
39910 [""]={ "e","̰" },
39911 [""]={ "Ȩ","̆" },
39912 [""]={ "ȩ","̆" },
39913 [""]={ "F","̇" },
39914 [""]={ "f","̇" },
39915 [""]={ "G","̄" },
39916 [""]={ "g","̄" },
39917 [""]={ "H","̇" },
39918 [""]={ "h","̇" },
39919 [""]={ "H","̣" },
39920 [""]={ "h","̣" },
39921 [""]={ "H","̈" },
39922 [""]={ "h","̈" },
39923 [""]={ "H","̧" },
39924 [""]={ "h","̧" },
39925 [""]={ "H","̮" },
39926 [""]={ "h","̮" },
39927 [""]={ "I","̰" },
39928 [""]={ "i","̰" },
39929 [""]={ "Ï","́" },
39930 [""]={ "ï","́" },
39931 [""]={ "K","́" },
39932 [""]={ "k","́" },
39933 [""]={ "K","̣" },
39934 [""]={ "k","̣" },
39935 [""]={ "K","̱" },
39936 [""]={ "k","̱" },
39937 [""]={ "L","̣" },
39938 [""]={ "l","̣" },
39939 [""]={ "","̄" },
39940 [""]={ "","̄" },
39941 [""]={ "L","̱" },
39942 [""]={ "l","̱" },
39943 [""]={ "L","̭" },
39944 [""]={ "l","̭" },
39945 [""]={ "M","́" },
39946 ["ḿ"]={ "m","́" },
39947 [""]={ "M","̇" },
39948 [""]={ "m","̇" },
39949 [""]={ "M","̣" },
39950 [""]={ "m","̣" },
39951 [""]={ "N","̇" },
39952 [""]={ "n","̇" },
39953 [""]={ "N","̣" },
39954 [""]={ "n","̣" },
39955 [""]={ "N","̱" },
39956 [""]={ "n","̱" },
39957 [""]={ "N","̭" },
39958 [""]={ "n","̭" },
39959 [""]={ "Õ","́" },
39960 [""]={ "õ","́" },
39961 [""]={ "Õ","̈" },
39962 [""]={ "õ","̈" },
39963 [""]={ "Ō","̀" },
39964 [""]={ "ō","̀" },
39965 [""]={ "Ō","́" },
39966 [""]={ "ō","́" },
39967 [""]={ "P","́" },
39968 [""]={ "p","́" },
39969 [""]={ "P","̇" },
39970 [""]={ "p","̇" },
39971 [""]={ "R","̇" },
39972 [""]={ "r","̇" },
39973 [""]={ "R","̣" },
39974 [""]={ "r","̣" },
39975 [""]={ "","̄" },
39976 [""]={ "","̄" },
39977 [""]={ "R","̱" },
39978 [""]={ "r","̱" },
39979 [""]={ "S","̇" },
39980 [""]={ "s","̇" },
39981 [""]={ "S","̣" },
39982 [""]={ "s","̣" },
39983 [""]={ "Ś","̇" },
39984 [""]={ "ś","̇" },
39985 [""]={ "Š","̇" },
39986 [""]={ "š","̇" },
39987 [""]={ "","̇" },
39988 [""]={ "","̇" },
39989 [""]={ "T","̇" },
39990 [""]={ "t","̇" },
39991 [""]={ "T","̣" },
39992 [""]={ "t","̣" },
39993 [""]={ "T","̱" },
39994 [""]={ "t","̱" },
39995 [""]={ "T","̭" },
39996 [""]={ "t","̭" },
39997 [""]={ "U","̤" },
39998 [""]={ "u","̤" },
39999 [""]={ "U","̰" },
40000 [""]={ "u","̰" },
40001 [""]={ "U","̭" },
40002 [""]={ "u","̭" },
40003 [""]={ "Ũ","́" },
40004 [""]={ "ũ","́" },
40005 [""]={ "Ū","̈" },
40006 [""]={ "ū","̈" },
40007 [""]={ "V","̃" },
40008 [""]={ "v","̃" },
40009 [""]={ "V","̣" },
40010 ["ṿ"]={ "v","̣" },
40011 [""]={ "W","̀" },
40012 [""]={ "w","̀" },
40013 [""]={ "W","́" },
40014 [""]={ "w","́" },
40015 [""]={ "W","̈" },
40016 [""]={ "w","̈" },
40017 [""]={ "W","̇" },
40018 [""]={ "w","̇" },
40019 [""]={ "W","̣" },
40020 [""]={ "w","̣" },
40021 [""]={ "X","̇" },
40022 [""]={ "x","̇" },
40023 [""]={ "X","̈" },
40024 [""]={ "x","̈" },
40025 [""]={ "Y","̇" },
40026 [""]={ "y","̇" },
40027 [""]={ "Z","̂" },
40028 [""]={ "z","̂" },
40029 [""]={ "Z","̣" },
40030 [""]={ "z","̣" },
40031 [""]={ "Z","̱" },
40032 [""]={ "z","̱" },
40033 [""]={ "h","̱" },
40034 [""]={ "t","̈" },
40035 [""]={ "w","̊" },
40036 [""]={ "y","̊" },
40037 [""]={ "ſ","̇" },
40038 [""]={ "A","̣" },
40039 [""]={ "a","̣" },
40040 [""]={ "A","̉" },
40041 [""]={ "a","̉" },
40042 [""]={ "Â","́" },
40043 [""]={ "â","́" },
40044 [""]={ "Â","̀" },
40045 [""]={ "â","̀" },
40046 [""]={ "Â","̉" },
40047 [""]={ "â","̉" },
40048 [""]={ "Â","̃" },
40049 [""]={ "â","̃" },
40050 [""]={ "","̂" },
40051 [""]={ "","̂" },
40052 [""]={ "Ă","́" },
40053 [""]={ "ă","́" },
40054 [""]={ "Ă","̀" },
40055 [""]={ "ă","̀" },
40056 [""]={ "Ă","̉" },
40057 [""]={ "ă","̉" },
40058 [""]={ "Ă","̃" },
40059 [""]={ "ă","̃" },
40060 [""]={ "","̆" },
40061 [""]={ "","̆" },
40062 [""]={ "E","̣" },
40063 [""]={ "e","̣" },
40064 [""]={ "E","̉" },
40065 [""]={ "e","̉" },
40066 [""]={ "E","̃" },
40067 [""]={ "e","̃" },
40068 [""]={ "Ê","́" },
40069 ["ế"]={ "ê","́" },
40070 [""]={ "Ê","̀" },
40071 [""]={ "ê","̀" },
40072 [""]={ "Ê","̉" },
40073 [""]={ "ê","̉" },
40074 [""]={ "Ê","̃" },
40075 [""]={ "ê","̃" },
40076 [""]={ "","̂" },
40077 [""]={ "","̂" },
40078 [""]={ "I","̉" },
40079 [""]={ "i","̉" },
40080 [""]={ "I","̣" },
40081 [""]={ "i","̣" },
40082 [""]={ "O","̣" },
40083 [""]={ "o","̣" },
40084 [""]={ "O","̉" },
40085 [""]={ "o","̉" },
40086 [""]={ "Ô","́" },
40087 [""]={ "ô","́" },
40088 [""]={ "Ô","̀" },
40089 [""]={ "ô","̀" },
40090 [""]={ "Ô","̉" },
40091 [""]={ "ô","̉" },
40092 [""]={ "Ô","̃" },
40093 [""]={ "ô","̃" },
40094 [""]={ "","̂" },
40095 [""]={ "","̂" },
40096 [""]={ "Ơ","́" },
40097 [""]={ "ơ","́" },
40098 [""]={ "Ơ","̀" },
40099 [""]={ "ơ","̀" },
40100 [""]={ "Ơ","̉" },
40101 [""]={ "ơ","̉" },
40102 [""]={ "Ơ","̃" },
40103 [""]={ "ơ","̃" },
40104 [""]={ "Ơ","̣" },
40105 [""]={ "ơ","̣" },
40106 [""]={ "U","̣" },
40107 [""]={ "u","̣" },
40108 [""]={ "U","̉" },
40109 [""]={ "u","̉" },
40110 [""]={ "Ư","́" },
40111 [""]={ "ư","́" },
40112 [""]={ "Ư","̀" },
40113 [""]={ "ư","̀" },
40114 [""]={ "Ư","̉" },
40115 [""]={ "ư","̉" },
40116 [""]={ "Ư","̃" },
40117 [""]={ "ư","̃" },
40118 [""]={ "Ư","̣" },
40119 [""]={ "ư","̣" },
40120 [""]={ "Y","̀" },
40121 [""]={ "y","̀" },
40122 [""]={ "Y","̣" },
40123 [""]={ "y","̣" },
40124 [""]={ "Y","̉" },
40125 [""]={ "y","̉" },
40126 [""]={ "Y","̃" },
40127 [""]={ "y","̃" },
40128 [""]={ "α","̓" },
40129 [""]={ "α","̔" },
40130 [""]={ "","̀" },
40131 [""]={ "","̀" },
40132 [""]={ "","́" },
40133 [""]={ "","́" },
40134 [""]={ "","͂" },
40135 [""]={ "","͂" },
40136 [""]={ "Α","̓" },
40137 [""]={ "Α","̔" },
40138 [""]={ "","̀" },
40139 [""]={ "","̀" },
40140 [""]={ "","́" },
40141 [""]={ "","́" },
40142 [""]={ "","͂" },
40143 [""]={ "","͂" },
40144 [""]={ "ε","̓" },
40145 [""]={ "ε","̔" },
40146 [""]={ "","̀" },
40147 [""]={ "","̀" },
40148 [""]={ "","́" },
40149 [""]={ "","́" },
40150 [""]={ "Ε","̓" },
40151 [""]={ "Ε","̔" },
40152 [""]={ "","̀" },
40153 [""]={ "","̀" },
40154 [""]={ "","́" },
40155 [""]={ "","́" },
40156 [""]={ "η","̓" },
40157 [""]={ "η","̔" },
40158 [""]={ "","̀" },
40159 [""]={ "","̀" },
40160 [""]={ "","́" },
40161 [""]={ "","́" },
40162 [""]={ "","͂" },
40163 [""]={ "","͂" },
40164 [""]={ "Η","̓" },
40165 [""]={ "Η","̔" },
40166 [""]={ "","̀" },
40167 [""]={ "","̀" },
40168 [""]={ "","́" },
40169 [""]={ "","́" },
40170 [""]={ "","͂" },
40171 [""]={ "","͂" },
40172 [""]={ "ι","̓" },
40173 [""]={ "ι","̔" },
40174 [""]={ "","̀" },
40175 [""]={ "","̀" },
40176 [""]={ "","́" },
40177 [""]={ "","́" },
40178 [""]={ "","͂" },
40179 [""]={ "","͂" },
40180 [""]={ "Ι","̓" },
40181 [""]={ "Ι","̔" },
40182 [""]={ "","̀" },
40183 [""]={ "","̀" },
40184 [""]={ "","́" },
40185 [""]={ "","́" },
40186 [""]={ "","͂" },
40187 ["Ἷ"]={ "","͂" },
40188 [""]={ "ο","̓" },
40189 [""]={ "ο","̔" },
40190 [""]={ "","̀" },
40191 [""]={ "","̀" },
40192 [""]={ "","́" },
40193 [""]={ "","́" },
40194 [""]={ "Ο","̓" },
40195 [""]={ "Ο","̔" },
40196 [""]={ "","̀" },
40197 [""]={ "","̀" },
40198 [""]={ "","́" },
40199 [""]={ "","́" },
40200 [""]={ "υ","̓" },
40201 [""]={ "υ","̔" },
40202 [""]={ "","̀" },
40203 [""]={ "","̀" },
40204 [""]={ "","́" },
40205 [""]={ "","́" },
40206 [""]={ "","͂" },
40207 [""]={ "","͂" },
40208 [""]={ "Υ","̔" },
40209 [""]={ "","̀" },
40210 [""]={ "","́" },
40211 [""]={ "","͂" },
40212 [""]={ "ω","̓" },
40213 [""]={ "ω","̔" },
40214 [""]={ "","̀" },
40215 [""]={ "","̀" },
40216 [""]={ "","́" },
40217 [""]={ "","́" },
40218 [""]={ "","͂" },
40219 [""]={ "","͂" },
40220 [""]={ "Ω","̓" },
40221 [""]={ "Ω","̔" },
40222 [""]={ "","̀" },
40223 [""]={ "","̀" },
40224 [""]={ "","́" },
40225 [""]={ "","́" },
40226 [""]={ "","͂" },
40227 [""]={ "","͂" },
40228 [""]={ "α","̀" },
40229 [""]={ "ε","̀" },
40230 [""]={ "η","̀" },
40231 [""]={ "ι","̀" },
40232 [""]={ "ο","̀" },
40233 [""]={ "υ","̀" },
40234 [""]={ "ω","̀" },
40235 [""]={ "","ͅ" },
40236 [""]={ "","ͅ" },
40237 [""]={ "","ͅ" },
40238 [""]={ "","ͅ" },
40239 [""]={ "","ͅ" },
40240 [""]={ "","ͅ" },
40241 [""]={ "","ͅ" },
40242 [""]={ "","ͅ" },
40243 [""]={ "","ͅ" },
40244 [""]={ "","ͅ" },
40245 [""]={ "","ͅ" },
40246 [""]={ "","ͅ" },
40247 [""]={ "","ͅ" },
40248 [""]={ "","ͅ" },
40249 [""]={ "","ͅ" },
40250 [""]={ "","ͅ" },
40251 [""]={ "","ͅ" },
40252 [""]={ "","ͅ" },
40253 [""]={ "","ͅ" },
40254 [""]={ "","ͅ" },
40255 [""]={ "","ͅ" },
40256 [""]={ "","ͅ" },
40257 [""]={ "","ͅ" },
40258 [""]={ "","ͅ" },
40259 [""]={ "","ͅ" },
40260 [""]={ "","ͅ" },
40261 [""]={ "","ͅ" },
40262 [""]={ "","ͅ" },
40263 [""]={ "","ͅ" },
40264 [""]={ "","ͅ" },
40265 [""]={ "","ͅ" },
40266 [""]={ "","ͅ" },
40267 [""]={ "","ͅ" },
40268 [""]={ "","ͅ" },
40269 [""]={ "","ͅ" },
40270 [""]={ "","ͅ" },
40271 [""]={ "","ͅ" },
40272 [""]={ "","ͅ" },
40273 [""]={ "","ͅ" },
40274 [""]={ "","ͅ" },
40275 [""]={ "","ͅ" },
40276 [""]={ "","ͅ" },
40277 [""]={ "","ͅ" },
40278 [""]={ "","ͅ" },
40279 [""]={ "","ͅ" },
40280 [""]={ "","ͅ" },
40281 [""]={ "","ͅ" },
40282 [""]={ "","ͅ" },
40283 [""]={ "α","̆" },
40284 [""]={ "α","̄" },
40285 [""]={ "","ͅ" },
40286 [""]={ "α","ͅ" },
40287 [""]={ "ά","ͅ" },
40288 [""]={ "α","͂" },
40289 [""]={ "","ͅ" },
40290 [""]={ "Α","̆" },
40291 [""]={ "Α","̄" },
40292 [""]={ "Α","̀" },
40293 [""]={ "Α","ͅ" },
40294 [""]={ "¨","͂" },
40295 [""]={ "","ͅ" },
40296 [""]={ "η","ͅ" },
40297 [""]={ "ή","ͅ" },
40298 [""]={ "η","͂" },
40299 [""]={ "","ͅ" },
40300 [""]={ "Ε","̀" },
40301 [""]={ "Η","̀" },
40302 [""]={ "Η","ͅ" },
40303 [""]={ "᾿","̀" },
40304 [""]={ "᾿","́" },
40305 [""]={ "᾿","͂" },
40306 [""]={ "ι","̆" },
40307 [""]={ "ι","̄" },
40308 [""]={ "ϊ","̀" },
40309 [""]={ "ι","͂" },
40310 [""]={ "ϊ","͂" },
40311 [""]={ "Ι","̆" },
40312 [""]={ "Ι","̄" },
40313 [""]={ "Ι","̀" },
40314 [""]={ "","̀" },
40315 [""]={ "","́" },
40316 [""]={ "","͂" },
40317 [""]={ "υ","̆" },
40318 [""]={ "υ","̄" },
40319 [""]={ "ϋ","̀" },
40320 [""]={ "ρ","̓" },
40321 [""]={ "ρ","̔" },
40322 [""]={ "υ","͂" },
40323 [""]={ "ϋ","͂" },
40324 [""]={ "Υ","̆" },
40325 [""]={ "Υ","̄" },
40326 [""]={ "Υ","̀" },
40327 [""]={ "Ρ","̔" },
40328 [""]={ "¨","̀" },
40329 [""]={ "","ͅ" },
40330 [""]={ "ω","ͅ" },
40331 [""]={ "ώ","ͅ" },
40332 [""]={ "ω","͂" },
40333 [""]={ "","ͅ" },
40334 [""]={ "Ο","̀" },
40335 [""]={ "Ω","̀" },
40336 [""]={ "Ω","ͅ" },
40337 [""]={ "","̸" },
40338 [""]={ "","̸" },
40339 [""]={ "","̸" },
40340 [""]={ "","̸" },
40341 [""]={ "","̸" },
40342 [""]={ "","̸" },
40343 [""]={ "","̸" },
40344 [""]={ "","̸" },
40345 [""]={ "","̸" },
40346 [""]={ "","̸" },
40347 [""]={ "","̸" },
40348 [""]={ "","̸" },
40349 [""]={ "","̸" },
40350 [""]={ "","̸" },
40351 [""]={ "","̸" },
40352 [""]={ "=","̸" },
40353 [""]={ "","̸" },
40354 [""]={ "","̸" },
40355 [""]={ "<","̸" },
40356 [""]={ ">","̸" },
40357 [""]={ "","̸" },
40358 [""]={ "","̸" },
40359 [""]={ "","̸" },
40360 [""]={ "","̸" },
40361 [""]={ "","̸" },
40362 [""]={ "","̸" },
40363 [""]={ "","̸" },
40364 [""]={ "","̸" },
40365 [""]={ "","̸" },
40366 [""]={ "","̸" },
40367 [""]={ "","̸" },
40368 [""]={ "","̸" },
40369 [""]={ "","̸" },
40370 [""]={ "","̸" },
40371 [""]={ "","̸" },
40372 [""]={ "","̸" },
40373 [""]={ "","̸" },
40374 [""]={ "","̸" },
40375 [""]={ "","̸" },
40376 [""]={ "","̸" },
40377 [""]={ "","̸" },
40378 [""]={ "","̸" },
40379 [""]={ "","̸" },
40380 [""]={ "","̸" },
40381 [""]={ "","̸" },
40382 [""]={ "","" },
40383 [""]={ "","" },
40384 [""]={ "","" },
40385 [""]={ "","" },
40386 [""]={ "","" },
40387 [""]={ "","" },
40388 [""]={ "","" },
40389 [""]={ "","" },
40390 [""]={ "","" },
40391 [""]={ "","" },
40392 [""]={ "","" },
40393 [""]={ "","" },
40394 [""]={ "","" },
40395 [""]={ "","" },
40396 [""]={ "","" },
40397 [""]={ "","" },
40398 [""]={ "","" },
40399 [""]={ "","" },
40400 [""]={ "","" },
40401 [""]={ "","" },
40402 [""]={ "","" },
40403 [""]={ "","" },
40404 [""]={ "","" },
40405 [""]={ "","" },
40406 [""]={ "","" },
40407 [""]={ "","" },
40408 [""]={ "","" },
40409 [""]={ "","" },
40410 [""]={ "","" },
40411 [""]={ "","" },
40412 [""]={ "","" },
40413 [""]={ "","" },
40414 [""]={ "","" },
40415 [""]={ "","" },
40416 [""]={ "","" },
40417 [""]={ "","" },
40418 [""]={ "","" },
40419 [""]={ "","" },
40420 [""]={ "","" },
40421 [""]={ "","" },
40422 [""]={ "","" },
40423 [""]={ "","" },
40424 [""]={ "","" },
40425 [""]={ "","" },
40426 [""]={ "","" },
40427 [""]={ "","" },
40428 [""]={ "","" },
40429 [""]={ "","" },
40430 [""]={ "","" },
40431 [""]={ "","" },
40432 [""]={ "","" },
40433 [""]={ "","" },
40434 [""]={ "","" },
40435 [""]={ "","" },
40436 [""]={ "","" },
40437 [""]={ "","" },
40438 [""]={ "","" },
40439 [""]={ "","" },
40440 [""]={ "י","ִ" },
40441 [""]={ "ײ","ַ" },
40442 [""]={ "ש","ׁ" },
40443 [""]={ "ש","ׂ" },
40444 [""]={ "","ׁ" },
40445 [""]={ "","ׂ" },
40446 [""]={ "א","ַ" },
40447 [""]={ "א","ָ" },
40448 [""]={ "א","ּ" },
40449 [""]={ "ב","ּ" },
40450 [""]={ "ג","ּ" },
40451 [""]={ "ד","ּ" },
40452 [""]={ "ה","ּ" },
40453 [""]={ "ו","ּ" },
40454 [""]={ "ז","ּ" },
40455 [""]={ "ט","ּ" },
40456 [""]={ "י","ּ" },
40457 [""]={ "ך","ּ" },
40458 [""]={ "כ","ּ" },
40459 [""]={ "ל","ּ" },
40460 [""]={ "מ","ּ" },
40461 [""]={ "נ","ּ" },
40462 [""]={ "ס","ּ" },
40463 [""]={ "ף","ּ" },
40464 [""]={ "פ","ּ" },
40465 [""]={ "צ","ּ" },
40466 [""]={ "ק","ּ" },
40467 [""]={ "ר","ּ" },
40468 [""]={ "ש","ּ" },
40469 [""]={ "ת","ּ" },
40470 [""]={ "ו","ֹ" },
40471 [""]={ "ב","ֿ" },
40472 [""]={ "כ","ֿ" },
40473 [""]={ "פ","ֿ" },
40474 ["𑂚"]={ "𑂙","𑂺" },
40475 ["𑂜"]={ "𑂛","𑂺" },
40476 ["𑂫"]={ "𑂥","𑂺" },
40477 ["𑄮"]={ "𑄱","𑄧" },
40478 ["𑄯"]={ "𑄲","𑄧" },
40479 ["𑍋"]={ "𑍇","𑌾" },
40480 ["𑍌"]={ "𑍇","𑍗" },
40481 ["𑒻"]={ "𑒹","𑒺" },
40482 ["𑒼"]={ "𑒹","𑒰" },
40483 ["𑒾"]={ "𑒹","𑒽" },
40484 ["𑖺"]={ "𑖸","𑖯" },
40485 ["𑖻"]={ "𑖹","𑖯" },
40486 ["𝅗𝅥"]={ "𝅗","𝅥" },
40487 ["𝅘𝅥"]={ "𝅘","𝅥" },
40488 ["𝅘𝅥𝅮"]={ "𝅘𝅥","𝅮" },
40489 ["𝅘𝅥𝅯"]={ "𝅘𝅥","𝅯" },
40490 ["𝅘𝅥𝅰"]={ "𝅘𝅥","𝅰" },
40491 ["𝅘𝅥𝅱"]={ "𝅘𝅥","𝅱" },
40492 ["𝅘𝅥𝅲"]={ "𝅘𝅥","𝅲" },
40493 ["𝆹𝅥"]={ "𝆹","𝅥" },
40494 ["𝆺𝅥"]={ "𝆺","𝅥" },
40495 ["𝆹𝅥𝅮"]={ "𝆹𝅥","𝅮" },
40496 ["𝆺𝅥𝅮"]={ "𝆺𝅥","𝅮" },
40497 ["𝆹𝅥𝅯"]={ "𝆹𝅥","𝅯" },
40498 ["𝆺𝅥𝅯"]={ "𝆺𝅥","𝅯" },
40499   },
40500  },
40501 },
40502 ["name"]="collapse",
40503 ["prepend"]=true,
40504 ["type"]="ligature",
40505}
40506
40507end -- closure
40508
40509do -- begin closure to overcome local limits and interference
40510
40511if not modules then modules={} end modules ['luatex-fonts-gbn']={
40512 version=1.001,
40513 comment="companion to luatex-*.tex",
40514 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
40515 copyright="PRAGMA ADE / ConTeXt Development Team",
40516 license="see context related readme files"
40517}
40518if context then
40519--removed
40520
40521end
40522local next=next
40523local fonts=fonts
40524local nodes=nodes
40525local nuts=nodes.nuts 
40526local traverseid=nuts.traverseid
40527local flushnode=nuts.flushnode
40528local glyph_code=nodes.nodecodes.glyph
40529local disc_code=nodes.nodecodes.disc
40530local tonode=nuts.tonode
40531local tonut=nuts.tonut
40532local getfont=nuts.getfont
40533local getchar=nuts.getchar
40534local getid=nuts.getid
40535local getboth=nuts.getboth
40536local getprev=nuts.getprev
40537local getnext=nuts.getnext
40538local getdisc=nuts.getdisc
40539local setchar=nuts.setchar
40540local setlink=nuts.setlink
40541local setprev=nuts.setprev
40542local n_ligaturing=node.ligaturing
40543local n_kerning=node.kerning
40544local d_ligaturing=nuts.ligaturing
40545local d_kerning=nuts.kerning
40546local basemodepass=true
40547local function l_warning() logs.report("fonts","don't call 'node.ligaturing' directly") l_warning=nil end
40548local function k_warning() logs.report("fonts","don't call 'node.kerning' directly") k_warning=nil end
40549function node.ligaturing(...)
40550 if basemodepass and l_warning then
40551  l_warning()
40552 end
40553 return n_ligaturing(...)
40554end
40555function node.kerning(...)
40556 if basemodepass and k_warning then
40557  k_warning()
40558 end
40559 return n_kerning(...)
40560end
40561function nuts.ligaturing(...)
40562 if basemodepass and l_warning then
40563  l_warning()
40564 end
40565 return d_ligaturing(...)
40566end
40567function nuts.kerning(...)
40568 if basemodepass and k_warning then
40569  k_warning()
40570 end
40571 return d_kerning(...)
40572end
40573function nodes.handlers.setbasemodepass(v)
40574 basemodepass=v
40575end
40576local function nodepass(head,groupcode,size,packtype,direction)
40577 local fontdata=fonts.hashes.identifiers
40578 if fontdata then
40579  local usedfonts={}
40580  local basefonts={}
40581  local prevfont=nil
40582  local basefont=nil
40583  local variants=nil
40584  local redundant=nil
40585  local nofused=0
40586  for n in traverseid(glyph_code,head) do
40587   local font=getfont(n)
40588   if font~=prevfont then
40589    if basefont then
40590     basefont[2]=getprev(n)
40591    end
40592    prevfont=font
40593    local used=usedfonts[font]
40594    if not used then
40595     local tfmdata=fontdata[font] 
40596     if tfmdata then
40597      local shared=tfmdata.shared 
40598      if shared then
40599       local processors=shared.processes
40600       if processors and #processors>0 then
40601        usedfonts[font]=processors
40602        nofused=nofused+1
40603       elseif basemodepass then
40604        basefont={ n,nil }
40605        basefonts[#basefonts+1]=basefont
40606       end
40607      end
40608      local resources=tfmdata.resources
40609      variants=resources and resources.variants
40610      variants=variants and next(variants) and variants or false
40611     end
40612    else
40613     local tfmdata=fontdata[prevfont]
40614     if tfmdata then
40615      local resources=tfmdata.resources
40616      variants=resources and resources.variants
40617      variants=variants and next(variants) and variants or false
40618     end
40619    end
40620   end
40621   if variants then
40622    local char=getchar(n)
40623    if (char>=0xFE00 and char<=0xFE0F) or (char>=0xE0100 and char<=0xE01EF) then
40624     local hash=variants[char]
40625     if hash then
40626      local p=getprev(n)
40627      if p and getid(p)==glyph_code then
40628       local variant=hash[getchar(p)]
40629       if variant then
40630        setchar(p,variant)
40631       end
40632      end
40633     end
40634     if not redundant then
40635      redundant={ n }
40636     else
40637      redundant[#redundant+1]=n
40638     end
40639    end
40640   end
40641  end
40642  local nofbasefonts=#basefonts
40643  if redundant then
40644   for i=1,#redundant do
40645    local r=redundant[i]
40646    local p,n=getboth(r)
40647    if r==head then
40648     head=n
40649     setprev(n)
40650    else
40651     setlink(p,n)
40652    end
40653    if nofbasefonts>0 then
40654     for i=1,nofbasefonts do
40655      local bi=basefonts[i]
40656      if r==bi[1] then
40657       bi[1]=n
40658      end
40659      if r==bi[2] then
40660       bi[2]=n
40661      end
40662     end
40663    end
40664    flushnode(r)
40665   end
40666  end
40667  for d in traverseid(disc_code,head) do
40668   local _,_,r=getdisc(d)
40669   if r then
40670    for n in traverseid(glyph_code,r) do
40671     local font=getfont(n)
40672     if font~=prevfont then
40673      prevfont=font
40674      local used=usedfonts[font]
40675      if not used then
40676       local tfmdata=fontdata[font] 
40677       if tfmdata then
40678        local shared=tfmdata.shared 
40679        if shared then
40680         local processors=shared.processes
40681         if processors and #processors>0 then
40682          usedfonts[font]=processors
40683          nofused=nofused+1
40684         end
40685        end
40686       end
40687      end
40688     end
40689    end
40690   end
40691  end
40692  if next(usedfonts) then
40693   for font,processors in next,usedfonts do
40694    for i=1,#processors do
40695     head=processors[i](head,font,0,direction,nofused) or head
40696    end
40697   end
40698  end
40699  if basemodepass and nofbasefonts>0 then
40700   for i=1,nofbasefonts do
40701    local range=basefonts[i]
40702    local start=range[1]
40703    local stop=range[2]
40704    if start then
40705     local front=head==start
40706     local prev,next
40707     if stop then
40708      next=getnext(stop)
40709      start,stop=d_ligaturing(start,stop)
40710      start,stop=d_kerning(start,stop)
40711     else
40712      prev=getprev(start)
40713      start=d_ligaturing(start)
40714      start=d_kerning(start)
40715     end
40716     if prev then
40717      setlink(prev,start)
40718     end
40719     if next then
40720      setlink(stop,next)
40721     end
40722     if front and head~=start then
40723      head=start
40724     end
40725    end
40726   end
40727  end
40728 end
40729 return head
40730end
40731local function basepass(head)
40732 if basemodepass then
40733  head=d_ligaturing(head)
40734  head=d_kerning(head)
40735 end
40736 return head
40737end
40738local protectpass=node.direct.protectglyphs or node.direct.protect_glyphs
40739local injectpass=nodes.injections.handler
40740function nodes.handlers.nodepass(head,...)
40741 if head then
40742  return tonode(nodepass(tonut(head),...))
40743 end
40744end
40745function nodes.handlers.basepass(head)
40746 if head then
40747  return tonode(basepass(tonut(head)))
40748 end
40749end
40750function nodes.handlers.injectpass(head)
40751 if head then
40752  return tonode(injectpass(tonut(head)))
40753 end
40754end
40755function nodes.handlers.protectpass(head)
40756 if head then
40757  protectpass(tonut(head))
40758  return head
40759 end
40760end
40761function nodes.simple_font_handler(head,groupcode,size,packtype,direction)
40762 if head then
40763  head=tonut(head)
40764  head=nodepass(head,groupcode,size,packtype,direction)
40765  head=injectpass(head)
40766  if not basemodepass then
40767   head=basepass(head)
40768  end
40769  protectpass(head)
40770  head=tonode(head)
40771 end
40772 return head
40773end
40774
40775end -- closure
40776